4.2 KiB
Task I: Storage Abstraction and Approved Artifact Lifecycle
1. Files Added
src/features/foundation/storage/types.tssrc/features/foundation/storage/service.tssrc/features/foundation/storage/server/local-provider.tssrc/features/foundation/storage/server/s3-provider.tssrc/features/foundation/storage/server/provider.tssrc/features/foundation/storage/server/checksum.tssrc/features/foundation/document-artifact/server/service.tssrc/app/api/crm/document-artifacts/[id]/download/route.tsdrizzle/0009_lazy_shard.sqldrizzle/meta/0009_snapshot.json
2. Files Modified
package.jsonpackage-lock.jsonsrc/db/schema.tssrc/lib/auth/rbac.tssrc/features/foundation/pdf-generator/server/service.tssrc/features/foundation/approval/server/service.tssrc/features/crm/quotations/api/types.tssrc/features/crm/quotations/server/service.tssrc/features/crm/quotations/components/quotation-detail.tsxsrc/app/api/crm/quotations/[id]/approved-pdf/route.tsscripts/seed-task-h1-fixture.jsdocs/implementation/technical-debt.mddocs/adr/0009-approved-document-storage-lifecycle.md
3. Storage Provider Added
Added a storage foundation under src/features/foundation/storage/**.
Providers:
- local provider for development
- S3 / MinIO-compatible provider for production-oriented storage
Configuration supported:
STORAGE_PROVIDERLOCAL_STORAGE_ROOTS3_ENDPOINTS3_REGIONS3_BUCKETS3_ACCESS_KEY_IDS3_SECRET_ACCESS_KEYS3_FORCE_PATH_STYLE
4. Artifact Schema Added
Added crm_document_artifacts with:
- organization/entity identity
- document and artifact types
- template version reference
- storage provider and storage key
- file metadata
- checksum
- lifecycle status
- generated / locked / voided metadata
- JSON metadata payload
Added approved_artifact_id to crm_quotations.
5. Approved PDF Refactor
Approved quotation PDFs now:
- write through
StorageProvider.putObject() - persist checksum via SHA-256
- create a
crm_document_artifactsrow - lock the artifact after generation
- update quotation
approvedArtifactId - keep
approvedPdfUrlas compatibility reference inartifact:<artifactId>form
Rules enforced:
- only approved quotations can generate approved PDF
- locked approved artifacts cannot be overwritten
- existing active approved artifact blocks silent regeneration
6. Secure Download Added
Added secure artifact route:
GET /api/crm/document-artifacts/[id]/download
Updated quotation approved-PDF flow so secure reads resolve artifact metadata from the database and fetch bytes through the storage provider instead of treating public file paths as source of truth.
7. UI Updated
Quotation detail now shows approved artifact metadata when available:
- file name
- generated by
- generated at
- checksum short form
- locked status badge
It also shows a legacy warning when a quotation still references old /generated/... storage without an artifact record.
8. Permissions Added
crm.document_artifact.readcrm.document_artifact.downloadcrm.document_artifact.void
Defaults were added alongside the existing quotation PDF permissions in RBAC role derivation.
9. Audit Integration
Artifact service now audits:
createlockvoiddownload
Entity type:
crm_document_artifact
10. Compatibility Notes
Compatibility behavior now supports:
approvedArtifactIdwhen presentapprovedPdfUrl = artifact:<artifactId>during migration- legacy
/generated/...approved PDF paths with warning fallback
Task I intentionally does not bulk-migrate legacy files yet.
11. Remaining Risks
- artifact void/regeneration still has no admin UI workflow
- legacy approved PDFs still need one-time migration into artifact storage
- signed-URL delivery is not enabled yet; downloads are still server-streamed
- storage-provider health and bucket policy checks are still operational concerns outside the app
12. Task J Readiness
Task I leaves the app ready for:
- richer artifact lifecycle tooling
- legacy-file migration command
- object-storage rollout beyond local development
- future secure delivery strategies such as signed URLs
13. Verification
npx tsc --noEmitnpm run gen