# Task H.3: Approval Signature Strategy

## Goal

ทำให้ PDF ใบเสนอราคาสามารถแสดงข้อมูลผู้จัดทำ ผู้อนุมัติ และผู้มีอำนาจอนุมัติได้อย่างถูกต้อง

รองรับทั้ง:

```txt
Preview PDF
Approved PDF
Approved Snapshot
Document Artifact
```

โดยข้อมูลลายเซ็นต้องมาจาก Approval Workflow จริง ไม่ใช่ค่าคงที่ใน Template

---

# Background

Task H.2 เพิ่ม:

```txt
Dynamic Topic Engine
PDFME Runtime Mapping
Template Mapping Resolver
```

Task H.1 เพิ่ม:

```txt
Approved Snapshot
Artifact Storage
```

Task H.3 จะเติมส่วนที่ยังขาด:

```txt
Prepared By
Approved By
Authorized By
Position
Approval Timeline Resolution
```

---

# Current Problem

Template ปัจจุบันมี placeholder เช่น:

```txt
app1
app1_position

app2
app2_position

app3
app3_position
```

แต่ยังไม่มี strategy กลางสำหรับดึงข้อมูลจริงจาก:

```txt
quotation
approval workflow
approval actions
membership
business role
```

---

# Scope H3.1 Signature Data Contract

Create:

```txt
src/features/crm/quotations/document/signature.types.ts
```

Define:

```ts
type SignatureBlock = {
  preparedBy: {
    name: string;
    position: string;
  };

  approvedBy: {
    name: string;
    position: string;
  };

  authorizedBy: {
    name: string;
    position: string;
  };
};
```

---

# Scope H3.2 Position Resolution Strategy

Create:

```txt
src/features/crm/quotations/document/signature-position.ts
```

Resolve position from:

```txt
membership.businessRole
```

Recommended mapping:

```txt
sales
→ Sales Engineer

sales_support
→ Sales Support

sales_manager
→ Sales Manager

department_manager
→ Department Manager

top_manager
→ General Manager
```

Rules:

Do NOT hardcode display strings inside PDF generator.

Source from:

```txt
crm_job_title
```

master option when available.

Fallback:

```txt
businessRole label
```

---

# Scope H3.3 Prepared By Resolution

Prepared By source:

Priority:

```txt
quotation.salesmanId
```

Fallback:

```txt
quotation.createdBy
```

Output:

```txt
preparedBy.name
preparedBy.position
```

Rules:

Must resolve display name.

Never use raw user id.

---

# Scope H3.4 Approved By Resolution

Resolve from approval workflow history.

Source:

```txt
crm_approval_actions
```

Rules:

Find latest approved action from:

```txt
sales_manager
```

or

```txt
department_manager
```

depending on workflow configuration.

Output:

```txt
approvedBy.name
approvedBy.position
```

---

# Scope H3.5 Authorized By Resolution

Resolve from final approval step.

Source:

```txt
crm_approval_actions
```

Rules:

Find final approved action.

Expected role:

```txt
top_manager
```

Output:

```txt
authorizedBy.name
authorizedBy.position
```

---

# Scope H3.6 Signature Resolver

Create:

```txt
src/features/crm/quotations/document/server/signature-resolver.ts
```

Expose:

```ts
resolveQuotationSignatures(
  quotationId,
  organizationId
)
```

Returns:

```ts
SignatureBlock
```

Responsibilities:

```txt
load quotation
load approval history
resolve users
resolve positions
build final signature object
```

---

# Scope H3.7 PDF Mapping Integration

Update:

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

Inject:

```txt
signatures.preparedBy.name
signatures.preparedBy.position

signatures.approvedBy.name
signatures.approvedBy.position

signatures.authorizedBy.name
signatures.authorizedBy.position
```

Into:

```txt
documentData
templateInput
approvedSnapshot
```

---

# Scope H3.8 PDFME Placeholder Mapping

Update seed mappings.

Expected:

```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
```

Rules:

Idempotent seed.

Update existing mappings if incorrect.

---

# Scope H3.9 Approved Snapshot Integration

Update:

```txt
prepareApprovedQuotationSnapshot()
```

Snapshot must store:

```txt
resolved signatures
```

Purpose:

Future PDF regeneration must preserve:

```txt
who approved
who authorized
```

even if users later change.

---

# Scope H3.10 Preview Behavior

Preview PDF:

```txt
resolve live signatures
```

Approved PDF:

```txt
prefer approved snapshot signatures
```

Rules:

Approved artifact must remain immutable.

---

# Scope H3.11 UI Visibility

Update quotation detail.

Add section:

```txt
Approval Signatures
```

Display:

```txt
Prepared By
Approved By
Authorized By
```

with:

```txt
name
position
approval timestamp
```

if available.

---

# Scope H3.12 Verification

Create:

```txt
scripts/verify-task-h3.js
```

Verify:

```txt
preparedBy exists
approvedBy exists
authorizedBy exists

app1 mapped
app2 mapped
app3 mapped

snapshot contains signatures

approved PDF contains names
```

---

# ADR

Create:

```txt
docs/adr/0012-approval-signature-strategy.md
```

Freeze:

```txt
Prepared By rule
Approved By rule
Authorized By rule
Position resolution rule
Snapshot immutability rule
```

---

# Explicit Non-Scope

Do NOT implement:

```txt
Digital signature
Image signature
Certificate signature
PKI
e-Signature
QR verification
Stamp image upload
```

Only text-based approval identity.

---

# Output

1. Files Added
2. Files Modified
3. Signature Resolution Strategy
4. Position Resolution Strategy
5. PDF Mapping Changes
6. Snapshot Changes
7. Verification Result
8. ADR Added
9. Remaining Risks

---

# Definition of Done

✔ Prepared By resolves correctly

✔ Approved By resolves correctly

✔ Authorized By resolves correctly

✔ Position resolves correctly

✔ PDF Preview displays signatures

✔ Approved PDF displays signatures

✔ Approved Snapshot stores signatures

✔ app1/app2/app3 mappings work

✔ Artifact remains immutable

✔ ADR created
