# Task H.5.3: PDFME Template Version Remap + Static Label Mapping Fix

## Goal

รองรับการแก้ไข PDFME template version ใหม่ทั้งหมด หลังจากมีการลบ/เพิ่ม/เปลี่ยน field ใน template

พร้อมแก้ปัญหา static label เช่น:

```txt
Tel
Email
Att
Project
Location
```

ไม่แสดงใน PDF

---

# Background

Current issue:

Template แสดงค่าฝั่งข้อมูล เช่น:

```txt
02-000-1000
demo-customer@local.test
Task H.1 Contact
Task H.5 Audit Fixture
Bangkok HQ
```

แต่ label ฝั่งซ้ายไม่แสดง:

```txt
Tel
Email
Att
Project
Location
```

Cause:

Field label เช่น:

```txt
tel_label
email_label
att_label
project_label
site_label
```

ยังไม่มี runtime input / mapping ที่ตรงกับ template version ใหม่

อีกทั้ง template มีการลบ field แล้ว จึงต้อง remap ใหม่ทั้ง version

---

# Important Rule

Do NOT patch the old template version in-place.

Create a new template version.

Example:

```txt
ALLA Quotation Standard v1.0
→
ALLA Quotation Standard v1.1
```

Approved PDF เดิมต้องยังอ้าง version เดิมได้

---

# Must Read

```txt
docs/business/pdf-mapping-registry.md
docs/business/pdf-placeholder-registry.md
docs/adr/0013-pdf-visual-parity-strategy.md
docs/implementation/task-h5-pdf-mapping-audit-visual-parity.md
docs/implementation/task-h51-pdf-integrity-audit.md

src/features/foundation/document-template/**
src/features/foundation/pdf-generator/**
src/features/crm/quotations/document/**
src/db/seeds/foundation.seed.ts
scripts/audit-pdf-template-inventory.ts
scripts/audit-pdf-mapping-coverage.ts
scripts/audit-pdf-runtime-payload.ts
scripts/generate-pdf-integrity-report.ts
```

---

# Scope H5.3.1 Template Version Ingestion

Add support to ingest/register new PDFME template JSON as a new version.

Required behavior:

* read latest ALLA / ONVALLA template JSON
* create new `crm_document_template_versions`
* mark new version active
* deactivate previous active version for same template
* do not delete old version
* preserve approved snapshots that reference old version

Rules:

```txt
one active version per template
approved snapshots remain immutable
```

---

# Scope H5.3.2 Full Field Inventory From New Template

For the new template version, scan all schema names.

Classify fields into:

```txt
static input field
dynamic topic template
readonly/static visual field
system field
unknown field
deleted field from previous version
new field
```

Special handling:

Dynamic topic template fields:

```txt
topic
data_topic
```

must not become static mappings.

Runtime generated fields:

```txt
topic_*
item_topic_*
```

must not be stored in DB mapping.

---

# Scope H5.3.3 Full Mapping Rebuild For New Version

For the new template version:

1. create mappings only for fields that exist in the new template
2. do not copy orphan mappings from old version
3. do not map deleted fields
4. use `pdf-placeholder-registry.md` and actual field inventory
5. create missing mappings for valid fields
6. mark unsupported fields as warning, not silent pass

Mapping categories:

## Static Label Fields

```txt
tel_label       -> pdfme.labels.tel
email_label     -> pdfme.labels.email
att_label       -> pdfme.labels.att
project_label   -> pdfme.labels.project
site_label      -> pdfme.labels.location
```

Expected values:

```txt
Tel
Email
Att
Project
Location
```

or Thai labels if configured:

```txt
โทร
อีเมล
เรียน
โครงการ
สถานที่
```

## Customer Fields

```txt
customer_name   -> customer.name
customer_addr   -> customer.address
customer_tel    -> customer.phone
customer_email  -> customer.email
customer_att    -> quotation.attention
```

## Project / Quotation Fields

```txt
project_name       -> quotation.projectName
site_location      -> quotation.projectLocation
quotation_code     -> quotation.code
quotation_code_data -> quotation.code
quotation_date     -> pdfme.quotation_date
quotation_date_data -> pdfme.quotation_date
```

## Price Table

Canonical:

```txt
quotation_price_data -> pdfme.quotation_price_data
```

Keep compatibility if template still has scalar placeholders:

```txt
quotation_price -> pdfme.quotation_price
currency        -> pdfme.currency
```

## Exclusion

```txt
exclusion_data -> pdfme.exclusion_data
```

## Signature

```txt
app1          -> signatures.preparedBy.name
app1_position -> signatures.preparedBy.position
app2          -> signatures.approvedBy.name
app2_position -> signatures.approvedBy.position
app3          -> signatures.authorizedBy.name
app3_position -> signatures.authorizedBy.position
```

---

# Scope H5.3.4 Runtime Document Data Update

Update:

```txt
src/features/crm/quotations/document/server/service.ts
```

Ensure `documentData.pdfme.labels` exists:

```ts
pdfme: {
  labels: {
    tel: "Tel";
    email: "Email";
    att: "Att";
    project: "Project";
    location: "Location";
  }
}
```

Optional Thai mode:

```ts
pdfme: {
  labels: {
    tel: "โทร";
    email: "อีเมล";
    att: "เรียน";
    project: "โครงการ";
    location: "สถานที่";
  }
}
```

Rules:

* never return undefined
* label values should be controlled by terminology/config later
* for now default to current PDF language
* do not hardcode in template only

---

# Scope H5.3.5 Resolver Safety

Update mapping resolver to:

* resolve nested paths such as `pdfme.labels.tel`
* fallback to mapping.defaultValue
* fallback to `"-"` if still empty
* preserve table values as `string[][]`
* not stringify table input

---

# Scope H5.3.6 Audit Update

Update audit scripts to support version remap.

Checks:

```txt
new version active
old version inactive but retained
deleted fields removed from mapping
new fields mapped or classified
label fields resolved
price table present
dynamic topics still valid
signature fields still valid
approved snapshot parity still pass for newly generated artifact
```

Special check:

```txt
tel_label
email_label
att_label
project_label
site_label
```

must be non-empty.

---

# Scope H5.3.7 Seed / Migration Strategy

Update:

```txt
src/db/seeds/foundation.seed.ts
```

or create a dedicated script:

```txt
scripts/reseed-pdf-template-version.ts
```

Recommended:

Use dedicated script for remap:

```txt
npm run seed:pdf-template-version
```

because template version remap is operationally different from foundation seed.

Rules:

* no hardcoded organizationId
* handles every organization
* handles ALLA / ONVALLA branch template
* idempotent per template version
* no duplicate active versions

---

# Scope H5.3.8 Approved Snapshot Rule

Existing approved artifacts:

* keep using old template version
* do not regenerate automatically
* do not update old snapshot mapping

New approved artifacts:

* use new active template version
* use new mappings
* pass parity audit

---

# Scope H5.3.9 Verification

Run:

```txt
npm run seed:pdf-template-version
npm run audit:pdf
```

Expected:

```txt
Overall Status: PASS
Template Version: PASS
Placeholder Integrity: PASS
Payload Parity: PASS
Topic Runtime: PASS
Approved Snapshot Parity: PASS
Price Table: PASS
Static Labels: PASS
```

Visual check:

```txt
Tel      : 02-000-1000
Email    : demo-customer@local.test
Att      : Task H.1 Contact
Project  : Task H.5 Audit Fixture
Location : Bangkok HQ
```

---

# Scope H5.3.10 Documentation

Update:

```txt
docs/business/pdf-mapping-registry.md
docs/business/pdf-placeholder-registry.md
docs/implementation/task-h5-pdf-mapping-audit-visual-parity.md
docs/implementation/technical-debt.md
```

Add:

```txt
Template version remap process
Static label mapping strategy
Deleted field handling
Dynamic topic reserved fields
Approved snapshot immutability rule
```

---

# Explicit Non-Scope

Do NOT implement:

```txt
visual template designer
signature image / draw signature
digital signature
currency exchange calculation
report center
permission center
```

---

# Output

After completion, summarize:

1. Files Added
2. Files Modified
3. New Template Version Created
4. Deleted Fields Detected
5. New Field Inventory
6. Mappings Rebuilt
7. Static Labels Fixed
8. Audit Result
9. Remaining Risks

---

# Definition of Done

Task H.5.3 passes when:

* new template version is created
* old template version is retained
* old mappings are not blindly copied
* deleted fields do not remain as active mappings
* new fields are mapped or classified
* `tel_label` renders
* `email_label` renders
* `att_label` renders
* `project_label` renders
* `site_label` renders
* price table still renders
* dynamic topics still render
* signatures still render
* approved snapshot parity passes for newly generated approved PDF
* `npm run audit:pdf` returns Overall Status PASS
