task-d5.5.1

This commit is contained in:
phaichayon
2026-06-25 12:16:41 +07:00
parent f2c7156851
commit c2a74b6764
121 changed files with 3407 additions and 2679 deletions

View File

@@ -0,0 +1,60 @@
# Task D.5.5.1: Force Rename Enquiry Domain Opportunity
## Objective
Rename the sales execution domain from `Enquiry` to `Opportunity` across active application code for the development-only reset phase of D.5.5.1.
## Review Completed
- `AGENTS.md`
- `plans/task-d.5.5.1.md`
- `plans/task-d.5.5.md`
- `docs/adr/0018-lead-enquiry-domain-separation.md`
- `docs/implementation/task-d55-opportunity-sales-workspace-refinement.md`
- `docs/security/crm-authorization-boundaries.md`
- `src/db/schema.ts`
- `src/config/nav-config.ts`
- current CRM route and feature structure
## What Changed
- Renamed active CRM feature module from `src/features/crm/enquiries` to:
- [src/features/crm/opportunities](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/crm/opportunities)
- Renamed API route base from `src/app/api/crm/enquiries` to:
- [src/app/api/crm/opportunities](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/crm/opportunities)
- Renamed dashboard route base from `src/app/dashboard/crm/enquiries` to:
- [src/app/dashboard/crm/opportunities](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/dashboard/crm/opportunities)
- Renamed opportunity-facing component files, including:
- `opportunity-detail.tsx`
- `opportunities-table.tsx`
- `opportunity-form-sheet.tsx`
- `opportunity-followups-tab.tsx`
- `opportunity-assignment-dialog.tsx`
- `opportunity-outcome-card.tsx`
- `opportunity-status-badge.tsx`
- Renamed schema file:
- `opportunity.schema.ts`
- Replaced active application imports, symbols, route strings, and permission identifiers in `src/` from `enquiry` terminology to `opportunity` terminology.
- Updated active CRM permission namespace usage in code from `crmEnquiry*` to `crmOpportunity*`.
- Updated active sales route URLs from `/dashboard/crm/enquiries` to `/dashboard/crm/opportunities`.
- Updated active API URLs from `/api/crm/enquiries` to `/api/crm/opportunities`.
- Renamed active report routes from `/dashboard/crm/reports/enquiry-aging` and `/api/crm/reports/enquiry-aging` to `/dashboard/crm/reports/opportunity-aging` and `/api/crm/reports/opportunity-aging`.
- Updated active governance references in project foundations, UI/UX rules, and CRM access inventory to point at the `opportunity` domain.
- Fixed the corrupted Thai branch label in `src/db/seeds/foundation.seed.ts` and normalized touched config/seed files to UTF-8.
## Key Rename Direction
- `Enquiry` -> `Opportunity`
- `enquiry` -> `opportunity`
- `crm_enquiries` -> `crm_opportunities`
- `crm_enquiry` -> `crm_opportunity`
- `crm.enquiry.*` -> `crm.opportunity.*`
## Development Reset Implication
This task is implemented under the development-only breaking-change assumption from the task contract:
- database reset is expected
- migration history compatibility is not preserved
- seed/config/document-sequence data must be regenerated around the new opportunity domain
## Verification
- `npm exec tsc --noEmit`
## Known Follow-up Areas
- Historical docs under `docs/**` still contain legacy enquiry references where they describe earlier phases or legacy architecture.
- Database reset, migration regeneration, and seed verification still need to be executed explicitly in the development environment before treating the rename as operationally complete.

View File

@@ -13,7 +13,7 @@
| --- | --- | --- | --- |
| Customers | `/api/crm/customers` | `Protected` | List/detail/update/delete now pass resolved CRM scope context and customer visibility is filtered by ownership plus related enquiry/quotation signals |
| Contacts | `/api/crm/customers/[id]/contacts` | `Protected` | Contact APIs now inherit customer visibility and creator/admin/team visibility rules from resolved CRM access |
| Leads / Enquiries | `/api/crm/enquiries` and child routes | `Partially Protected` | Uses branch/product/own-scope logic already, but still passes legacy `businessRole` fields through route/service seams |
| Leads / Opportunities | `/api/crm/opportunities` and child routes | `Partially Protected` | Uses branch/product/own-scope logic already, but still passes legacy `businessRole` fields through route/service seams |
| Quotations | `/api/crm/quotations` and `[id]` | `Protected` | List/detail/create/update/delete now pass resolved CRM scope context and enforce branch/product/own visibility |
| Quotation pricing surfaces | document data, preview, PDF preview/download, approved PDF | `Protected` | Pricing-bearing outputs now require pricing visibility and emit `crm_security_access` audit events when denied |
| Document artifacts | `/api/crm/document-artifacts/[id]/download` | `Protected` | Approved quotation artifacts now require artifact permission plus pricing visibility guard |

View File

@@ -113,7 +113,7 @@ If ADR coverage is incomplete, this registry marks the gap explicitly.
| Related ADRs | ADR-0006. Governance gap: no dedicated ADR yet for numbering policy or reset policy. |
| Reusable services | `listDocumentSequences()`, `getDocumentSequence()`, `createDocumentSequence()`, `updateDocumentSequence()`, `resetDocumentSequence()`, `previewDocumentSequenceById()`, `previewNextDocumentCode()`, `generateNextDocumentCode()` |
| Reusable APIs | `/api/crm/settings/document-sequences`, `/api/crm/settings/document-sequences/[id]`, `/api/crm/settings/document-sequences/[id]/preview`, `/api/crm/settings/document-sequences/[id]/reset` |
| Reuse status | Reusable and active. Current production source for customer, contact, enquiry, quotation, and approval codes. |
| Reuse status | Reusable and active. Current production source for customer, contact, opportunity, quotation, and approval codes. |
### Document Template Foundation
@@ -247,31 +247,31 @@ If ADR coverage is incomplete, this registry marks the gap explicitly.
| Reusable services | None production-ready yet. D.5.1 only stabilizes schema and seed foundations before D.5.2 API work. |
| Reusable APIs | None yet. Lead API surface is explicitly deferred to Task D.5.2. |
| Reuse status | Foundation introduced and partially stabilized. Schema and seed contracts exist, but feature services, APIs, UI, migration flows, and separated datasets are not complete yet. |
| Governance note | This foundation supersedes the long-term direction of the old single-record lead/enquiry model in ADR-0011, but current production behavior still largely runs on the shared `crm_enquiries` implementation until later D.5 phases are completed. |
| Governance note | This foundation supersedes the old shared lead/enquiry model in ADR-0011. After Task D.5.5.1, active sales execution behavior runs on the renamed `crm_opportunities` implementation while older ADRs and implementation notes remain historical references. |
### Lead / Enquiry Foundation
### Lead / Opportunity Foundation
| Field | Details |
| --- | --- |
| Purpose | Single-record `crm_enquiries` lifecycle with marketing-owned leads, sales-owned enquiries, assignment governance, related project parties, and follow-up child resources |
| Location | `src/features/crm/enquiries/**`, `src/app/api/crm/enquiries/**`, `docs/adr/0011-lead-enquiry-ownership-model.md` |
| Purpose | Shared opportunity lifecycle with linked lead provenance, assignment governance, related project parties, and follow-up child resources |
| Location | `src/features/crm/opportunities/**`, `src/app/api/crm/opportunities/**`, `docs/adr/0011-lead-enquiry-ownership-model.md`, `docs/implementation/task-d551-force-rename-enquiry-domain-opportunity.md` |
| Related tasks | Task D, Task D.1, Task D.3, Task D.3.1 |
| Related ADRs | ADR-0011, ADR-0014 |
| Reusable services | `getEnquiryReferenceData()`, `listEnquiries()`, `getEnquiryDetail()`, `createEnquiry()`, `updateEnquiry()`, `softDeleteEnquiry()`, `assignEnquiryToUser()`, `reassignEnquiryToUser()`, `listEnquiryProjectParties()` |
| Reusable APIs | `/api/crm/enquiries`, `/api/crm/enquiries/[id]`, `/api/crm/enquiries/[id]/assign`, `/api/crm/enquiries/[id]/reassign`, `/api/crm/enquiries/[id]/customers` |
| Reuse status | Reusable and active. This is the source of truth for lead versus enquiry separation. |
| Governance note | ADR-0018 introduces the target split-domain direction, but this shared enquiry foundation still describes the active production service layer until D.5 migration phases complete. |
| Reusable services | `getOpportunityReferenceData()`, `listOpportunities()`, `getOpportunityDetail()`, `createOpportunity()`, `updateOpportunity()`, `softDeleteOpportunity()`, `assignOpportunityToUser()`, `reassignOpportunityToUser()`, `listOpportunityProjectParties()` |
| Reusable APIs | `/api/crm/opportunities`, `/api/crm/opportunities/[id]`, `/api/crm/opportunities/[id]/assign`, `/api/crm/opportunities/[id]/reassign`, `/api/crm/opportunities/[id]/customers` |
| Reuse status | Reusable and active. This is the source of truth for the sales opportunity domain. |
| Governance note | Historical ADR/task lineage may still say `enquiry`, but active application code, APIs, and schema were force-renamed to `opportunity` in Task D.5.5.1. |
### Won / Lost Governance Foundation
| Field | Details |
| --- | --- |
| Purpose | Freeze business outcome lifecycle on `crm_enquiries`, including PO capture, lost reason governance, and reopen rules |
| Location | `src/features/crm/enquiries/**`, `src/app/api/crm/enquiries/[id]/mark-won/route.ts`, `src/app/api/crm/enquiries/[id]/mark-lost/route.ts`, `src/app/api/crm/enquiries/[id]/reopen/route.ts` |
| Purpose | Freeze business outcome lifecycle on `crm_opportunities`, including PO capture, lost reason governance, and reopen rules |
| Location | `src/features/crm/opportunities/**`, `src/app/api/crm/opportunities/[id]/mark-won/route.ts`, `src/app/api/crm/opportunities/[id]/mark-lost/route.ts`, `src/app/api/crm/opportunities/[id]/reopen/route.ts` |
| Related tasks | Task D.4, Task J, Task K |
| Related ADRs | ADR-0016 |
| Reusable services | `markEnquiryAsWon()`, `markEnquiryAsLost()`, `reopenLostEnquiry()`, PO attachment helpers under enquiry service |
| Reusable APIs | `/api/crm/enquiries/[id]/mark-won`, `/api/crm/enquiries/[id]/mark-lost`, `/api/crm/enquiries/[id]/reopen`, `/api/crm/enquiries/[id]/po-attachments` |
| Reusable services | `markOpportunityAsWon()`, `markOpportunityAsLost()`, `reopenLostOpportunity()`, PO attachment helpers under opportunity service |
| Reusable APIs | `/api/crm/opportunities/[id]/mark-won`, `/api/crm/opportunities/[id]/mark-lost`, `/api/crm/opportunities/[id]/reopen`, `/api/crm/opportunities/[id]/po-attachments` |
| Reuse status | Reusable and active. Mandatory for outcome transitions and outcome-driven KPI/report work. |
### Quotation Foundation
@@ -328,14 +328,14 @@ If ADR coverage is incomplete, this registry marks the gap explicitly.
| Field | Details |
| --- | --- |
| Purpose | Shared follow-up tracking across enquiries and quotations, including list/detail child resources, dashboard analytics, and report visibility |
| Location | `src/features/crm/enquiries/**`, `src/features/crm/quotations/**`, `src/features/crm/dashboard/**`, `src/features/crm/reports/server/datasets/pipeline-report.dataset.ts` |
| Purpose | Shared follow-up tracking across opportunities and quotations, including list/detail child resources, dashboard analytics, and report visibility |
| Location | `src/features/crm/opportunities/**`, `src/features/crm/quotations/**`, `src/features/crm/dashboard/**`, `src/features/crm/reports/server/datasets/pipeline-report.dataset.ts` |
| Related tasks | Task D, Task E, Task J, Task K |
| Related ADRs | ADR-0011, ADR-0016, ADR-0017 |
| Reusable services | `listEnquiryFollowups()`, `createEnquiryFollowup()`, `updateEnquiryFollowup()`, `softDeleteEnquiryFollowup()`, quotation follow-up mutation and query flows under `src/features/crm/quotations/server/service.ts`, dashboard follow-up analytics in `getCrmDashboardData()` |
| Reusable APIs | `/api/crm/enquiries/[id]/followups`, `/api/crm/enquiries/[id]/followups/[followupId]`, `/api/crm/quotations/[id]/followups` |
| Reusable services | `listOpportunityFollowups()`, `createOpportunityFollowup()`, `updateOpportunityFollowup()`, `softDeleteOpportunityFollowup()`, quotation follow-up mutation and query flows under `src/features/crm/quotations/server/service.ts`, dashboard follow-up analytics in `getCrmDashboardData()` |
| Reusable APIs | `/api/crm/opportunities/[id]/followups`, `/api/crm/opportunities/[id]/followups/[followupId]`, `/api/crm/quotations/[id]/followups` |
| Reuse status | Active but fragmented. |
| Governance gap | There is no single shared standalone follow-up server foundation yet. Reuse existing enquiry and quotation follow-up services rather than building a third implementation. |
| Governance gap | There is no single shared standalone follow-up server foundation yet. Reuse existing opportunity and quotation follow-up services rather than building a third implementation. |
### Reporting Foundation
@@ -345,8 +345,8 @@ If ADR coverage is incomplete, this registry marks the gap explicitly.
| Location | `src/features/crm/reports/**`, `src/app/api/crm/reports/**`, `docs/adr/0017-report-foundation.md` |
| Related tasks | Task K.1, Task K.2 |
| Related ADRs | ADR-0010, ADR-0011, ADR-0016, ADR-0017 |
| Reusable services | `buildResolvedReportContext()`, `getCrmReportsResponse()`, `getCrmReportCatalogResponse()`, `getCrmReportFiltersResponse()`, `getCrmPipelineReportResponse()`, `getCrmLeadAgingReportResponse()`, `getCrmEnquiryAgingReportResponse()`, `buildSharedReportFilters()`, export helpers in `server/exports/service.ts` |
| Reusable APIs | `/api/crm/reports`, `/api/crm/reports/catalog`, `/api/crm/reports/filters`, `/api/crm/reports/pipeline`, `/api/crm/reports/lead-aging`, `/api/crm/reports/enquiry-aging`, `/api/crm/reports/export` |
| Reusable services | `buildResolvedReportContext()`, `getCrmReportsResponse()`, `getCrmReportCatalogResponse()`, `getCrmReportFiltersResponse()`, `getCrmPipelineReportResponse()`, `getCrmLeadAgingReportResponse()`, `getCrmOpportunityAgingReportResponse()`, `buildSharedReportFilters()`, export helpers in `server/exports/service.ts` |
| Reusable APIs | `/api/crm/reports`, `/api/crm/reports/catalog`, `/api/crm/reports/filters`, `/api/crm/reports/pipeline`, `/api/crm/reports/lead-aging`, `/api/crm/reports/opportunity-aging`, `/api/crm/reports/export` |
| Reuse status | Reusable and active. Mandatory for new CRM reports and exports. |
## Governance Gaps And Duplication Risks

View File

@@ -44,7 +44,7 @@ Reference docs and files:
- `docs/forms.md`
- `src/features/crm/customers/components/customer-form-sheet.tsx`
- `src/features/crm/enquiries/components/enquiry-form-sheet.tsx`
- `src/features/crm/opportunities/components/opportunity-form-sheet.tsx`
- `src/features/crm/quotations/components/quotation-form-sheet.tsx`
## Table Standards
@@ -59,7 +59,7 @@ Reference files:
- `src/components/ui/table/data-table.tsx`
- `src/features/users/components/users-table/index.tsx`
- `src/features/crm/customers/components/customers-table.tsx`
- `src/features/crm/enquiries/components/enquiries-table.tsx`
- `src/features/crm/opportunities/components/opportunities-table.tsx`
## Filter Standards