15 KiB
Technical Debt
After Task D
Database foreign keys
Customer, contact, and enquiry relationships are still enforced mainly in application logic.
Future:
- add FK constraints after the CRM schema settles
- review cascade behavior before enabling hard relational enforcement
Date input UX
Several forms still use plain YYYY-MM-DD text/date inputs.
Future:
- move to a shared date picker pattern
- standardize timezone handling for CRM forms
Related enquiry pagination
Customer detail can show related enquiries, but that view still has no dedicated pagination strategy.
Future:
- add paging once real data volume grows
Follow-up activity timeline
Activity history still relies heavily on audit payloads instead of a curated domain timeline.
Future:
- build a combined activity view/service for CRM interactions
After Task D.1
Enquiry Own / Assigned Scope
Current: sales role ยังอ่าน enquiry ในระดับ organization scope
Future: เพิ่ม server-side policy:
- sales เห็นเฉพาะ enquiry ที่ตัวเองสร้าง
- หรือ enquiry ที่ assigned ให้ตัวเอง
- sales_manager เห็นทั้งทีม
Priority: High
Legacy Business Role Backfill
Current: ระบบ runtime ใช้ CRM businessRole แล้ว แต่ DB เก่าอาจยังมี role จาก IT-CENTER
Future: ทำ one-time migration/backfill script สำหรับ memberships.businessRole
Priority: Medium
After Task E
Mixed tax rollup
Quotation items support per-line tax input, but summary calculation still assumes a header-centric tax model.
Future:
- support mixed-tax aggregation from actual item rows
- align document totals and reporting with per-line tax logic
Attachment storage abstraction
Quotation attachments started as metadata-only and approved PDFs now write to local disk, but there is still no real storage abstraction.
Future:
- introduce a provider abstraction
- support upload/download lifecycle consistently across manual attachments and generated artifacts
- define migration strategy for existing local/public paths
Revision snapshot coverage
Revision copy currently focuses on quotation header, items, customers, and topics.
Future:
- decide whether follow-ups and attachments belong in revision snapshots
- define immutable vs mutable child-data behavior across revisions
CRM foreign keys
Core CRM tables still depend on organization-scoped validation in service code.
Future:
- add FK constraints after schema churn slows down
- review delete and soft-delete interactions first
After Task F
Permission sync for existing memberships
New permissions are defined in code, but old membership rows may still hold stale permission arrays.
Future:
- add a permission sync/backfill command
- provide admin tooling for role and permission maintenance
Approval workflow configuration UI
Approval workflows are seeded and usable, but still not configurable from the dashboard.
Future:
- build workflow setup screens
- add step editing and role mapping management
Approval notifications
Approval flow has no queue-backed notification channel yet.
Future:
- add notification jobs
- support reminders and escalation policy
After Task G
Document mapping editor
Template mappings are seeded and readable, but not manageable from UI.
Future:
- add mapping CRUD for admins
- support table column editing
- add draft/publish template workflow
Product-specific template resolution
Quotation document template resolution still defaults to a coarse product selection strategy.
Future:
- define clearer rules for crane, dock door, solar, and service-specific templates
After Task H / H.1
Font compatibility fallback
PDF generation now uses vendored Cordia TTF files from public/fonts, which fixed the TTC runtime issue, but generator-side fallback normalization still remains as a safety net.
Future:
- keep validating Thai text metrics against designer output
- remove fallback normalization only after render parity is proven stable
Local filesystem storage
Approved PDFs currently persist under public/generated/quotations/<organizationId>/.
Future:
- replace local public storage for production with object storage
- add signed/private delivery where required
- define backup and cleanup expectations
Approved artifact immutability
Approved PDF persistence exists, but the lifecycle is not immutable by policy yet.
Future:
- define whether regeneration is allowed after approval
- version approved artifacts explicitly if regeneration must remain possible
- document which snapshot fields are contractual records
Post-approval automation
Approved PDF generation is still manual by design.
Future:
- add a non-blocking auto-generation hook after final approval
- move heavy generation/retry behavior to a background job when needed
PDF pipeline test coverage
Task H.1 added dev fixture and HTTP verification scripts, but there is still no CI-backed E2E coverage for the PDF pipeline.
Future:
- promote fixture verification into automated test coverage
- add regression checks for template mappings, storage persistence, and permission enforcement
Current PDFME template coverage
Current:
- payment, warranty, delivery, and extra topic sections now flow through the dynamic
topic/data_topicengine on page 2 instead of fixed placeholder fields - approval signature placeholders now resolve through the H.3 signature strategy and
crm_job_titleposition lookup quotation_price_datais now the canonical runtime table input for the price row, while active template JSON still embeds nested{quotation_price}and{currency}cells inside that table field
Future:
- keep validating pagination and closing-block placement against production designer expectations for large topic sets
- add fixture-backed end-to-end PDF generation verification in CI once a stable runtime path is available
- remove nested price-table placeholders in a controlled template revision once design change windows allow it
- decide whether static template field
lineshould remain a tolerated designer-only artifact or be normalized in future audits
Template version remap operations
Current:
- template version remap is now handled by
npm run seed:pdf-template-version, not by the base foundation seed - active
1.1mappings intentionally preserve historical1.0versions for snapshot integrity
Future:
- decide whether template version promotion needs an operator-facing review/approve workflow
- add artifacting or changelog snapshots for template-schema diffs before activation
- decide whether the remap command should write a persistent audit history table instead of JSON-only artifacts
After Task I
Storage provider production rollout
Task I introduced a storage provider abstraction with local and S3/MinIO-compatible implementations, but the production rollout still depends on environment configuration and infrastructure ownership outside the app.
Future:
- validate real bucket policies, credentials rotation, and environment separation
- add operational runbooks for provider misconfiguration and storage outage handling
- add smoke checks for startup-time storage provider health
Legacy approved PDF migration
Task I keeps compatibility for legacy public/generated/... approved PDFs, but those legacy files are still outside the new artifact source-of-truth model.
Future:
- add a one-time migration script from legacy local paths into
crm_document_artifacts - backfill
approvedArtifactIdwhere possible - remove legacy compatibility once migration is complete and verified
Artifact lifecycle policy depth
Approved artifacts are now immutable-first and locked after generation, but void/regeneration policy is still service-level rather than a full operator workflow.
Future:
- add explicit admin tooling for artifact void and replacement flows
- define whether artifact voiding also clears or supersedes quotation-facing references automatically
- document retention expectations for voided objects in object storage
Secure artifact delivery model
Approved-PDF viewing now goes through secure server routes and storage-backed reads, but signed-url/offload behavior is not yet used.
Future:
- decide when direct signed URLs are acceptable versus mandatory server streaming
- add response caching strategy for large artifact downloads
- evaluate optional download-audit sampling if volume grows
After Task J.0
Missing lifecycle timestamps for KPI precision
Task J.0 freezes KPI rules around pipelineStage, but the schema still lacks explicit lifecycle timestamps for stage conversion and closure events.
Future:
- add
convertedToOpportunityAtfor precise lead-to-opportunity timing - add
closedWonAtfor won-date reporting - add
closedLostAtfor lost-date reporting - backfill reporting logic to prefer explicit lifecycle timestamps over inference when available
Lost reason analytics
Closed-lost semantics are frozen, but there is still no structured lostReason field for dashboard grouping and sales analysis.
Future:
- add
lostReasonto the CRM enquiry lifecycle model - define a controlled vocabulary or master-option category for loss analysis
- expose lost-reason reporting only after the field is reliably captured
Default customer party role behavior
Customer party definitions are frozen, but there is still no defaultPartyRole behavior to help normalize customer selection and reduce operator ambiguity.
Future:
- decide whether customers should carry a suggested default project-party role
- add
defaultPartyRoleonly if it improves data-entry quality without creating hidden automation - keep dashboard logic independent from this field until the model is formally introduced
After Task D.2.1
Unified project-party reporting projection
Revenue attribution is now frozen, but the schema still stores enquiry and quotation parties in separate tables rather than a dedicated reporting projection.
Future:
- add a unified reporting view or materialized projection if dashboard/report queries become heavy
- keep quotation-party precedence and enquiry fallback centralized in one service until that projection exists
- avoid duplicating attribution logic in dashboard-specific code
Historical party snapshot fidelity
Current revenue attribution uses live project-party relationships with quotation-first fallback behavior, but it does not yet provide effective-dated historical party snapshots for reporting.
Future:
- decide whether approved quotation snapshots or another immutable reporting snapshot should become the historical source of truth
- define how reporting should behave if project parties change after quotation approval or after a won/lost outcome
- add backfill or reconciliation tooling if historical party drift becomes a business issue
After Task J
Closed-won lifecycle fidelity
Task J ships a live CRM dashboard, but the current schema still lacks a first-class enquiry closed_won lifecycle field and dedicated close timestamps.
Current:
- dashboard won-stage metrics currently use quotation status
acceptedas the practical proxy forclosed_won
Future:
- add explicit enquiry lifecycle support for
closed_won - add
closedWonAtto support precise won-date analytics - remove dashboard proxy logic once the lifecycle model is formalized
Follow-up completion semantics
Task J adds follow-up analytics, but the follow-up model still has no explicit completion flag.
Current:
- dashboard
Completedfollow-up metrics infer completion fromoutcomepresence
Future:
- add an explicit completion state or activity outcome model for follow-ups
- separate scheduled, completed, cancelled, and skipped follow-up reporting cleanly
Dashboard own-scope policy
Task J introduces crm.dashboard.read, but sales users still view organization-wide KPI data for now.
Future:
- add own-scope dashboard filtering for sales roles
- define whether mixed-role users see own, team, or organization scope by default
- keep exports aligned with the same scope policy once enforced
After Task L.1
Deprecated membership.businessRole for CRM authorization
Current:
memberships.businessRole is now a compatibility fallback only. Primary CRM authorization moves to crm_user_role_assignments.
Future:
- remove CRM authorization dependence on
memberships.businessRoleentirely - update user-management flows to assign CRM roles through assignment rows instead of membership payloads
- remove the deprecated column only after all CRM modules and admin flows have migrated
After Task L.2
Legacy compatibility mirror on membership.businessRole
Current:
User management now writes CRM role assignments directly, but memberships.businessRole is still mirrored from the primary CRM role for compatibility with remaining legacy seams.
Future:
- remove mirror writes once every consumer fully resolves CRM access from
crm_user_role_assignments - delete the column only after migration tooling, admin screens, and downstream integrations no longer depend on it
Global project-party filter coverage
Task J adds a global Project Party Role filter in the dashboard UI, but the strongest enforcement today is in revenue analytics and export sections.
Future:
- decide which non-revenue widgets should fully honor project-party role filtering
- add a unified filtered reporting projection if cross-widget party-role filtering becomes a hard requirement
After Task L.3
Customer and contact ownership enforcement
Current: Customer/contact modules are still more organization-wide than quotation security and need the same resolved ownership model applied consistently.
Future:
- add resolved CRM access context to every customer/contact service path
- enforce shared-contact visibility without falling back to blanket organization reads
Approval visibility scoping
Current: Approval step handling now resolves multi-role actors correctly, but approval list/detail visibility is still broader than final quotation-scoped security.
Future:
- scope approval requests by accessible entity visibility, not organization membership alone
- align dashboard approval widgets and approval detail pages with the same rule
Team-scope fidelity
Current:
Resolved CRM access supports team, but the domain still lacks a first-class subordinate/team graph for precise enforcement.
Future:
- define the canonical team relationship source
- replace current coarse team handling with explicit team membership or manager hierarchy logic
Contact-sharing persistence gap
Current: Task C.1 closes the contact-sharing persistence gap, but cross-feature regression coverage for owner/share visibility is still light and team-scope remains approximate.
Future:
- add deeper automated regression coverage for owner/share visibility across customer, lead, enquiry, and quotation flows
- introduce a first-class CRM team hierarchy if the business still needs inherited team visibility