92 lines
5.2 KiB
Markdown
92 lines
5.2 KiB
Markdown
# Lomda Hub - AI Coding Agent Instructions
|
|
|
|
## Architecture Overview
|
|
|
|
**Stack**: React+Vite (TypeScript) frontend, FastAPI backend, PostgreSQL database with SQLAlchemy 2.0 ORM, Alembic migrations.
|
|
|
|
**Deployment**: Docker Compose with 3 services (db, backend, frontend). Frontend on 5173, backend on 8000, postgres on 5433.
|
|
|
|
**Auth**: JWT access/refresh tokens + Google OAuth. Tokens passed via `Authorization: Bearer` header. Two roles: `admin` and `learner`.
|
|
|
|
## Key Structural Patterns
|
|
|
|
### Backend Structure
|
|
- **Models** ([backend/app/models.py](../backend/app/models.py)): SQLAlchemy 2.0 with type hints (`Mapped[T]`). Enums: `UserRole`, `ModuleType`, `ProgressStatus`, `QuestionType`.
|
|
- **Routers**: Three main routers in [backend/app/routers](../backend/app/routers): `auth.py` (login/register/OAuth), `admin.py` (course/module CRUD), `learner.py` (enrollments/progress).
|
|
- **Dependencies** ([backend/app/deps.py](../backend/app/deps.py)): `get_db()` for DB sessions, `get_current_user()` for auth, `require_admin()` for admin-only routes.
|
|
- **Config** ([backend/app/core/config.py](../backend/app/core/config.py)): Settings loaded from env vars using Pydantic `BaseSettings`.
|
|
|
|
### Frontend Structure
|
|
- **Pages** ([frontend/src/pages](../frontend/src/pages)): Each major view (login, courses, player, admin dashboard/editor) as separate page component.
|
|
- **API Client** ([frontend/src/api](../frontend/src/api)): Centralized API calls. Token management in `client.ts` with localStorage.
|
|
- **Routing**: React Router v6 in [App.tsx](../frontend/src/App.tsx). Admin routes prefixed with `/admin`.
|
|
|
|
### Data Flow: Locked Course Progression
|
|
Courses have ordered modules. Learner must complete module N before unlocking N+1:
|
|
1. On enrollment, first module is `unlocked`, rest are `locked` (see `ModuleProgress` model).
|
|
2. Content modules: mark completed when viewed.
|
|
3. Quiz modules: mark completed only if attempt passes (`score >= pass_score`).
|
|
4. Backend logic in [learner.py](../backend/app/routers/learner.py): `submit_quiz_attempt` updates progress and unlocks next module.
|
|
|
|
## Critical Workflows
|
|
|
|
### Database Migrations
|
|
1. After model changes: `cd backend && alembic revision --autogenerate -m "description"`
|
|
2. Apply: `alembic upgrade head` (or `docker compose restart backend` for Docker)
|
|
3. Seed data: `python -m app.scripts.seed` (creates admin user + sample data)
|
|
|
|
### Development Commands
|
|
**Docker**: `docker compose up --build` (runs migrations + seed automatically via Dockerfile CMD)
|
|
**Local backend**: `uvicorn app.main:app --reload` (from backend dir with venv active)
|
|
**Local frontend**: `npm run dev` (from frontend dir)
|
|
|
|
### Google OAuth Flow
|
|
- Login: GET `/auth/google/login` → redirects to Google → callback at `/auth/google/callback`
|
|
- Callback returns `RedirectResponse` to `FRONTEND_URL/auth/callback?access_token=...&refresh_token=...`
|
|
- Frontend ([GoogleCallbackPage.tsx](../frontend/src/pages/GoogleCallbackPage.tsx)) extracts tokens from URL params and saves to localStorage
|
|
- **Critical**: FastAPI route must NOT have trailing slash mismatch or it will 307 redirect infinitely
|
|
|
|
## Project-Specific Conventions
|
|
|
|
### API Response Patterns
|
|
- Use Pydantic schemas for request/response validation (see [schemas.py](../backend/app/schemas.py))
|
|
- Admin endpoints return extended models with `group_ids` arrays
|
|
- Learner endpoints filter by current user (never expose other learners' data)
|
|
|
|
### Error Handling
|
|
- Raise `HTTPException` with appropriate status codes (400 bad request, 401 unauthorized, 403 forbidden, 404 not found)
|
|
- No generic try/except unless specific recovery logic needed
|
|
|
|
### Database Relationships
|
|
- Use SQLAlchemy relationship cascades: `cascade="all, delete-orphan"` for parent→child
|
|
- Unique constraints for enrollment, progress, group membership: prevent duplicates via `__table_args__`
|
|
|
|
### Frontend State Management
|
|
- No global state library; use React hooks + fetch in components
|
|
- Token refresh: not auto-implemented; tokens expire after 30min (access) / 7days (refresh)
|
|
|
|
## Integration Points
|
|
|
|
### External Dependencies
|
|
- Google OAuth: requires `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `GOOGLE_REDIRECT_URI` env vars
|
|
- SMTP: config present but not actively used (future email features)
|
|
|
|
### Cross-Component Communication
|
|
- Frontend calls backend REST API; no WebSockets or real-time updates
|
|
- CORS: configured in [main.py](../backend/app/main.py) via `CORS_ORIGINS` env var (default: `http://localhost:5173`)
|
|
|
|
## Common Gotchas
|
|
|
|
1. **Trailing slashes**: FastAPI auto-redirects `/path/` to `/path` (307). Define routes without trailing slashes consistently.
|
|
2. **Password hashing**: bcrypt truncates at 72 bytes; see defensive check in [auth.py](../backend/app/auth.py).
|
|
3. **Module ordering**: `order_index` is manually managed. No auto-reordering on deletion.
|
|
4. **Admin seed**: Default admin created with email from `ADMIN_SEED_EMAIL` env var (default: `admin@example.com`).
|
|
|
|
## Key Files to Reference
|
|
|
|
- [models.py](../backend/app/models.py): All database schema
|
|
- [schemas.py](../backend/app/schemas.py): Request/response validation
|
|
- [deps.py](../backend/app/deps.py): Auth dependencies
|
|
- [learner.py](../backend/app/routers/learner.py): Core learning flow logic
|
|
- [App.tsx](../frontend/src/App.tsx): Frontend routing and navigation
|