Skip to main content

Project Structure

mvp-v2/
├── CLAUDE.md # Project standards and patterns
├── SPEC.md # Full technical specification
├── CHANGELOG.md # Version changelog
├── docker-compose.yml # Local dev (postgres, redis, backend, vite)
├── docker-compose.prod.yml # Production (+ nginx)
├── .env.example # Required backend env vars template

├── docs/
│ ├── BACKEND.md # Backend architecture reference
│ ├── FRONTEND.md # Frontend architecture reference
│ ├── LXD.md # LXD container setup
│ ├── SERVER.md # Server configuration
│ ├── auth-design.md # Authentication design
│ ├── audits/ # Code/UX audit reports
│ ├── plans/ # Implementation plans
│ └── standards/ # Coding standards (this directory)

├── backend/
│ ├── Dockerfile
│ ├── requirements.txt
│ ├── .env # Local secrets (gitignored)
│ ├── .env.example # Committed template
│ ├── alembic.ini
│ ├── alembic/
│ │ └── versions/ # Migration files (001_*.py ... NNN_*.py)
│ └── app/
│ ├── main.py # FastAPI entry point, container/auth endpoints, WebSocket
│ ├── auth.py # JWT creation and validation, password hashing
│ ├── config.py # Pydantic Settings (reads from env)
│ ├── database.py # AsyncSession factory
│ ├── lxc_manager.py # LXD container lifecycle (HTTPS API)
│ ├── websocket.py # Terminal WebSocket → SSH tunnel
│ ├── db/
│ │ ├── models.py # All SQLAlchemy ORM models
│ │ └── init_db.py # DB init and seed data
│ ├── api/
│ │ ├── admin.py # Admin CRUD (requires admin role)
│ │ ├── exams.py # Exam lifecycle
│ │ ├── laboratories.py # Lab practice
│ │ ├── lessons.py # Lesson viewing and progress
│ │ ├── dashboard.py # Stats and activity
│ │ ├── modules.py # Module listing
│ │ └── profile.py # User profile and avatar
│ └── services/
│ ├── lessons_service.py # Markdown from private GitLab repo
│ ├── exam_verifier.py # SSH-based exam grading
│ └── laboratory_verifier.py # SSH-based lab grading

├── frontend/
│ ├── Dockerfile
│ ├── package.json
│ ├── package-lock.json
│ ├── vite.config.js
│ ├── .env # Local dev (VITE_API_URL)
│ ├── .env.production # Production API URL (committed)
│ └── src/
│ ├── main.js # Vue app init, router, auth guards
│ ├── services/
│ │ └── api.js # All API methods (single source of truth)
│ ├── views/ # Route-level components (one per route)
│ │ ├── Login.vue
│ │ ├── Register.vue
│ │ ├── Dashboard.vue
│ │ ├── LessonViewer.vue
│ │ ├── ExamAttempt.vue
│ │ ├── ExamResults.vue
│ │ ├── LaboratoryAttempt.vue
│ │ ├── Sandbox.vue
│ │ ├── Profile.vue
│ │ └── AdminDashboard.vue
│ └── components/ # Reusable components
│ ├── MainLayout.vue
│ ├── Sidebar.vue
│ ├── TerminalComponent.vue
│ ├── PerformanceChart.vue
│ ├── ActivityTimeline.vue
│ ├── ProgressCard.vue
│ └── ProfileMenu.vue

├── nginx/
│ └── nginx.conf # Reverse proxy: SPA + /api/ + /ws/

└── scripts/
├── deploy.sh # Production deploy script
├── setup-lxd.sh # LXD server setup
└── build-exam-image.sh # Build custom LXD image with SSH

Rules

  • One router file per domain in backend/app/api/ — don't merge exam and lesson logic
  • All API methods in api.js — never call axios directly from Vue components
  • One view file per route in frontend/src/views/
  • Reusable components in components/ — if used in more than one view
  • All ORM models in db/models.py — single source of truth for database schema
  • Migrations in alembic/versions/ — one file per logical schema change