# JSON I/O, State Machine, and Folders (Minimal) ## Folders - `input/` — source exam JSON files - `attempts/{userId}/{examId}/{attemptId}.json` — current attempt files - `output/{examId}_{attemptId}.json` — final bundle `{ exam, attempt }` - `progress/{userId}.json` — per-user snapshot - `manifest.json` — registry of published exams and user completion ## Input Exam JSON - Must conform to `docs/exam-format.md` ## Attempt JSON ``` { "attemptId": "", "userId": "", "examId": "", "status": "in_progress|submitted|finished", "startedAt": "ISO-8601", "updatedAt": "ISO-8601", "submittedAt": "ISO-8601?", "answers": [ { "questionId": "q1", "response": , "timeSec": 25 } ] } ``` ## Output JSON ``` { "exam": { /* original exam JSON */ }, "attempt": { /* final attempt JSON */ } } ``` ## State Machine - `draft` → `published` → `in_progress` → `submitted` → `finished` ## Publish & Finish - Publish: `manifest.json` marks `{ examId, published: true }` - Finish for a user: attempt.status `finished` AND output bundle exists AND manifest.users[userId].finished includes examId ## Autosave & Integrity - Write to temp file then atomic rename for attempts/progress/output/manifest - Server returns `updatedAt` for reconciliation - One active attempt per exam per user (simple lock) ## Naming - `attemptId = --` - Output file name: `_.json` ## Versioning - Store `examVersion` in attempt; warn on resume if drift ## Permissions (minimal) - Local file permissions: read-only for `input/`; write for others