# Task H.1: PDF Generation Stabilization ## Goal Stabilize Task H PDF generation before starting Task I. Task H already added: * pdfme server-side generation * preview/download PDF APIs * approved PDF generation * approved snapshot persistence * approved PDF attachment metadata * quotation detail PDF actions Task H.1 focuses on validation, hardening, and documentation. --- ## Must Read ```txt docs/implementation/technical-debt.md docs/adr/0008-attachment-storage-strategy.md src/features/foundation/pdf-generator/** src/features/foundation/document-template/** src/features/crm/quotations/document/** src/features/crm/quotations/** src/features/foundation/approval/** src/app/api/crm/quotations/[id]/pdf-preview/route.ts src/app/api/crm/quotations/[id]/pdf-download/route.ts src/app/api/crm/quotations/[id]/approved-pdf/route.ts src/db/schema.ts ``` --- ## Scope 1: Smoke Test With Real Quotation Create or identify one real quotation record in dev database. The record must include: ```txt customer contact enquiry optional at least one item quotation customer role scope topic exclusion topic payment topic approved status or approval flow completed ``` Then verify: ```txt Preview PDF Download PDF Generate Approved PDF View Approved PDF ``` If no real record exists, create a minimal seed/dev fixture. Rules: * dev fixture must be organization-scoped * do not hardcode organizationId * do not pollute production seed * place fixture under dev-only seed or clearly named script --- ## Scope 2: PDF Output Validation Check generated PDF for: ```txt file opens correctly page count is reasonable customer block appears quotation code appears item table appears total amount appears scope/exclusion/payment appears approval block appears signature placeholder appears ``` If layout breaks: * adjust mapping normalization * adjust template input preparation * do not rewrite template designer * do not hardcode quotation-specific hacks into generic pdf generator --- ## Scope 3: Approved PDF API Validation Validate: ```txt 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 behavior: * preview returns inline PDF * download returns attachment PDF * approved-pdf POST only works for approved quotation * approved-pdf GET returns stored file if available * non-approved quotation cannot generate approved PDF --- ## Scope 4: Persistence Validation After approved PDF generation verify: ```txt quotation.approvedPdfUrl populated quotation.approvedSnapshot populated quotation.approvedTemplateVersionId populated quotation attachment metadata created or updated audit log generated file exists in public/generated/quotations// ``` If any part is missing, fix only the persistence pipeline. --- ## Scope 5: Permission Validation Verify permissions: ```txt crm.quotation.pdf.preview crm.quotation.pdf.download crm.quotation.pdf.generate_approved ``` Check behavior for: ```txt super_admin admin regular user with permission regular user without permission ``` Do not rewrite RBAC model. --- ## Scope 6: Error Handling Improve user-safe/server-safe errors for: ```txt template not found template version not found mapping missing quotation not approved generated file missing pdfme generation error local storage write error permission denied ``` Rules: * API must return meaningful status codes * UI should show readable toast/message * do not expose stack trace to client --- ## Scope 7: Documentation / ADR Update: ```txt docs/implementation/technical-debt.md ``` Confirm or add: ```txt pdfme font fallback workaround local filesystem storage limitation missing object storage abstraction approved PDF lifecycle not immutable yet no full E2E test in CI yet ``` Create ADR if not exists: ```txt docs/adr/0009-approved-document-storage-lifecycle.md ``` Include: ```txt Current: local public/generated storage Decision: acceptable for development/MVP only Future: object storage abstraction signed URL immutable approved artifacts retention policy ``` --- ## Scope 8: Optional Small Fix If approval finalization already has a clean hook point, add a non-blocking TODO or optional manual trigger note for: ```txt auto-generate approved PDF after final approval ``` Do not force automatic generation in Task H.1 if it risks breaking approval flow. --- ## ห้ามทำ ```txt object storage production signed URL service template designer mapping editor email notification report dashboard KPI large refactor ``` --- ## Output After completion, summarize: 1. Files Added 2. Files Modified 3. Smoke Test Record Used 4. PDF APIs Verified 5. Persistence Verified 6. Permission Verified 7. Error Handling Improved 8. ADR / Technical Debt Updated 9. Remaining Risks 10. Task I Readiness --- ## Definition of Done Task H.1 passes when: ✔ PDF preview works with a real quotation ✔ PDF download works with a real quotation ✔ Approved PDF generation works for approved quotation ✔ Approved PDF GET returns stored PDF ✔ Non-approved quotation cannot generate approved PDF ✔ approvedSnapshot is saved ✔ approvedPdfUrl is saved ✔ approvedTemplateVersionId is saved ✔ attachment metadata is created/updated ✔ audit log exists for approved PDF generation ✔ permissions are enforced ✔ errors are user-safe ✔ storage lifecycle ADR exists ✔ ready for Task I