Skip to content

Question Write Parity Task

Agent workflow: follow README.md for Audit -> Investigate -> Code -> Test -> Fix; keep this pack's writable scope and verification commands authoritative.

Dispatch type: orchestrator

Owner: question-bank-service / canonical question-service.

Goal:

Close native question create/update/archive/delete/folder/group write gaps after read projection parity, without changing exam/attempt snapshot ownership.

Legacy source evidence:

  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/questions/**
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/prisma/schema.prisma
  • frontend question editor callers under /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/web.

Writable files:

  • services/question-bank-service/**
  • contracts/openapi/services/question-bank-service.yaml
  • docs/api/question-bank-service.md
  • docs/agents/service-tasks/question-write-parity.md

Delegated gateway verification scope:

  • Route examples: deploy/gateway/routes.questions-write-native-example.json and deploy/gateway/routes.questions-write-native-localhost-example.json.
  • Test scripts: scripts/test/question-write-route-coverage.sh, scripts/test/question-write-live-smoke.sh, scripts/test/question-write-browser-smoke.sh, and scripts/test/question-write-browser-smoke.mjs.
  • QA docs: docs/qa/question-write-route-rehearsals.md.
  • Root Makefile only for test-question-write-routes, test-question-write-live, and test-question-write-browser.

Orchestrator-owned files:

  • Gateway route tables, browser smoke artifacts, shared import/exam/attempt contracts, frontend editor code, and default route promotion.

Tasks:

  • Add canonical create/update APIs preserving rich content JSON, answer keys, options, media/formula refs, taxonomy refs, custom type metadata, and scoring. Manual native create now exists at POST /v1/questions. Native update and version replacement now exists at PATCH /v1/questions/{id} with omitted fields preserved, supplied options/tags/media/formula refs replaced, and a new question_versions row promoted to currentVersionId on each successful update.
  • Add archive-vs-hard-delete behavior and bulk actions. Normal native delete now exists at DELETE /v1/questions/{id}: rows with projected usage or clone refs are archived, and unused rows are hard-deleted only inside question-bank-service ownership. PATCH /v1/questions/bulk-status covers scoped status changes. Service-local permanent-delete batch now exists at POST /v1/questions/permanent-delete; it skips out-of-scope IDs and never deletes exam/attempt/course owner data. Service-local permanent-delete impact preview now exists at POST /v1/questions/permanent-delete-impact for selected IDs and the first scoped archived batch, using question_usage_counts and question_exam_refs projections. Detailed affected exam metadata now hydrates from PUT /v1/questions/exam-refs rows published by exam-service or migration tooling. Service-local permanent-delete job foundation now exists at POST /v1/questions/permanent-delete/jobs, GET /v1/questions/permanent-delete/jobs/{id}, GET /v1/questions/permanent-delete/jobs/{id}/events, and POST /v1/questions/permanent-delete/jobs/{id}/cancel; durable broker/worker parity remains pending owner-service work.
  • Add folder/group management parity. Native question group list/create is now covered by GET /v1/question-groups and POST /v1/question-groups. Native question folder list/create/update/delete is now covered by GET/POST/PATCH/DELETE /v1/question-folders; manual create validates and stores scoped folderId. Group update/delete and public route promotion remain pending only if a later legacy/browser parity slice proves they are needed.
  • Add editor save regression coverage for manual type overrides and versioning.

Acceptance:

  • Native writes never mutate exam/attempt snapshots directly.
  • Import approval remains the only import-to-question write path.
  • Browser editor save parity is proven before public route promotion. If no named browser/live target covers the changed editor save path, the agent must add one before moving any default question write route.
  • The named editor save/reload gate is docs/qa/question-write-route-rehearsals.md with make test-question-write-routes, QUESTION_WRITE_SELF_TEST=1 make test-question-write-live, and QUESTION_WRITE_BROWSER_SELF_TEST=1 make test-question-write-browser.
  • Default question write route promotion requires rollback route-table evidence.

Verification:

  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/...
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_CreateManualQuestion' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run TestServer_CreateQuestionManualWriteAndListScope -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run TestQuestionService_UpdateManualQuestionPreservesOmittedFieldsAndVersions -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run TestServer_UpdateQuestionCreatesReplacementVersionAndPreservesOmittedFields -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(DeleteManualQuestion|PermanentDeleteQuestions)' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(DeleteQuestion|PermanentDeleteQuestions)' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(PermanentDeleteImpact|PermanentDeleteQuestions)' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(PermanentDeleteImpact|PermanentDeleteQuestions)' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(QuestionExamRef|PermanentDeleteImpact)' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(QuestionExamRef|PermanentDeleteImpact)' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(PermanentDeleteJob|PermanentDeleteImpact|PermanentDeleteQuestions)' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(PermanentDeleteJob|PermanentDeleteImpact|PermanentDeleteQuestions)' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/usecase -run 'TestQuestionService_(QuestionFolder|CreateManualQuestion.*Folder)' -count=1 -v
  • GOTOOLCHAIN=go1.25.11 go test ./services/question-bank-service/internal/http -run 'TestServer_(QuestionFolder|CreateQuestionManualWriteAndListScope)' -count=1 -v
  • make test-question-types-routes test-question-read-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
  • Run the real live/browser modes from docs/qa/question-write-route-rehearsals.md before public route promotion; route/read tests alone do not prove write parity.
  • ruby -e "require 'yaml'; ARGV.each { |f| YAML.load_file(f) }" services/question-bank-service/api/openapi.yaml contracts/openapi/services/question-bank-service.yaml

Go-platform documentation is generated from repository Markdown.