# 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//`. 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_topic` engine on page 2 instead of fixed placeholder fields - approval signature placeholders now resolve through the H.3 signature strategy and `crm_job_title` position lookup 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 ## 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 `approvedArtifactId` where 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 `convertedToOpportunityAt` for precise lead-to-opportunity timing - add `closedWonAt` for won-date reporting - add `closedLostAt` for 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 `lostReason` to 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 `defaultPartyRole` only 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 `accepted` as the practical proxy for `closed_won` Future: - add explicit enquiry lifecycle support for `closed_won` - add `closedWonAt` to 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 `Completed` follow-up metrics infer completion from `outcome` presence 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 ### 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