diff --git a/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md b/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md index f62990ad..f39286a6 100644 --- a/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md +++ b/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md @@ -16,10 +16,10 @@ Build GoChat as a Go backend that can directly reuse the frontend from `referenc ## Current Baseline -- Latest implementation checkpoint: `8eed2f1 feat(crm): persist contact data imports`. +- Latest implementation checkpoint: `47c2b80 feat(crm): persist contact export artifacts`. - Worktree status at this planning checkpoint: clean. - `go test ./...` passes. -- Route dump succeeds with `TOTAL: 818`; the latest data-import checkpoint did not change routes. +- Route dump succeeds with `TOTAL: 819` after adding the persisted contact export download route. - Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`. - Tracked frontend-critical route audit covers 262 Chatwoot routes: 262 exact, 0 method-compatible, 0 parameter-compatible, 0 missing. - `/api/v1/widget` stubs are burned down and public inbox/contact/conversation/message core flows are backed by real handlers. @@ -77,19 +77,20 @@ This ledger records the committed parity checkpoints that future slices should b | `7a033e2 feat(crm): complete contact label avatar gaps` | Completed the next B4 CRM route/behavior slice: added `contact_labels` persistence, Chatwoot `{ payload: labels }` contact label list/update endpoints, contact list/search label filtering via contact labels, contact/company avatar delete responses, company `destroy_custom_attributes`, and tracked trailing-slash nested route aliases. | Focused CRM tests passed; handler/service/repository/router tests passed; route dump regenerated with `TOTAL: 817`; route parity is `261 exact, 0 missing`; sandboxed full `go test ./...` failed on local socket restrictions, escalated full `go test ./...` passed; `git diff --check` passed. | Continue B4 with contact merge, import/export job/data-import behavior, contact/company notes serializer depth, Meilisearch-backed CRM search, and frontend smoke fixtures. | | `1e3bf47 feat(crm): align contact merge action` | Completed B4 contact merge parity for the reused dashboard action: added the exact `POST /api/v1/accounts/:account_id/actions/contact_merge` route, changed merge responses to the raw Chatwoot contact model serializer, moved conversations/contact inboxes/notes/messages from mergee to base, preserved base attributes while filling blanks from mergee, and covered legacy lowercase contact message senders. | Focused merge/CRM tests passed; handler/service/repository/router tests passed; route dump regenerated with `TOTAL: 818`; route parity is `262 exact, 0 missing`; full `go test ./...` passed; `git diff --check` passed. | Continue B4 with import/export job/data-import behavior, contact/company notes serializer depth, Meilisearch-backed CRM search, and frontend smoke fixtures. | | `8eed2f1 feat(crm): persist contact data imports` | Advanced B4 import/data-import parity: added Chatwoot-shaped `data_imports` fields and migration, changed contacts import missing-file errors to `422`, successful imports to empty `200 OK`, persisted import lifecycle states/counts/errors, and made CSV import merge/update existing contacts by identifier/email/phone with labels/custom attributes. | Focused import tests passed; handler/service/repository/router package tests passed; full `go test ./...` passed; `git diff --check` passed. | Continue B4.6 with contacts export async artifact/download/notification parity, then notes serializer depth, Meilisearch-backed CRM search, and frontend smoke fixtures. | +| `47c2b80 feat(crm): persist contact export artifacts` | Advanced B4 export parity: `POST /contacts/export` now creates a persisted `contact_exports` artifact, stores Chatwoot default/requested CSV columns with UTF-8 BOM, supports label/filter export inputs, exposes a local download URL, and creates a user notification with export metadata. | Focused export tests passed; handler/service/repository/router package tests passed; regenerated route dump `TOTAL: 819`; route parity remains `262 exact, 0 missing`; full `go test ./...` passed; `git diff --check` passed. | Continue B4 with real email delivery for export completion if required by mailer infrastructure, contact/company notes payload depth, Meilisearch-backed CRM search, and frontend smoke fixtures. | ## Next Slice Contract -Completed implementation slice: B4 contact merge and contact import checkpoints now cover contact/company CRUD payloads, company-contact relations, contact labels, label filtering, avatar deletion, selected custom-attribute deletion, company destroy-custom-attributes, dashboard contact merge behavior, and persisted contact import lifecycle behavior for the CRM flows. +Completed implementation slice: B4 contact merge, contact import, and contact export checkpoints now cover contact/company CRUD payloads, company-contact relations, contact labels, label filtering, avatar deletion, selected custom-attribute deletion, company destroy-custom-attributes, dashboard contact merge behavior, persisted contact import lifecycle behavior, and persisted contact export artifacts for the CRM flows. -Next implementation slice: continue B4.6 with contacts export async artifact/download/notification behavior, then contact/company note serializer depth and Meilisearch-backed CRM search. Keep B3 in review for delivery/storage side-effect parity. +Next implementation slice: continue B4 with contact/company note serializer depth and Meilisearch-backed CRM search. Keep B3 in review for delivery/storage side-effect parity, and keep real SMTP/email delivery for export completion tied to the broader mailer infrastructure work. | Step | Required result | Reference source | Verification | | --- | --- | --- | --- | -| N1 | Finish remaining contact/company behavior gaps: contacts export async artifacts plus notes/conversations depth. | Chatwoot contacts and enterprise companies controllers/Jbuilder views/frontend API clients. | Handler/service tests assert status codes, persistence, and exact `{ payload }` or `{ meta, payload }` shape. | +| N1 | Finish remaining contact/company behavior gaps: notes/conversations depth and any export email-delivery side effects not covered by the persisted notification. | Chatwoot contacts and enterprise companies controllers/Jbuilder views/frontend API clients. | Handler/service tests assert status codes, persistence, and exact `{ payload }` or `{ meta, payload }` shape. | | N2 | Move CRM search behavior to Meilisearch-backed document shape instead of DB/LIKE as the final path. | Chatwoot search usage and local Meilisearch decision. | Search tests run against mocked Meilisearch engine and preserve CRM payload contracts. | | N3 | Preserve completed auth/profile/conversation/message fixtures while expanding the CRM suite. | Existing focused tests and Chatwoot frontend clients. | Existing auth/profile/conversation/message focused tests remain green. | -| N4 | Regenerate route artifacts after route changes; current route dump is `TOTAL: 818` and tracked route parity is `262 exact, 0 missing`. | `cmd/dump_routes`, `cmd/route_parity`. | Route commands run when applicable. | +| N4 | Regenerate route artifacts after route changes; current route dump is `TOTAL: 819` and tracked route parity is `262 exact, 0 missing`. | `cmd/dump_routes`, `cmd/route_parity`. | Route commands run when applicable. | | N5 | Update this tracker after every implementation checkpoint. | This document. | `git diff --check`; `go test ./...` for Go changes. | Current B2 profile checkpoint: @@ -131,8 +132,9 @@ Current B4 contacts/companies checkpoint: - Added trailing-slash aliases for Chatwoot nested label/contact-inbox collection routes. - Added exact `POST /api/v1/accounts/:account_id/actions/contact_merge` and raw contact-model response shape for dashboard merge actions; merge moves conversations, contact inboxes, notes, and contact-sender messages to the base contact while preserving base attributes over mergee attributes. - Added Chatwoot-shaped `data_imports` persistence for contact CSV imports. Missing `import_file` now returns `422 { error: "failed to import contacts" }`, successful imports return empty `200 OK`, import state/count/error fields are recorded, and CSV rows merge/update existing contacts by identifier/email/phone while preserving labels and unknown/custom columns in contact attributes. -- Route dump is now `TOTAL: 818` and tracked route parity is `262 exact, 0 missing`. -- Remaining B4 gaps: contacts export async artifact/download/notification behavior, contact/company notes payload depth, CRM Meilisearch search shape, stricter import label validation against account labels, and frontend smoke validation. +- Added persisted contact export artifacts for `POST /contacts/export`: default/requested column handling, label/filter export inputs, UTF-8 BOM CSV content, local download URL, row counts, and a user notification carrying file metadata. +- Route dump is now `TOTAL: 819` and tracked route parity is `262 exact, 0 missing`. +- Remaining B4 gaps: contact/company notes payload depth, CRM Meilisearch search shape, stricter import label validation against account labels, real SMTP/email delivery for export completion, and frontend smoke validation. Active B4 task board: @@ -144,7 +146,8 @@ Active B4 task board: | B4.4 | Contact/company avatar delete and company destroy-custom-attributes. | Contacts controller `avatar`; enterprise companies controller `avatar` and `destroy_custom_attributes`. | Done | `7a033e2`; avatar/custom-attribute tests. | | B4.5 | Contact merge behavior and response shape. | `actions/contact_merges_controller.rb`, `ContactMergeAction`, contact merge Jbuilder view. | Done | `1e3bf47`; merge route/handler/service tests. | | B4.6a | Contact import/data-import persistence. | Contacts import controller, data import model/job, `DataImport::ContactManager`. | Done | `8eed2f1`; import handler/service tests cover status codes, lifecycle persistence, merge/update matching, labels, and custom attributes. | -| B4.6b | Contacts export async artifact behavior. | Contacts export controller and `Account::ContactsExportJob`. | Todo | Async request, export record/download artifact, notification/email side effects, and frontend-visible completion behavior. | +| B4.6b | Contacts export artifact/download behavior. | Contacts export controller and `Account::ContactsExportJob`. | Done | `47c2b80`; export request persists CSV artifact, download URL, label/filter data, row count, and notification metadata. | +| B4.6c | Contacts export email delivery. | `AdministratorNotifications::AccountNotificationMailer#contact_export_complete`. | Todo | Real mailer delivery is wired once mail infrastructure work reaches P5.4; current checkpoint persists notification metadata only. | | B4.7 | Contact/company notes and conversations payload depth. | Nested notes/conversations controllers and Jbuilder views. | Todo | Payload fixtures match Chatwoot serializers for nested CRM views. | | B4.8 | CRM search through Meilisearch document shape. | Chatwoot frontend search usage and local Meilisearch engine. | Todo | Mocked Meilisearch tests cover contacts/companies and DB fallback is not the final path. | | B4.9 | Reused frontend CRM smoke. | `reference/chatwoot` dashboard contacts/companies screens. | Todo | Contact list/search/show/edit/labels/company relation flows run without frontend adapters. | @@ -679,3 +682,4 @@ Verification milestone gates: - 2026-06-05: B4 contacts/companies second checkpoint committed as `7a033e2 feat(crm): complete contact label avatar gaps`; contact labels now persist through `contact_labels`, label list/update returns Chatwoot `{ payload }`, CRM contact list/search/filter labels use contact labels, contact/company avatar delete and company destroy-custom-attributes match Chatwoot response envelopes, route dump is `TOTAL: 817`, route parity is `261 exact, 0 missing`, escalated full `go test ./...` passed, and `git diff --check` passed. - 2026-06-05: B4 contact merge checkpoint committed as `1e3bf47 feat(crm): align contact merge action`; `/api/v1/accounts/:account_id/actions/contact_merge` now matches Chatwoot route usage, merge returns the raw contact model serializer, moves mergee conversations/contact inboxes/notes/messages to the base contact, preserves base attributes while filling blanks from mergee, route dump is `TOTAL: 818`, route parity is `262 exact, 0 missing`, full `go test ./...` passed, and `git diff --check` passed. - 2026-06-05: B4 contact import/data-import checkpoint committed as `8eed2f1 feat(crm): persist contact data imports`; contact imports now persist Chatwoot-shaped `data_imports`, missing `import_file` returns `422`, successful imports return empty `200 OK`, lifecycle counts/errors are recorded, and CSV rows merge/update existing contacts by identifier/email/phone while applying labels and custom attributes. Focused import tests, handler/service/repository/router package tests, full `go test ./...`, and `git diff --check` passed. +- 2026-06-05: B4 contact export artifact checkpoint committed as `47c2b80 feat(crm): persist contact export artifacts`; `POST /contacts/export` now persists `contact_exports`, generates Chatwoot default/requested CSV columns with UTF-8 BOM, supports label/filter export inputs, stores a download URL and row count, and creates a user notification with file metadata. Focused export tests, handler/service/repository/router package tests, regenerated route dump `TOTAL: 819`, route parity `262 exact, 0 missing`, full `go test ./...`, and `git diff --check` passed.