Appearance
Task Breakdown
Phase: 1 Architecture Plan Status: backlog before Go implementation
Phase 0 Audit Tasks
| ID | Task | Output | Status |
|---|---|---|---|
| P0-001 | Inventory repo structure, backend entrypoints, runtime roles | current-system-audit.md | Done |
| P0-002 | Extract grouped legacy API route map | legacy-api-map.md | Done |
| P0-003 | Inventory Prisma models/enums and ownership buckets | legacy-database-inventory.md | Done |
| P0-004 | Capture auth, tenant, import, question, exam, attempt rules | legacy-business-rules.md | Done |
| P0-005 | Draft legacy DB ownership map | legacy-database-map.md | Done |
Phase 1 Planning Tasks
| ID | Task | Output | Status |
|---|---|---|---|
| P1-001 | Define target Go service topology | target-go-microservices.md | Done |
| P1-002 | Define service boundaries | service-boundaries.md | Done |
| P1-003 | Define DB-per-service strategy | database-per-service-strategy.md | Done |
| P1-004 | Define service database implementation rules | database-strategy.md | Done |
| P1-005 | Define gateway/API contract strategy | api-contract-strategy.md | Done |
| P1-006 | Define migration phases | migration-plan.md | Done |
| P1-007 | Define migration/data validation/rollback docs | docs/migration/* | Done |
| P1-008 | Define agent orchestration and handoff format | docs/agents/* | Done |
| P1-009 | Maintain decision log and risk register | decision-log.md, risk-register.md | Done |
Phase 2 Platform Skeleton Tasks
These are the first implementation tasks after docs are accepted.
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P2-001 | Initialize Go workspace/module under go-platform/ | platform | Done | go test ./... passes with no legacy file changes. |
| P2-002 | Add shared config package | platform | Done | Env loading and service defaults exist. Production secret guards remain for domain services. |
| P2-003 | Add shared logging/request context package | platform | Done | JSON logs include request and correlation IDs. |
| P2-004 | Add shared error/envelope package | platform | Done | Gateway can map internal errors to JSON responses. |
| P2-005 | Add health/ready/metrics helpers | platform | Done | Every service skeleton exposes /healthz, /readyz, /metrics. |
| P2-006 | Build proxy-only api-gateway | api-gateway | Done | /api/* forwards to legacy; /api/health/* compatibility present. |
| P2-007 | Add gateway route state table | api-gateway | Done | Routes can be marked legacy_proxy, shadow_read, native_read, native_write. |
| P2-008 | Add Docker Compose for Go platform dependencies | platform | Done | Compose syntax validates for gateway, sample service, Postgres, Redis, MinIO, and NATS. |
| P2-009 | Add service skeletons | all services | Done | Each target service has cmd, health, config, logger. |
| P2-010 | Add OpenAPI generation placeholder | platform | Done | Placeholder contracts exist for gateway and all target services. |
Phase 3 First Route Tasks
| ID | Task | Service/Area | Definition Of Done |
|---|---|---|---|
| P3-001 | Capture legacy OpenAPI/route snapshot | api-gateway | Done. Static NestJS controller route snapshot is stored under go-platform/docs/contracts/legacy/ as JSON plus Markdown, covering all 430 legacy controller routes across 36 controller files with method/path/handler/source evidence, global /api prefix, /api/v1 compatibility alias, grouped counts, and a reproducible make test-legacy-route-snapshot check. Full Nest Swagger export can still be added later for request/response schemas, but route migration has an immutable legacy path inventory. |
| P3-002 | Implement document-service media asset read parity | document-service | Partial. Metadata create/list/get, legacy-shaped /v1/storage/presigned-upload, /v1/storage/media-assets, content streaming with `variant=trim |
| P3-003 | Implement question type list parity | question-bank-service | Partial. Native GET /v1/question-types returns the legacy success envelope, active core system definitions, actor-scoped custom definitions, summary/status/q filters, OpenAPI, tests, service-owned question_type_definitions migration, pgx/memory stores, and gateway shadow/native read examples. P3-012 adds opt-in browser-route evidence tooling for /teacher/questions/types. Full default cutover remains pending on executing live browser parity against a running gateway/native service and approving default route promotion. |
| P3-004 | Implement shadow-read diff runner | api-gateway | Done. Gateway returns legacy response, calls native target for safe read methods, and logs status match/diff without affecting response. |
| P3-005 | Implement DOCX import job status read model | docx-import-service | Partial. Native /v1/import/docx/teacher-library, /v1/import/docx/jobs/events, and /v1/import/docx/jobs/{id}/status now project service-owned DOCX jobs into legacy-shaped summary/status/SSE fields for stored jobs. P3-007 adds non-default gateway adapter examples, and P3-008 adds opt-in gateway auth/header injection for selected native routes. P4-001 adds in-process live SSE fanout, P4-008 adds Redis multi-process fanout, P4-009 adds native queue snapshots, P4-010 adds durable payload refs/recovery, P4-026 wires the queued payload spool to persistent offline K8s/Helm storage, P4-027 adds a read-only BullMQ snapshot bridge for legacy queue depth/position during cutover, P4-028 adds opt-in live-smoke tooling for the status route plus bridge queue fields, P4-029 adds browser-route smoke tooling for /teacher/exams/library, and P4-030 adds static import-status route coverage. Default gateway cutover and executing live browser verification remain pending. |
| P3-006 | Add method-aware gateway routes | api-gateway | Done. Gateway route entries support methods, exact, and suffix_segments, so read-only routes such as GET /api/questions and GET /api/questions/:id can be shadowed independently while write methods and nested subroutes remain on legacy. Rollback is deleting the specific route entry or setting it back to legacy_proxy. |
| P3-007 | Add DOCX import status/history gateway adapter examples | api-gateway, docx-import-service | Done. Added non-default Compose/localhost route-table examples and gateway regression coverage for GET /api/exam-import/teacher-library, GET /api/exam-import/algorithm-jobs/events, GET /api/exam-import/jobs/:id/status, and GET /api/imports/:jobId/status rewriting to native P3-005 endpoints while sibling import routes and the default route table stay legacy. |
| P3-008 | Add gateway auth header adapter foundation | api-gateway | Done. Route entries can opt into require_auth, required_roles, and require_organization; the gateway verifies legacy-shaped access tokens from Authorization/cookie, enforces route roles, derives organization context, and forwards native identity/organization headers while default routes stay legacy. |
| P3-009 | Add question type GET native route rehearsal | api-gateway, question-bank-service | Done. Added non-default GET-only exact shadow/native route examples and static coverage for /api/question-types read rehearsal, while keeping POST/PATCH/DELETE and nested question-type routes on the broad legacy fallback. Default route table remains legacy until native write parity and browser cutover evidence are available. Verified by route JSON parse, shell syntax, make test-question-types-routes, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P3-010 | Add native question type write foundation | question-bank-service, api-gateway | Done. Added native POST /v1/question-types, PATCH /v1/question-types/{id}, DELETE /v1/question-types/{id}, PATCH /v1/question-types/bulk-status, and POST /v1/question-types/bulk-delete; preserved legacy validation, actor-scoped custom conflicts, system-type admin guard, unused custom hard-delete vs archive behavior, OpenAPI/docs, service-owned actor-scope migration, focused service/gateway tests, and non-default native write route examples. Default /api/question-types remains legacy until browser parity and route promotion are proven. Verified by focused question-bank tests, focused gateway tests, route coverage, OpenAPI parse/mirror diff, full Go tests, go vet, diff check, and no legacy diff. |
| P3-011 | Add question type write live gateway smoke | scripts, docs | Done. Added scripts/test/question-types-live-smoke.sh and make test-question-types-live as an opt-in live smoke for the non-default native question-type write route. The script verifies /v1/routes, creates a custom type through /api/question-types, updates it, bulk-archives it, hard-deletes it, confirms nested GET manager paths still route to legacy, requires explicit auth/org context, and includes a hermetic self-test path. Live write execution remains pending on a running gateway with native route table plus real auth. Verified by shell syntax, self-test, route coverage, focused gateway tests, full Go tests, go vet, diff check, and no legacy diff. |
| P3-012 | Add question type browser-route smoke | scripts, docs | Done. Added scripts/test/question-types-browser-smoke.sh, Playwright runner, QA doc, and make test-question-types-browser as an opt-in browser smoke for the real /teacher/questions/types page. The smoke seeds browser auth/org state, requires the web app to point NEXT_PUBLIC_API_URL at the gateway, verifies browser-observed GET /api/question-types includes question-types-read/native_read gateway headers, checks core question-type codes, writes artifacts, and leaves the default route table unchanged. Verified by self-test, script syntax, route coverage, full Go tests, go vet, diff check, and no legacy diff. |
| P3-013 | Add storage media real-sample parity smoke | scripts, docs | Done. Added scripts/test/storage-media-parity-smoke.sh, Python runner, QA doc, and make test-storage-media-parity as an opt-in read-only smoke for P3-002. The smoke fetches legacy media detail/content, compares native document-service or gateway content bytes by SHA-256, supports original, trim, and formula variants when native metadata exists, supports storage-key object reads before backfill, writes artifacts, and leaves default routing unchanged. Verified by self-test, script syntax, full Go tests, go vet, diff check, and no legacy diff. |
Phase 4 High-Risk Domain Tasks
| ID | Task | Service/Area | Definition Of Done |
|---|---|---|---|
| P4-001 | Model DOCX import job state and events | docx-import-service | Partial. Job/status/event endpoints, in-memory repository, pgx repository, tests, Postgres schema, stored-job SSE replay, in-process live event fanout, Redis pub/sub multi-process fanout, native bounded worker queue snapshots, read-only BullMQ legacy queue snapshot bridge, durable queued upload payload refs/recovery, periodic SSE heartbeat, logging middleware flush support, offline K8s/Helm persistent payload spool wiring, BullMQ status live-smoke tooling, and import-library browser smoke tooling exist. Executing browser cutover verification remains pending; shared native/legacy worker execution remains deferred unless needed for cutover. |
| P4-002 | Wrap existing Go Formula DOCX endpoint | docx-import-service | Done. Current docx-import-service wraps the existing Go Formula DOCX runtime through /v1/import/docx/simple, sends legacy-compatible multipart flags, maps parser latency, stats, question fields, warnings, answer hints, annotated fallback rows, media references, renderable-image counts, and warning-safe review signals into native QAS output. Later P4/P5 slices added internal runtime wiring, materialization, corpus checks, warning parity, and benchmark coverage. Default public DOCX routes remain legacy until browser cutover evidence is complete. Verified by focused Go Formula parser tests, DOCX import service tests, runtime/corpus/warning coverage scripts, full Go tests, go vet, and no legacy diff. |
| P4-003 | Preserve import review save/reload | docx-import-service | Manual type overrides survive save/reload in browser verification. |
| P4-004 | Implement import approval saga | docx-import, question-bank, exam | Partial. Native internal approval boundary now approves completed DOCX jobs into question-bank and optional draft exam snapshots, and a non-default gateway adapter example now covers legacy-compatible POST /api/exam-import/jobs/:id/approve with opt-in gateway auth/header injection. Default public cutover, browser review verification, and full legacy taxonomy/folder/link parity remain pending. |
| P4-005 | Implement attempt save/submit parity | attempt-service | Done. Native POST /v1/attempts/{attemptId}/answers preserves legacy attempt-owner checks, client/server answer version conflict behavior, and SAVE_ANSWER events. Native POST /v1/attempts/{attemptId}/submit grades from attempt-owned snapshots, updates answer scores plus attempt totals, records SUBMIT/TIMEOUT, and stores answer/grading state in the attempt-service database. Public /api/attempts/* remains legacy until adapter, browser parity, and default route cutover evidence are complete. Verified by focused attempt tests, HTTP tests, full Go tests, go vet, OpenAPI mirror checks, and no legacy diff. |
| P4-006 | Add native import approval orchestrator boundary | docx-import-service | Done. docx-import-service accepts approval for a completed import job, stores idempotency through import events, calls question-bank-service POST /v1/questions/import-docx-output, and optionally creates/updates an exam draft through exam-service without joining other service databases. Verified by focused approval tests, full Go tests/vet, OpenAPI/YAML parse, compose config, K8s/Helm coverage, and no legacy diff. |
| P4-007 | Add import approval gateway adapter example | api-gateway, docx-import-service | Done. Added route-table suffix guard, non-default Compose/localhost examples with opt-in auth/header injection, and gateway regression coverage for POST /api/exam-import/jobs/:id/approve rewriting to POST /v1/import/docx/jobs/{id}/approve without capturing sibling job actions. Default /api/exam-import* stays legacy until browser review verification and full approval parity are proven. |
| P4-008 | Add DOCX import Redis multi-process fanout | docx-import-service | Done. Added Redis-backed event bus around P4-001 in-process fanout, runtime REDIS_URL setup with in-process fallback, self-echo suppression, redacted Redis payloads, deploy/env docs, and fake-broker tests so native SSE subscribers can receive job.updated events across service processes. Default routes remain legacy and real worker queue position parity remains pending. |
| P4-009 | Add native DOCX import queue snapshot foundation | docx-import-service | Done. Added a bounded in-process native worker queue, async POST /v1/import/docx/qas/jobs, job.queued lifecycle events, legacy-shaped job.queue snapshots for waiting/active native import jobs, worker concurrency env/deploy docs, and queue snapshot tests. P4-027 adds a read-only BullMQ fallback snapshot bridge for jobs still visible only in the legacy queue. Browser verification and public cutover remain pending. |
| P4-010 | Add durable DOCX import payload spool and restart recovery | docx-import-service | Done. Uploaded DOCX payloads are stored outside queue memory with opaque job payload_refs, PENDING/PROCESSING jobs recover on startup when the payload exists, missing payload refs fail explicitly with DOCX_IMPORT_PAYLOAD_MISSING, DOCX_IMPORT_PAYLOAD_DIR is documented for Compose/K8s/Helm, and default routes remain legacy. P4-026 adds persistent offline K8s/Helm storage for the payload spool before public cutover. |
| P4-011 | Add DOCX Fast legacy create-job adapter foundation | document-service, docx-import-service, api-gateway | Done. Preserves legacy POST /api/exam-import/docx-fast-jobs JSON shape by reading uploaded DOCX bytes from questionStorageKey through document-service, enqueueing the native DOCX import job without direct storage/database coupling, returning a legacy success envelope, and adding non-default authenticated gateway route examples while default routes remain legacy. Browser cutover verification plus temp asset content parity remain pending. |
| P4-012 | Add DOCX Fast create idempotency parity | docx-import-service | Done. Preserves legacy 15-minute idempotency behavior for POST /api/exam-import/docx-fast-jobs by storing idempotencyKey plus questionStorageKey, returning the recent matching native job before re-fetching storage or enqueueing, and keeping default routes legacy. Adds scoped service-owned migration/index, OpenAPI docs, and regression coverage. Verified by focused/full Go tests, vet, YAML parse, compose config, Helm lint/template, and no legacy diff. |
| P4-013 | Add DOCX Fast auto-approval trigger foundation | docx-import-service | Done. Preserves the legacy autoApproveToQuestionBank path for native DOCX Fast jobs by storing request metadata, triggering native QUESTION_BANK approval after successful parse, recording auto_approval.completed/auto_approval.failed events, and keeping default routes legacy. Adds service-owned metadata migration, OpenAPI docs, and regression coverage. Verified by focused/full Go tests, vet, YAML parse, compose config, Helm lint/template, and no legacy diff. |
| P4-014 | Add DOCX Fast materialized temp-draft read adapter | docx-import-service, api-gateway | Done. Preserves the legacy materialized temp-draft read shape for native completed DOCX Fast jobs by returning a legacy success envelope with parseResult and empty temp assets, while temp asset content stays legacy. Adds non-default gateway routes, OpenAPI/docs, and regression coverage. Verified by focused/full Go tests, vet, YAML/JSON parse, compose config, Helm lint/template, and no legacy diff. |
| P4-015 | Add DOCX Fast reprocess adapter foundation | docx-import-service, api-gateway | Done. Preserves the legacy POST /api/exam-import/docx-fast-jobs/{id}/reprocess path for native DOCX Fast jobs by re-reading the stored source DOCX, requeueing the same native job id, clearing previous parse output, returning the legacy success envelope, and keeping default routes legacy. Adds non-default gateway routes, OpenAPI/docs, and regression coverage. Verified by focused/full Go tests, vet, YAML/JSON parse, compose config, Helm lint/template, and no legacy diff. |
| P4-016 | Add DOCX Fast materialized asset content adapter | docx-import-service, api-gateway | Done. Preserves the legacy temp asset content guard for native materialized jobs by serving only media assets referenced by the completed native job parse result through document-service, keeping the materialized temp-draft payload assets: [], and adding non-default gateway route examples. Verified by focused/full Go tests, vet, YAML/JSON parse, compose config, Helm lint/template, and no legacy diff. |
| P4-017 | Add Go Formula DOCX internal runtime wiring | deploy, docx-import-service | Done. Keeps apps/go-formula-docx source read-only while building and deploying it as an internal parser runtime for local Compose, offline K8s, and Helm. Wires docx-import-service to http://go-formula-docx:8080, adds runtime image coverage, and keeps the default public gateway routes legacy until browser parity is verified. Verified by runtime coverage, compose config, K8s service coverage, Helm render coverage, shell/YAML parse, full Go tests/vet, and no legacy diff. |
| P4-018 | Add import review save/reload backend foundation | docx-import-service, api-gateway | Done. Preserves reviewed parse payloads, including manual question-type override metadata, in service-owned storage through a native PATCH /v1/import/docx/jobs/{id}/review endpoint and non-default gateway route example. Materialized DOCX Fast temp-draft reads prefer the saved reviewed payload for reload parity. Source-text reparse, temp-draft token materialization, default public cutover, and real browser verification remain under P4-003. Verified by focused review-save and gateway tests, full Go tests/vet, OpenAPI/route JSON parse, compose config, K8s migration coverage, Helm render coverage, and no legacy diff. |
| P4-019 | Add import job detail reload adapter | docx-import-service, api-gateway | Done. Returns legacy-compatible job detail fields, including reviewed parseResultJson, from native GET /v1/import/docx/jobs/{id} and adds a non-default gateway route for GET /api/exam-import/jobs/{id}. Sibling paths such as /status, /review, and /approve stay legacy unless separately routed. Default public cutover and browser save/reload proof remain under P4-003. Verified by focused detail reload and gateway tests, full Go tests/vet, OpenAPI/route JSON parse, compose config, Helm render coverage, and no legacy diff. |
| P4-020 | Add combined import review save/detail route smoke | api-gateway, scripts | Done. Combines the P4-018 review-save and P4-019 detail-reload gateway carve-outs into one non-default route table so save then reload can be smoke-tested through the gateway before any browser/default cutover. Status, approve, stop, nested review, and unrelated import siblings stay legacy unless explicitly routed. Verified by JSON parse, static route coverage script, focused gateway regression test, full gateway package tests, full Go tests, go vet, shell syntax check, and no legacy diff. |
| P4-021 | Add live import review save/detail smoke script | scripts, docs | Done. Adds an opt-in live gateway smoke that fetches a real import job detail, saves a reviewed parse payload through PATCH /api/exam-import/jobs/{id}/review, reloads GET /api/exam-import/jobs/{id}, and verifies manual question-type review markers. The script requires explicit job/auth inputs, defaults to restoring the original parse payload, supports artifacts and custom payloads, and does not claim browser parity or default cutover. Verified by self-test, shell syntax checks, route coverage, Makefile smoke targets, full Go tests, go vet, and no legacy diff. |
| P4-022 | Preserve reviewed sourceText on native review reload | docx-import-service | Done. When PATCH /v1/import/docx/jobs/{id}/review receives a reviewed parseResult plus sourceText, native save response, detail reload, and DOCX Fast materialized temp-draft reload expose that source text as parseResultJson.sourceText without mutating the stored raw reviewed payload shape. SourceText-only parser reprocess and non-materialized temp-draft token asset materialization remain separate P4-003 gaps. Verified by focused HTTP test, docx-import HTTP package test, full Go tests, go vet, and no legacy diff. |
| P4-023 | Add sourceText-only review reparse baseline | docx-import-service | Done. Adds a native baseline for PATCH /v1/import/docx/jobs/{id}/review requests that include sourceText but no parseResult, parsing simple Câu n source text with A/B/C/D options into a legacy-shaped parseResultJson and explicit SOURCE_TEXT_REPARSE_BASELINE warning. This is a compatibility foundation, not full legacy parseAlgorithmExamImport parity. Verified by focused usecase/HTTP tests, full Go tests, go vet, and no legacy diff. |
| P4-024 | Accept native DOCX Fast materialized temp-draft review token | docx-import-service | Done. Exposes native materialized DOCX Fast temp-draft metadata on job detail and accepts the native materialized-{jobId} token on PATCH /v1/import/docx/jobs/{id}/review so review save does not fail when the editor includes a materialized token. This does not implement the legacy non-materialized temp-draft file store or client asset upload materialization. Verified by focused usecase/HTTP tests, full Go tests, go vet, OpenAPI YAML parse, and no legacy diff. |
| P4-025 | Add import review browser-route smoke | scripts, docs | Done. Adds an opt-in Playwright browser smoke that opens the real import editor route, seeds existing auth/organization state, verifies gateway GET detail and PATCH review routes hit native carve-outs, reloads the editor, and checks manual review markers survive in browser-observed responses. This is browser evidence tooling, not default public cutover. Verified by self-test, route coverage, script syntax checks, full Go tests, go vet, and no legacy diff. |
| P4-026 | Add DOCX import payload PVC deployment wiring | deploy, scripts, docs | Done. Added a docx-import-payloads PersistentVolumeClaim to the static offline K8s manifest, switched the docx-import-service payload spool mount from emptyDir to the PVC, added Helm service-level persistence rendering with the same claim and 5Gi request, and added make test-docx-payload-persistence coverage to reject ephemeral payload storage. Verified by payload persistence coverage, Helm render coverage, K8s service coverage, Compose config, full Go tests, go vet, diff check, and no legacy diff. |
| P4-027 | Add DOCX import BullMQ snapshot bridge | docx-import-service, deploy, scripts | Done. Added an opt-in read-only BullMQ snapshot bridge for legacy exam-import-algorithm queue state. When enabled with DOCX_IMPORT_BULLMQ_BRIDGE_ENABLED=1, native status/list summaries fall back from the in-process native queue to BullMQ Redis keys and preserve legacy waiting/active/delayed/prioritized/waitingChildren/failed/totalPending/waitingPosition/jobsAhead/workerConcurrency fields for matching data.jobId. The bridge never enqueues, removes, retries, or claims BullMQ jobs. Verified by focused usecase/http tests, bridge config coverage, Helm/K8s/Compose coverage, full Go tests, go vet, diff check, and no legacy diff. |
| P4-028 | Add DOCX import BullMQ status live smoke | scripts, docs | Done. Added scripts/test/docx-import-bullmq-status-smoke.sh, make test-docx-bullmq-status, and QA/runbook docs for opt-in live verification of the non-default import status route table plus BullMQ queue fields on GET /api/exam-import/teacher-library?q=<jobId>. The smoke is read-only, supports direct native service mode, includes a hermetic self-test, and does not claim default route cutover. Verified by script syntax, self-test, diff check, and no legacy diff. |
| P4-029 | Add DOCX import library browser-route smoke | scripts, docs | Done. Added scripts/test/docx-import-library-browser-smoke.sh, Playwright runner, make test-docx-import-library-browser, and QA/runbook docs for the real /teacher/exams/library page. The smoke seeds browser auth/org state, verifies browser-observed GET /api/exam-import/teacher-library uses exam-import-teacher-library/native_read, optionally searches by job id and asserts the row's BullMQ queue snapshot, and leaves default routes unchanged. Verified by script syntax, Node syntax, self-test, full Go tests, go vet, diff check, and no legacy diff. |
| P4-030 | Add import status route-table coverage | scripts, api-gateway | Done. Added scripts/test/import-status-route-coverage.sh and make test-import-status-routes to statically validate the default, Compose, and localhost import-status route tables. Coverage requires teacher-library, algorithm events, and both status aliases to be GET-only native reads with auth/org guards and expected targets, while broad /api/exam-import, /api/imports, and fallback routes remain legacy-proxied and ordered after native carve-outs. Verified by script syntax, route coverage, full Go tests, go vet, diff check, and no legacy diff. |
| P4-031 | Add DOCX Fast create route-table coverage | scripts, api-gateway | Done. Added scripts/test/import-create-route-coverage.sh and make test-import-create-routes to statically validate the default, Compose, and localhost DOCX Fast create route tables. Coverage requires exact POST create, scoped GET temp-draft, scoped GET materialized asset content, and scoped POST reprocess to target docx-import-service with auth/org/role guards, while broad /api/exam-import and fallback routes remain legacy-proxied and ordered after the native carve-outs. Verified by script syntax, route coverage, full Go tests, go vet, diff check, and no legacy diff. |
| P4-032 | Add DOCX Fast create live gateway smoke | scripts, api-gateway, docx-import-service | Done. Added scripts/test/import-create-live-smoke.sh and make test-import-create-live as an opt-in write smoke for the non-default DOCX Fast create route table. The smoke requires explicit confirmation, auth/org context, and a caller-supplied DOCX questionStorageKey; verifies /v1/routes, asserts POST /api/exam-import/docx-fast-jobs hits exam-import-docx-fast-create as native_write, checks a sibling job detail route still uses broad legacy routing, and validates the legacy success envelope without changing default routing. Verified by script syntax, hermetic self-test, route coverage, full Go tests, go vet, diff check, and no legacy diff. |
| P4-033 | Add DOCX Fast create browser-route smoke | scripts, api-gateway, docx-import-service | Done. Added scripts/test/import-create-browser-smoke.sh, Playwright runner, QA doc, and make test-import-create-browser for opt-in browser evidence on the real DOCX Fast create surface. The smoke opens the import UI with browser auth/org state, verifies the non-default import-create route table, creates a DOCX Fast job either through the UI file input or through a browser-context POST using an existing questionStorageKey, asserts browser-observed gateway headers exam-import-docx-fast-create/native_write, validates the legacy success envelope, writes artifacts, and keeps default routing unchanged. Verified by shell/Node syntax, hermetic self-test, static route coverage, full Go tests, go vet, diff check, and no legacy diff. |
| P4-034 | Add DOCX Fast reprocess live gateway smoke | scripts, api-gateway, docx-import-service | Done. Added scripts/test/import-reprocess-live-smoke.sh, make test-import-reprocess-live, QA/API/runbook docs, and handoff notes for the opt-in DOCX Fast reprocess live smoke. The smoke requires explicit confirmation, a native DOCX Fast job id, auth/org context, verifies /v1/routes, asserts a sibling job detail route stays broad legacy, checks POST /api/exam-import/docx-fast-jobs/{id}/reprocess hits exam-import-docx-fast-reprocess as native_write, and validates the legacy success envelope keeps the same job id with message DOCX Fast import reprocessed. Verified by script syntax, hermetic self-test, Make target self-test, static route coverage, full Go tests, go vet, diff check, and no legacy diff. |
| P4-035 | Add DOCX Fast temp-draft live gateway smoke | scripts, api-gateway, docx-import-service | Done. Added scripts/test/import-temp-draft-live-smoke.sh, make test-import-temp-draft-live, QA/API/runbook docs, and handoff notes for the read-only DOCX Fast materialized temp-draft live smoke. The smoke requires a completed native DOCX Fast job id plus auth/org context, verifies /v1/routes, asserts GET /api/exam-import/docx-fast-jobs/{id}/temp-draft hits exam-import-docx-fast-temp-draft as native_read, validates the legacy materialized draft envelope with token materialized-{id}, and proves sibling temp-draft asset metadata stays on the broad legacy import route. Verified by script syntax, hermetic self-test, Make target self-test, static route coverage, full Go tests, go vet, diff check, and no legacy diff. |
| P4-036 | Add DOCX Fast temp asset content live gateway smoke | scripts, api-gateway, docx-import-service | Done. Added scripts/test/import-temp-asset-live-smoke.sh, make test-import-temp-asset-live, QA/API/runbook docs, and handoff notes for the read-only materialized temp asset content live smoke. The smoke requires a completed native DOCX Fast job id, materialized temp asset id, and auth/org context; verifies /v1/routes; asserts GET /api/exam-import/docx-fast-jobs/{id}/temp-draft/assets/{asset}/content hits exam-import-docx-fast-asset-content as native_read; validates binary content headers/body size; and proves sibling asset metadata stays on the broad legacy import route. Verified by script syntax, hermetic self-test, Make target self-test, static route coverage, full Go tests, go vet, diff check, and no legacy diff. |
Phase 5 DOCX Import Service Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P5-001 | Create DOCX parser interface and required parser package layout | docx-import-service | Done | internal/parser/docx, question, formula, media, table, classifier, output exist. |
| P5-002 | Implement required QAS endpoint shell | docx-import-service | Done | POST /v1/import/docx/qas validates upload and returns warning-safe output. |
| P5-003 | Implement stream endpoint shell | docx-import-service | Done | POST /v1/import/docx/qas/stream returns NDJSON events. |
| P5-004 | Add upload validation | docx-import-service | Done | Enforces .docx, ZIP-based Office magic header, 50MB limit, timeout. |
| P5-005 | Port audited parser behavior | docx-import-service | Done | Go Formula /v1/import/docx/simple adapter maps direct output, materializes extractable package images through document-service, applies payload-level DOCX style answer hints, builds annotated fallback QAS when Go returns 0 questions, has a deterministic classifier baseline, runs native OOXML style-hint extraction for Math/English/DGNL template-gated DOCX files, builds DGNL QAS fallback questions from native option/answer rows, reports renderable images before raw OLE/formula artifacts, has opt-in live document-service materialization and native warning artifact capture scripts, and includes native warning coverage for missing answer markers, template review-only, media fallback review, and image metadata review. The filtered live corpus warning comparison against output/import-audit-20260702/api passes with DOCX_WARNING_PARITY_ALLOW_EXTRA_NATIVE=1, because native emits additional review-safety warnings. Verified by focused parser tests, live capture/comparator, full Go tests, go vet, and no legacy diff. |
| P5-006 | Add fixtures from real DOCX corpus | docx-import-service | Done | Portable mixed-output/style-hint/annotated-fallback fixtures plus generated OOXML style-hint/DGNL fallback DOCX tests lock QAS/media/warning/native answer mapping; opt-in corpus integration verifies Physics 28Q (28, 18/4/6, 7 renderable images, 84 formulas), Math 22Q (22, 12/4/6, 7 renderable images, 125 formulas), English 40Q (40, all single-choice), and DGNL 102Q (102, 9 answer-only/review-required rows); opt-in materialization integration verifies Physics 28Q 7 images become fetchable MediaAsset content; filtered warning comparison against output/import-audit-20260702/api passes with DOCX_WARNING_PARITY_ALLOW_EXTRA_NATIVE=1. Verified by live make test-docx-corpus, live make test-docx-materialization, live warning capture/comparator, full Go tests, go vet, and no legacy diff. |
| P5-007 | Benchmark parser latency | docx-import-service | Done | Handler benchmark exists, external parser latency is passed through from Go Formula response when available, and BenchmarkMapGoFormulaResult now covers mixed fixture mapping, annotated fallback mapping, and warning parity mapping with allocation metrics. Verified by focused benchmark, parser tests, full Go tests, go vet, and no legacy diff. |
| P5-008 | Add DOCX parser warning parity baseline | docx-import-service | Done | Added deterministic Go Formula warning coverage for missing answer markers after style hints/fallback and image metadata that lacks rendered HTML, while avoiding false positives for WMF/OLE formula previews. Verified by focused parser tests, docx-import-service tests, full Go tests, go vet, and no legacy diff. |
| P5-009 | Add DOCX corpus warning parity comparator | scripts, docs | Done | Added opt-in tooling that compares legacy audit warning categories against native DOCX import response warnings from caller-supplied JSON artifacts, with a hermetic self-test and no hard-coded claim that corpus parity has passed. Verified by shell/Python syntax checks, self-test target, full Go tests, go vet, and no legacy diff. |
| P5-010 | Add native DOCX warning artifact capture runner | scripts, docs | Done | Added an opt-in runner that posts the real Physics/Math/English/DGNL DOCX corpus to live docx-import-service /v1/import/docx/qas and writes stable physics.json, math.json, english.json, and dgnl.json native artifacts for the P5-009 comparator. The runner documents live-service prerequisites, supports subset/per-fixture path overrides plus dry-run corpus resolution, avoids committing binary DOCX files or generated artifacts, and does not claim warning parity until compared with legacy audit JSON. Verified by script syntax, dry-run against the local corpus, comparator self-test, full Go tests, go vet, and no legacy diff. |
| P5-011 | Normalize native DOCX warning comparator categories | scripts, docs | Done | Updated the warning comparator so native GO_FORMULA_DOCX_INCOMPLETE_QUESTION records count toward missing-answer review coverage, native DOCX_NATIVE_DGNL_FALLBACK counts toward annotated fallback coverage, and live comparisons can explicitly filter to the fixture stems captured by P5-010. The comparator still fails on true missing legacy warning categories and does not claim corpus warning parity; the filtered live report now shows remaining DGNL media/missing-answer and Physics template-review gaps. Verified by comparator self-test, filtered live report, full Go tests, go vet, and no legacy diff. |
| P5-012 | Cover remaining native DOCX corpus warning categories | docx-import-service | Done | Added native review-safety warnings for the live corpus categories still missing after P5-011: DGNL fallback questions without answer evidence, DGNL package media/fallback review evidence when native fallback replaces a zero-question Go Formula result, and Physics template/type mismatch review-only evidence when parser types already conflict with the THPT template expectation. Parser output stays deterministic and does not coerce semantic type. The filtered live warning comparator now passes with DOCX_WARNING_PARITY_ALLOW_EXTRA_NATIVE=1, because native emits additional review-safety warnings beyond legacy. Verified by focused parser tests, live capture/comparator, full Go tests, go vet, and no legacy diff. |
Phase 6 Question Bank Service Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P6-001 | Add native question core schema | question-bank-service | Done | Service-owned migration 000003_question_core.sql creates questions, question_versions, question_options, grouping, tags, media refs, and formula refs with indexes and rollback. |
| P6-002 | Ingest DOCX import output into question-bank | question-bank-service | Partial | Native POST /v1/questions/import-docx-output writes Question + QuestionVersion + QuestionOption rows transactionally from DOCX QAS output, preserving media refs, formula HTML/LaTeX, answer keys, source metadata, and grouping metadata without mutating semantic type from group detection alone. docx-import-service now has an internal approval boundary that calls this endpoint, and P4-007 adds a non-default approval gateway adapter example; default public cutover and full exam-import approval parity remain pending. |
| P6-003 | Add read/list/detail parity for native questions | question-bank-service | Partial | GET /v1/questions returns hydrated items/meta rows with current version, options, group refs, media refs, formula refs, tags, pagination metadata, core scalar filters, nullable taxonomy/source reference filters, unclassifiedOnly, missingExplanationOnly, fidelityStatus, sourceMetadataSource, safe actor scoping, admin-only allOrgs, and legacy-compatible relation/count placeholders. Native reads now hydrate customType from question_type_definitions and taxonomy named refs from question_taxonomy_refs when read-model rows exist. GET /v1/questions/{id} returns one hydrated row, accepts view=editor, preserves legacy archived-detail visibility within actor/tenant scope, and returns 404 QUESTION_NOT_FOUND for missing/out-of-scope reads. P6-032 adds opt-in browser-route evidence tooling for the real /teacher/questions list page and optional editor detail page through the legacy projection adapter; P6-033 adds admin /admin/questions allOrgs=1 browser-query evidence tooling. Full /api/questions cutover still requires executing teacher/admin browser smoke against real backfilled data, final taxonomy/user/org/usage backfill acceptance, and write parity. |
| P6-004 | Add legacy adapter/cutover route plan | api-gateway, question-bank-service | Partial | Added GET /api/questions and GET /api/questions/:id shadow/native-read route examples plus live smoke scripts for legacy-vs-gateway shadow parity and direct-native-adapter-vs-gateway native parity. Detail routing uses suffix_segments: 1 so /api/questions/ai-classify/*, writes, and deeper subroutes remain legacy_proxy. P6-032/P6-033 add opt-in browser smokes that verify browser-observed questions-list/questions-detail gateway headers and admin allOrgs=1 query routing while leaving the default route table legacy-proxied. Native read cutover still requires executing live admin/browser parity with real backfilled data and final default-route approval. |
| P6-005 | Add native AI classification job foundation | ai-classifier-service | Done | Added service-owned classification job/status/error/SSE foundation with deterministic mock provider, usage event persistence shape, native migrations, OpenAPI contracts, and legacy-compatible success envelope. Public /api/questions/ai-classify/* stays legacy-proxied until real provider, question-bank apply adapter, RBAC, and browser parity are proven. Verified by focused service tests, full Go tests, go vet, OpenAPI YAML parse, and no legacy diff. |
| P6-006 | Add AI classifier persistent job store | ai-classifier-service | Done | Added pgx-backed persistence for classification_jobs and provider_usage_events using the service-owned schema, with DATABASE_URL runtime selection, ping-verified Postgres setup, in-memory fallback, JSONB scope/progress/result scanning, focused repository tests, full Go tests, go vet, OpenAPI YAML parse, and no legacy diff. Public /api/questions/ai-classify/* remains legacy-proxied. |
| P6-007 | Add native AI classification apply foundation | question-bank-service | Done | Added internal PATCH /v1/questions/ai-classify/apply accepting legacy-shaped apply items, updating service-owned question classification fields, recording sourceMetadataJson.aiClassification audit/history, preserving tenant/owner scope, syncing OpenAPI/contracts/docs, and keeping public /api/questions/ai-classify/apply legacy-proxied. Verified by focused question-bank tests, full Go tests, go vet, OpenAPI YAML parse, and no legacy diff. |
| P6-008 | Add taxonomy-aware AI classification apply parity | question-bank-service | Done | Extended native AI classification apply with taxonomy-backed id/code/name normalization and derived field parity: native question_type_definitions maps customTypeId to base type, taxonomy gradeId maps to numeric gradeLevel, and taxonomy difficultyLevelId maps to engine difficulty. Public /api/questions/ai-classify/apply remains legacy-proxied. Verified by focused question-bank tests, full Go tests, go vet, OpenAPI YAML parse, and no legacy diff. |
| P6-009 | Add AI classification apply gateway adapter example | api-gateway, question-bank-service | Done | Added non-default gateway route-table examples and regression tests for PATCH /api/questions/ai-classify/apply mapping to native PATCH /v1/questions/ai-classify/apply, while leaving other /api/questions/ai-classify/* routes legacy-proxied until auth/RBAC/browser parity are proven. Verified by focused gateway/question-bank tests, full Go tests, go vet, route JSON parse, and no legacy diff. |
| P6-010 | Enrich native question reads with custom type definitions | question-bank-service | Done | Hydrated list/detail customType from native question_type_definitions when customTypeId or core type matches a definition, preserving placeholder fallbacks and keeping /api/questions public cutover pending. Verified by focused question-bank tests, full Go tests, go vet, and no legacy diff. |
| P6-011 | Strengthen question read shadow legacy guard smoke | scripts, api-gateway | Done | Extended the opt-in question-read shadow parity smoke to assert the route table keeps the broad /api/questions fallback on legacy_proxy and byte-compares a nested AI-classification read subroute through legacy vs gateway. Verified by shell syntax, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-012 | Add native taxonomy reference read-model foundation | question-bank-service | Done | Added service-owned taxonomy ref storage and internal list/upsert endpoints for legacy Subject, Chapter, Topic, EducationLevel, Grade, Curriculum, CurriculumNode, ExamTrack, QuestionSource, and DifficultyLevel, then hydrated question read subject/chapter/topic from that read model with placeholder fallback. Verified by focused question-bank tests, full Go tests, go vet, OpenAPI YAML parse, and no legacy diff. |
| P6-013 | Use taxonomy refs for native AI classification apply context | question-bank-service | Done | Native AI classification apply now builds taxonomy context from active service-owned question_taxonomy_refs with global fallback, so subjectId, educationLevelId, gradeId, curriculumId, curriculumNodeId, examTrackId, questionSourceId, and difficultyLevelId normalize by id/code/name without relying on client-supplied taxonomy payloads. Verified by focused question-bank tests, full Go tests, go vet, and no legacy diff. |
| P6-014 | Hydrate native question reads with extended taxonomy refs | question-bank-service | Done | Added service-owned named refs to native list/detail question payloads for educationLevel, grade, curriculum, curriculumNode, examTrack, questionSource, and difficultyLevel from question_taxonomy_refs, preserving existing ID fields and placeholder fallback. Public /api/questions stays on the current route plan until legacy adapter projection and browser parity are proven. Verified by focused question-bank tests, full Go tests, go vet, and no legacy diff. |
| P6-015 | Add question read native gateway rehearsal routes | api-gateway, question-bank-service | Done | Added non-default native-read gateway route-table examples for GET /api/questions and GET /api/questions/:id rewriting to native /v1/questions, preserving legacy fallback for writes and nested subroutes. Default /api/questions remains legacy-proxied until real backfill, adapter projection, auth/RBAC, browser parity, and rollback evidence are proven. Verified by JSON parse, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-016 | Add native question usage-count read model | question-bank-service | Done | Added a service-owned question_usage_counts projection plus internal PUT /v1/questions/usage-counts so native question reads hydrate _count.examItems, _count.attemptItems, and _count.answers without querying exam/attempt databases. Missing projections remain zero-compatible placeholders, and public /api/questions stays on the current route plan until backfill, adapter projection, browser parity, and rollback evidence are proven. Verified by focused/full Go tests, OpenAPI YAML parse, go vet, and no legacy diff. |
| P6-017 | Add native question relation read models | question-bank-service | Done | Added service-owned question_user_refs and question_organization_refs projections plus internal PUT /v1/questions/relation-refs so native question reads hydrate legacy createdBy and organization fields without joining user-service, school-service, or legacy databases. Missing projections retain placeholder fallback, and public /api/questions stays on the current route plan until backfill, adapter projection, browser parity, and rollback evidence are proven. Verified by focused/full Go tests, OpenAPI YAML parse, go vet, and no legacy diff. |
| P6-018 | Add question read-model backfill dry-run SQL | question-bank-service, migrations | Done | Expanded the question-bank legacy migration script with read-only extraction queries for taxonomy refs, usage counts, user refs, and organization refs that feed the P6-012/P6-016/P6-017 service-owned read models. Added SQL coverage validation to keep the script read-only and warning queries for rows that need manual handling before native read cutover. Verified by coverage script, migrator plan/dry-run, full Go tests, go vet, and no legacy diff. |
| P6-019 | Add native question editor detail projection | question-bank-service | Done | Native GET /v1/questions/{id}?view=editor returns the legacy editor-selected shape used by GET /api/questions/:id?view=editor, including rich content/explanation JSON, taxonomy/source IDs, group passage fields, current-version answer keys/sub-items, and ordered editor option fields, while normal detail reads keep the hydrated native row. Public /api/questions/:id stays on the current route plan until browser parity and rollback evidence are proven. Verified by focused question-bank tests, full Go tests, OpenAPI YAML parse, go vet, and no legacy diff. |
| P6-020 | Add native question editor projection parity smoke assertion | scripts, question-bank-service | Done | Extended the opt-in question read shadow parity smoke so QUESTION_READ_PARITY_REQUIRE_NATIVE=1 verifies native GET /v1/questions/{id}?view=editor returns the editor projection shape, including currentVersion.answerKeysJson, currentVersion.subItemsJson, ordered option editor fields, optional group passage fields, and no full-row _count/createdBy/organization leakage. Gateway shadow mode still returns byte-identical legacy responses, and default /api/questions routes stay legacy. Verified by script syntax, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-021 | Add question read native rollback rehearsal | scripts, api-gateway | Done | Added a no-legacy-edit rollback rehearsal for the non-default question read native route table: statically validates the native-read table can be reverted to the default legacy table, asserts the rollback route table leaves broad /api/questions on legacy_proxy, rejects active rollback carve-outs, and provides an opt-in live gateway check that verifies list/detail requests are routed through the broad legacy route after rollback. Verified by shell syntax, script self-test, static rehearsal, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-022 | Add native legacy question read projection endpoints | question-bank-service | Done | Added internal compatibility projection endpoints for future /api/questions native cutover without changing the native service contract: /v1/legacy/questions returns the legacy list envelope shape over the native read model, /v1/legacy/questions/{id} returns the legacy normal detail shape, and /v1/legacy/questions/{id}?view=editor preserves the editor projection already proven by P6-019/P6-020. Default gateway routes remain legacy until route-table cutover evidence is updated. Verified by focused HTTP projection tests, question-bank service tests, OpenAPI YAML parse, full Go tests, go vet, and no legacy diff. |
| P6-023 | Retarget question read native route examples to legacy projection adapter | api-gateway, scripts | Done | Updated only the non-default question read native route-table examples so future /api/questions native-read rehearsals rewrite to /v1/legacy/questions instead of raw /v1/questions, kept the default route table legacy-proxied, and updated rollback/static validation tooling to require the adapter target prefix by default. Verified by route JSON parse, shell syntax, rollback rehearsal self/static tests, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-024 | Add question read adapter parity smoke assertions | scripts, question-bank-service | Done | Updated the opt-in question read shadow parity smoke so native checks target the compatibility adapter /v1/legacy/questions by default, while still allowing raw /v1/questions checks for older experiments. The smoke now asserts adapter list/detail/editor shapes before any public cutover and keeps gateway shadow responses byte-identical to legacy. Verified by script syntax, hermetic assertion self-test, full Go tests, go vet, and no legacy diff. |
| P6-025 | Retarget question read shadow route examples to legacy projection adapter | api-gateway, scripts | Done | Aligned the non-default question-read shadow route-table examples with the P6-022 compatibility adapter by rewriting shadow requests to /v1/legacy/questions, and added a parity smoke guard that fails if /v1/routes points questions-list or questions-detail at an unexpected target prefix. Verified by route JSON parse, shell syntax, parity self-test, rollback rehearsal, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-026 | Add legacy adapter admin all-org read coverage | question-bank-service | Done | Added focused compatibility-adapter coverage proving /v1/legacy/questions?allOrgs=1 preserves the native admin-only all-organization rule before any /api/questions cutover. Documented the live admin all-org shadow-smoke command. Verified by focused question-bank HTTP tests, question-bank service tests, full Go tests, go vet, and no legacy diff. |
| P6-027 | Add question read-model backfill report metadata | tools/migrator, docs/migration | Done | Extended migrator report --service question-bank-service so it emits explicit read-only report items for the question read-model backfill projections required before /api/questions cutover: taxonomy refs, usage counts, user refs, organization refs, and warning counts. Verified by migrator unit tests, report JSON assertion, read-only SQL coverage, full Go tests, go vet, and no legacy diff. |
| P6-028 | Add static question-read route-table coverage | scripts, api-gateway | Done | Added a static coverage script and Make target that validates default, shadow, and native question-read route-table examples keep writes/nested routes on legacy and rewrite only list/detail reads to the legacy projection adapter. Verified by shell syntax, make test-question-read-routes, rollback rehearsal, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-029 | Add question-read native gateway parity smoke | scripts, api-gateway | Done | Added an opt-in live smoke that runs against the non-default native-read route table and byte-compares gateway /api/questions list/detail/editor responses with direct /v1/legacy/questions adapter responses while verifying writes and nested routes remain legacy-routed. Verified by shell syntax, hermetic self-test, static route coverage, rollback rehearsal, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-030 | Add import approval route-table coverage | scripts, api-gateway | Done | Added static coverage for the non-default import approval native route examples so only POST /api/exam-import/jobs/{id}/approve is carved out to docx-import-service and sibling import job actions stay on the broad legacy route. Verified by shell syntax, make test-import-approval-routes, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-031 | Add import approval live gateway smoke | scripts, api-gateway, docx-import-service | Done | Added an opt-in live smoke for the non-default native approval route that requires explicit write confirmation, a completed import job, auth/org context, and native dependencies before calling POST /api/exam-import/jobs/{id}/approve. The smoke asserts the gateway route table/header/state, validates native approval response fields, keeps sibling import detail on the broad legacy route, and leaves the default route table unchanged. Verified by shell syntax, hermetic self-test, Make target self-test, route-table coverage, focused gateway tests, full Go tests, go vet, and no legacy diff. |
| P6-032 | Add question read browser-route smoke | scripts, api-gateway, question-bank-service | Done | Added scripts/test/question-read-browser-smoke.sh, Playwright runner, QA doc, and make test-question-read-browser as an opt-in browser smoke for the real /teacher/questions page and optional /teacher/questions/{id}/edit detail page. The smoke seeds browser auth/org state, requires the web app to point NEXT_PUBLIC_API_URL at the gateway, verifies browser-observed GET /api/questions uses questions-list/native_read, optionally verifies GET /api/questions/{id}?view=editor uses questions-detail/native_read, checks legacy-compatible list/detail payload shapes, writes artifacts, and leaves the default route table unchanged. Verified by self-test, script syntax, static route coverage, native gateway self-test, rollback rehearsal, full Go tests, go vet, diff check, and no legacy diff. |
| P6-033 | Add question read admin all-org browser smoke | scripts, api-gateway, question-bank-service | Done | Extended scripts/test/question-read-browser-smoke.mjs with QUESTION_READ_BROWSER_EXPECT_QUERY and added make test-question-read-browser-admin for the real /admin/questions page. The admin target seeds admin browser auth/org state, waits for browser-observed GET /api/questions with allOrgs=1, verifies questions-list/native_read gateway headers, checks the legacy-compatible list payload shape, and leaves the default route table unchanged. Verified by self-test, script syntax, static route coverage, native gateway self-test, rollback rehearsal, full Go tests, go vet, diff check, and no legacy diff. |
| P6-034 | Add AI classification apply live gateway smoke | scripts, api-gateway, question-bank-service | Done | Added scripts/test/question-classification-apply-live-smoke.sh, make test-question-classification-apply-live, QA/API/runbook docs, and handoff notes for the opt-in native AI classification apply live smoke. The smoke requires explicit confirmation, a real native question id or caller-supplied apply body, auth/org context, verifies /v1/routes, asserts PATCH /api/questions/ai-classify/apply hits question-classification-apply as native_write, validates the legacy-shaped apply result counts and question id, proves sibling AI classification job routes stay on the broad legacy questions route, and keeps default routing unchanged. Verified by script syntax, hermetic self-test, Make target self-test, focused gateway/question-bank tests, full Go tests, go vet, diff check, and no legacy diff. |
| P6-035 | Add AI classification apply route-table coverage | scripts, api-gateway | Done | Added scripts/test/question-classification-apply-route-coverage.sh, make test-question-classification-apply-routes, API/runbook/QA docs, and handoff notes for static AI classification apply route-table coverage. The coverage proves the default table has no active apply carve-out, native examples route only exact PATCH /api/questions/ai-classify/apply to question-bank-service with auth/org/role guards, broad /api/questions and fallback remain legacy-proxied, and the apply route is ordered before broad legacy routes. Verified by shell syntax, route coverage, live-smoke self-test, focused gateway tests, full Go tests, go vet, diff check, and no legacy diff. |
| P6-036 | Add AI classification job route guard coverage | scripts, api-gateway, ai-classifier-service | Done | Audited legacy and native AI classification job contracts, kept POST /api/questions/ai-classify/suggestions, /api/questions/ai-classify/jobs*, job SSE, error history, and cancel routes legacy-proxied because ai-classifier-service still uses the deterministic mock provider and lacks BullMQ/provider/runtime parity, while preserving the existing exact PATCH /api/questions/ai-classify/apply carve-out to question-bank-service. Verified by shell syntax, make test-ai-classification-job-route-guard, existing apply route coverage, focused gateway/ai-classifier tests, full Go tests, go vet, and no legacy diff. |
| P6-037 | Add AI classifier provider adapter foundation | ai-classifier-service | Done | Added env-configured provider adapters for mock, OpenAI-compatible chat completions, native Gemini generateContent, and local/Ollama chat while preserving mock as the default, recording provider usage telemetry for success/failure, and enforcing timeout, retry, and circuit breaker behavior. Wired runtime env docs/deploy defaults for AI_CLASSIFIER_PROVIDER, AI_PROVIDER_TIMEOUT_MS, retry, and circuit settings. Public /api/questions/ai-classify/suggestions and job routes remain legacy-proxied until BullMQ/runtime, taxonomy prompt context, RBAC, and browser parity are proven. Verified by focused provider/service tests, gateway tests, route guards, full Go tests, go vet, YAML/OpenAPI parse, Helm render, whitespace scan, and no legacy diff. |
| P6-038 | Add AI classification input context endpoint | question-bank-service | Done | Added internal POST /v1/questions/ai-classify/context for bounded provider prompt input: scoped question content, explanation, options, current classification, question-type candidates, taxonomy candidates, candidate grades, and candidate curriculum nodes. Mirrored the legacy AI job onlyUnclassified predicate, including deterministic legacy difficulty reclassification, without changing public /api/questions/ai-classify/suggestions or job routing. Verified by question-bank and ai-classifier tests, route guards, full Go tests, go vet, OpenAPI parse, whitespace scan, and no legacy diff. |
Phase 7 Exam And Attempt Service Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P7-001 | Add native exam question snapshot foundation | exam-service | Done | exam-service owns a service-local exam_question_snapshots table plus internal PUT /v1/exams/{examId}/question-snapshots and GET /v1/exams/{examId}/question-snapshots APIs. The write contract accepts already-hydrated question payloads from question-bank-service or an import approval saga, preserves content JSON, options, sub-items, answer keys, scoring rule, media/formula refs, option order, section/order metadata, and never joins the question-bank database directly. Rollback keeps /api/exams/:id/questions and /api/exams/:id/publish on legacy proxy routes. |
| P7-002 | Implement native exam authoring CRUD | exam-service | Done | Native exams table plus POST /v1/exams, GET /v1/exams, GET /v1/exams/{id}, PATCH /v1/exams/{id}, and DELETE /v1/exams/{id} preserve owner/tenant scope, workflow/status/folder filters, duration/access/result-mode fields, access password hashing, password-hash redaction, direct-publish rejection, closed/published update guards, draft-only delete, and rollback by keeping /api/exams routes legacy-proxied. |
| P7-003 | Implement native publish workflow | exam-service | Done | Native POST /v1/exams/{id}/publish publishes only draft exams, requires at least one stored or supplied snapshot, optionally refreshes snapshots through the native snapshot contract before status change, creates the default access link with legacy guest/login attempt limits, records a service-local exam.published outbox event for later attempt-service/notification dispatch, keeps legacy-compatible error messages, and rolls back by keeping /api/exams/:id/publish legacy-proxied. |
| P7-004 | Implement attempt start snapshot copy | attempt-service | Done | Native POST /v1/exams/{examId}/attempts validates student/runtime/access state from a supplied exam runtime snapshot, copies exam question snapshots into attempt-owned rows, records START events, applies question/option shuffle behavior, never reads live question rows or another service database for attempt content, and rolls back by keeping /api/exams/:examId/start and /api/attempts/* legacy-proxied. |
| P7-005 | Implement answer save and submit grading parity | attempt-service | Done | Native POST /v1/attempts/{attemptId}/answers preserves attempt-owner checks, clientVersion/serverVersion conflict behavior, and SAVE_ANSWER events; native POST /v1/attempts/{attemptId}/submit grades from attempt-owned snapshots only, updates answer correctness/scores plus attempt totals, records SUBMIT/TIMEOUT events, adds 000003_attempt_answers_grading.sql, and rolls back by keeping /api/attempts/* legacy-proxied. Verified by focused/full Go tests, vet, OpenAPI parse, compose config, and runtime smoke. |
| P7-006 | Implement attempt event and result read parity | attempt-service | Done | Native POST /v1/attempts/{attemptId}/events, GET /v1/attempts/{attemptId}/events, and GET /v1/attempts/{attemptId}/result preserve exam-room event history, TIMEOUT submit delegation, ascending event listing, result visibility redaction, hidden reasons, unrounded scorePercent, and rollback by keeping /api/attempts/* legacy-proxied. Adds attempt-local exam result policy snapshot fields via 000004_attempt_result_events.sql instead of querying exam-service DB. Verified by focused/full Go tests, vet, OpenAPI parse, compose config, and runtime smoke. |
| P7-007 | Add attempt route-table rehearsal coverage | api-gateway, attempt-service, scripts | Done | Added a native attempt start compatibility alias at POST /v1/exams/{examId}/start, non-default Compose/localhost attempt route-table examples, static route-table coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes. Coverage proves default routing stays legacy, POST /api/exams/:examId/start rewrites safely to attempt-service, exact attempt detail/save/submit/events/result routes reach attempt-service with auth/role/org guards, broad /api/exams, broad /api/attempts, and fallback remain legacy-proxied, and native carve-outs are ordered before broad legacy routes. Verified by route JSON parse, shell syntax, make test-attempt-routes, OpenAPI parse/mirror diff, focused attempt/gateway tests, full Go tests, go vet, and no legacy diff. |
Phase 8 Auth User School Classroom Course Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P8-001 | Add native auth credential/session foundation | auth-service | Done | Native POST /v1/auth/register, POST /v1/auth/login, POST /v1/auth/refresh, POST /v1/auth/logout, and GET /v1/auth/me preserve the legacy session envelope, bcrypt password verification, refresh-token jti hash/revoke behavior, access-token payload fields required by current guards/frontend, and rollback by keeping /api/auth/* legacy-proxied. Adds service-owned identities, identity_memberships, and refresh_tokens via 000002_auth_identity.sql; native refresh tokens are SHA-256 digested before bcrypt hashing to avoid raw token storage and Go bcrypt long-input limits. Verified by focused/full Go tests, vet, OpenAPI parse/diff, compose/K8s YAML checks, and runtime smoke. |
| P8-002 | Add native user profile foundation | user-service | Done | Native PUT /v1/users/{userId}/profile-snapshot, GET /v1/users/{userId}/profile, PATCH /v1/users/{userId}/profile, and role-specific teacher/student/parent profile PATCH endpoints preserve legacy profile hydration, base profile validation, email/phone uniqueness, nullable role-profile payloads, and rollback by keeping /api/auth/me* legacy-proxied. Adds service-owned users, teacher_profiles, student_profiles, parent_profiles, teacher_kyc, and parent_students via 000002_user_profiles.sql; credentials and password changes remain auth-service-owned. Verified by focused user-service tests, full Go tests, vet, OpenAPI parse/diff, compose/K8s YAML checks, and runtime smoke. |
| P8-003 | Add native school organization/member foundation | school-service | Done | Native organization, unit, member, user-membership, and tenant resolve/validate APIs preserve legacy organization CRUD, admin/non-admin list scoping, default organization fallback, unit-code uniqueness, member upsert, and last active OWNER protection. Adds service-owned organizations, organization_units, and organization_members; public /api/organizations* remains legacy-proxied until gateway adapters enforce auth/RBAC and legacy response compatibility. Verified by focused school-service tests, full Go tests, vet, OpenAPI parse/diff, compose/K8s YAML checks, no-legacy-diff check, and runtime smoke. |
| P8-004 | Add native classroom/member foundation | classroom-service | Done | Native classroom CRUD, status, delete-impact, purge, member, student, join, and placeholder progress APIs preserve legacy manager/member scoping, teacher-member creation, teacher transfer guard, student join by code/id, member upsert, primary-teacher reassignment, and archive-vs-delete behavior for service-owned data. Adds service-owned classrooms and classroom_members; public /api/classrooms* and /api/admin/classrooms* remain legacy-proxied until gateway adapters enforce auth/RBAC, cross-service validation, and response hydration. Verified by focused classroom-service tests, full Go tests, vet, OpenAPI parse/diff, compose/K8s YAML checks, no-legacy-diff check, and runtime smoke. |
| P8-005 | Add native course content/enrollment foundation | course-service | Done | Native course, section, lesson, material metadata, enrollment, student progress, and public course projection APIs preserve legacy manager scoping, course archive semantics, section ordering, lesson/material publish flags, enrollment upsert, active enrollment checks, progress status derivation, video progress completion, and material view counting for service-owned data. Adds service-owned courses, course_sections, course_lessons, course_materials, course_enrollments, course_lesson_progress, course_video_progress, and course_material_views; public /api/courses*, /api/student/courses*, and /api/public/catalog* remain legacy-proxied until gateway adapters enforce auth/RBAC, cross-service validation, wallet purchase, file streaming, question/quiz contracts, and response hydration. Verified by focused/full Go tests, vet, OpenAPI parse/diff, compose/K8s YAML checks, no-legacy-diff check, and runtime smoke. |
| P8-006 | Add auth route-table rehearsal coverage | api-gateway, auth-service, scripts | Done | Added non-default auth route-table examples, static route coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes for the Phase 8 native auth session foundation while default routing stays legacy. Coverage proves only POST /api/auth/register, POST /api/auth/login, POST /api/auth/refresh, POST /api/auth/logout, and GET /api/auth/me rewrite to auth-service, sibling auth routes such as Google, test-login, forgot/reset password, profile, KYC, and email-change stay on broad legacy auth routing, native auth routes do not use the gateway auth adapter, and native carve-outs are ordered before broad /api/auth plus fallback. Verified by route JSON parse, shell syntax, make test-auth-routes, OpenAPI parse/mirror diff, focused auth/gateway tests, full Go tests, go vet, and no legacy diff. |
| P8-007 | Add organization read route-table rehearsal coverage | api-gateway, school-service, scripts | Done | Added non-default read-only organization route-table examples, static route coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes for the Phase 8 native school-service foundation while default routing stays legacy. Coverage proves only GET /api/organizations, GET /api/organizations/:id, GET /api/organizations/:id/units, and GET /api/organizations/:id/members rewrite to school-service with gateway auth/organization header injection and no global role adapter; organization writes, purge, unit/member mutations, student-imports, broad /api/organizations, and fallback remain legacy-proxied until RBAC/tenant adapters and response hydration are explicit. Verified by route JSON parse, shell syntax, make test-organization-routes, focused gateway/school-service tests, full Go tests, go vet, and no legacy diff. |
| P8-008 | Add student course read route-table rehearsal coverage | api-gateway, course-service, scripts | Done | Added non-default student-course route-table examples, static route coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes for the Phase 8 native course-service foundation while default routing stays legacy. Coverage proves only GET /api/student/courses and GET /api/student/courses/{courseId} rewrite to course-service with gateway auth, global STUDENT role checks, and organization header injection. Student recommendation, purchase, progress/video/material writes, broad /api/student/courses, broad /api/courses, broad /api/public, and fallback remain legacy-proxied until recommendation, wallet, progress-write, file-streaming, and response hydration adapters are explicit. Verified by route JSON parse, shell syntax, make test-student-course-routes, focused gateway/course-service tests, full Go tests, go vet, and no legacy diff. |
| P8-009 | Add student course progress route-table rehearsal coverage | api-gateway, course-service, scripts | Done | Added non-default student-course progress route-table examples, static route coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes for the Phase 8 native course-service foundation while default routing stays legacy. Coverage proves only POST /api/student/courses/{courseId}/lessons/{lessonId}/progress, POST /api/student/courses/{courseId}/lessons/{lessonId}/video-progress, and POST /api/student/courses/{courseId}/materials/{materialId}/view rewrite to course-service with gateway auth, global STUDENT role checks, and organization header injection. Student course list/detail are covered by P8-008 but remain legacy in this progress-only table; mastery, recommendation, purchase, broad /api/student/courses, broad /api/courses, broad /api/public, and fallback remain legacy-proxied until response hydration, recommendation, wallet, and file-streaming adapters are explicit. Verified by route JSON parse, shell syntax, make test-student-course-progress-routes, focused gateway/course-service tests, full Go tests, go vet, and no legacy diff. |
| P8-010 | Add classroom gateway adapter preflight guard coverage | api-gateway, classroom-service, scripts | Done | Audited legacy and native classroom contracts, kept /api/classrooms* and /api/admin/classrooms* legacy-proxied because current native rows still lack cross-service validation, response hydration, and deferred counts, added static guard coverage so default and rehearsal route tables cannot accidentally promote classroom public/admin routes, and made classroom-service accept gateway-injected X-User-* actor headers as a compatibility preflight for future adapters. Verified by shell syntax, make test-classroom-route-guard, focused classroom-service/gateway tests, full Go tests, go vet, and no legacy diff. |
Phase 9 Notification Analytics Admin Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P9-001 | Add native notification inbox/preferences foundation | notification-service | Done | Native notification list/detail/create/batch/event, mark-read, delete, preference, parent-alert, and weak-topic alert APIs preserve legacy inbox paging, ALL/UNREAD/READ/SUPPORT filters, summary counts, admin-vs-owner scoping, parent alert rows, weak-topic alert fanout input, default-allow preferences, and service-owned notification events. Adds service-owned notifications, notification_preferences, and notification_events; public /api/notifications*, /api/parent/alerts*, /api/alerts*, and /api/admin/inbox* remain legacy-proxied until gateway adapters enforce auth/RBAC, recipient resolution, role broadcast, email delivery, support ticket integration, and admin audit logging. Verified by focused/full Go tests, vet, OpenAPI parse/diff, compose/K8s YAML checks, no-legacy-diff check, and runtime smoke. |
| P9-002 | Add native analytics result/event foundation | analytics-service | Done | Native analytics result snapshot, result list, weak-topic rollup, exam/classroom/student summary, and event ingestion APIs preserve legacy result row shape, filters, paging defaults, weak-topic rollup formula, and service-local event capture for already-hydrated attempt data. Adds service-owned analytics_attempt_results and analytics_events; public /api/analytics*, /api/students*, /api/parents*, /api/exams/*/analytics, and classroom report export remain legacy-proxied until gateway adapters enforce auth/RBAC, parent-child/classroom access, result visibility, export formatting, and cross-service hydration. Verified by focused/full Go tests, vet, OpenAPI parse/diff, compose/K8s YAML checks, no-legacy-diff check, and runtime smoke. |
| P9-003 | Add native admin feature-maintenance and audit-log foundation | admin-service | Done | Native feature maintenance list/public/update APIs preserve the legacy feature registry, active-key public payload, admin update shape, message trimming, and read-only AI classification job bypass contract for gateway/consumer use. Native audit-log create/list APIs preserve action/entity/entityId/actorId/organizationId/metadata fields, newest-first listing, and legacy limit/skip filter defaults. Adds service-owned feature_maintenance and audit_logs; public /api/feature-maintenance* and /api/admin/feature-maintenance* remain legacy-proxied until gateway auth/RBAC and maintenance guard adapters are explicit. Public /api/admin/operations*, users, AI settings, wallet, support, and admin dashboard routes remain legacy-proxied. Verified by focused/full Go tests, vet, OpenAPI parse/diff, compose/K8s YAML checks, no-legacy-diff check, and runtime smoke. |
| P9-004 | Add notification inbox/preferences route-table rehearsal coverage | api-gateway, notification-service, scripts | Done | Added non-default notification route-table examples, static route coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes for the Phase 9 native notification foundation while default routing stays legacy. Coverage proves notification inbox list/detail, read/delete, read-all/delete-all, and both preferences aliases (/api/notifications/preferences and /api/alerts/preferences) rewrite to notification-service with gateway auth header injection and no organization requirement, while notification create/batch/snapshot, parent alerts, weak-topic alerts, admin inbox, broad /api/notifications, broad /api/alerts, broad /api/admin, and fallback remain legacy-proxied until recipient resolution, role broadcast, support-ticket, and audit adapters are explicit. Verified by route JSON parse, shell syntax, make test-notification-routes, focused gateway/notification-service tests, full Go tests, go vet, and no legacy diff. |
| P9-005 | Add admin feature-maintenance route-table rehearsal coverage | api-gateway, admin-service, scripts | Done | Added non-default feature-maintenance route-table examples, static route coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes for the Phase 9 native admin feature-maintenance foundation while default routing stays legacy. Coverage proves only GET /api/feature-maintenance/public, GET /api/admin/feature-maintenance, and PATCH /api/admin/feature-maintenance/{key} rewrite to admin-service; admin routes require gateway auth plus global ADMIN role header injection, while public status stays unauthenticated. Broad /api/feature-maintenance, broad /api/admin, AI classification job reads, operations/audit routes, admin users/settings/wallet/support/dashboard, broad /api/questions, and fallback remain legacy-proxied until maintenance guard, RBAC, audit, and response compatibility adapters are explicit. Verified by route JSON parse, shell syntax, make test-feature-maintenance-routes, focused gateway/admin-service tests, full Go tests, go vet, and no legacy diff. |
| P9-006 | Add analytics results/weak-topics route-table rehearsal coverage | api-gateway, analytics-service, scripts | Done | Added non-default analytics route-table examples, static route coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes for the Phase 9 native analytics foundation while default routing stays legacy. Coverage proves only GET /api/analytics/results and GET /api/analytics/weak-topics rewrite to analytics-service with gateway auth, global ADMIN/TEACHER role checks, and organization header injection. Analytics snapshot/event writes, exam/classroom/student/parent analytics, classroom export, broad /api/analytics, broad /api/exams, broad /api/classrooms, broad /api/students, broad /api/parents, and fallback remain legacy-proxied until summary path adapters, parent-child access, report export, result visibility, and cross-service hydration are explicit. Verified by route JSON parse, shell syntax, make test-analytics-routes, focused gateway/analytics-service tests, full Go tests, go vet, and no legacy diff. |
| P9-007 | Add admin operations audit route-table rehearsal coverage | api-gateway, admin-service, scripts | Done | Added non-default admin audit route-table examples, static route coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes for the Phase 9 native admin audit-log foundation while default routing stays legacy. Coverage proves only GET /api/admin/operations/audit rewrites to admin-service /v1/admin/audit-logs with gateway auth and global ADMIN role header injection. Admin operations health, queues, retry/clear commands, metrics, import jobs, outbox, AI settings, feature-maintenance routes not included in this table, broad /api/admin, and fallback remain legacy-proxied until operational controls, tenant filtering, and response compatibility are explicit. Verified by route JSON parse, shell syntax, make test-admin-audit-routes, focused gateway/admin-service tests, full Go tests, go vet, and no legacy diff. |
| P9-008 | Add parent alert route-table rehearsal coverage | api-gateway, notification-service, scripts | Done | Added non-default parent-alert route-table examples, static route coverage, gateway regression coverage, Make/docs/runbook updates, and handoff notes for the Phase 9 native notification foundation while default routing stays legacy. Coverage proves only GET /api/parent/alerts, POST /api/parent/alerts/{notificationId}/read, and POST /api/parent/alerts/read-all rewrite to notification-service with gateway auth plus global PARENT role header injection. Weak-topic alert creation, parent-child relationship lookup, broad /api/parent/alerts, broad /api/alerts, broad /api/notifications, broad /api/admin, and fallback remain legacy-proxied until recipient resolution and response compatibility adapters are explicit. Verified by route JSON parse, shell syntax, make test-parent-alert-routes, focused gateway/notification-service tests, full Go tests, go vet, and no legacy diff. |
Phase 10 DevOps Hardening Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P10-001 | Complete offline K8s service deployment coverage | deploy/k8s, scripts/dev | Done | Every target Go service that scripts/dev/services.sh builds and loads has a matching offline K8s Deployment/Service manifest with local image, imagePullPolicy: Never, configmap/secret envs where needed, service-owned database URL, health/readiness probes, and basic resource requests/limits. k8s-deploy.sh applies all manifests and rolls the requested image tag across gateway plus every service deployment. Runbook documents the service coverage check. Verified by YAML parse, service coverage script, deploy script shell syntax, compose config, full Go tests/vet, and no legacy diff. |
| P10-002 | Add offline K8s schema migration jobs per service | tools/migrator, deploy/k8s/jobs, scripts/dev | Done | Migrator image can apply or report target service schema migrations from services/{service}/migrations without mutating the legacy database. Each service with SQL migrations has a matching offline K8s Job using service-owned DATABASE_URL, local migrator image, and imagePullPolicy: Never; k8s-migrate.sh applies these jobs idempotently. Runbooks document schema migration commands and their separation from legacy backfill commands. Verified by migrator unit tests, job coverage script, YAML parse, shell syntax, full Go tests/vet, compose config, and no legacy diff. |
| P10-003 | Add offline K8s observability scrape baseline | deploy/k8s/observability, scripts/dev, scripts/test | Done | Offline kind deployment includes a Prometheus manifest that scrapes /metrics for every service in scripts/dev/services.sh, uses an explicitly preloaded local observability image, and exposes a local service for target inspection. Deployment/load scripts account for observability images. Runbooks document image preloading, target checks, and coverage validation. Verified by observability coverage script, YAML parse, shell syntax, compose config, full Go tests/vet, and no legacy diff. |
| P10-004 | Expand offline Helm chart render baseline | deploy/helm, scripts/test, docs/runbooks | Done | Helm chart renders the namespace, platform config/secret, local infra, API gateway, every service in scripts/dev/services.sh, ingress, Prometheus scrape config, and optional schema migration Jobs with local image tags and imagePullPolicy: Never. Runbook documents offline Helm render/install flow. Verified by Helm lint/template coverage, YAML parse, compose config, full Go tests/vet, and no legacy diff. |
Phase 11 Frontend Platform Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P11-001 | Add VoidZero frontend platform workspace | apps, packages, frontend tooling | Done | Added a new go-platform frontend workspace without touching legacy apps/ or root packages/: independent Vite React apps for admin, teacher, student, parent, and public surfaces; shared frontend packages for UI, API client, auth client, config, types, and validators; pnpm/Turborepo orchestration; Vitest projects; Oxlint/OXC linting; Vite 8/Rolldown-compatible build setup; and docs/runbook coverage for local dev and Cloudflare Pages-style per-app builds. Frontend apps call the Go API Gateway/BFF through VITE_API_BASE_URL, not individual microservices. Verified by pnpm install, pnpm frontend:typecheck, pnpm frontend:test, pnpm frontend:lint, pnpm frontend:build, and git diff -- apps packages --exit-code. |
| P11-002 | Harden frontend platform architecture gates | apps, packages, frontend tooling | Done | Audited P11-001 against the frontend-platform note, then added the missing large-platform gates without touching legacy apps/ or root packages/: app ownership folders, shared shadcn/Tailwind-style primitives, TanStack Query provider wiring, Zustand auth/session store, OpenAPI-generated gateway client types, Playwright smoke scaffold, and Cloudflare Pages deployment manifest. Verified with pnpm install, pnpm peers check, pnpm frontend:generate-api, pnpm frontend:typecheck, pnpm frontend:test, pnpm frontend:lint, pnpm frontend:build, pnpm frontend:e2e --project=chromium --reporter=line, git diff -- apps packages --exit-code, and curl -I http://127.0.0.1:5201/. |
Phase 12 Frontend Auth/Public Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P12-001 | Add auth/public audit, handoff, and QA image workflow | frontend docs | Done | Created evidence-backed docs for legacy auth/public behavior, Phase 12 handoff, and screenshot workflow before implementation. Legacy root apps//packages/ stayed read-only. |
| P12-002 | Add frontend i18n structure | packages/i18n, apps | Done | Added Vietnamese-default and English-supported dictionaries with typed locale helpers. Apps and shared UI can consume locale-aware copy without duplicating strings. |
| P12-003 | Add seed auth helpers and shared auth UI | packages/auth-client, packages/ui | Done | Modeled seed accounts [email protected], [email protected], [email protected], [email protected] with password Hoctapaz@123; added login/register/forgot/Google-entry components shared by role apps; remember behavior stores email only. |
| P12-004 | Wire role app auth routes | apps/admin-web, apps/teacher-web, apps/student-web, apps/parent-web | Done | /login, /auth/login, /register, /auth/register, /forgot-password, and /auth/forgot-password render role-aware auth pages while root still renders the app workspace shell. |
| P12-005 | Implement public-web homepage parity surface | apps/public-web, packages/ui | Done | public-web root renders a HocTapAZ public homepage aligned with the current legacy teacher-toolkit home, with brand, auth CTAs, teacher toolkit labels, and responsive desktop/mobile layout. |
| P12-006 | Verify checks and Chrome screenshots | frontend tests, docs/demo-images | Done | Passed frontend typecheck/test/lint/build/e2e. Saved images under go-platform/docs/demo-images/frontend-auth-public/round-01-after-implementation/ and inspected representative desktop/mobile screenshots. Chrome extension captured public-home images; auth images used Chrome channel fallback after extension UI blocked automation. |
Phase 13 Frontend Staff/Auth/Cloudflare Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P13-001 | Add staff/auth/Cloudflare audit, handoff, and QA workflow | frontend docs | Done | Audit, handoff, and runbook were created before source edits, then updated with final validation and screenshot results. |
| P13-002 | Enforce admin seed-only registration in native Go auth | auth-service | Done | Native /v1/auth/register rejects ADMIN, allows TEACHER/STUDENT/PARENT, OpenAPI register schemas exclude admin, and focused Go tests pass with CGO_ENABLED=0. |
| P13-003 | Connect shared frontend auth to Gateway/native auth | packages/auth-client, packages/ui | Done | Login/register use Gateway /api/auth/login and /api/auth/register when available, preserve local seed demo fallback for non-production login, and do not store plaintext passwords. |
| P13-004 | Add staff-web app and shared app config | apps/staff-web, packages/config, packages/types | Done | Staff app builds/tests like other role apps, has its own host/port/deploy metadata, and does not expose self-registration. |
| P13-005 | Link public auth CTAs to role frontends | packages/ui, public-web | Done | Public home shows role-specific login/register actions targeting teacher, student, parent, staff, and admin frontends instead of dead local auth links. |
| P13-006 | Update Cloudflare/performance structure | deploy/cloudflare, frontend tooling | Done | Pages manifest includes six apps from the go-platform monorepo root, app-specific Vite build outputs, static SPA headers/redirects, and lazy-loaded route chunks. |
| P13-007 | Verify production gates and screenshot QA | tests, Chrome, docs/demo-images | Done | Go/frontend test gates pass; Chrome desktop/mobile screenshots were captured, visually inspected, and notes were updated by workflow. |
Phase 14 Frontend Structure And Cloudflare V2 Dev Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P14-001 | Restructure packages/ui for large-project ownership | packages/ui | Done | UI package has explicit component/layout/module/router folders, auth/public modules are split out of monolith files, compatibility wrappers remain thin, and package-level tests pass independently. |
| P14-002 | Restore public role portal contract | public-web, packages/ui | Done | Public portal links teacher/student/parent login+register and staff/admin login-only, matching auth-service registration rules. |
| P14-003 | Add AI-followable frontend structure docs | docs/architecture, docs/agents | Done | Architecture and handoff docs describe app boundaries, UI package rules, CSS rules, and verification commands for future agents. |
| P14-004 | Prepare Cloudflare Pages v2-dev deploy flow | deploy/cloudflare, scripts/deploy, docs/runbooks | Done | Manifest maps six apps to v2.dev.* domains, deploy script supports Direct Upload via Wrangler, and runbook documents auth/domain prerequisites. |
| P14-005 | Verify six app gates and local runtime | apps, tests | Done | Typecheck, package UI test, full frontend tests, lint, build, e2e, dry-run deploy expansion, and local HTTP checks pass for all six apps. |
| P14-006 | Deploy Cloudflare Pages v2-dev | Cloudflare Pages | Done | Pages projects, custom-domain attachments, proxied CNAME records, and asset deployments exist for all six v2.dev.* hostnames in the hoctapaz.com Cloudflare zone. Cloudflare API reports the latest deployment stage success and custom domain status active for admin, staff, teacher, student, parent, and public. Verified by Wrangler Direct Upload, Cloudflare API metadata, dig @1.1.1.1, curl 200 checks for all custom domains plus SPA fallback paths, and live Playwright smoke on public/admin domains. |
Phase 15 VitePress Docs And API Guide Tasks
| ID | Task | Service/Area | Status | Definition Of Done |
|---|---|---|---|---|
| P15-001 | Add VitePress documentation site | docs, frontend tooling | Done | go-platform/docs is served by VitePress with local search, API/architecture/contracts/runbooks/QA navigation, shared theme assets, and root scripts docs:dev, docs:build, and docs:preview. Legacy root apps/ and root packages/ remain untouched. Verified by pnpm docs:build, VitePress preview, and route smoke for /, /api/, and /contracts/openapi/. |
| P15-002 | Publish gateway-first API guide | docs/api, contracts | Done | API guidance now documents the public /api/* gateway contract, environment matrix, required headers, route-state lifecycle, gateway/native calling examples, OpenAPI source locations, service guide index, and cutover checklist. The guide keeps browser clients on API Gateway/BFF and reserves native /v1/* routes for service tests, adapters, and migration tooling. |
| P15-003 | Deploy docs site to Cloudflare Pages v2-dev | Cloudflare Pages | Done | Pages project hoctapaz-v2-dev-docs-web, custom domain v2.dev.docs.hoctapaz.com, and proxied CNAME exist in the hoctapaz.com zone. deploy/cloudflare/pages.frontend.json includes docs-web, and the docs output deploys from docs/.vitepress/dist. Verified by Wrangler Direct Upload, Cloudflare API metadata, dig @1.1.1.1, curl 200 checks, and live Playwright smoke on the VitePress home/API/contracts pages. |
Task Rules
- Every implementation task must cite the legacy files used as evidence.
- Every route migration task must include rollback instructions.
- Every DB task must include validation queries.
- No task may edit
apps/api,apps/web,packages/shared, or existing legacy config unless explicitly approved in a later phase.