Frontend Documentation
Overview
Vue 3 + Vite-based single-page application for the Learning Platform.
Architecture
frontend/
├── src/
│ ├── assets/ # Static assets (CSS, images)
│ ├── components/ # Reusable Vue components
│ │ ├── TerminalComponent.vue # XTerm.js terminal
│ │ └── ...
│ ├── views/ # Page components
│ │ ├── Dashboard.vue # Student dashboard
│ │ ├── AdminDashboard.vue # Admin panel
│ │ ├── Sandbox.vue # Sandbox environment
│ │ ├── ExamList.vue # Exam catalog
│ │ ├── ExamAttempt.vue # Exam taking view
│ │ └── Login.vue # Authentication
│ ├── services/ # API client
│ │ └── api.js # Axios-based API service
│ ├── router/ # Vue Router configuration
│ │ └── index.js
│ ├── App.vue # Root component
│ └── main.js # Application entry point
├── Dockerfile
├── nginx.conf # Nginx configuration for SPA
├── package.json
└── vite.config.js
Key Components
1. Terminal Component (TerminalComponent.vue)
- Based on XTerm.js and xterm-addon-fit
- WebSocket connection to backend terminal endpoint
- Features:
- Auto-reconnect on connection loss
- Terminal resize handling
- Bidirectional communication with container
Usage:
<TerminalComponent
:containerId="container.id"
:containerIp="container.ip_address"
@connected="handleConnected"
@error="handleError"
/>
2. Dashboard (Dashboard.vue)
- User statistics display
- Activity timeline
- Performance charts (Chart.js)
- Quick links to sandbox and exams
Data Structure:
{
lessons_completed: 0,
total_lessons: 0,
progress_percentage: 0,
exams_taken: 0,
exams_passed: 0,
average_score: 0,
current_streak: 1
}
3. Admin Dashboard (AdminDashboard.vue)
- Tabbed interface: Overview, Users, Exams, Attempts
- User management (create, update role, delete)
- Exam management (CRUD operations)
- System statistics display
4. Sandbox (Sandbox.vue)
- Environment selection (Ubuntu/CentOS)
- Container lifecycle management
- Integrated terminal
- Container status monitoring
5. Exam System
ExamList (ExamList.vue)
- Grid display of available exams
- Exam status badges (Not Started, In Progress, Passed, Failed)
- Start/Resume exam buttons
ExamAttempt (ExamAttempt.vue)
- Task list with descriptions
- Integrated terminal
- Timer countdown
- Submit exam button
API Service (services/api.js)
Configuration
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
const api = axios.create({
baseURL: API_BASE_URL,
headers: { 'Content-Type': 'application/json' },
withCredentials: true
});
Interceptors
- Request: Automatically adds JWT token from localStorage
- Response: Handles 401 errors (redirects to login)
API Methods
Authentication
authAPI.login(username, password)
authAPI.register(userData)
authAPI.me()
authAPI.logout()
Containers
containerAPI.create(sandboxType)
containerAPI.getSandbox()
containerAPI.get(containerId)
containerAPI.start(containerId)
containerAPI.stop(containerId)
containerAPI.delete(containerId)
Exams
examAPI.getAll()
examAPI.get(examId)
examAPI.getMyAttempts()
examAPI.start(examId)
examAPI.submit(examId)
examAPI.getResults(attemptId)
Dashboard
dashboardAPI.getStats()
dashboardAPI.getActivity(limit)
dashboardAPI.getAnalytics()
Routing
Public Routes
/- Landing page/login- Login page/register- Registration page
Protected Routes (Require Authentication)
/dashboard- Student dashboard/sandbox- Sandbox environment/exams- Exam list/exams/:id- Exam details/exams/:id/attempt- Take exam/admin- Admin panel (requires admin role)
Route Guards
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('token');
if (to.meta.requiresAuth && !token) {
next('/login');
} else if (to.meta.requiresAdmin && !isAdmin()) {
next('/dashboard');
} else {
next();
}
});
State Management
Currently using Vue 3 Composition API with reactive state. No Vuex/Pinia needed for MVP.
Shared State Pattern
// composables/useAuth.js
export function useAuth() {
const user = ref(null);
const isAuthenticated = computed(() => !!user.value);
const login = async (credentials) => {
const response = await authAPI.login(credentials);
localStorage.setItem('token', response.access_token);
user.value = await authAPI.me();
};
return { user, isAuthenticated, login };
}
Styling
Technology
- Vanilla CSS (no preprocessor)
- CSS Grid and Flexbox for layouts
- CSS Variables for theming
Design System
:root {
--primary-color: #3b82f6;
--success-color: #10b981;
--danger-color: #ef4444;
--warning-color: #f59e0b;
--bg-color: #1f2937;
--surface-color: #374151;
--text-color: #f9fafb;
}
Responsive Breakpoints
- Mobile: < 640px
- Tablet: 640px - 1024px
- Desktop: > 1024px
Build & Deployment
Development
npm install
npm run dev # Runs on http://localhost:5173
Production Build
npm run build # Output: dist/
Docker Build
FROM node:18-alpine as build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
Environment Variables
# .env
VITE_API_URL=https://mvp-api.zafarsaidov.uz
WebSocket Terminal Connection
Connection Flow
- Get JWT token from localStorage
- Connect to
wss://mvp-api.zafarsaidov.uz/ws/terminal/{containerId}?token={jwt} - Handle connection states: connecting, connected, disconnected, error
- Auto-reconnect on disconnect (up to 3 attempts)
Message Format
// Client → Server
{ type: 'input', data: 'ls -la\n' }
{ type: 'resize', data: { cols: 80, rows: 24 } }
// Server → Client
{ type: 'output', data: 'file1\nfile2\n' }
{ type: 'error', data: 'Connection failed' }
Performance Optimizations
- Code Splitting: Route-based lazy loading
- Asset Optimization: Vite's built-in minification
- Caching: Browser cache for static assets (1 year)
- API Caching: Store frequently accessed data in localStorage
- Terminal: Virtual scrolling for large output
Browser Support
- Chrome/Edge: Latest 2 versions
- Firefox: Latest 2 versions
- Safari: Latest 2 versions
- Mobile: iOS Safari 14+, Chrome Android 90+
Dependencies
Core
Terminal
Charts
Development
- [email protected]
- @vitejs/plugin-[email protected]
Common Issues
-
CORS Errors
- Check nginx configuration allows your origin
- Verify API_BASE_URL is correct
-
Terminal Not Connecting
- Check WebSocket URL includes token
- Verify backend WebSocket endpoint is accessible
- Check browser console for errors
-
404 on Refresh
- Ensure nginx
try_filesincludes fallback to index.html - SPA routing requires all routes to serve index.html
- Ensure nginx
-
Build Failures
- Clear node_modules and reinstall
- Check Node.js version (requires 16+)
- Verify all environment variables are set