Files
alla-allaos-fullstack/plans/task-p.4.1-verification-report.md
phaichayon 0c0450b152 taks-p.4.3
2026-06-29 11:18:08 +07:00

458 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Task P.4.1 Verification Report
## Scope
This report completes the runtime verification requested by [task-p.4.1.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/plans/task-p.4.1.md).
No production template files were modified.
No new rendering pipeline was created.
No implementation for Task P.4 has started yet.
---
## 1. Verified Runtime Findings
### 1.1 Current quotation PDF runtime chain
The current quotation document routes do not use separate template pipelines.
Verified route chain:
- `document-data` calls `buildQuotationDocumentData`
- [src/app/api/crm/quotations/[id]/document-data/route.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/crm/quotations/[id]/document-data/route.ts:39)
- `document-preview` calls `getQuotationDocumentPreviewData`
- [src/app/api/crm/quotations/[id]/document-preview/route.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/crm/quotations/[id]/document-preview/route.ts:39)
- `pdf-preview` calls `generateQuotationPreviewPdf`
- [src/app/api/crm/quotations/[id]/pdf-preview/route.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/crm/quotations/[id]/pdf-preview/route.ts:39)
- `pdf-download` calls `generateQuotationPdf`
- [src/app/api/crm/quotations/[id]/pdf-download/route.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/crm/quotations/[id]/pdf-download/route.ts:39)
- `approved-pdf` reads stored artifact first and falls back to generation path when needed
- [src/app/api/crm/quotations/[id]/approved-pdf/route.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/crm/quotations/[id]/approved-pdf/route.ts:44)
Verified shared pipeline:
- `generateQuotationPdf()` calls `getQuotationDocumentPreviewData()`
- [src/features/foundation/pdf-generator/server/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/pdf-generator/server/service.ts:304)
- `generateQuotationPreviewPdf()` simply delegates to `generateQuotationPdf()`
- [src/features/foundation/pdf-generator/server/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/pdf-generator/server/service.ts:317)
- `generateApprovedQuotationPdf()` also calls `getQuotationDocumentPreviewData()`
- [src/features/foundation/pdf-generator/server/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/pdf-generator/server/service.ts:326)
Verified preview builder chain:
- `getQuotationDocumentPreviewData()` builds `documentData`
- resolves active template and active version
- resolves version mappings
- maps `documentData` to `templateInput`
- applies topic page expansion
Reference:
- [src/features/crm/quotations/document/server/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/crm/quotations/document/server/service.ts:661)
### 1.2 Same active template/version/mapping pipeline
Confirmed: `document-preview`, `pdf-preview`, `pdf-download`, and approved PDF generation all depend on the same active template/version/mapping pipeline.
Shared resolution calls:
- `resolveTemplateForDocument()`
- [src/features/crm/quotations/document/server/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/crm/quotations/document/server/service.ts:669)
- `resolveTemplateMappings()`
- [src/features/crm/quotations/document/server/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/crm/quotations/document/server/service.ts:674)
- `mapDocumentDataToTemplateInput()`
- [src/features/crm/quotations/document/server/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/crm/quotations/document/server/service.ts:688)
Conclusion:
- there is one active runtime pipeline for quotation PDF generation
- there is no separate preview-only template source
- there is no separate download-only template source
- approved PDF generation reuses the same active version before persistence
---
## 2. Active Template Runtime Source Verification
### 2.1 Database active versions
Verified against live database:
```json
[
{
"organizationName": "ALLA",
"templateName": "ALLA Quotation Standard",
"version": "1.0",
"filePath": "src/pdfme_template/ALLA_template_pdfme_fainal3.json",
"mappingCount": "20"
},
{
"organizationName": "ONVALLA",
"templateName": "ONVALLA Quotation Standard",
"version": "1.0",
"filePath": "src/pdfme_template/ONVALLA_template_pdfme_fainal3.json",
"mappingCount": "20"
}
]
```
Interpretation:
- runtime selects active version rows from DB
- each active version still keeps `filePath` pointing to the original JSON file source
- mapping count is currently `20` for both active versions
### 2.2 DB schema vs file source
Verified that the active version `schema_json` in DB matches the JSON file on disk exactly for both organizations.
Evidence:
```json
{
"organization": "ALLA",
"filePath": "src/pdfme_template/ALLA_template_pdfme_fainal3.json",
"matches": true
}
{
"organization": "ONVALLA",
"filePath": "src/pdfme_template/ONVALLA_template_pdfme_fainal3.json",
"matches": true
}
```
Conclusion:
- runtime renders from `schema_json` stored in DB
- the current DB value is seeded from the JSON file and currently matches it
- changing only the JSON file will not change runtime behavior unless DB version rows are reseeded or updated
### 2.3 Seed/runtime source conclusion
Runtime uses both, but with different roles:
- DB active template/version/mapping is the actual runtime source
- JSON file is the seed/reseed source of truth for version payload creation
This means P.4 must update:
- new template JSON files
- seed or reseed logic that publishes those JSON files into DB versions
Relevant current source selectors:
- [src/db/seeds/foundation.seed.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/db/seeds/foundation.seed.ts:854)
- [scripts/pdf-audit-utils.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/scripts/pdf-audit-utils.ts:667)
---
## 3. Current Template Page Structure
### 3.1 Active page count
Verified from active DB runtime schema:
- `ALLA` active template version has `2` pages
- `ONVALLA` active template version has `2` pages
### 3.2 Schema names per page
Verified runtime schema dump for `ALLA`:
```text
PAGE 1 FIELDS:
company1, company2, company_addr1, company_addr2, company_tel, company_email,
company_tax, line, customer_name, customer_addr, customer_tel, customer_email,
dear_sirs, quotation_price_data, quotation_date_labe, quotation_date_data,
quotation_code_lable, quotation_code_data, customer_att, project_name,
site_location, colon, colon copy, colon_tel, colon_fax, colon_email,
colon_att, colon_project, colon_site, tel_label, email_label,
att_label, project_label, site_label
PAGE 2 FIELDS:
topic, data_topic, Please_do_not, yours_faithfuly,
app1, app1_position, app2, app2_position, app3, app3_position
```
Verified runtime schema dump for `ONVALLA`:
```text
PAGE 1 FIELDS:
company, company_addr1, company_addr2, company_tel, company_email,
company_tax, line, customer_name, customer_addr, customer_tel, customer_email,
dear_sirs, quotation_price_data, quotation_date_labe, quotation_date_data,
quotation_code_lable, quotation_code_data, customer_att, project_name,
site_location, colon, colon copy, colon_tel, colon_fax, colon_email,
colon_att, colon_project, colon_site, tel_label, email_label,
att_label, project_label, site_label
PAGE 2 FIELDS:
topic, data_topic, Please_do_not, yours_faithfuly,
app1, app1_position, app2, app2_position, app3, app3_position
```
### 3.3 Topic/signature page index
Confirmed:
- topic/signature page is currently page index `1` in zero-based runtime terms
- this matches the hardcoded topic engine default
Reference:
- [src/features/crm/quotations/document/server/pdf-topic-engine.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/crm/quotations/document/server/pdf-topic-engine.ts:14)
This is the key verification that explains why inserting a new page in the middle will break the current engine if no runtime change is made first.
---
## 4. PDFMe Table Capability Verification
### 4.1 Verification method
Temporary verification was performed using:
- `@pdfme/generator`
- `@pdfme/schemas` table plugin
- `@pdfme/pdf-lib` for page counting
No production template was modified.
A temporary verification PDF was generated at:
- [rows_30_short.pdf](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/artifacts/task-p4-verification/rows_30_short.pdf)
### 4.2 Runtime source-code evidence for repeat header
The installed table plugin contains explicit repeat-header logic:
```text
node_modules/@pdfme/schemas/dist/dynamicTemplate-CXBCt5wk.js:488
schema.showHead = schema.showHead === false ? false : !schema.__isSplit || schema.repeatHead === true;
node_modules/@pdfme/schemas/dist/dynamicTemplate-CXBCt5wk.js:704
if (!(schema.repeatHead && isBlankPdf(args.basePdf) && headerHeight > 0)) return baseHeights;
```
Interpretation:
- `repeatHead` is a real runtime behavior in the installed table plugin
- repeated header behavior is only applied when using blank/object-style `basePdf`
- this matches the P.4 requirement and also matches the projects current template style
### 4.3 Temporary generation results
Verified generation results:
```json
{"label":"rows_5_short","rowCount":5,"pageCount":1,"pdfBytes":8869}
{"label":"rows_30_short","rowCount":30,"pageCount":2,"pdfBytes":21737}
{"label":"rows_100_short","rowCount":100,"pageCount":4,"pdfBytes":55297}
{"label":"rows_30_long","rowCount":30,"pageCount":3,"pdfBytes":26739}
```
Verified conclusions:
- `5 rows` fits on `1` page
- `30 rows` breaks to `2` pages
- `100 rows` breaks to `4` pages
- `30` long-description rows consume `3` pages instead of `2`
### 4.4 Table behavior conclusions
Confirmed:
- auto page break works
- multi-page table generation works
- row height behavior changes pagination when descriptions become longer
- repeat header is implemented in the installed runtime and tied to `repeatHead: true`
Important nuance:
- visual image-based confirmation was not performed because this environment does not have PDF raster/text inspection tools installed
- however the runtime code path plus successful multi-page generation confirms the feature support exists in the actual installed library
---
## 5. Product Item Mapping Verification
### 5.1 Actual source fields found
Verified live DB columns for `crm_quotation_items`:
```text
id
organization_id
quotation_id
item_number
product_type
description
quantity
unit
unit_price
discount
discount_type
tax_rate
total_price
notes
sort_order
created_at
updated_at
deleted_at
```
### 5.2 Actual document runtime fields exposed
Verified quotation document runtime exposes:
- `itemNumber`
- `productTypeCode`
- `productTypeLabel`
- `description`
- `quantity`
- `unitCode`
- `unitLabel`
- `unitPrice`
- `discount`
- `discountTypeCode`
- `taxRate`
- `totalPrice`
- `notes`
Reference:
- [src/features/crm/quotations/document/server/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/crm/quotations/document/server/service.ts:564)
- [src/features/crm/quotations/document/types.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/crm/quotations/document/types.ts:83)
### 5.3 Actual mapping coverage for `items_table`
Verified active mapping rows already include `items_table` for both organizations.
Current columns:
- `Item``itemNumber`
- `Description``description`
- `Qty``quantity`
- `Unit``unitLabel`
- `Unit Price``unitPrice`
- `Total``totalPrice`
### 5.4 Gap analysis against Task P.4.1 required fields
| Required field | Verified source | Status |
| --- | --- | --- |
| product code | no dedicated field found | gap |
| description | `description` | available |
| specification | no dedicated field found | gap |
| quantity | `quantity` | available |
| unit | `unit` / `unitLabel` | available |
| unit price | `unitPrice` | available |
| discount | `discount` | available |
| amount | `totalPrice` | available |
| remark | closest existing field is `notes` | gap / mapping decision needed |
Conclusion:
- `product code` does not exist as a standalone quotation item field in the current model
- `specification` does not exist as a standalone quotation item field in the current model
- `remark` likely maps to `notes`, but this should be treated as a business decision, not assumed silently
---
## 6. Final Implementation Strategy
Recommended implementation order:
1. generalize topic/signature runtime targeting so it no longer depends on hardcoded page index `1`
2. create new template JSON files
- `ALLA_template_pdfme_product_v1.json`
- `ONVALLA_template_pdfme_product_v1.json`
3. place the Product Item page between customer detail and topic/signature pages
4. configure the Product Item page with official PDFMe `table` schema using:
- `showHead: true`
- `repeatHead: true`
- blank/object-style `basePdf`
5. keep old versions untouched and inactive/active-switchable
6. update reseed/audit source selectors so the new JSON files can be published into DB
7. verify runtime behavior for both old and new versions through the existing routes
Important implementation constraint:
- because runtime currently renders from DB `schema_json`, adding only new JSON files is not sufficient
- reseed or explicit version creation in template admin is required for runtime adoption
---
## 7. Rollback Plan
Recommended rollback:
1. do not delete the current active `1.0` versions
2. publish the new Product Item design as a separate version only
3. if regression occurs, deactivate the new version
4. reactivate the current `1.0` version in `/dashboard/crm/settings/templates`
5. if needed, revert reseed script changes independently from runtime code changes
Why rollback is low-risk:
- versioned template storage already exists
- runtime resolves active version dynamically
- current production version remains intact
---
## 8. Regression Test Matrix
### 8.1 Runtime routes
Verify for both `ALLA` and `ONVALLA`:
- `GET /api/crm/quotations/[id]/document-data`
- `GET /api/crm/quotations/[id]/document-preview`
- `GET /api/crm/quotations/[id]/pdf-preview`
- `GET /api/crm/quotations/[id]/pdf-download`
- approved PDF generation flow
- approved PDF retrieval flow after artifact exists
### 8.2 Template versions
Verify both:
- old version `1.0`
- new product-item version
### 8.3 Row-volume cases
Verify with quotation items around:
- 5 rows
- 30 rows
- 100 rows
- long wrapped descriptions
### 8.4 Output expectations
Verify:
- old template still renders exactly as before
- new template inserts Product Item page between page 1 and topic/signature page
- topic/signature block still lands on the correct page
- repeated table header appears when multiple product pages exist
- long descriptions affect row height without layout corruption
- preview and download use the same selected version
- approved PDF persists the expected template version ID
---
## 9. Summary
Task P.4.1 verification confirms:
- quotation PDF runtime uses one shared active template/version/mapping pipeline
- current active runtime template is still the 2-page `*_fainal3.json` structure
- runtime source is DB `schema_json`, while JSON files remain the seed/reseed source
- official PDFMe table support is sufficient for multi-page product item tables
- current quotation item model is missing dedicated `product code` and `specification` fields
- the biggest implementation blocker is still the topic engines hardcoded page targeting, not the table plugin itself