Creating & Publishing Test Content
Creation flow
CreateContent.tsx (src/ui/pages/admin/) provides form-based creation for each module's nested entity tree:
- Reading: test → passages → question groups → questions
- Writing: test → tasks
- Listening: test → sections → question groups → questions
Draft / Published status
Every test row (reading_tests, writing_tests, listening_tests) has a status column defaulting to 'draft'. There is no database-level CHECK constraint restricting it to draft/published (unlike user_test_sessions.status or user_roles.role, which do have CHECK constraints) — it's a free-form string field, conventionally set to 'draft' or 'published' by the admin UI.
Ownership/visibility is enforced in the repository layer's find_by_id/find_all queries, which return a row if the requester is its created_by owner or its status is 'published':
"SELECT ... FROM reading_tests WHERE id = ? AND (created_by = ? OR status = 'published')"
This means a non-owner cannot see another admin's draft test — see the export authorization note in Exporting Tests as ZIP Archives for the same pattern applied to the export flow.
Pre-publish review
TestPreviewModal (src/ui/components/admin/TestPreviewModal.tsx) renders a candidate-facing preview of a test before an admin toggles it to published, letting them sanity-check passage/section/task content and question rendering without leaving the CMS.
Content Library menu actions
Each row in ContentLibrary.tsx has a 3-dot menu with three actions, in this order:
- Edit — navigates to the edit form for that test.
- Export — downloads the test as a
.zip(see Exporting Tests as ZIP Archives). - Delete — prompts a confirmation dialog, then calls the corresponding
delete_*_testscommand.