Skip to content

file-service Agent Tasks

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

Dispatch type: per-service

Dispatch ID: SVC-011

Current implementation: services/document-service.

Owns: files, media assets, object metadata, signed URLs, teaching documents.

Must read:

  • storage/media parity QA docs under docs/qa/
  • legacy storage/media/document modules under /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/storage/, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/ai-import/, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/documents/, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/admin/content-admin.service.ts, and /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/public/public-catalog.controller.ts if the task touches marketplace behavior.

Legacy source evidence:

  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/storage/**
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/documents/**
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/admin/content-admin.*
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/public/public-catalog.controller.ts

Writable files:

  • services/document-service/**
  • contracts/openapi/services/document-service.yaml
  • docs/api/document-service.md

Orchestrator-owned files:

  • storage route examples under deploy/gateway/routes.storage-*.json, storage route tests under scripts/test/storage-*.sh, billing/wallet purchase decisions, default route table, and shared deploy manifests unless explicitly delegated.

Delegated gateway verification scope:

  • Only when the orchestrator assigns a storage/file route/live/browser proof subtask, this service agent may update non-default deploy/gateway/routes.storage-*.json examples, scripts/test/storage-*.sh, docs/qa/storage-*.md, and root Makefiletest-storage-* targets.
  • Billing/wallet/usage purchase and quota route decisions, the default gateway route table, and frontend marketplace routes remain orchestrator-owned unless explicitly delegated. Public promotion still requires browser/runtime proof and rollback notes.

Initial tasks:

  • Treat document-service as the current implementation target for the file-service domain alias; do not create a separate file-service scaffold.
  • Maintain the native teaching document search projection: GET /v1/documents/search-projections emits copied DOCUMENT search docs for search-service rebuilds from service-owned teaching_documents rows.
  • Done: add the first admin dashboard owner read for teaching document reviews. GET /v1/admin/documents/review-summary returns service-owned total and status counts, including PENDING_REVIEW, for admin-service/BFF dashboard traceability. It is service-local, supports organization scoping, and does not move purchase/quota/wallet decisions or public /documents routes.
  • Done: add workflow tests for upload -> metadata -> content read -> variant read through the storage compatibility HTTP routes and memory object store.
  • Done: hardened object content reads for /v1/storage/objects/content; normal reads require X-Organization-Id with a matching storage-key prefix, and trusted service-to-service reads require DOCUMENT_OBJECT_READ_TOKEN plus X-Document-Object-Read-Token.
  • Done: add bounded delete/archive object lifecycle coverage. DELETE /v1/storage/objects?storageKey=... deletes object bytes only inside the caller's X-Organization-Id prefix, and POST /v1/admin/documents/{id}/archive archives teaching documents for the owner or ADMIN/STAFF actors in the same organization. The route clears publish/feature state and keeps purchase, entitlement, wallet, quota, share, hard purge, and public marketplace behavior out of scope.
  • Done: teaching-document canonical writes now create a document-service-owned, monotonically versioned search.projection.changed.v1 outbox envelope in the same PostgreSQL transaction. Archive emits a DELETE tombstone because the default pull projection excludes archived rows. The JetStream publisher is opt-in through DOCUMENT_SEARCH_PROJECTION_EVENT_TRANSPORT=nats; it leases, retries, and dead-letters owner outbox rows without changing canonical data. Isolated PostgreSQL and broker smoke tests prove this owner path only. The default transport, Gateway routes, and course/exam producers remain unchanged.
  • Add quota/AZ Credit integration points for upload/storage checks through future usage-service/wallet-service APIs, not local wallet logic.
  • Audit teaching document ownership versus future billing/wallet purchase flows. File-service owns teaching document metadata, review, archive, share, and search projection state only; billing/wallet/usage own purchase, quota, debit, refund, entitlement, and paid-access decisions.
  • Done for the bounded SVC-011-storage-media-browser-proof slice: document-service upload/read/variant and storage parity harness coverage is recorded with explicit browser and rollback gates. Default storage/document routes remain legacy-proxied until real frontend/browser evidence exists.
  • Done: POST /v1/internal/generated-artifacts is the trusted binary boundary for service-produced files. document-service verifies INTERNAL_SERVICE_TOKEN, creates the organization-scoped object key, stores bytes, and owns the media_assets metadata. The first producer is exam-service durable DOCX print export; producers must not write MinIO/S3 or this service's database directly. This endpoint is deliberately absent from gateway/browser routes.
  • Done: POST /v1/internal/media-assets is the trusted binary boundary for extracted import images. docx-import-service sends a token, actor scope, file metadata, and image bytes; document-service creates the object key and media_assets row atomically from the producer's point of view. This avoids using browser-facing presigned URLs from a Compose container while preserving the legacy presigned fallback for callers without an internal token.
  • Done for the non-default OCR/MathType source slice: POST /v1/import-sources accepts Gateway-authenticated multipart uploads and returns an opaque sourceAssetId only. GET /v1/internal/import-sources/{id}/content requires the shared internal token plus exact organization, actor, purpose, and source-kind checks. Generic media reads are intentionally unchanged for existing image rendering.

Acceptance:

  • File-service does not parse DOCX/PDF content or charge credits.
  • Object keys and media variants remain compatible with import/question editor.
  • Signed URL behavior is covered for browser-facing hostnames.
  • Teaching document metadata/review/archive flows may be implemented here, but purchase, entitlement, wallet debit/refund, and quota decisions must be delegated to billing/wallet/usage through explicit APIs or deferred with gateway routes kept legacy-proxied.
  • Admin dashboard document totals and pending-review counts must come from GET /v1/admin/documents/review-summary, not admin-service DB joins.
  • Search projection stays copied data only; public document routes remain legacy until full write/review/share/purchase APIs and browser parity are proven.
  • Generated artifact reads require a later authenticated gateway/BFF contract; the trusted producer endpoint must not be promoted to a frontend route.
  • Import-source browser upload may use only the orchestrator-owned non-default Gateway candidate. It must not expose object keys or promote default storage or import routes.

Verification:

  • GOTOOLCHAIN=go1.25.11 go test ./services/document-service/... -count=1
  • DOCUMENT_SEARCH_PROJECTION_OUTBOX_POSTGRES_CONFIRM=disposable-postgres make test-document-search-projection-outbox-postgres
  • DOCUMENT_SEARCH_PROJECTION_BROKER_SMOKE_CONFIRM=disposable-runtime make test-document-search-projection-broker-live
  • GOTOOLCHAIN=go1.25.11 go test ./services/docx-import-service/internal/http -run 'TestCreateLegacyDocxFastJobFetchesStorageKeyAndReturnsEnvelope|TestReprocess' -count=1
  • STORAGE_PARITY_SELF_TEST=1 make test-storage-media-parity
  • Live parity, when a legacy media asset and token are available: STORAGE_PARITY_MEDIA_ASSET_ID=<legacy-media-asset-id> STORAGE_PARITY_AUTHORIZATION='Bearer <token>' STORAGE_PARITY_ORGANIZATION_ID=<org-id> STORAGE_PARITY_NATIVE_MODE=auto make test-storage-media-parity
  • docs/qa/storage-media-parity-smoke.md records the browser proof gate: HTTP/media byte parity is not public promotion evidence until a later browser smoke loads real media through the frontend and gateway.

Go-platform documentation is generated from repository Markdown.