Files
alla-allaos-fullstack/plans/task-h.3.md
phaichayon a85d24235c task-h.4
2026-06-19 12:30:26 +07:00

531 lines
6.1 KiB
Markdown

# 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