37 lines
1.6 KiB
Markdown
37 lines
1.6 KiB
Markdown
# Minimal Architecture (Django + Angular)
|
|
|
|
## Goals
|
|
- Read exam JSON from `input/`, render online, autosave progress, submit, and write bundled JSON to `output/`.
|
|
- Keep logic simple, deterministic, and file-backed.
|
|
|
|
## Components
|
|
- Frontend: Angular SPA (exam UI, autosave, timer, resume)
|
|
- Backend: Django REST API (file I/O, attempt state, publish/finish checks)
|
|
- Storage: File system folders (`input/`, `attempts/`, `output/`, `progress/`, `manifest.json`)
|
|
- Web: Nginx (serve Angular, proxy `/api/` to Django)
|
|
|
|
## Data Flow
|
|
1. Angular requests `/api/exams` → Django lists published exams by reading `manifest.json` + `input/`.
|
|
2. Start/resume attempt: `/api/exams/{examId}/attempt` → Django reads/writes `attempts/` and returns current attempt JSON.
|
|
3. Autosave: PUT `/api/attempts/{attemptId}` → backend persists answers and updates `progress/`.
|
|
4. Submit: POST `/api/attempts/{attemptId}/submit` → backend writes `output/{examId}_{attemptId}.json` with `{ exam, attempt }` and marks finished.
|
|
|
|
## Minimal State Machine
|
|
- draft → published → in_progress → submitted → finished
|
|
|
|
## Files & Folders
|
|
- `input/` — source exam JSON files
|
|
- `attempts/{userId}/{examId}/{attemptId}.json` — current attempt
|
|
- `output/{examId}_{attemptId}.json` — final bundle `{ exam, attempt }`
|
|
- `progress/{userId}.json` — per-user progress snapshot
|
|
- `manifest.json` — registry of exams (published flags) and per-user finished set
|
|
|
|
## Security (minimal)
|
|
- Auth: simple token cookie, userId in session
|
|
- CORS/CSRF configured for Angular origin
|
|
- No external services required
|
|
|
|
## Observability
|
|
- Request logs, error logs
|
|
- Autosave frequency metric (client)
|