# Task H - PDF Generation and Approved Document Persistence ## Files Added - `src/features/foundation/pdf-generator/server/service.ts` - `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` - `drizzle/0007_luxuriant_malice.sql` ## Files Modified - `package.json` - `package-lock.json` - `src/components/icons.tsx` - `src/db/schema.ts` - `src/lib/auth/rbac.ts` - `src/features/crm/quotations/api/types.ts` - `src/features/crm/quotations/server/service.ts` - `src/features/crm/quotations/document/types.ts` - `src/features/crm/quotations/document/server/service.ts` - `src/features/foundation/approval/server/service.ts` - `src/app/dashboard/crm/quotations/[id]/page.tsx` - `src/features/crm/quotations/components/quotation-detail.tsx` - `src/features/crm/enquiries/components/enquiry-form-sheet.tsx` - `src/features/crm/enquiries/schemas/enquiry.schema.ts` - `src/features/crm/quotations/schemas/quotation.schema.ts` - `docs/implementation/technical-debt.md` ## PDF Generator Added - Added production server-side `pdfme` generation in `src/features/foundation/pdf-generator/server/service.ts`. - Installed: - `@pdfme/common` - `@pdfme/generator` - `@pdfme/schemas` - Implemented: - `generatePdfFromTemplate()` - `generateQuotationPdf()` - `generateQuotationPreviewPdf()` - `generateApprovedQuotationPdf()` - `getStoredApprovedQuotationPdf()` ## API Routes Added - `GET /api/crm/quotations/[id]/pdf-preview` - `GET /api/crm/quotations/[id]/pdf-download` - `GET /api/crm/quotations/[id]/approved-pdf` - `POST /api/crm/quotations/[id]/approved-pdf` Behavior: - preview returns inline PDF from current quotation state - download returns attachment PDF from current quotation state - approved-pdf POST generates, persists, audits, and returns the approved PDF - approved-pdf GET streams the already stored approved artifact ## UI Actions Added Quotation detail now supports: - `Preview PDF` - `Download PDF` - `Generate Approved PDF` - `View Approved PDF` The detail page also now displays: - `Approved At` - `Approved Template Version` ## Approved Snapshot Persistence Added quotation persistence fields: - `approvedAt` - `approvedPdfUrl` - `approvedSnapshot` - `approvedTemplateVersionId` Approved snapshot now stores: - quotation id - approved timestamp - normalized document data - template version id - mapped template input - generated timestamp - generated by user id ## Attachment Metadata Integration After generating an approved PDF: - a local file is written under `public/generated/quotations//` - quotation attachment metadata is created or updated with: - `fileName` - `originalFileName` - `filePath` - `fileSize` - `fileType = application/pdf` - `description = Approved quotation PDF` - `uploadedBy` - `uploadedAt` ## Permission Added - `crm.quotation.pdf.preview` - `crm.quotation.pdf.download` - `crm.quotation.pdf.generate_approved` ## Audit Integration Required audit was added for approved PDF generation with: - `entityType = crm_quotation_pdf_generate_approved` - `action = generate_approved` Preview and download remain unaudited by design. ## Remaining Risks - Current `pdfme` generation uses a font fallback normalization step because the provided templates reference `cordia/cordiaBold`, while direct TTC-based rendering did not behave reliably with table layout generation. - Approved PDF storage uses local filesystem placeholder output under `public/generated/...`, not external object storage. - The environment used during implementation had no quotation rows available in the database, so full quotation-specific end-to-end smoke testing through a live record could not be completed here. ## Task I Readiness Task H leaves the repo ready for: - auto-generate approved PDF after final approval - object-storage abstraction - signed download / retention policy - immutable approved artifact lifecycle rules - richer template version publish controls