taks-p.4.3

This commit is contained in:
phaichayon
2026-06-29 11:18:08 +07:00
parent 2540d52670
commit 0c0450b152
20 changed files with 4900 additions and 505 deletions

View File

@@ -0,0 +1,457 @@
# 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