task-h.1 complate
This commit is contained in:
251
plans/task-d.1.md
Normal file
251
plans/task-d.1.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Task D.1: Enquiry Assignment + CRM Role Permission Stabilization
|
||||
|
||||
## Goal
|
||||
|
||||
เพิ่มระบบ Assign Sales ให้ Enquiry และปรับ Role/Permission ให้รองรับ ALLA OS CRM ไม่ใช่เฉพาะ IT-CENTER template
|
||||
|
||||
## Must Read
|
||||
|
||||
```txt
|
||||
docs/implementation/task-a-template-audit.md
|
||||
docs/implementation/task-b-template-audit.md
|
||||
docs/implementation/task-b1-foundation-stabilization.md
|
||||
src/features/crm/enquiries/**
|
||||
src/features/crm/customers/**
|
||||
src/features/foundation/**
|
||||
src/lib/auth/rbac.ts
|
||||
src/db/schema.ts
|
||||
src/db/seeds/foundation.seed.ts
|
||||
```
|
||||
|
||||
## Scope 1: Audit Current Enquiry Assignment
|
||||
|
||||
ตรวจสอบว่า `crm_enquiries` มี field เหล่านี้หรือยัง:
|
||||
|
||||
```txt
|
||||
assignedToUserId
|
||||
assignedAt
|
||||
assignedBy
|
||||
assignmentRemark
|
||||
```
|
||||
|
||||
ตรวจสอบ UI:
|
||||
|
||||
```txt
|
||||
Assign Sales
|
||||
Reassign Sales
|
||||
My Enquiries
|
||||
Assigned Enquiries
|
||||
```
|
||||
|
||||
ตรวจสอบ permission:
|
||||
|
||||
```txt
|
||||
crm.enquiry.assign
|
||||
crm.enquiry.reassign
|
||||
```
|
||||
|
||||
ถ้าไม่มี ให้ implement ตาม scope ถัดไป
|
||||
|
||||
## Scope 2: Schema
|
||||
|
||||
เพิ่ม field ใน `crm_enquiries`:
|
||||
|
||||
```txt
|
||||
assignedToUserId
|
||||
assignedAt
|
||||
assignedBy
|
||||
assignmentRemark
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
* assignedToUserId อ้างถึง user ใน organization เดียวกัน
|
||||
* assignedBy คือ current user
|
||||
* assignedAt คือเวลาที่ assign ล่าสุด
|
||||
* assignmentRemark optional
|
||||
* soft delete ไม่เกี่ยวกับ assignment
|
||||
|
||||
## Scope 3: API
|
||||
|
||||
เพิ่ม route:
|
||||
|
||||
```txt
|
||||
POST /api/crm/enquiries/[id]/assign
|
||||
POST /api/crm/enquiries/[id]/reassign
|
||||
```
|
||||
|
||||
Payload:
|
||||
|
||||
```ts
|
||||
{
|
||||
assignedToUserId: string
|
||||
remark?: string
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
* ต้อง require organization access
|
||||
* ต้อง validate assignee อยู่ใน organization เดียวกัน
|
||||
* assign/reassign ต้อง audit
|
||||
* assign ครั้งแรกใช้ action = assign
|
||||
* เปลี่ยนคนใช้ action = reassign
|
||||
|
||||
## Scope 4: Permission
|
||||
|
||||
เพิ่ม permission:
|
||||
|
||||
```txt
|
||||
crm.enquiry.assign
|
||||
crm.enquiry.reassign
|
||||
```
|
||||
|
||||
Role recommendation:
|
||||
|
||||
```txt
|
||||
super_admin: all permissions
|
||||
organization_admin: all crm permissions
|
||||
sales_manager: read/create/update/assign/reassign enquiry
|
||||
sales: read/create/update own/assigned enquiry
|
||||
sales_support: read/create/update enquiry
|
||||
viewer: read only
|
||||
```
|
||||
|
||||
อย่า hardcode เฉพาะ IT-CENTER roles
|
||||
|
||||
## Scope 5: UI
|
||||
|
||||
ใน Enquiry Detail เพิ่ม action:
|
||||
|
||||
```txt
|
||||
Assign Sales
|
||||
Reassign Sales
|
||||
```
|
||||
|
||||
แสดงเมื่อ:
|
||||
|
||||
```txt
|
||||
user has crm.enquiry.assign หรือ crm.enquiry.reassign
|
||||
```
|
||||
|
||||
แสดงข้อมูล:
|
||||
|
||||
```txt
|
||||
Assigned Sales
|
||||
Assigned At
|
||||
Assigned By
|
||||
Assignment Remark
|
||||
```
|
||||
|
||||
ใน Enquiry List เพิ่ม column:
|
||||
|
||||
```txt
|
||||
Assigned Sales
|
||||
```
|
||||
|
||||
## Scope 6: Form
|
||||
|
||||
ใช้ Sheet/Dialog pattern
|
||||
|
||||
Field:
|
||||
|
||||
```txt
|
||||
Sales User
|
||||
Remark
|
||||
```
|
||||
|
||||
Sales User dropdown ต้องดึงจาก users/memberships ใน organization ปัจจุบัน
|
||||
|
||||
ห้าม hardcode user
|
||||
|
||||
## Scope 7: Audit
|
||||
|
||||
Audit entity:
|
||||
|
||||
```txt
|
||||
crm_enquiry
|
||||
```
|
||||
|
||||
Actions:
|
||||
|
||||
```txt
|
||||
assign
|
||||
reassign
|
||||
```
|
||||
|
||||
beforeData:
|
||||
|
||||
```txt
|
||||
oldAssignedToUserId
|
||||
```
|
||||
|
||||
afterData:
|
||||
|
||||
```txt
|
||||
newAssignedToUserId
|
||||
remark
|
||||
```
|
||||
|
||||
## Scope 8: Membership/Permission Stabilization
|
||||
|
||||
ตรวจ Workspace Membership UI ว่ายังเป็น IT-CENTER template อยู่หรือไม่
|
||||
|
||||
ถ้ายังเป็น IT-CENTER ให้เพิ่ม CRM permissions เข้าไปก่อน โดยไม่ลบของเดิมทันที
|
||||
|
||||
เพิ่ม permission groups:
|
||||
|
||||
```txt
|
||||
crm.customer.*
|
||||
crm.contact.*
|
||||
crm.enquiry.*
|
||||
crm.quotation.*
|
||||
crm.approval.*
|
||||
crm.document_template.*
|
||||
```
|
||||
|
||||
อย่างน้อยต้องมี:
|
||||
|
||||
```txt
|
||||
crm.enquiry.read
|
||||
crm.enquiry.create
|
||||
crm.enquiry.update
|
||||
crm.enquiry.delete
|
||||
crm.enquiry.assign
|
||||
crm.enquiry.reassign
|
||||
```
|
||||
|
||||
## ห้ามทำ
|
||||
|
||||
```txt
|
||||
Quotation assignment
|
||||
Approval assignment
|
||||
Notification
|
||||
Dashboard KPI
|
||||
Report
|
||||
Major RBAC rewrite
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
สรุป:
|
||||
|
||||
1. Files Added
|
||||
2. Files Modified
|
||||
3. Schema Added
|
||||
4. API Routes Added
|
||||
5. Permissions Added
|
||||
6. UI Added
|
||||
7. Audit Integration
|
||||
8. Remaining Risks
|
||||
|
||||
## Definition of Done
|
||||
|
||||
* Enquiry assign sales ได้
|
||||
* Reassign sales ได้
|
||||
* Enquiry list แสดง assigned sales
|
||||
* Enquiry detail แสดง assigned sales
|
||||
* Permission guard ทำงาน
|
||||
* super_admin เห็นปุ่ม assign
|
||||
* audit log ถูกสร้าง
|
||||
* ไม่กระทบ Customer/Quotation/Approval
|
||||
302
plans/task-h.1.md
Normal file
302
plans/task-h.1.md
Normal file
@@ -0,0 +1,302 @@
|
||||
# Task H.1: PDF Generation Stabilization
|
||||
|
||||
## Goal
|
||||
|
||||
Stabilize Task H PDF generation before starting Task I.
|
||||
|
||||
Task H already added:
|
||||
|
||||
* pdfme server-side generation
|
||||
* preview/download PDF APIs
|
||||
* approved PDF generation
|
||||
* approved snapshot persistence
|
||||
* approved PDF attachment metadata
|
||||
* quotation detail PDF actions
|
||||
|
||||
Task H.1 focuses on validation, hardening, and documentation.
|
||||
|
||||
---
|
||||
|
||||
## Must Read
|
||||
|
||||
```txt
|
||||
docs/implementation/technical-debt.md
|
||||
docs/adr/0008-attachment-storage-strategy.md
|
||||
|
||||
src/features/foundation/pdf-generator/**
|
||||
src/features/foundation/document-template/**
|
||||
src/features/crm/quotations/document/**
|
||||
src/features/crm/quotations/**
|
||||
src/features/foundation/approval/**
|
||||
src/app/api/crm/quotations/[id]/pdf-preview/route.ts
|
||||
src/app/api/crm/quotations/[id]/pdf-download/route.ts
|
||||
src/app/api/crm/quotations/[id]/approved-pdf/route.ts
|
||||
src/db/schema.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scope 1: Smoke Test With Real Quotation
|
||||
|
||||
Create or identify one real quotation record in dev database.
|
||||
|
||||
The record must include:
|
||||
|
||||
```txt
|
||||
customer
|
||||
contact
|
||||
enquiry optional
|
||||
at least one item
|
||||
quotation customer role
|
||||
scope topic
|
||||
exclusion topic
|
||||
payment topic
|
||||
approved status or approval flow completed
|
||||
```
|
||||
|
||||
Then verify:
|
||||
|
||||
```txt
|
||||
Preview PDF
|
||||
Download PDF
|
||||
Generate Approved PDF
|
||||
View Approved PDF
|
||||
```
|
||||
|
||||
If no real record exists, create a minimal seed/dev fixture.
|
||||
|
||||
Rules:
|
||||
|
||||
* dev fixture must be organization-scoped
|
||||
* do not hardcode organizationId
|
||||
* do not pollute production seed
|
||||
* place fixture under dev-only seed or clearly named script
|
||||
|
||||
---
|
||||
|
||||
## Scope 2: PDF Output Validation
|
||||
|
||||
Check generated PDF for:
|
||||
|
||||
```txt
|
||||
file opens correctly
|
||||
page count is reasonable
|
||||
customer block appears
|
||||
quotation code appears
|
||||
item table appears
|
||||
total amount appears
|
||||
scope/exclusion/payment appears
|
||||
approval block appears
|
||||
signature placeholder appears
|
||||
```
|
||||
|
||||
If layout breaks:
|
||||
|
||||
* adjust mapping normalization
|
||||
* adjust template input preparation
|
||||
* do not rewrite template designer
|
||||
* do not hardcode quotation-specific hacks into generic pdf generator
|
||||
|
||||
---
|
||||
|
||||
## Scope 3: Approved PDF API Validation
|
||||
|
||||
Validate:
|
||||
|
||||
```txt
|
||||
GET /api/crm/quotations/[id]/pdf-preview
|
||||
GET /api/crm/quotations/[id]/pdf-download
|
||||
POST /api/crm/quotations/[id]/approved-pdf
|
||||
GET /api/crm/quotations/[id]/approved-pdf
|
||||
```
|
||||
|
||||
Expected behavior:
|
||||
|
||||
* preview returns inline PDF
|
||||
* download returns attachment PDF
|
||||
* approved-pdf POST only works for approved quotation
|
||||
* approved-pdf GET returns stored file if available
|
||||
* non-approved quotation cannot generate approved PDF
|
||||
|
||||
---
|
||||
|
||||
## Scope 4: Persistence Validation
|
||||
|
||||
After approved PDF generation verify:
|
||||
|
||||
```txt
|
||||
quotation.approvedPdfUrl populated
|
||||
quotation.approvedSnapshot populated
|
||||
quotation.approvedTemplateVersionId populated
|
||||
quotation attachment metadata created or updated
|
||||
audit log generated
|
||||
file exists in public/generated/quotations/<organizationId>/
|
||||
```
|
||||
|
||||
If any part is missing, fix only the persistence pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Scope 5: Permission Validation
|
||||
|
||||
Verify permissions:
|
||||
|
||||
```txt
|
||||
crm.quotation.pdf.preview
|
||||
crm.quotation.pdf.download
|
||||
crm.quotation.pdf.generate_approved
|
||||
```
|
||||
|
||||
Check behavior for:
|
||||
|
||||
```txt
|
||||
super_admin
|
||||
admin
|
||||
regular user with permission
|
||||
regular user without permission
|
||||
```
|
||||
|
||||
Do not rewrite RBAC model.
|
||||
|
||||
---
|
||||
|
||||
## Scope 6: Error Handling
|
||||
|
||||
Improve user-safe/server-safe errors for:
|
||||
|
||||
```txt
|
||||
template not found
|
||||
template version not found
|
||||
mapping missing
|
||||
quotation not approved
|
||||
generated file missing
|
||||
pdfme generation error
|
||||
local storage write error
|
||||
permission denied
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
* API must return meaningful status codes
|
||||
* UI should show readable toast/message
|
||||
* do not expose stack trace to client
|
||||
|
||||
---
|
||||
|
||||
## Scope 7: Documentation / ADR
|
||||
|
||||
Update:
|
||||
|
||||
```txt
|
||||
docs/implementation/technical-debt.md
|
||||
```
|
||||
|
||||
Confirm or add:
|
||||
|
||||
```txt
|
||||
pdfme font fallback workaround
|
||||
local filesystem storage limitation
|
||||
missing object storage abstraction
|
||||
approved PDF lifecycle not immutable yet
|
||||
no full E2E test in CI yet
|
||||
```
|
||||
|
||||
Create ADR if not exists:
|
||||
|
||||
```txt
|
||||
docs/adr/0009-approved-document-storage-lifecycle.md
|
||||
```
|
||||
|
||||
Include:
|
||||
|
||||
```txt
|
||||
Current:
|
||||
local public/generated storage
|
||||
|
||||
Decision:
|
||||
acceptable for development/MVP only
|
||||
|
||||
Future:
|
||||
object storage abstraction
|
||||
signed URL
|
||||
immutable approved artifacts
|
||||
retention policy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scope 8: Optional Small Fix
|
||||
|
||||
If approval finalization already has a clean hook point, add a non-blocking TODO or optional manual trigger note for:
|
||||
|
||||
```txt
|
||||
auto-generate approved PDF after final approval
|
||||
```
|
||||
|
||||
Do not force automatic generation in Task H.1 if it risks breaking approval flow.
|
||||
|
||||
---
|
||||
|
||||
## ห้ามทำ
|
||||
|
||||
```txt
|
||||
object storage production
|
||||
signed URL service
|
||||
template designer
|
||||
mapping editor
|
||||
email notification
|
||||
report
|
||||
dashboard KPI
|
||||
large refactor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output
|
||||
|
||||
After completion, summarize:
|
||||
|
||||
1. Files Added
|
||||
2. Files Modified
|
||||
3. Smoke Test Record Used
|
||||
4. PDF APIs Verified
|
||||
5. Persistence Verified
|
||||
6. Permission Verified
|
||||
7. Error Handling Improved
|
||||
8. ADR / Technical Debt Updated
|
||||
9. Remaining Risks
|
||||
10. Task I Readiness
|
||||
|
||||
---
|
||||
|
||||
## Definition of Done
|
||||
|
||||
Task H.1 passes when:
|
||||
|
||||
✔ PDF preview works with a real quotation
|
||||
|
||||
✔ PDF download works with a real quotation
|
||||
|
||||
✔ Approved PDF generation works for approved quotation
|
||||
|
||||
✔ Approved PDF GET returns stored PDF
|
||||
|
||||
✔ Non-approved quotation cannot generate approved PDF
|
||||
|
||||
✔ approvedSnapshot is saved
|
||||
|
||||
✔ approvedPdfUrl is saved
|
||||
|
||||
✔ approvedTemplateVersionId is saved
|
||||
|
||||
✔ attachment metadata is created/updated
|
||||
|
||||
✔ audit log exists for approved PDF generation
|
||||
|
||||
✔ permissions are enforced
|
||||
|
||||
✔ errors are user-safe
|
||||
|
||||
✔ storage lifecycle ADR exists
|
||||
|
||||
✔ ready for Task I
|
||||
Reference in New Issue
Block a user