Skip to main content

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 --from=build /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

  1. Get JWT token from localStorage
  2. Connect to wss://mvp-api.zafarsaidov.uz/ws/terminal/{containerId}?token={jwt}
  3. Handle connection states: connecting, connected, disconnected, error
  4. 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

  1. Code Splitting: Route-based lazy loading
  2. Asset Optimization: Vite's built-in minification
  3. Caching: Browser cache for static assets (1 year)
  4. API Caching: Store frequently accessed data in localStorage
  5. 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

Common Issues

  1. CORS Errors

    • Check nginx configuration allows your origin
    • Verify API_BASE_URL is correct
  2. Terminal Not Connecting

    • Check WebSocket URL includes token
    • Verify backend WebSocket endpoint is accessible
    • Check browser console for errors
  3. 404 on Refresh

    • Ensure nginx try_files includes fallback to index.html
    • SPA routing requires all routes to serve index.html
  4. Build Failures

    • Clear node_modules and reinstall
    • Check Node.js version (requires 16+)
    • Verify all environment variables are set