Appearance
Service Workflow Test Matrix
Status: orchestrator-owned dispatch aid for service agents.
Use this with docs/architecture/service-responsibility-matrix.md, docs/agents/agent-task-matrix.md, and the assigned service task pack. It does not replace any task pack; it gives each agent a quick workflow and test target before they audit, code, test, and fix one vertical slice.
Dispatch Invariants
- Work stays inside
go-platform/; legacy paths are read-only evidence. - Frontend callers go through
api-gatewayor an approved BFF. - One agent owns one implementation directory per active slice.
- Alias services use the current implementation directory from the matrix; do not create duplicate directories such as
services/question-service. - Default gateway promotion needs browser/runtime proof and rollback evidence.
- Shared files such as root
Makefile, Compose, Helm, VitePress navigation, and default route tables are orchestrator-owned unless explicitly delegated.
Core Service Workflows
| Dispatch ID | Service | Current implementation | Next workflow slice | Focused verification |
|---|---|---|---|---|
| SVC-001 | api-gateway | services/api-gateway | Protected route rehearsal with IAM RS256/JWKS, HS256 fallback, role/org guards, rollback route table, and route-specific adapters such as exam_start_adapter. | GOTOOLCHAIN=go1.25.11 go test ./services/api-gateway/... plus named route targets for touched surfaces such as make test-auth-routes test-auth-routes-live test-auth-routes-browser test-auth-routes-session-browser test-profile-routes test-organization-routes test-attempt-routes test-bff-routes test-teacher-ai-preview-routes; exam_start_adapter slices also require the opt-in make test-attempt-live and make test-attempt-browser proof hooks before any public promotion. DOCX_PHYSICS_GATEWAY_ATTEMPT_LOCAL_POSTGRES_CONFIRM=local-postgres make test-docx-physics-attempt-local-postgres is the isolated end-to-end candidate that verifies its dynamic served route table, real IAM/Exam/Attempt owner path, and Student Web browser start -> answer-save -> submit -> result-read journey, without default promotion. |
| SVC-002 | bff-service | services/bff-service | Screen aggregation and bounded owner-service composition previews without primary business DB or hidden writes. | GOTOOLCHAIN=go1.25.11 go test ./services/bff-service/..., make test-bff-routes, and BFF_ADMIN_OVERVIEW_ISOLATED_CONFIRM=bff-admin-overview-isolated make test-bff-admin-overview-isolated for the direct owner/BFF runtime. BFF_ADMIN_OVERVIEW_ISOLATED_CONFIRM=bff-admin-overview-isolated make test-bff-admin-overview-browser additionally runs Admin Vite -> temporary authenticated Gateway -> BFF -> admin-service/AI with one browser request, native route headers, rendered source state, and a local latency ceiling. Both are disposable/non-default and do not promote broad /api/admin. |
| SVC-003 | iam-service | services/iam-service | Credentials, sessions, JWKS, management guards, access scopes, invites, and IAM-owned organization membership. | GOTOOLCHAIN=go1.25.11 go test ./services/iam-service/..., make test-auth-routes, AUTH_ROUTE_LIVE_SELF_TEST=1 make test-auth-routes-live, AUTH_ROUTE_BROWSER_SELF_TEST=1 make test-auth-routes-browser, AUTH_SESSION_BROWSER_SELF_TEST=1 make test-auth-routes-session-browser, make test-organization-routes, and ORGANIZATION_MEMBERSHIP_WRITE_SELF_TEST=1 make test-organization-membership-write-live when membership routes change. |
| SVC-004 | profile-service | services/profile-service | Education profile, contacts, parent-child read models, parent-recipient resolution, safe teacher KYC self-service/admin review, redacted audit projection, and current-user profile route proof through api-gateway. | GOTOOLCHAIN=go1.25.11 go test ./services/profile-service/..., make test-profile-routes test-profile-kyc-routes test-profile-admin-kyc-routes, PROFILE_ROUTE_LIVE_SELF_TEST=1 make test-profile-routes-live, and PROFILE_ROUTE_BROWSER_SELF_TEST=1 make test-profile-routes-browser; live/browser profile promotion still requires orchestrator approval and default-route rollback evidence. |
| SVC-005 | organization-service | services/school-service alias | School/center/campus/org-unit and academic-year metadata plus IAM-synchronized membership read model for tenant validation. | GOTOOLCHAIN=go1.25.11 go test ./services/school-service/..., make test-organization-routes, make test-academic-year-routes, make test-academic-year-route-runtime, make test-academic-year-postgres, and make test-academic-year-browser. The browser target starts fresh PostgreSQL, temporary school/Gateway/Admin Vite processes, and proves list/draft/activate only through the opt-in candidate; all academic-year evidence remains disposable/non-default and broad organization routes stay legacy-backed. |
| SVC-006 | classroom-service | services/classroom-service | Classroom-local class/member/teacher-assignment workflows using profile/org references only. | GOTOOLCHAIN=go1.25.11 go test ./services/classroom-service/... and make test-classroom-route-guard. |
| SVC-007 | course-service | services/course-service | Course/module/lesson/material metadata, enrollment, progress, visibility, owner catalog snapshots, and public/student route rehearsal. | GOTOOLCHAIN=go1.25.11 go test ./services/course-service/..., COURSE_SEARCH_PROJECTION_OUTBOX_POSTGRES_CONFIRM=disposable-postgres make test-course-learning-catalog-delivery-postgres test-course-learning-progress-delivery-postgres, and COURSE_LEARNING_ANALYTICS_RUNTIME_CONFIRM=local-postgres make test-course-learning-analytics-runtime for native Course -> Analytics catalog/progress delivery and mastery read with separate fresh owner databases. Also run make test-student-course-routes test-student-course-progress-routes and STUDENT_COURSE_BROWSER_SELF_TEST=1 make test-student-course-browser; all outbox/runtime targets are local/disposable and do not promote a route. docs/qa/student-course-route-rehearsals.md keeps live/browser proof required before student route promotion. |
| SVC-008 | question-service | services/question-bank-service alias | Question CRUD/read projections, type definitions, taxonomy, AI context, import ingest handoff, and editor write save/reload proof. | GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/... plus make test-question-read-routes test-question-types-routes test-question-classification-apply-routes, make test-question-write-routes, QUESTION_WRITE_SELF_TEST=1 make test-question-write-live, QUESTION_WRITE_BROWSER_SELF_TEST=1 make test-question-write-browser, make test-question-types-live test-question-types-browser, and make test-question-read-browser test-question-read-browser-admin for read/type/apply/write route slices. |
| SVC-009 | exam-service | services/exam-service | Exam authoring, persistent matrix blueprints/rules, publish snapshots, native assignment/result-release, access decision API, and next share-link/export contracts. | GOTOOLCHAIN=go1.25.11 go test ./services/exam-service/..., ATTEMPT_RESULT_RELEASE_NOTIFICATION_SELF_TEST=1 make test-attempt-result-release-notification-workflow, EXAM_RESULT_RELEASE_POSTGRES_CONFIRM=disposable-postgres make test-exam-result-release-postgres, make test-exam-result-release-deploy, and EXAM_RESULT_RELEASE_RUNTIME_CONFIRM=exam-result-release-isolated make test-exam-result-release-runtime, plus make test-exam-authoring-routes test-teacher-exam-blueprint-bff-routes. The result-release workflow proves the exam-owned durable relay before attempt-service's notification outbox; the disposable Postgres proof verifies owner migration, transaction rollback, and restart recovery; the runtime proof verifies the authenticated relay opens an actual hidden submitted attempt; and the deployment guard keeps its target/auth/worker configuration present. All remain disposable/non-default, not shared/live or public Gateway promotion. Run DOCX_PHYSICS_EXAM_BLUEPRINT_ISOLATED_CONFIRM=docx-physics-exam-blueprint-isolated make test-docx-physics-exam-blueprint-isolated for a fresh Compose proof of a real 28-question DOCX matrix through BFF, including source-solution parity in Question Bank, 16 ordered true/false statements in online/offline snapshots and Word, embedded snapshot images, and every formula as OMML or a visible fallback. Matrix rehearsal remains non-default until browser/rollback proof, while start adapter slices also require make test-attempt-routes, make test-attempt-live, and make test-attempt-browser. |
| SVC-010 | attempt-service | services/attempt-service | Attempt sessions, copied snapshots, answers, grading, events, results, exam result-release propagation, and public attempt surfaces. | GOTOOLCHAIN=go1.25.11 go test ./services/attempt-service/... plus make test-attempt-routes, make test-attempt-live, and make test-attempt-browser; gateway/BFF adapter tests are required before public route promotion. ATTEMPT_RESULT_RELEASE_NOTIFICATION_SELF_TEST=1 make test-attempt-result-release-notification-workflow covers result visibility, retry, and two-dispatcher lease claiming before notification-service publish. DOCX_PHYSICS_GATEWAY_ATTEMPT_LOCAL_POSTGRES_CONFIRM=local-postgres make test-docx-physics-attempt-local-postgres proves a Physics-backed Student Web browser start -> save -> submit -> result-read -> GRADED attempt with fresh IAM/Exam/Attempt databases and no shared runtime or default route. |
| SVC-011 | file-service | services/document-service alias | File/media metadata, signed reads, teaching documents, and owner projection for search. | GOTOOLCHAIN=go1.25.11 go test ./services/document-service/... plus make test-storage-media-parity when upload/download behavior changes; docs/qa/storage-media-parity-smoke.md keeps browser proof required before public storage promotion. |
| SVC-012 | import-service | services/docx-import-service alias | Import jobs, parser orchestration, review save, approval saga, SSE/status/download, direct Mistral OCR, formula provenance bridge, direct and durable MathType-to-OMML conversion, and draft handoff to question/exam. | GOTOOLCHAIN=go1.25.11 go test ./services/docx-import-service/... plus make test-import-create-routes test-import-status-routes test-import-approval-routes test-import-review-roundtrip-routes, make test-import-pdf-ocr-workflow, and the matching live/browser smoke target for changed workflows. make test-docx-corpus reads all four local fixtures, then runs a real in-process Import approval against an isolated Question Bank HTTP boundary: complete Physics payloads forward unchanged, while untouched Math, English, and DGNL remain blocked before any owner write. It then saves review-safe source-evidence subsets (Math 13, English 34, DGNL 37), asserts exact owner payload plus recomputed review stats, and verifies canonical type plus source-label-to-option-ID, numeric-value, and Physics true/false statement mappings; no missing or nonnumeric placeholder answer is inferred. `GOTOOLCHAIN=go1.25.11 go test ./services/docx-import-service/internal/usecase ./services/docx-import-service/internal/http -run 'TestHTTPApprovalUsage |
| SVC-013 | formula-docx-service | source-controlled runtimes/go-formula-docx runtime behind import adapters | Parser determinism, MathType/OMML/OLE/table conversion, per-question formula provenance, metrics, and corpus evidence through docx-import-service adapter tests. | sh scripts/test/go-formula-runtime-coverage.sh, make test-docx-corpus, DOCX_FORMULA_DETERMINISM_CONFIRM=read-only-formula-runtime make test-docx-formula-determinism, and GOTOOLCHAIN=go1.25.11 go test ./services/docx-import-service/internal/parser/docx -count=1 when parser behavior changes. The determinism target repeats Math (22/125, 117 MTEF-OLE plus 8 OMML) and Physics (28/84 MTEF-OLE) against the external runtime, then has the real Go adapter require byte-identical import-visible JSON after latency_ms is cleared. Raw OLE/WMF diagnostic asset paths remain filtered non-display provenance, not persisted browser media. |
| SVC-014 | search-service | services/search-service | Rebuildable owner-service indexes, sync checkpoints, filters, and source projection pulls; /api/public/catalog* remains course-service-owned until an explicit legacy route mapping selects search-service. | GOTOOLCHAIN=go1.25.11 go test ./services/search-service/... -count=1, make test-search-rebuild, make test-search-routes, and make test-search-projection-freshness-latency; SEARCH_PROJECTION_PULL_WORKER_POSTGRES_CONFIRM=disposable-postgres make test-search-projection-pull-worker-postgres runs the real binary against fresh PostgreSQL, proves one-page PARTIAL checkpoints resume to SYNCED after process restart, and verifies native search/sync reads. All are local/disposable only; route rehearsals must cite the exact legacy controller/owner mapping first. |
| SVC-015 | ai-service | services/ai-classifier-service alias | Provider adapters, AI jobs, AI-owned non-secret default provider runtime selection, prompt context, generate/explain/grade contracts, and usage/wallet integration points only through explicit APIs; AI must not own quota checks or credit movement. | GOTOOLCHAIN=go1.25.11 go test ./services/ai-classifier-service/..., make test-ai-provider-settings, make test-ai-classification-job-route-guard test-teacher-ai-preview-routes, AI_CLASSIFICATION_JOB_SELF_TEST=1 make test-ai-classification-job-live, and make test-question-classification-apply-routes; AI_GENERATION_SETTLEMENT_LOCAL_POSTGRES_CONFIRM=local-postgres make test-ai-generation-settlement-local-postgres uses a fresh initdb cluster, seeds only an AI-owned non-secret mock provider_settings selection, and asserts both native binary starts report configurationSource=database before its separate usage/wallet settlement restart proof. The explicitly isolated make test-docx-physics-exam-blueprint-isolated also proves mock similar/explanation previews from an imported Question Bank reference stay no-write until the teacher-reviewed Question Bank draft/version APIs run idempotently. Run make test-monetization-event-chain when touching usage/wallet handoff contracts, and use make test-question-classification-apply-live only for explicit live write smoke. |
| SVC-016 | billing-service | services/billing-service | Plan catalog, subscription lifecycle, invoices, entitlement events, renewal/proration policy. | GOTOOLCHAIN=go1.25.11 go test ./services/billing-service/... plus make test-monetization-event-chain and make test-monetization-broker-transport when emitting to usage/wallet. |
| SVC-017 | wallet-service | services/wallet-service | AZ Credits balance, immutable ledger, top-up/withdrawal admin review, grants/debits/refunds, event consumers, and first legacy-compatible wallet/admin adapter rehearsal. | GOTOOLCHAIN=go1.25.11 go test ./services/wallet-service/... plus make test-monetization-event-chain test-monetization-routes test-monetization-broker-transport for replay/idempotency, route guards, and broker transport. |
| SVC-018 | usage-service | services/usage-service | Feature gates, quotas, counters, check/consume/reset, entitlement sync, and limit overrides. | GOTOOLCHAIN=go1.25.11 go test ./services/usage-service/... plus make test-monetization-event-chain and make test-monetization-broker-transport for billing entitlement replay and broker transport. |
| SVC-019 | payment-service | services/payment-service | Payment orders, provider webhooks, idempotency, reconcile, and paid-event outbox. | GOTOOLCHAIN=go1.25.11 go test ./services/payment-service/... plus make test-monetization-event-chain test-monetization-routes test-monetization-broker-transport before public hook cutover. `PAYMENT_SERVICE_POSTGRES_TEST_DATABASE_URL='payment-test-dsn' GOTOOLCHAIN=go1.25.11 go test ./services/payment-service/internal/repository -run 'TestPostgresPaymentWebhookReplayIntegration |
| SVC-020 | notification-service | services/notification-service | Inbox, preferences, read/delete state, parent alerts, fanout consumers, and delivery metadata. attempt-service is a bounded grade-release producer dependency, including delayed MANUAL/pre-close AFTER_CLOSE result release, not an implementation owner. | GOTOOLCHAIN=go1.25.11 go test ./services/notification-service/... plus GOTOOLCHAIN=go1.25.11 go test ./services/attempt-service/..., ATTEMPT_RESULT_RELEASE_NOTIFICATION_SELF_TEST=1 make test-attempt-result-release-notification-workflow, make test-notification-routes test-parent-alert-routes test-attempt-routes, NOTIFICATION_EVENT_FANOUT_POSTGRES_CONFIRM=disposable-postgres make test-notification-event-fanout-postgres, and make test-student-notification-browser. The fanout and browser targets use disposable owner storage or memory-only candidate processes and do not promote the default route. |
| SVC-021 | audit-service | services/audit-service | Append-only audit/security events, replay/idempotency, retention/legal-hold scans, producer projections, and compatibility backfill target. | GOTOOLCHAIN=go1.25.11 go test ./services/audit-service/..., make test-audit-admin-compat-routes, AUDIT_REPLAY_RETENTION_POSTGRES_CONFIRM=disposable-postgres make test-audit-replay-retention-postgres, make test-admin-audit-owner-browser, plus producer contract tests for IAM/payment/billing/wallet/admin/gateway. The Postgres and Admin browser targets are disposable/non-default evidence; they do not establish legacy backfill parity or promote the default route. |
| SVC-022 | analytics-service | services/analytics-service | Dashboard/result/progress/mastery projections and weak-topic rollups from owner events. | GOTOOLCHAIN=go1.25.11 go test ./services/analytics-service/..., ANALYTICS_POSTGRES_REBUILD_CONFIRM=disposable-postgres make test-analytics-course-learning-projection-outbox-postgres, make test-analytics-course-learning-projection-worker-config, and COURSE_LEARNING_ANALYTICS_RUNTIME_CONFIRM=local-postgres make test-course-learning-analytics-runtime for the native two-service handoff. Also run make test-analytics-routes and event projection fixtures for changed producers. The Course outboxes and Analytics 000008 worker remain opt-in/local only and never add a Gateway route. |
| SVC-023 | admin-service | services/admin-service | Admin read models, feature maintenance guard decisions, moderation/support workflows, and owner-service adapters; dashboards must use owner APIs/source snapshots instead of synthesizing source-service totals. | GOTOOLCHAIN=go1.25.11 go test ./services/admin-service/... plus owner-source/source-snapshot tests, make test-feature-maintenance-routes test-admin-audit-routes test-admin-owner-source-routes, and make test-admin-owner-source-browser. The browser target uses memory-only Admin storage, a disposable owner fixture, temporary Gateway/Vite processes, and default legacy rollback; it does not prove dashboard parity or promote a route. |
Cutover And Alias Workflows
| Pack | Routed owner | Workflow gate |
|---|---|---|
auth-service | IAM only | Not a Go-platform service row. /api/auth* and /v1/auth* are compatibility namespaces backed by iam-service; do not create an auth-service task pack, API doc, OpenAPI contract, deployment, or runtime directory. |
iam-org-membership-canonical | IAM plus organization coordination | IAM remains the only permission-bearing membership writer; school-service sync routes reject ordinary callers and preserve event ordering/tombstones; non-default gateway write proof uses ORGANIZATION_MEMBERSHIP_WRITE_SELF_TEST=1 make test-organization-membership-write-live before any live bearer-token smoke. |
iam-profile-cutover-hardening | Orchestrator with IAM/Profile/Gateway/Migration | UUID/backfill/default-route cutover is not done until make test-iam-profile-backfill-report, browser proof, rollback evidence, UUID migration implementation, and clean-cluster proof exist. |
user-service-retirement | Orchestrator retirement only | No new product work enters services/user-service; removal waits for IAM/Profile route parity and data backfill evidence. |
docx-corpus-question-bank-local-postgres | Import and Question Bank owners | DOCX_CORPUS_QUESTION_BANK_LOCAL_POSTGRES_CONFIRM=local-postgres make test-docx-corpus-question-bank-local-postgres creates two service-owned temporary databases, applies migration Up blocks, and proves the four-fixture HTTP persistence/read-back flow without Docker or a shared database. It does not promote a Gateway route or cover Exam, AI, or browser behavior. |
docx-physics-exam-blueprint-local-postgres | Document, Import, Question Bank, Exam, BFF, and AI owners | DOCX_PHYSICS_EXAM_BLUEPRINT_LOCAL_POSTGRES_CONFIRM=local-postgres make test-docx-physics-exam-blueprint-local-postgres creates five service-owned temporary databases, materializes Physics media through Document, then proves the BFF matrix, online/offline snapshots, Word export, and reviewed mock AI writes. Object bytes are intentionally in-memory and it is not Gateway, browser, OCR-provider, or production evidence. |
docx-physics-gateway-attempt-local-postgres | Gateway, IAM, Classroom, Document, Import, Question Bank, Exam, and Attempt owners | DOCX_PHYSICS_GATEWAY_ATTEMPT_LOCAL_POSTGRES_CONFIRM=local-postgres make test-docx-physics-attempt-local-postgres creates seven service-owned temporary databases, verifies the complete dynamically served candidate table, authenticates isolated teacher/student identities, and persists the Physics 18/6/4 Question Bank -> online Exam -> Attempt GRADED path. It drives the Student Web candidate through one each of start, answer-save, submit, and result-read requests, with the access-link code and bearer header redacted in artifacts. Document bytes stay in-memory; it is not Mistral, default-route, deployed, or production proof. |
entitlement-service | Usage alias only | Do not spawn a separate service owner unless an ADR renames usage-service. |
monetization-scaffold-wave | Billing/Wallet/Usage/Payment coordination | Money, entitlement, wallet ledger, and payment webhook responsibilities stay split by service and verified through replay-safe events. |
Agent Closeout Checklist
Every service agent closeout must include:
- Docs read, including the service task pack and this matrix.
- Legacy evidence read, with file paths.
- Files changed, limited to the writable scope.
- Focused tests and service verification command output.
- Route/default cutover status and rollback notes if any route changed.
- Remaining risks and the next recommended task.