Appearance
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.tsif 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.yamldocs/api/document-service.md
Orchestrator-owned files:
- storage route examples under
deploy/gateway/routes.storage-*.json, storage route tests underscripts/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-*.jsonexamples,scripts/test/storage-*.sh,docs/qa/storage-*.md, and rootMakefiletest-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-serviceas the current implementation target for thefile-servicedomain alias; do not create a separatefile-servicescaffold. - Maintain the native teaching document search projection:
GET /v1/documents/search-projectionsemits copiedDOCUMENTsearch docs for search-service rebuilds from service-ownedteaching_documentsrows. - Done: add the first admin dashboard owner read for teaching document reviews.
GET /v1/admin/documents/review-summaryreturns service-owned total and status counts, includingPENDING_REVIEW, foradmin-service/BFF dashboard traceability. It is service-local, supports organization scoping, and does not move purchase/quota/wallet decisions or public/documentsroutes. - 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 requireX-Organization-Idwith a matching storage-key prefix, and trusted service-to-service reads requireDOCUMENT_OBJECT_READ_TOKENplusX-Document-Object-Read-Token. - Done: add bounded delete/archive object lifecycle coverage.
DELETE /v1/storage/objects?storageKey=...deletes object bytes only inside the caller'sX-Organization-Idprefix, andPOST /v1/admin/documents/{id}/archivearchives teaching documents for the owner orADMIN/STAFFactors 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.v1outbox envelope in the same PostgreSQL transaction. Archive emits aDELETEtombstone because the default pull projection excludes archived rows. The JetStream publisher is opt-in throughDOCUMENT_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-serviceAPIs, 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-proofslice: 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-artifactsis the trusted binary boundary for service-produced files. document-service verifiesINTERNAL_SERVICE_TOKEN, creates the organization-scoped object key, stores bytes, and owns themedia_assetsmetadata. 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-assetsis the trusted binary boundary for extracted import images.docx-import-servicesends a token, actor scope, file metadata, and image bytes; document-service creates the object key andmedia_assetsrow 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-sourcesaccepts Gateway-authenticated multipart uploads and returns an opaquesourceAssetIdonly.GET /v1/internal/import-sources/{id}/contentrequires 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=1DOCUMENT_SEARCH_PROJECTION_OUTBOX_POSTGRES_CONFIRM=disposable-postgres make test-document-search-projection-outbox-postgresDOCUMENT_SEARCH_PROJECTION_BROKER_SMOKE_CONFIRM=disposable-runtime make test-document-search-projection-broker-liveGOTOOLCHAIN=go1.25.11 go test ./services/docx-import-service/internal/http -run 'TestCreateLegacyDocxFastJobFetchesStorageKeyAndReturnsEnvelope|TestReprocess' -count=1STORAGE_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.mdrecords 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.