1.6 KiB
1.6 KiB
JSON I/O, State Machine, and Folders (Minimal)
Folders
input/— source exam JSON filesattempts/{userId}/{examId}/{attemptId}.json— current attempt filesoutput/{examId}_{attemptId}.json— final bundle{ exam, attempt }progress/{userId}.json— per-user snapshotmanifest.json— registry of published exams and user completion
Input Exam JSON
- Must conform to
docs/exam-format.md
Attempt JSON
{
"attemptId": "<id>",
"userId": "<user>",
"examId": "<exam>",
"status": "in_progress|submitted|finished",
"startedAt": "ISO-8601",
"updatedAt": "ISO-8601",
"submittedAt": "ISO-8601?",
"answers": [ { "questionId": "q1", "response": <any>, "timeSec": 25 } ]
}
Output JSON
{
"exam": { /* original exam JSON */ },
"attempt": { /* final attempt JSON */ }
}
State Machine
draft→published→in_progress→submitted→finished
Publish & Finish
- Publish:
manifest.jsonmarks{ examId, published: true } - Finish for a user: attempt.status
finishedAND 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
updatedAtfor reconciliation - One active attempt per exam per user (simple lock)
Naming
attemptId = <userId>-<examId>-<timestamp>- Output file name:
<examId>_<attemptId>.json
Versioning
- Store
examVersionin attempt; warn on resume if drift
Permissions (minimal)
- Local file permissions: read-only for
input/; write for others