From c7f2b43b4ab903f2c42beea6c583d205cb294e31 Mon Sep 17 00:00:00 2001 From: Rogee Date: Fri, 5 Jun 2026 02:56:21 +0800 Subject: [PATCH] docs: land chatwoot parity tracking plan --- docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md | 50 +++++++++++++++++------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md b/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md index 326a56d0..1f4fa6db 100644 --- a/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md +++ b/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md @@ -16,12 +16,12 @@ Build GoChat as a Go backend that can directly reuse the frontend from `referenc ## Current Baseline -- Latest implementation checkpoint: `3481597 feat(crm): align contact company payloads`. +- Latest implementation checkpoint: `7a033e2 feat(crm): complete contact label avatar gaps`. - Worktree status at this planning checkpoint: clean. - `go test ./...` passes. -- Route dump succeeds with `TOTAL: 809` after contacts/companies Chatwoot-compatible PATCH/search/contact-assignment routes were added. +- Route dump succeeds with `TOTAL: 817` after contacts/companies labels, avatar, custom-attribute, and trailing-slash nested route aliases were added. - Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`. -- Tracked frontend-critical route audit covers 251 Chatwoot routes: 251 exact, 0 method-compatible, 0 parameter-compatible, 0 missing. +- Tracked frontend-critical route audit covers 261 Chatwoot routes: 261 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. - Handler test stability fixes are committed into the baseline before feature parity work continues. - `.codegraph/` is generated indexing output and is not part of tracked product code. @@ -74,19 +74,20 @@ This ledger records the committed parity checkpoints that future slices should b | `9f89cbf feat(conversations): align chatwoot message serializers` | Added Chatwoot conversation/message serializer boundary for dashboard list/show/filter, message index, message create/update/retry, status toggle payloads, display-id route resolution, outgoing/private message defaults, `echo_id`, `content_attributes`, and conversation/message parity migration fields. | Focused conversation/message handler tests passed; full `go test ./...` passed; `git diff --check` passed. | Continue B3 with delete/update status parity, multipart attachment create, team assignment response parity, and deeper message finder before moving to contacts/companies. | | `a465bbe feat(conversations): finish message mutation parity` | Finished the B3 mutation gap set: message delete now returns the Chatwoot deleted-message serializer and clears attachments; message status update supports `status`/`external_error` with API-inbox-only enforcement; `MessageFinder` now supports latest, `before`, `after`, and between windows; multipart `attachments[]` create attachment rows and serialize them in message payloads; team assignment returns the raw team payload. | Focused handler/service/repository tests passed; full `go test ./...` passed; `git diff --check` passed. | B3 core dashboard message flows move to review; continue with B4 contacts/companies while tracking deeper delivery/storage side effects. | | `3481597 feat(crm): align contact company payloads` | Started B4 contacts/companies parity: added Chatwoot-shaped `{ meta, payload }` and `{ payload }` CRM serializers, strict empty-query `422` handling, contact create `{ contact, contact_inbox }` envelope, selected custom-attribute deletion, companies nested `company` params, company contacts on `contacts.company_id`, relation search/add routes, and Rails-compatible PATCH routes. | Focused contacts/companies tests passed; handler/service/repository tests passed; route dump regenerated with `TOTAL: 809`; route parity remained `251 exact, 0 missing`; sandboxed full `go test ./...` failed on socket restrictions, escalated full `go test ./...` passed; `git diff --check` passed. | Continue B4 with merge/import/export/labels/avatar/company destroy-custom-attributes, contact/company notes payload depth, Meilisearch-backed CRM search, and frontend smoke fixtures. | +| `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. | ## Next Slice Contract -Completed implementation slice: B4 first checkpoint now returns Chatwoot dashboard-compatible contact/company CRUD, search, custom-attribute, and company-contact relation payloads for the core CRM flows. +Completed implementation slice: B4 second checkpoint now covers contact/company CRUD payloads, company-contact relations, contact labels, label filtering, avatar deletion, selected custom-attribute deletion, and company destroy-custom-attributes for the dashboard CRM flows. -Next implementation slice: continue B4 contacts/companies behavior fixtures, while keeping B3 in review for delivery/storage side-effect parity. +Next implementation slice: continue B4 with contact merge, import/export/data-import job behavior, contact/company note serializer depth, and Meilisearch-backed CRM search. Keep B3 in review for delivery/storage side-effect parity. | Step | Required result | Reference source | Verification | | --- | --- | --- | --- | -| N1 | Finish contact/company relation behavior gaps: merge, labels, import/export, avatar, company destroy-custom-attributes, and 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: merge, import/export/data-import, and 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. | | 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: 809` and tracked route zero-missing status remains. | `cmd/dump_routes`, `cmd/route_parity`. | Route commands run when applicable. | +| N4 | Regenerate route artifacts after route changes; current route dump is `TOTAL: 817` and tracked route parity is `261 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: @@ -122,8 +123,25 @@ Current B4 contacts/companies checkpoint: - Empty contact/company search queries now return `422` with `Specify search string with parameter q`, matching Chatwoot controllers. - Company list/search/show/create/update now return enterprise Chatwoot `payload` and `meta.total_count/page` shapes; create/update accept nested `{ company: ... }` params while retaining flat compatibility inside the service boundary. - Company contact relations now use `contacts.company_id` instead of the older local many-to-many join table, matching Chatwoot enterprise company membership semantics. -- Added Chatwoot-compatible `PATCH /contacts/:contact_id`, `PATCH /companies/:company_id`, `GET /companies/:company_id/contacts/search`, and `POST /companies/:company_id/contacts` body-based contact assignment routes; route dump is now `TOTAL: 809` and tracked route parity remains zero-missing. -- Remaining B4 gaps: contact merge/import/export/labels/avatar coverage, company avatar and destroy-custom-attributes behavior, note serializers, CRM Meilisearch search shape, and frontend smoke validation. +- Added Chatwoot-compatible `PATCH /contacts/:contact_id`, `PATCH /companies/:company_id`, `GET /companies/:company_id/contacts/search`, and `POST /companies/:company_id/contacts` body-based contact assignment routes. +- Added `contact_labels` persistence and Chatwoot-compatible `GET/POST /contacts/:contact_id/labels` responses as `{ payload: [...] }`; contact list/search/filter label params now filter contact label lists instead of conversation labels. +- Added `DELETE /contacts/:contact_id/avatar`, `DELETE /companies/:company_id/avatar`, and `POST /companies/:company_id/destroy_custom_attributes` with Chatwoot-shaped `{ payload }` responses and `422 { error: "custom_attributes must be an array" }` validation. +- Added trailing-slash aliases for Chatwoot nested label/contact-inbox collection routes; route dump is now `TOTAL: 817` and tracked route parity is `261 exact, 0 missing`. +- Remaining B4 gaps: contact merge, import/export/data-import job behavior, contact/company notes payload depth, CRM Meilisearch search shape, and frontend smoke validation. + +Active B4 task board: + +| ID | Task | Reference source | Status | Exit gate | +| --- | --- | --- | --- | --- | +| B4.1 | Contact/company CRUD/search serializers and empty-search errors. | Contacts and enterprise companies controllers/views. | Done | `3481597`; CRM handler tests. | +| B4.2 | Company-contact relation semantics on `contacts.company_id`. | Enterprise company contacts controller. | Done | `3481597`; relation add/list/search tests. | +| B4.3 | Contact label list/update and label-filtered contact search. | `contacts/labels_controller.rb`, `LabelConcern`, contact frontend API. | Done | `7a033e2`; label update/list/filter tests. | +| 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. | `contacts_controller.rb#merge`, merge service/jobs. | Todo | Merge preserves conversations/contact inboxes/custom attributes and returns Chatwoot payload. | +| B4.6 | Import/export/data-import behavior. | Contacts import/export controllers, data import models/jobs. | Todo | Async request, persisted import/export records, and frontend-visible status/download behavior. | +| 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. | ## Immediate Execution Queue @@ -308,7 +326,7 @@ Current Phase 2 route findings: | Type | Count | Required action | | --- | --- | --- | -| Exact tracked critical routes | 251 | Keep covered while expanding audit scope. | +| Exact tracked critical routes | 261 | Keep covered while expanding audit scope. | | Method-compatible update routes | 0 | First tracked batch now has exact Rails-compatible method coverage. | | Missing tracked critical routes | 0 | Current tracked frontend-critical route set has no route-level gaps. | @@ -328,6 +346,7 @@ Expanded tracked groups now covered by route parity: | Widget API | Chatwoot `/api/v1/widget/*` route surface plus legacy `/widget/*` compatibility. | | Public API | Public inbox contact/conversation/message routes and public CSAT survey route. | | Reports v2 | `/api/v2/accounts/:account_id` summary reports, reports, and live reports. | +| CRM nested routes | Contact active/search/filter/export/import, contactable inboxes, contact labels/contact inboxes, company avatar/custom-attribute/contact search routes. | New route groups tracked in this slice: @@ -381,10 +400,10 @@ Frontend-critical API groups to audit first: | ID | Area | Scope | Status | | --- | --- | --- | --- | -| P3.1 | Auth/session/profile | Login, logout, current user, profile, availability, notification settings. | Todo | +| P3.1 | Auth/session/profile | Login, logout, current user, profile, availability, notification settings. | Done | | P3.2 | Accounts/users/teams | Account settings, users, agents, teams, invitations, roles, permissions. | Todo | | P3.3 | Inboxes/channels | Inbox CRUD, assignable agents, avatars, channel config, business hours, widget config. | Todo | -| P3.4 | Conversations/messages | List filters, status changes, assignment, labels, private notes, attachments, drafts, typing/read events. | Todo | +| P3.4 | Conversations/messages | List filters, status changes, assignment, labels, private notes, attachments, drafts, typing/read events. | Review | | P3.5 | Contacts/companies | CRUD, merge, labels, notes, custom attributes, import/export, conversations relation. | Doing | | P3.6 | Labels/custom attributes/custom filters | Create/update/list behavior and exact response shapes. | Todo | | P3.7 | Notifications/reports/help center/campaigns | Frontend-visible payloads and pagination/error envelopes. | Todo | @@ -395,8 +414,8 @@ Serializer parity work plan: | Order | Endpoint family | Reference sources | Verification artifact | Status | | --- | --- | --- | --- | --- | -| S1 | Auth and profile | `reference/chatwoot/app/controllers/api/v1/profile*`, frontend auth API usage | fixture tests for current user/profile payloads | Todo | -| S2 | Conversations and messages | `reference/chatwoot/app/controllers/api/v1/accounts/conversations*`, serializers/entities | fixture tests for index/show/message create/update | Todo | +| S1 | Auth and profile | `reference/chatwoot/app/controllers/api/v1/profile*`, frontend auth API usage | fixture tests for current user/profile payloads | Done | +| S2 | Conversations and messages | `reference/chatwoot/app/controllers/api/v1/accounts/conversations*`, serializers/entities | fixture tests for index/show/message create/update | Review | | S3 | Contacts and companies | `reference/chatwoot/app/controllers/api/v1/accounts/contacts*`, `companies*` | fixture tests for list/show/search/merge/relation payloads | Doing | | S4 | Inboxes and channels | `reference/chatwoot/app/controllers/api/v1/accounts/inboxes*`, channel controllers | fixture tests for inbox CRUD, channel settings, widget config | Todo | | S5 | Notifications and settings | `reference/chatwoot/app/controllers/api/v1/accounts/notifications*` | fixture tests for notification list/actions/settings | Todo | @@ -535,7 +554,7 @@ Tracking table: | ID | Area | Known references | Required next work | Status | | --- | --- | --- | --- | --- | | P6.1 | Account APIs | `docs/ROUTE_GAP_ANALYSIS.md`, account handlers | Replace placeholder responses with repository-backed behavior and serializer tests. | Todo | -| P6.2 | Contact APIs | `docs/ROUTE_GAP_ANALYSIS.md`, contact handlers/services | Implement show/create/update/list/search relations, labels, notes, merge. | Doing | +| P6.2 | Contact APIs | `docs/ROUTE_GAP_ANALYSIS.md`, contact handlers/services | Finish merge, import/export/data-import, notes serializer depth, and Meilisearch-backed CRM search. | Doing | | P6.3 | Conversation APIs | `docs/ROUTE_GAP_ANALYSIS.md`, conversation handlers/services | Implement frontend-critical filters, assignment, status, snooze, merge, bulk actions. | Todo | | P6.4 | Message APIs | `docs/ROUTE_GAP_ANALYSIS.md`, message handlers/services | Implement create/list/delete, private notes, attachments, source attribution, events. | Todo | | P6.5 | Inbox APIs | `docs/ROUTE_GAP_ANALYSIS.md`, inbox handlers/services | Implement CRUD, assignable agents, avatar, campaigns, channel settings, reset secret. | Todo | @@ -651,3 +670,4 @@ Verification milestone gates: - 2026-06-05: Finalized P6.7 provider classification. Twitter CRC now returns `sha256=` like Chatwoot, Twitter route-level CRC/event tests exist, Instagram rejects unsigned signed-required event payloads without persistence, and Telegram, SMS/Twilio, Instagram, Shopify, and the already completed providers are marked Done in the webhook ingress tracker. Focused webhook/API tests and full `go test ./...` passed. - 2026-06-05: Started B3 dashboard conversation/message serializer parity. Conversation list/filter/show/create/update and message list/create/update/retry now return Chatwoot frontend payload shapes instead of the Go response envelope; message creation accepts frontend composer JSON/multipart fields and preserves `echo_id`/`content_attributes`; account-scoped conversation `display_id` routing is now generated and resolved. Verified focused conversation/message handler tests, full `go test ./...`, and `git diff --check`. - 2026-06-05: B4 contacts/companies first checkpoint committed as `3481597 feat(crm): align contact company payloads`; focused CRM tests, handler/service/repository tests, escalated full `go test ./...`, route dump `TOTAL: 809`, route parity `251 exact, 0 missing`, and `git diff --check` passed. +- 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.