task-i
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
# Task D.1: Enquiry Assignment and CRM Role Stabilization
|
||||
|
||||
## 1. Files Added
|
||||
|
||||
- `src/app/api/crm/enquiries/[id]/_schemas.ts`
|
||||
- `src/app/api/crm/enquiries/[id]/assign/route.ts`
|
||||
- `src/app/api/crm/enquiries/[id]/reassign/route.ts`
|
||||
- `src/features/crm/enquiries/components/enquiry-assignment-dialog.tsx`
|
||||
- `drizzle/0008_clean_justin_hammer.sql`
|
||||
- `drizzle/meta/0008_snapshot.json`
|
||||
|
||||
## 2. Files Modified
|
||||
|
||||
- `src/db/schema.ts`
|
||||
- `src/lib/auth/rbac.ts`
|
||||
- `src/app/dashboard/crm/enquiries/page.tsx`
|
||||
- `src/app/dashboard/crm/enquiries/[id]/page.tsx`
|
||||
- `src/features/crm/enquiries/api/types.ts`
|
||||
- `src/features/crm/enquiries/api/service.ts`
|
||||
- `src/features/crm/enquiries/api/mutations.ts`
|
||||
- `src/features/crm/enquiries/server/service.ts`
|
||||
- `src/features/crm/enquiries/components/enquiry-columns.tsx`
|
||||
- `src/features/crm/enquiries/components/enquiries-table.tsx`
|
||||
- `src/features/crm/enquiries/components/enquiry-listing.tsx`
|
||||
- `src/features/crm/enquiries/components/enquiry-detail.tsx`
|
||||
- `src/features/crm/enquiries/components/enquiry-cell-action.tsx`
|
||||
- `src/features/users/api/types.ts`
|
||||
- `src/features/users/schemas/user.ts`
|
||||
- `src/features/users/components/user-form-sheet.tsx`
|
||||
- `src/app/api/users/_lib.ts`
|
||||
- `src/app/api/users/route.ts`
|
||||
- `src/app/api/organizations/route.ts`
|
||||
- `src/features/foundation/auth-context/service.ts`
|
||||
|
||||
## 3. Schema Added
|
||||
|
||||
Added assignment fields to `crm_enquiries`:
|
||||
|
||||
- `assigned_to_user_id`
|
||||
- `assigned_at`
|
||||
- `assigned_by`
|
||||
- `assignment_remark`
|
||||
|
||||
Rules implemented:
|
||||
|
||||
- assignee must belong to the same organization
|
||||
- assigner is the current user
|
||||
- latest assignment timestamp is persisted
|
||||
- assignment remark is optional
|
||||
|
||||
## 4. API Routes Added
|
||||
|
||||
- `POST /api/crm/enquiries/[id]/assign`
|
||||
- `POST /api/crm/enquiries/[id]/reassign`
|
||||
|
||||
Payload:
|
||||
|
||||
```ts
|
||||
{
|
||||
assignedToUserId: string;
|
||||
remark?: string;
|
||||
}
|
||||
```
|
||||
|
||||
Behavior:
|
||||
|
||||
- requires organization access
|
||||
- enforces `crm.enquiry.assign` or `crm.enquiry.reassign`
|
||||
- validates assignee organization membership
|
||||
- rejects assign on already-assigned enquiry
|
||||
- rejects reassign on unassigned enquiry
|
||||
|
||||
## 5. Permissions Added
|
||||
|
||||
- `crm.enquiry.assign`
|
||||
- `crm.enquiry.reassign`
|
||||
|
||||
CRM business-role set was also stabilized around:
|
||||
|
||||
- `sales_manager`
|
||||
- `sales`
|
||||
- `sales_support`
|
||||
- `department_manager`
|
||||
- `top_manager`
|
||||
|
||||
Legacy IT-CENTER business roles were removed from active runtime paths and defaults.
|
||||
|
||||
## 6. UI Added
|
||||
|
||||
Enquiry detail now supports:
|
||||
|
||||
- `Assign Sales`
|
||||
- `Reassign Sales`
|
||||
- assigned sales metadata display
|
||||
|
||||
Enquiry list now shows:
|
||||
|
||||
- `Assigned Sales` column
|
||||
|
||||
Assignment dialog now includes:
|
||||
|
||||
- `Sales User`
|
||||
- `Remark`
|
||||
|
||||
The sales-user dropdown is populated from organization memberships instead of hardcoded values.
|
||||
|
||||
## 7. Audit Integration
|
||||
|
||||
Assignment writes audit logs under:
|
||||
|
||||
- `entityType = crm_enquiry`
|
||||
|
||||
Actions added:
|
||||
|
||||
- `assign`
|
||||
- `reassign`
|
||||
|
||||
Audit payload shape:
|
||||
|
||||
- `beforeData.oldAssignedToUserId`
|
||||
- `afterData.newAssignedToUserId`
|
||||
- `afterData.remark`
|
||||
|
||||
## 8. Membership / Permission Stabilization
|
||||
|
||||
Workspace membership management now uses CRM-aligned business roles instead of the old template roles.
|
||||
|
||||
Updated areas:
|
||||
|
||||
- user API types and validation
|
||||
- membership defaults
|
||||
- organization-management fallbacks
|
||||
- auth-context business-role fallback
|
||||
|
||||
## 9. Remaining Risks
|
||||
|
||||
- current `sales` access still operates at organization scope; there is not yet a server-enforced “own or assigned only” data policy
|
||||
- old database rows that still carry removed legacy business-role strings may need a one-time data backfill if they exist in a real environment
|
||||
- assignable-user filtering currently accepts organization admins plus sales-oriented roles; if future CRM staffing rules become stricter, that policy should move into a dedicated assignment rule layer
|
||||
|
||||
## 10. Verification
|
||||
|
||||
- `npx tsc --noEmit`
|
||||
- `npx oxlint` on changed Task D.1 files
|
||||
122
docs/implementation/task-h1-pdf-generation-stabilization.md
Normal file
122
docs/implementation/task-h1-pdf-generation-stabilization.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# Task H.1: PDF Generation Stabilization
|
||||
|
||||
## 1. Files Added
|
||||
|
||||
- `scripts/seed-task-h1-fixture.js`
|
||||
- `scripts/verify-task-h1.js`
|
||||
- `docs/adr/0009-approved-document-storage-lifecycle.md`
|
||||
|
||||
## 2. Files Modified
|
||||
|
||||
- `package.json`
|
||||
- `docs/implementation/technical-debt.md`
|
||||
|
||||
Task H.1 builds on the Task H PDF pipeline and focuses on validation, fixture support, documentation, and storage-lifecycle clarification.
|
||||
|
||||
## 3. Smoke Test Record Used
|
||||
|
||||
Added a dev-only fixture script for a real quotation scenario:
|
||||
|
||||
- approved fixture code: `QT-TASK-H1-APPROVED`
|
||||
- draft fixture code: `QT-TASK-H1-DRAFT`
|
||||
- customer fixture code: `CUS-TASK-H1`
|
||||
|
||||
Fixture script provisions:
|
||||
|
||||
- organization-scoped customer and contact
|
||||
- approved quotation with item, customer role, scope/exclusion/payment topics, and completed approval history
|
||||
- draft quotation for negative approved-PDF validation
|
||||
- test users for permission checks
|
||||
|
||||
## 4. PDF APIs Verified
|
||||
|
||||
Task H.1 verification script covers:
|
||||
|
||||
- `GET /api/crm/quotations/[id]/pdf-preview`
|
||||
- `GET /api/crm/quotations/[id]/pdf-download`
|
||||
- `POST /api/crm/quotations/[id]/approved-pdf`
|
||||
- `GET /api/crm/quotations/[id]/approved-pdf`
|
||||
|
||||
Expected checks included:
|
||||
|
||||
- preview responds as inline PDF
|
||||
- download responds as attachment PDF
|
||||
- approved-PDF POST succeeds for approved quotation
|
||||
- approved-PDF GET returns persisted artifact
|
||||
- non-approved quotation cannot generate approved PDF
|
||||
|
||||
## 5. Persistence Verified
|
||||
|
||||
Task H.1 verification targets:
|
||||
|
||||
- `approvedPdfUrl`
|
||||
- `approvedSnapshot`
|
||||
- `approvedTemplateVersionId`
|
||||
- quotation attachment metadata row
|
||||
- audit log row
|
||||
- generated file under `public/generated/quotations/<organizationId>/`
|
||||
|
||||
## 6. Permission Verified
|
||||
|
||||
Fixture and verification support explicit checks for:
|
||||
|
||||
- `super_admin`
|
||||
- admin workspace member
|
||||
- regular user with PDF permissions
|
||||
- regular user without PDF permissions
|
||||
|
||||
Permissions covered:
|
||||
|
||||
- `crm.quotation.pdf.preview`
|
||||
- `crm.quotation.pdf.download`
|
||||
- `crm.quotation.pdf.generate_approved`
|
||||
|
||||
## 7. Error Handling / Hardening
|
||||
|
||||
Task H.1 centered hardening around safe operational verification rather than a large refactor.
|
||||
|
||||
The main stabilization additions were:
|
||||
|
||||
- reusable dev fixture creation
|
||||
- repeatable HTTP verification script
|
||||
- clearer storage lifecycle documentation
|
||||
- explicit debt tracking for fonts, local storage, and approved-artifact policy
|
||||
|
||||
## 8. ADR / Technical Debt Updated
|
||||
|
||||
Added ADR:
|
||||
|
||||
- `docs/adr/0009-approved-document-storage-lifecycle.md`
|
||||
|
||||
Updated debt notes in:
|
||||
|
||||
- `docs/implementation/technical-debt.md`
|
||||
|
||||
Tracked concerns include:
|
||||
|
||||
- font compatibility fallback
|
||||
- local filesystem storage limitation
|
||||
- approved artifact immutability policy
|
||||
- post-approval automation gap
|
||||
- missing CI-backed PDF E2E coverage
|
||||
|
||||
## 9. Remaining Risks
|
||||
|
||||
- approved PDF storage still uses local public filesystem semantics and is not production-grade object storage
|
||||
- approved artifact lifecycle is still not immutable by policy
|
||||
- PDF verification is script-based and not yet part of CI
|
||||
- task fixture scripts currently depend on a prepared local environment and seeded master-option / approval data
|
||||
|
||||
## 10. Task I Readiness
|
||||
|
||||
Task H.1 leaves the PDF flow better prepared for Task I by providing:
|
||||
|
||||
- a repeatable quotation fixture path
|
||||
- a repeatable verification script
|
||||
- explicit storage-lifecycle decision documentation
|
||||
- visible technical-debt boundaries for future production hardening
|
||||
|
||||
## 11. Verification Commands
|
||||
|
||||
- `npm run seed:task-h1-fixture`
|
||||
- `npm run verify:task-h1`
|
||||
155
docs/implementation/task-i-storage-artifact-lifecycle.md
Normal file
155
docs/implementation/task-i-storage-artifact-lifecycle.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# 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`
|
||||
@@ -3,136 +3,242 @@
|
||||
## After Task D
|
||||
|
||||
### Database foreign keys
|
||||
|
||||
Customer, contact, and enquiry relationships are still enforced mainly in application logic.
|
||||
|
||||
Future:
|
||||
|
||||
- add FK constraints after the CRM schema settles
|
||||
- review cascade behavior before enabling hard relational enforcement
|
||||
|
||||
### Date input UX
|
||||
|
||||
Several forms still use plain `YYYY-MM-DD` text/date inputs.
|
||||
|
||||
Future:
|
||||
|
||||
- move to a shared date picker pattern
|
||||
- standardize timezone handling for CRM forms
|
||||
|
||||
### Related enquiry pagination
|
||||
|
||||
Customer detail can show related enquiries, but that view still has no dedicated pagination strategy.
|
||||
|
||||
Future:
|
||||
|
||||
- add paging once real data volume grows
|
||||
|
||||
### Follow-up activity timeline
|
||||
|
||||
Activity history still relies heavily on audit payloads instead of a curated domain timeline.
|
||||
|
||||
Future:
|
||||
|
||||
- build a combined activity view/service for CRM interactions
|
||||
|
||||
## After Task D.1
|
||||
|
||||
### Enquiry Own / Assigned Scope
|
||||
|
||||
Current:
|
||||
sales role ยังอ่าน enquiry ในระดับ organization scope
|
||||
|
||||
Future:
|
||||
เพิ่ม server-side policy:
|
||||
|
||||
- sales เห็นเฉพาะ enquiry ที่ตัวเองสร้าง
|
||||
- หรือ enquiry ที่ assigned ให้ตัวเอง
|
||||
- sales_manager เห็นทั้งทีม
|
||||
|
||||
Priority:
|
||||
High
|
||||
|
||||
### Legacy Business Role Backfill
|
||||
|
||||
Current:
|
||||
ระบบ runtime ใช้ CRM businessRole แล้ว แต่ DB เก่าอาจยังมี role จาก IT-CENTER
|
||||
|
||||
Future:
|
||||
ทำ one-time migration/backfill script สำหรับ memberships.businessRole
|
||||
|
||||
Priority:
|
||||
Medium
|
||||
|
||||
## After Task E
|
||||
|
||||
### Mixed tax rollup
|
||||
|
||||
Quotation items support per-line tax input, but summary calculation still assumes a header-centric tax model.
|
||||
|
||||
Future:
|
||||
|
||||
- support mixed-tax aggregation from actual item rows
|
||||
- align document totals and reporting with per-line tax logic
|
||||
|
||||
### Attachment storage abstraction
|
||||
|
||||
Quotation attachments started as metadata-only and approved PDFs now write to local disk, but there is still no real storage abstraction.
|
||||
|
||||
Future:
|
||||
|
||||
- introduce a provider abstraction
|
||||
- support upload/download lifecycle consistently across manual attachments and generated artifacts
|
||||
- define migration strategy for existing local/public paths
|
||||
|
||||
### Revision snapshot coverage
|
||||
|
||||
Revision copy currently focuses on quotation header, items, customers, and topics.
|
||||
|
||||
Future:
|
||||
|
||||
- decide whether follow-ups and attachments belong in revision snapshots
|
||||
- define immutable vs mutable child-data behavior across revisions
|
||||
|
||||
### CRM foreign keys
|
||||
|
||||
Core CRM tables still depend on organization-scoped validation in service code.
|
||||
|
||||
Future:
|
||||
|
||||
- add FK constraints after schema churn slows down
|
||||
- review delete and soft-delete interactions first
|
||||
|
||||
## After Task F
|
||||
|
||||
### Permission sync for existing memberships
|
||||
|
||||
New permissions are defined in code, but old membership rows may still hold stale permission arrays.
|
||||
|
||||
Future:
|
||||
|
||||
- add a permission sync/backfill command
|
||||
- provide admin tooling for role and permission maintenance
|
||||
|
||||
### Approval workflow configuration UI
|
||||
|
||||
Approval workflows are seeded and usable, but still not configurable from the dashboard.
|
||||
|
||||
Future:
|
||||
|
||||
- build workflow setup screens
|
||||
- add step editing and role mapping management
|
||||
|
||||
### Approval notifications
|
||||
|
||||
Approval flow has no queue-backed notification channel yet.
|
||||
|
||||
Future:
|
||||
|
||||
- add notification jobs
|
||||
- support reminders and escalation policy
|
||||
|
||||
## After Task G
|
||||
|
||||
### Document mapping editor
|
||||
|
||||
Template mappings are seeded and readable, but not manageable from UI.
|
||||
|
||||
Future:
|
||||
|
||||
- add mapping CRUD for admins
|
||||
- support table column editing
|
||||
- add draft/publish template workflow
|
||||
|
||||
### Product-specific template resolution
|
||||
|
||||
Quotation document template resolution still defaults to a coarse product selection strategy.
|
||||
|
||||
Future:
|
||||
|
||||
- define clearer rules for crane, dock door, solar, and service-specific templates
|
||||
|
||||
## After Task H / H.1
|
||||
|
||||
### Font compatibility fallback
|
||||
|
||||
PDF generation now uses vendored Cordia TTF files from `public/fonts`, which fixed the TTC runtime issue, but generator-side fallback normalization still remains as a safety net.
|
||||
|
||||
Future:
|
||||
|
||||
- keep validating Thai text metrics against designer output
|
||||
- remove fallback normalization only after render parity is proven stable
|
||||
|
||||
### Local filesystem storage
|
||||
|
||||
Approved PDFs currently persist under `public/generated/quotations/<organizationId>/`.
|
||||
|
||||
Future:
|
||||
|
||||
- replace local public storage for production with object storage
|
||||
- add signed/private delivery where required
|
||||
- define backup and cleanup expectations
|
||||
|
||||
### Approved artifact immutability
|
||||
|
||||
Approved PDF persistence exists, but the lifecycle is not immutable by policy yet.
|
||||
|
||||
Future:
|
||||
|
||||
- define whether regeneration is allowed after approval
|
||||
- version approved artifacts explicitly if regeneration must remain possible
|
||||
- document which snapshot fields are contractual records
|
||||
|
||||
### Post-approval automation
|
||||
|
||||
Approved PDF generation is still manual by design.
|
||||
|
||||
Future:
|
||||
|
||||
- add a non-blocking auto-generation hook after final approval
|
||||
- move heavy generation/retry behavior to a background job when needed
|
||||
|
||||
### PDF pipeline test coverage
|
||||
|
||||
Task H.1 added dev fixture and HTTP verification scripts, but there is still no CI-backed E2E coverage for the PDF pipeline.
|
||||
|
||||
Future:
|
||||
|
||||
- promote fixture verification into automated test coverage
|
||||
- add regression checks for template mappings, storage persistence, and permission enforcement
|
||||
|
||||
## After Task I
|
||||
|
||||
### Storage provider production rollout
|
||||
|
||||
Task I introduced a storage provider abstraction with local and S3/MinIO-compatible implementations, but the production rollout still depends on environment configuration and infrastructure ownership outside the app.
|
||||
|
||||
Future:
|
||||
|
||||
- validate real bucket policies, credentials rotation, and environment separation
|
||||
- add operational runbooks for provider misconfiguration and storage outage handling
|
||||
- add smoke checks for startup-time storage provider health
|
||||
|
||||
### Legacy approved PDF migration
|
||||
|
||||
Task I keeps compatibility for legacy `public/generated/...` approved PDFs, but those legacy files are still outside the new artifact source-of-truth model.
|
||||
|
||||
Future:
|
||||
|
||||
- add a one-time migration script from legacy local paths into `crm_document_artifacts`
|
||||
- backfill `approvedArtifactId` where possible
|
||||
- remove legacy compatibility once migration is complete and verified
|
||||
|
||||
### Artifact lifecycle policy depth
|
||||
|
||||
Approved artifacts are now immutable-first and locked after generation, but void/regeneration policy is still service-level rather than a full operator workflow.
|
||||
|
||||
Future:
|
||||
|
||||
- add explicit admin tooling for artifact void and replacement flows
|
||||
- define whether artifact voiding also clears or supersedes quotation-facing references automatically
|
||||
- document retention expectations for voided objects in object storage
|
||||
|
||||
### Secure artifact delivery model
|
||||
|
||||
Approved-PDF viewing now goes through secure server routes and storage-backed reads, but signed-url/offload behavior is not yet used.
|
||||
|
||||
Future:
|
||||
|
||||
- decide when direct signed URLs are acceptable versus mandatory server streaming
|
||||
- add response caching strategy for large artifact downloads
|
||||
- evaluate optional download-audit sampling if volume grows
|
||||
|
||||
Reference in New Issue
Block a user