Files
alla-allaos-fullstack/docs/implementation/technical-debt.md
phaichayon a85d24235c task-h.4
2026-06-19 12:30:26 +07:00

12 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

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