156 lines
4.2 KiB
Markdown
156 lines
4.2 KiB
Markdown
# Task I: Storage Abstraction and Approved Artifact Lifecycle
|
|
|
|
## 1. Files Added
|
|
|
|
- `src/features/foundation/storage/types.ts`
|
|
- `src/features/foundation/storage/service.ts`
|
|
- `src/features/foundation/storage/server/local-provider.ts`
|
|
- `src/features/foundation/storage/server/s3-provider.ts`
|
|
- `src/features/foundation/storage/server/provider.ts`
|
|
- `src/features/foundation/storage/server/checksum.ts`
|
|
- `src/features/foundation/document-artifact/server/service.ts`
|
|
- `src/app/api/crm/document-artifacts/[id]/download/route.ts`
|
|
- `drizzle/0009_lazy_shard.sql`
|
|
- `drizzle/meta/0009_snapshot.json`
|
|
|
|
## 2. Files Modified
|
|
|
|
- `package.json`
|
|
- `package-lock.json`
|
|
- `src/db/schema.ts`
|
|
- `src/lib/auth/rbac.ts`
|
|
- `src/features/foundation/pdf-generator/server/service.ts`
|
|
- `src/features/foundation/approval/server/service.ts`
|
|
- `src/features/crm/quotations/api/types.ts`
|
|
- `src/features/crm/quotations/server/service.ts`
|
|
- `src/features/crm/quotations/components/quotation-detail.tsx`
|
|
- `src/app/api/crm/quotations/[id]/approved-pdf/route.ts`
|
|
- `scripts/seed-task-h1-fixture.js`
|
|
- `docs/implementation/technical-debt.md`
|
|
- `docs/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_PROVIDER`
|
|
- `LOCAL_STORAGE_ROOT`
|
|
- `S3_ENDPOINT`
|
|
- `S3_REGION`
|
|
- `S3_BUCKET`
|
|
- `S3_ACCESS_KEY_ID`
|
|
- `S3_SECRET_ACCESS_KEY`
|
|
- `S3_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_artifacts` row
|
|
- lock the artifact after generation
|
|
- update quotation `approvedArtifactId`
|
|
- keep `approvedPdfUrl` as compatibility reference in `artifact:<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.read`
|
|
- `crm.document_artifact.download`
|
|
- `crm.document_artifact.void`
|
|
|
|
Defaults were added alongside the existing quotation PDF permissions in RBAC role derivation.
|
|
|
|
## 9. Audit Integration
|
|
|
|
Artifact service now audits:
|
|
|
|
- `create`
|
|
- `lock`
|
|
- `void`
|
|
- `download`
|
|
|
|
Entity type:
|
|
|
|
- `crm_document_artifact`
|
|
|
|
## 10. Compatibility Notes
|
|
|
|
Compatibility behavior now supports:
|
|
|
|
- `approvedArtifactId` when present
|
|
- `approvedPdfUrl = 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 --noEmit`
|
|
- `npm run gen`
|