52 KiB
GoChat ↔ Chatwoot/Woochat Frontend Alignment Review And Plan
Date: 2026-06-11
Scope: review implementation differences between GoChat andreference/chatwoot, with Woochat/current Chatwoot frontend direct-connect compatibility as the acceptance target.
Output: gap list, priority order, and executable alignment plan for the refactored GoChat business service.
Status: Live enterprise browser smoke, route parity, Meilisearch search smoke, and full Go regression passed against the reused Chatwoot frontend; notification list/profile-preference browser-store smoke, provider callback/setup fixtures, Captain provider-mode fixtures, widget pubsub-token realtime fixtures, account actions contact-merge fixtures, agent-bot account route fixtures, assignable-agent query fixtures, assignment-policy fixtures, agent-capacity nested route fixtures, agent create fixtures, custom-attribute definition fixtures, audit-log fixtures, automation-rule fixtures, campaign fixtures, canned-response fixtures, bulk-action fixtures, Captain/Copilot API fixtures, core channel provider frontend fixtures, voice/WhatsApp setup fixtures, CRM company/contact/note fixtures, CSAT report fixtures, custom-role/custom-filter fixtures, dashboard-app fixtures,dashboard/api/endPoints.jsauth/profile literal fixtures, help-center dashboard fixtures, inbox conversation/message fixtures, inbox health/member/inbox fixtures, SAML settings fixtures, summary reports fixtures, generic integrations fixtures, Dyte/Linear/Slack literal integration runtime fixtures, labels/macros/notifications/reports/search/SLA literal runtime fixtures, teams/summary-reports/user-notification-settings/webhooks/year-in-review/CSAT public fixtures, widget literal runtime fixtures, account literal fixtures, agent-capacity literal fixtures, agent bulk-create literal triage, article literal triage, automation literal triage, company literal runtime paths, contacts literal runtime paths, conversations literal label/unread-count paths,endPoints.spec.jslegacy constants, CSAT reports literal runtime paths, and inbox conversation literal runtime paths and inbox message literal runtime path and inbox literal runtime paths are now covered.docs/parity/frontend_contract_inventory.mdnow has 0 rows markedMapped; needs fixture/smoke evidence; final release gates were rerun on 2026-06-13 and passed: route parity, full Go regression, and live enterprise Woochat/browser smoke.
Executive Summary
- The reused Woochat frontend contract is represented by
reference/chatwoot/app/javascript/dashboard/api,reference/chatwoot/app/javascript/widget/api,reference/chatwoot/app/javascript/survey/api, and their dependent stores/composables. - Current GoChat has strong route coverage for the tracked frontend-critical surface: refreshed route parity reports
435 exact,0 method-compatible,9 parameter-compatible, and0 missingout of444tracked critical routes. - The direct-connect blockers found in this pass were fresh-schema omissions, Chatwoot token-header/CSRF/CORS assumptions, Redis pool starvation under smoke load, trailing-slash collection-route redirects, Vite browser-smoke shell routing, dashboard boot feature gates, and missing fresh-schema team/campaign tables. These have been aligned for the covered dashboard/widget/public/enterprise API and browser paths.
- No independent
/home/rogee/Projects/*woochat*checkout was found during this review, so this plan treatsreference/chatwootas the current Woochat frontend source of truth. - This document now records the landed alignment work and the current completion evidence. Keep realtime and provider fixtures as drift guards, but the direct-connect release gates have current evidence.
Evidence Refresh
| Evidence | Current Result | Notes |
|---|---|---|
| Route dump | docs/parity/gochat_routes.txt refreshed from go run ./cmd/dump_routes |
Current dump contains 1010 lines including TOTAL: 1009. |
| Route parity | docs/parity/route_parity.md refreshed from go run ./cmd/route_parity |
435 exact, 0 method-compatible, 9 parameter-compatible, 0 missing out of 444 tracked critical routes. |
| Frontend contract scan | reference/chatwoot/app/javascript/dashboard/api, widget/api, survey/api |
Dashboard, widget, public survey, Captain, enterprise, channel, report, and integration clients define the direct-connect API contract. |
| Frontend contract inventory | docs/parity/frontend_contract_inventory.md |
Phase 0 inventory created with 224 frontend API contract entries grouped by owner area. |
| Live enterprise browser smoke | docs/parity/frontend_smoke_report.md; .tmp/frontend-smoke-live/browser-smoke-report.json |
Passed on 2026-06-13T12:24:17Z with 37 checks, 0 failures, reused reference/chatwoot dashboard/widget/enterprise screens against GoChat on port 13000. |
| Full Go regression | git diff --check && GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./... |
Passed on 2026-06-13 after smoke-script stabilization and route parity refresh. |
| Parameter-compatible route tests | internal/handler/api/v1/agent_capacity_handler_test.go and internal/handler/api/v1/article_handler_test.go |
Agent-capacity nested user/inbox-limit methods and help-center .md/.png suffix dispatch are covered by focused handler tests. |
| Auth/profile/account fixtures | internal/handler/api/v1/auth_handler_test.go, internal/handler/api/v1/profile_handler_test.go, internal/handler/api/v1/mfa_handler_test.go, internal/handler/api/v1/account_handler_test.go, internal/repository/account_repo_test.go |
Sign-in, validate-token, profile bootstrap, availability, auto-offline, active-account side effects, MFA raw payloads, and account cache keys now assert Chatwoot-style frontend-visible keys and persisted side effects. |
| Inbox fixtures | internal/handler/api/v1/inbox_handler_parity_test.go, internal/handler/api/v1/inbox_member_handler_test.go, internal/handler/api/v1/agent_capacity_handler_test.go, internal/handler/api/v1/agent_bot_handler_test.go |
Inbox list/detail envelopes, channel settings, admin-only sensitive fields, inbox member payload/diff updates, raw WhatsApp Cloud health payloads, agent create payloads, assignable-agent inbox_ids queries, assignment-policy list/inbox override flows, agent-capacity policy/nested user/inbox-limit success/error flows, agent-bot account CRUD/avatar/reset routes, Facebook/Google/Instagram/Microsoft/TikTok/Twilio/Twitter/Web/WhatsApp-call provider frontend routes, and provider callback/webhook drift guards now have frontend-contract fixtures. |
| Conversation/message fixtures | internal/handler/api/v1/conversation_handler_crud_test.go, internal/handler/api/v1/message_handler_test.go, internal/handler/api/v1/conversation_serializer_test.go |
Conversation list envelope/meta/label/attribute/last-message fields and message create/list/attachment fields now assert the Chatwoot dashboard store contract. |
| CRM/contact/company fixtures | internal/handler/api/v1/crm_frontend_smoke_test.go, contact_handler_crud_test.go, company_handler_test.go |
Contact/company dashboard smoke plus account actions contact merge, contact merge/import/export, contact notes, company nested contacts/conversations/notes, contact timeline attachments, contact/company update realtime events, contact delete realtime events, and merge update/delete realtime events now assert frontend-visible response and mutation contracts. |
| Voice/WhatsApp/CSAT/customization fixtures | internal/router/router_test.go, internal/service/whatsapp_authorization_service_test.go, internal/handler/api/v1/csat_survey_handler_test.go, custom_role_handler_test.go, custom_filter_handler_test.go, dashboard_app_handler_test.go |
Woochat voice conference callbacks/contact call initiation, WhatsApp embedded signup/reauthorization, CSAT dashboard list/metrics/download, custom roles, custom filters, and dashboard apps now have direct frontend-contract evidence in the inventory and focused command list. |
| Contract fixture coverage | docs/parity/contract_fixture_coverage.md |
P0/P1 owner areas now have a coverage matrix mapping frontend contract source, current GoChat evidence, and remaining evidence needed; auth/profile/account has focused fixture coverage for sign-in/profile/MFA/cache slices, while remaining avatar/accounts/conversations literals stay in the inventory backlog. |
| Regression test | git diff --check and GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./... passed again on 2026-06-13 after the Captain/provider/widget evidence updates and route regeneration. |
Covers the expanded direct-connect fixture suite, route boot, webhook receipt updates, service jobs, widget/API handlers, middleware, repository, router, and websocket packages. |
| Placeholder audit | docs/parity/placeholder_audit.md |
No chatwootParityStub remains on reused critical dashboard/widget/public paths; provider nil-fallbacks return explicit 503. |
| Frontend smoke harness | docs/parity/frontend_smoke_report.md, scripts/parity_frontend_smoke.sh, and scripts/parity_frontend_browser_smoke.mjs |
Fresh PostgreSQL/Redis/Meilisearch migration, seed, API smoke, enterprise API smoke, and live scripts/parity_frontend_smoke.sh --enterprise-browser-smoke passed on 2026-06-13 against GoChat on 127.0.0.1:13000 and reused Chatwoot Vite on localhost:3036; browser report is .tmp/frontend-smoke-live/browser-smoke-report.json with 37 checks and 0 API failures, including notification/profile preference store requests. |
Landed Alignment Work In This Pass
- Added fresh-schema migrations for dashboard apps, extended contacts/conversations/accounts/channel fields, companies, SLA, installation configs, CSAT responses, bot rules, automation rules, macros, macro executions, and audits so a clean PostgreSQL database can migrate and seed without hidden legacy state.
- Made smoke seed idempotent for the admin user and kept seed output parseable for the smoke harness even when bootstrap logs are emitted.
- Aligned Chatwoot direct-auth behavior by allowing DeviseTokenAuth-style
access-tokenheaders inAuthMiddlewareand skipping CSRF for token-auth API/public/widget paths that the reused frontend calls. - Increased Redis pool configurability/default capacity to avoid login/token storage failures under worker plus smoke concurrency.
- Registered both no-slash and trailing-slash collection routes for frontend-critical dashboard and enterprise paths to prevent Gin 301 HTML redirects from breaking JSON clients.
- Exposed and allowed DeviseTokenAuth headers through CORS so the browser can read
access-token,client,uid,token-type, andexpiry, persistcw_d_session_info, and validate dashboard sessions without frontend changes. - Hardened browser smoke to serve Chatwoot/Vite shell pages from a same-origin test server, proxy Vite assets, use CDP-captured requests for navigation assertions, send Chatwoot auth headers for browser-context Copilot requests, and fail on frontend-visible API 4xx/5xx responses.
- Added fresh-schema
teams,team_members, andcampaignsmigrations and made the dashboard portal list readable without a knowledge-base feature flag so boot-time unconditional frontend requests do not fail. - Extended smoke coverage through dashboard auth/profile/inbox/conversation/message/contact/company, widget config/message, public CSAT, SLA, CSAT reports/download, automation, macros, audit logs, custom roles, agent capacity, Captain, and Copilot.
- Added auth/profile/account contract fixtures for DeviseTokenAuth sign-in and validate-token payloads, profile bootstrap user/account keys, availability and auto-offline mutations,
set_active_accountmembershipactive_atpersistence, MFA raw payloads, and account cache keys. - Added inbox/provider contract fixtures for Chatwoot-style list/detail envelopes, channel settings, admin-sensitive fields, inbox member payload/diff updates, raw WhatsApp Cloud health responses, provider delivery/read/failure callbacks, and duplicate status-callback idempotency.
- Added conversation/message contract fixtures for Chatwoot-style conversation list envelopes, meta sender fields, labels, additional/custom attributes, last-message payloads, outgoing message create defaults, sender payloads, content attributes, attachments, and display conversation IDs.
- Fixed profile serialization to always expose
custom_attributesas an empty object when unset, matching the reused frontend's object-access assumptions, and made account-useractive_atupdates database-portable instead of relying on PostgreSQL-onlyNOW().
Alignment Target
Woochat/current Chatwoot frontend must be able to point at GoChat by changing only backend host/runtime configuration, without patching frontend API clients or store logic.
That requires parity across five layers:
- Route shape: every frontend-called path/method exists with Chatwoot-compatible path, query, multipart, and auth handling.
- Wire contract: JSON envelopes, pagination metadata, object keys, enum values, null/empty behavior, error status, and validation messages match frontend expectations.
- State transitions: mutations update all dependent models and counters that frontend stores read after success or realtime replay.
- Realtime contract: websocket/SSE/Redis event names and payloads match Chatwoot event consumers for conversation, message, notification, presence, typing, cache, inbox, and contact updates.
- Operational side effects: async jobs, search indexing, delivery status, webhook dispatch, CSAT, reports, and provider integrations are durable enough that the frontend does not observe stale or fake success states.
Current Functional Difference Map
| Priority | Area | Current GoChat State | Chatwoot/Woochat Expectation | Required Alignment |
|---|---|---|---|---|
| P0 | Full reused frontend smoke | API, browser, enterprise API, and enterprise browser smoke now pass for the covered route-request paths. | Dashboard, widget, public CSAT/help-center, and enterprise screens run unchanged against GoChat. | Keep the smoke gate in CI/release and convert any future failures into named implementation slices. |
| P0 | Auth/session bootstrap | DeviseTokenAuth-style access-token API auth, CSRF skip paths, browser CORS header exposure, sign-in/validate-token/profile user-account fixtures, availability, auto-offline, active-account persistence, MFA raw payloads, and cache keys are now aligned for direct API and browser calls. |
Login, validate-token, profile, account cache bootstrap, MFA-visible fields, active account, and token refresh behave like Chatwoot without frontend client changes. | Keep auth/profile/account fixtures as drift guards while moving to inbox and conversation fixture slices. |
| P0 | Serializer/envelope drift | Auth/profile/account, inbox list/detail/member/health, and core conversation/message fixtures now guard key frontend-visible payloads, but CRM, widget/public, reports, enterprise, and deeper mutation rows still need frozen fixtures. | Frontend stores consume exact Chatwoot object shapes, pagination, meta, and error envelopes. | Freeze representative fixture responses from Chatwoot and compare GoChat for contacts, reports, widget, public, enterprise screens, and remaining conversation mutations. |
| P0 | Route parameter compatibility | No tracked route is missing, but 9 are parameter-compatible rather than exact. | Frontend-visible literal paths must work; server-side parameter names are not visible, but suffix dispatchers must preserve .md/.png behavior. |
Agent-capacity nested users/inbox-limits and help-center article .md/.png routes now have focused proof; keep future parameter-compatible routes covered by external-path tests. |
| P0 | Realtime payload fidelity | Event constants, publisher, WS/SSE delivery, message/conversation mutation fixtures, typing/presence heartbeat and expiry fixtures, notification/cache fixtures, widget pubsub_token room message delivery fixtures, browser subscription create/destroy, user notification preference update fixtures, and live browser requests for the notification list/profile notification-preference screens exist for Chatwoot-style frontend behavior. |
Frontend stores expect message.created, conversation.updated, notification.created, typing/presence/cache events with Chatwoot payload fields; PushHelper and notification-preference screens expect raw Chatwoot payloads and account-scoped routes; widget ActionCable expects message.created on the contact pubsub_token room. |
Keep notification/preference and widget browser smoke as drift guards. |
| P0 | Fresh database bootstrap | Fresh-schema migrations and smoke seed were extended for dashboard apps, CRM, teams, campaigns, SLA, CSAT, automation, macros, audits, Captain, and account/inbox fields. | A new deployment can migrate, seed, sign in, and load Woochat frontend screens without relying on hidden legacy rows or manual SQL backfills. | Keep migration smoke as a release gate and add rollback/idempotency checks for the new Chatwoot-compatible schema slices. |
| P1 | Conversation/message behavior | Core services, serializers, labels, participants, drafts, attachments, status/assignment paths exist. | Finder filters, display IDs, unread counts, assignee/team/status transitions, private notes, reply-to, delete/retry/update, attachment payloads, and mentions match Chatwoot. | Add contract tests around conversation list/detail/search/message create-update-delete and verify frontend store refresh/realtime paths. |
| P1 | Inbox/channel/assignment setup | Inbox, member, assignable-agent, assignment-policy, agent-capacity, channel settings, health raw payload, provider-failure envelope, and assignment-policy inbox override routes are represented. | Inboxes and channels expose Chatwoot-compatible settings, members, availability, provider health/failure, assignment-policy override, and capacity payloads. | Add signed provider setup/callback fixtures beyond WhatsApp health and keep role-sensitive channel settings as drift guards. |
| P1 | CRM/contact/company | Contact/company handlers, custom attributes, notes, labels, search, and frozen dashboard payload-shape fixtures are represented for common contact/company flows; contact merge/import/export contracts, attachment timeline depth, contact/company realtime update payloads, and contact delete/merge source-side events now have focused fixture coverage. | Contact list/detail, contact inboxes, merge, import/export, company contacts, notes, custom attributes, labels, realtime updates, and timeline fields match dashboard stores. | Keep CRM fixtures as drift guards; contact update/delete/merge realtime source paths are now covered. |
| P1 | Widget/public inbox APIs | Widget routes, messages, campaigns, direct uploads, contact update, public inbox paths, focused widget config/pre-chat/message/ActiveStorage direct-upload/campaign/public contact/status/read/labels/events/realtime payload fixtures, cw_conversation query/cookie reuse fixtures, and expanded browser-smoke harness coverage for widget boot now exist. |
Widget API accepts Chatwoot query params (website_token, locale, cw_conversation, cw_d_session_info), persisted cw_conversation cookies, multipart attachments, ActiveStorage direct uploads, campaigns, labels/events, update/read semantics, widget message.created pubsub-token realtime delivery, and reused widget entrypoint boot requests. |
Keep live browser smoke and widget realtime fixtures as drift guards. |
| P1 | Search and indexing | Meilisearch-first engine, DB fallback, indexers, search handlers, seed-created help-center article data, live search API-smoke assertions for seeded conversation/message/contact/company/article payloads, valid Meilisearch document UIDs, explicit uid primary-key writes, and company/article mutation hook fresh-object tests exist. |
Search results for conversations, messages, contacts, companies, and articles are account-scoped, fresh after mutations, and shaped for frontend global/search modules. | Keep live Meilisearch smoke, reindex job, and fallback rejection in release mode as release gates. |
| P1 | Help-center/public portal | Portal/category/article/search/sitemap routes exist, including dashboard article CRUD, JSON, markdown, and tracking-pixel compatibility paths; dashboard create/list/show/edit/update/delete payloads, locale redirect/fallback, JSON list/filter, sitemap, .md, and .png fixtures now assert Chatwoot-compatible behavior. |
Public help center and dashboard article management support locale redirects, article/category listing, search, sitemap, .json, .md, .png tracking behavior, and Chatwoot dashboard article CRUD payloads. |
Keep as drift guard; add browser smoke only if Woochat portal UI changes. |
| P1 | Direct uploads and attachments | Account/widget direct upload handlers and attachment serializers exist; ActiveStorage create/complete response fields, storage bytes, signed IDs/upload UUIDs, widget attachment payloads, and unsupported MIME validation now have focused fixtures. | Chatwoot frontend can upload files through ActiveStorage-style direct-upload flow and send attachments in dashboard/widget messages. | Add provider send-payload and REST-vs-push attachment drift guards where channel delivery paths serialize attachments. |
| P1 | Automation/macros/campaigns | Automation rules, macros, macro executions, bot rules, campaigns, and canned responses are represented; automation-rule CRUD/clone/toggle validation and campaign lifecycle/trigger side effects, scheduled trigger job dispatch/realtime events, and bulk-action progress now have focused Chatwoot frontend contract fixtures, with service alignment for campaign display-id start/stop plus frontend audience-array trigger tolerance. | Dashboard automation-rule create/list/update/clone/toggle/delete, campaign create/update/start/stop, macro execute, and canned response CRUD/search flows return Chatwoot-compatible payloads or explicit action envelopes and mutate conversations/messages where applicable, including campaign-triggered conversation/message creation, scheduled campaign trigger job dispatch/completion, campaign trigger conversation/message realtime events, macro empty-200 execute response/validation behavior, and durable bulk-action completion/search-index side effects. | Keep this slice as a drift guard; re-open only if Woochat starts consuming a non-empty macro execute response body. |
| P1 | Notifications/preferences | Notification, notification-subscription, user notification settings, presence, and account cache routes exist; notification CRUD/read-state, PushHelper browser subscription create/destroy, user preference show/update persistence, source-side mutation publication, notification/cache realtime payload fixtures, and live browser route requests for /notifications?page=1 plus /notification_settings are covered. |
Notification lists, read/unread transitions, browser subscription state, user notification preferences, and online status stay in sync with frontend stores. | Keep as drift guard; broaden only if Woochat changes subscription/preference UI behavior or adds new notification-store calls. |
| P1 | Enterprise screens | SLA, audit logs, custom roles, agent capacity, assignment policies, Captain/Copilot, CSAT, limits and account enterprise routes pass API and browser route-request smoke; TestChatwootPermissionSetCreateUpdateListShowParity freezes Chatwoot's six custom-role permission keys; TestEnterpriseAccountLiteralFrontendPathsUseCurrentAccountContext covers literal enterprise account API paths; TestCaptainAssistantHandler_PlaygroundV2ProviderErrorReturnsChatwootFallback freezes Chatwoot's Captain V2 provider-error fallback shape; TestCopilotResponseJobForFollowupMessageUsesStoredThreadHistoryAndIdempotency covers background Copilot follow-up jobs. |
Enterprise frontend screens load and mutate without frontend patches or fake success states, including custom-role permission management, enterprise account limits/billing actions, Captain limit availability clamping, subscription existing-customer no-op behavior, Captain V2 provider-error conversation_handoff fallback, and Copilot follow-up response jobs through stored thread history. |
Keep live provider smoke and fixture drift guards as release gates. |
| P1 | Reports/live reports | API v2 reports and summary report routes exist; TestAPIV2Reports_ChatwootPayloadShapes, TestAPIV2Reports_AllFrontendEndpointShapes, TestAPIV2Reports_TimeseriesTimezoneValueParity, and TestAPIV2Reports_CSVDownloadEntrypointsMatchChatwootFrontend freeze summary, timeseries, timezone-offset day grouping values, CSV download, matrix, bot, distribution, conversation, and outgoing-count endpoint shapes; TestAPIV2LiveReports_ChatwootFrontendPayloadShapes freezes v2 live-report conversation/grouped payloads; TestAPIV2LiveReports_StoreRefreshSequenceMatchesChatwootFrontend covers the three Chatwoot liveReports store refresh actions; TestAPIV2LiveReportsRouterAuthAndAccountScope covers live-report auth/account-scope enforcement; audit list serializer filters, fixed page size, pagination meta, and descending page order have fixture coverage. |
Dashboard reports have focused frontend-direct-connect fixtures for API v2 report shape, value, CSV, live payload, auth, and store-refresh paths. | Keep reports fixtures as drift guards; broaden only if Woochat adds new report API calls. |
| P1 | CSAT/survey | Public CSAT and dashboard CSAT list/metrics/download paths are represented and included in API smoke; TestMetrics_DashboardValueDriftFiltersMatchChatwootFrontend freezes Chatwoot's response-filtered total_count/ratings_count and account/date-only total_sent_messages_count; review-note audit/serializer and public PUT/locked-update fixtures now cover the frontend-visible mutation edges. |
Public survey show/update plus dashboard metrics/download match Chatwoot status codes, validation errors, CSV/export payloads, date filters, dashboard metric filters, sent-count semantics, review-note audit effects, and public PUT/locked non-mutation behavior. | Keep status-transition/job-send fixtures as follow-up drift guards. |
| P2 | Provider integrations | Webhook/channel handlers now have fixtures for WhatsApp delivered/read/failed, Twilio delivered/read/failed plus duplicate status idempotency, Facebook/Instagram delivered/read receipts plus retry idempotency, TikTok read receipts plus retry idempotency, LINE valid/missing/invalid signature handling, Telegram webhook setup success/failure reauthorization flags, setup payloads, OAuth callback fallback/upsert edges, email OAuth token payload errors, and Linear/Shopify/Notion provider-error redirects without phantom hooks. | Frontend-visible channel setup and health states reflect real provider ack/failure/retry behavior. | Run live provider smoke where credentials are available; keep fixtures as drift guards for future provider payload changes. |
| P2 | Background jobs and durability | Worker/dispatch services exist for indexing, delivery, CSAT, import/export, reports, webhooks, Captain, and maintenance. | Chatwoot side effects are asynchronous, retryable, idempotent, and observable when the frontend refreshes or receives events. | Add job idempotency/retry tests and expose frontend-visible failure states instead of silent success. |
| P2 | SSO and identity edge | SSO/SAML/LDAP/OIDC are currently treated as excluded/partially wired in prior tracker text. | Woochat auth screens may still contain MFA/profile/session/token flows even if enterprise SSO is feature-gated. | Document deployment gates for SSO-family features; keep profile, session, MFA, token validation, and active-account behavior fully frontend-compatible. |
Required Alignment Function Points
The remaining alignment work should be tracked as frontend-owner slices, not only as backend packages, because the acceptance target is unchanged Woochat frontend code against GoChat.
| Owner Slice | Must Align For Direct Frontend Connect | Primary Evidence To Add |
|---|---|---|
| Auth/profile/account bootstrap | auth.js, account.js, enterprise/account.js, CacheEnabledApiClient.js, MFA, validate-token, active-account, auto-offline, account cache keys, installation config. |
Browser login smoke plus fixture assertions for /auth/sign_in, /auth/validate_token, /profile, /accounts, /accounts/:id, and enterprise account endpoints. |
| Inbox/channel/assignment | inboxes.js, inboxMembers.js, assignableAgents.js, assignmentPolicies.js, agentCapacityPolicies.js, channel clients, inbox health. |
Fixtures for inbox list/detail/settings/members, provider channel create/update, assignment-policy inbox overrides, assignable-agent availability, capacity users/inbox-limits, and health states. |
| Conversations/messages | conversations.js, inbox/conversation.js, inbox/message.js, conversation/message stores. |
Fixtures for list/detail/search/filter/meta, message create/update/delete/retry, private notes, attachments, labels, participants, drafts, assignment/status/team changes, and matching realtime events; update/delete/retry now include Chatwoot frontend route/body assertions plus message-mutation dispatch evidence for external-error, tombstone cleanup, and retry status reset; message.created/message.updated/conversation.updated/conversation.typing_on realtime wire shapes, Chatwoot presence users/contacts payloads, and conversation status/priority/labels/assignment change-data events are fixture-covered; draft collection and participants now resolve Chatwoot display conversation IDs end-to-end; unread/update-last-seen display-ID routes now cover last-seen rollback and notification read side effects. |
| CRM | contacts.js, companies.js, contactNotes.js, attributes.js, labels/custom attributes. |
Fixtures for contact/company list/detail, merge, notes, contact inboxes, import/export, labels, custom attribute CRUD, contact/company search, attachment timeline, and contact/company realtime updates. |
| Widget/public inbox | widget/api/*, public inbox/contact/conversation/message endpoints, direct uploads, campaigns. |
Browser widget smoke plus fixtures for config/pre-chat frontend mixin shape, cw_conversation cookie/query-session reuse during config boot and message history fetch, message pagination, contact update, labels, events, campaigns, multipart/direct upload, and public conversation status/read flows. |
| Help center/public portal | helpCenter/*, portal/api/article.js, /hc JSON/markdown/tracking/sitemap paths. |
Fixtures for locale fallback, portal/category/article listing, article JSON/markdown, search, sitemap, and tracking pixel side effect/content type. |
| Reports/CSAT/live reports | reports.js, summaryReports.js, liveReports.js, csatReports.js, survey/api/*. |
API v2 report endpoint shape fixtures are covered across reports.js index/summary/conversations/agents/inboxes/labels/teams/conversations_summary/conversation_traffic/bot_metrics/bot_summary, timeseries/CSV/matrix/distribution/outgoing-count, and live-report conversation/grouped paths; v2 timezone-offset day grouping value parity covers frontend timezone_offset semantics; v2 CSV download entrypoints now cover agents/inboxes/labels/teams/conversations_summary response headers and raw CSV bodies; live-report auth/account-scope enforcement now rejects unauthenticated and cross-account access while accepting Chatwoot access-token; live-report store-refresh sequence now covers account/agent/team actions and raw commit-ready payloads; outgoing message count value parity now covers agent/team/inbox/label grouping, invalid group_by, date-range exclusion, incoming-message exclusion, and bot sender exclusion for agent grouping; CSAT dashboard list/metrics/download, metric value-drift filters, review-note audit/serializer behavior, and public show/update/locked PUT edges are fixture-covered; keep status-transition/job-send fixtures as drift guards. |
| Automation/macros/campaigns | automation.js, macros.js, campaigns.js, cannedResponse.js, bulk actions. |
Automation-rule CRUD/clone/toggle validation fixture, campaign nested body/display-id lifecycle, trigger side-effect, scheduled job-dispatch, and realtime event fixtures, macro display-conversation execute side-effect fixture, canned response CRUD/search fixtures, bulk-action enqueue/progress/search-index fixtures, macro empty-200 execute response behavior, and broad bot-rule suites are covered; keep as drift guard unless Woochat changes the macro execute response contract. |
| Notifications/realtime/cache | notifications.js, notificationSubscription.js, user notification settings, websocket consumers, cache invalidation. |
Notification list/read/unread/delete fixtures plus notification.created/notification.updated/notification.deleted payload fixtures using { notification, unread_count, count }; account.cache_invalidated.cache_keys label/inbox/team fixture; PubSub subscriber now forwards updated/deleted/cache topics; read/unread/snooze/delete handlers now publish Chatwoot notification store payloads; browser PushHelper subscription create/destroy and user notification settings show/update persistence are fixture-covered. |
| Enterprise/Captain/Copilot | sla.js, customRole.js, auditLogs.js, captain/*, enterprise account APIs, limits. |
Enterprise browser smoke plus enterprise account literal-path limits/billing actions, Captain limit availability clamping, subscription existing-customer no-op behavior, and billing error no-mutation boundaries, custom-role Chatwoot permission key parity, Captain documents/responses payload and frontend filter fixtures, Captain document response-builder queue/idempotency/FAQ/embedding job fixtures, Captain playground legacy disabled fallback, Captain V2 enabled response and provider-error conversation_handoff fallback, Copilot thread provider-disabled/provider-enabled fixtures, background Copilot follow-up job history/idempotency, and SLA inbox association response/DB side effects are covered; keep as drift guard for new Captain/Copilot provider modes. |
| Provider integrations | channel/*, integrations/*, webhooks.js, provider callback routes. |
Signed provider callback fixtures, setup/health/delivery-state tests, retry/idempotency checks, and stable unsupported responses for unconfigured providers; WhatsApp signed delivery-status callback now persists delivered/read/failed message statuses, delivery status timestamps, status events, frontend-visible external_error for failures, and duplicate same-status callbacks as idempotent no-ops; Twilio delivery-status callbacks now normalize callback phone numbers, persist delivered/read/failed message statuses, delivery status rows, status events, frontend-visible external_error for failures, and suppress duplicate same-status callbacks as idempotent no-ops; TikTok read receipts now persist read message status, delivery status, status event, and duplicate read-receipt retries as idempotent no-ops; contact-level read receipts now also backfill per-contact delivery status rows for messages already at the target read status (TestIncomingPersisterQueuesContactMessagesStatusUpdateWithWorker); Facebook/Instagram delivery/read receipts now persist delivered/read message statuses, delivery status rows, status events from Chatwoot-compatible webhook endpoints, and duplicate receipt retries as idempotent no-ops; Facebook page setup now covers facebook_pages.json provider failure as 422, raw register_facebook_page inbox payload/config, and reauthorize_page config updates; root Instagram/TikTok/Twitter OAuth callbacks now persist serializer-readable inbox channel config before redirecting Woochat to inbox setup; repeated Google/Instagram/TikTok/Twitter callbacks refresh existing channel/inbox config and redirect to settings instead of the new-inbox agent step, while Google/Microsoft token payload errors redirect to the frontend fallback without creating phantom inboxes; Linear/Shopify/Notion token payload errors redirect to stable Chatwoot frontend destinations without creating phantom hooks; TikTok setup now returns stable {channel,inbox} payloads and persists channel config even when provider setup is disabled; Telegram webhook setup success stores webhook_url, and setup failure marks reauthorization_required instead of silently exposing a working channel; LINE/Twilio setup fixtures assert raw inbox payloads plus persisted channel linkage/config; LINE webhooks now cover valid, missing-signature, and invalid-signature behavior without creating phantom messages. |
Parameter-Compatible Route Follow-Up
These are not missing frontend paths, but they require explicit coverage because route parity is currently shape-compatible instead of exact-name-compatible:
| Priority | Route Family | Chatwoot Path Shape | GoChat Match | Alignment Action |
|---|---|---|---|---|
| P0 | Agent capacity users | /api/v1/accounts/:account_id/agent_capacity_policies/:agent_capacity_policy_id/users |
/api/v1/accounts/:account_id/agent_capacity_policies/:id/users |
Covered by TestChatwootPolicyInboxLimitAndUserFlow plus TestChatwootPolicyInboxLimitAndUserValidationErrors: create/list/delete response shape and validation/not-found envelopes use the Chatwoot literal frontend path. |
| P0 | Agent capacity inbox limits | /api/v1/accounts/:account_id/agent_capacity_policies/:agent_capacity_policy_id/inbox_limits/:id |
/api/v1/accounts/:account_id/agent_capacity_policies/:id/inbox_limits/:limit_id |
Covered by TestChatwootPolicyInboxLimitAndUserFlow plus TestChatwootPolicyInboxLimitAndUserValidationErrors: create/duplicate validation/PUT/PATCH/delete, negative-limit validation, and missing-limit not-found envelopes use the Chatwoot literal frontend path. |
| P0 | Help-center markdown | /hc/:slug/articles/:article_slug.md |
suffix-compatible article route | Covered by TestPublicMarkdown_ReturnsOnlyPublishedMarkdown: verifies text/markdown; charset=utf-8, raw body, locale-specific content, and draft 404 behavior. |
| P0 | Help-center tracking pixel | /hc/:slug/articles/:article_slug.png |
suffix-compatible article route | Covered by TestPublicTrackingPixel_IncrementsPublishedArticleViews: verifies image/png, 1x1 PNG body, private 24h cache header, published view increment, and draft non-increment behavior. |
Current evidence: TestChatwootPolicyInboxLimitAndUserFlow now covers agent-capacity inbox-limit POST/duplicate validation/PUT/PATCH/DELETE and user POST/GET/DELETE flows. TestChatwootPolicyInboxLimitAndUserValidationErrors covers negative-limit validation, missing-limit not-found, missing user validation, and missing account-user not-found envelopes on the same Chatwoot literal nested paths. TestInboxAssignmentPolicy_ChatwootRoutes covers assignment-policy inbox override attach/show/list/delete. TestInboxHandler_HealthReturnsWhatsAppCloudRawPayload and TestInboxHandler_HealthReturnsProviderFailureState cover frontend-visible WhatsApp Cloud health success/failure behavior. TestPublicMarkdown_ReturnsOnlyPublishedMarkdown and TestPublicTrackingPixel_IncrementsPublishedArticleViews cover help-center suffix dispatch behavior.
Prioritized Execution Plan
Phase 0 — Freeze Frontend Contract
- Generate an inventory of Woochat frontend API calls from
dashboard/api,widget/api,survey/api, relevant stores, and composables.docs/parity/frontend_contract_inventory.mdnow records the first owner-mapped API-client inventory. - Group each call by owner slice: auth/profile/account, inbox/channel, conversation/message, CRM, automation/macros, help center, widget/public, reports, enterprise, integrations, Captain.
- For each group, record method, path, query/body shape, expected success envelope, expected error envelope, and realtime/cache side effect.
- Deliverable:
docs/parity/frontend_contract_inventory.mdwith owner mapping and smoke coverage status.
Phase 1 — Close P0 Direct-Connect Gates
- Run
scripts/parity_frontend_smoke.sh --api-smokeagainst PostgreSQL, Redis, Meilisearch, and GoChat. - Run
scripts/parity_frontend_smoke.sh --browser-smokeagainst the reused Chatwoot/Vite frontend. - Run enterprise smoke modes when enterprise screens are enabled.
- Fix or ticket every failure with a reproducible endpoint, frontend component/store, expected Chatwoot behavior, and GoChat hotspot.
- Acceptance: smoke report records pass/fail by matrix row, no untriaged P0 failure remains.
Phase 2 — Contract Fixture Tests
- Capture or reconstruct Chatwoot-compatible fixtures for key dashboard pages: profile, account cache keys, inbox list/detail, conversation list/detail, message create/update/delete, contact/company, labels/teams, custom filters, reports.
- Add GoChat handler/serializer tests that assert exact keys, enum strings, nullable fields, pagination/meta, timestamps, and errors.
- Include widget/public fixtures for pre-chat, message pagination, direct upload, CSAT submit/update, help-center JSON/markdown/tracking routes.
- Acceptance: fixture tests fail on contract drift and cover all P0/P1 frontend entrypoints.
Phase 3 — Realtime And Store Consistency
- Compare Chatwoot ActionCable event payloads against GoChat WebSocket/SSE/Redis events.
- Verify that every mutation used by the frontend emits the events needed to update unread counts, conversation previews, active timelines, labels, assignments, contact details, notifications, and cache keys.
- Keep browser subscription and user notification settings fixtures as drift guards; the live enterprise browser smoke now also covers the current Chatwoot notification list and profile notification-preference route requests.
- Acceptance: frontend can rely on realtime updates without stale persisted state or manual refresh workarounds.
Phase 4 — Side Effects And Async Durability
- Validate search indexing after every searchable mutation and prove release-mode Meilisearch behavior.
- Validate background jobs for message delivery, delivery status, CSAT sends, contact import/export, webhook dispatch, report rollups, Captain/Copilot jobs, and maintenance cleanup.
- Add idempotency and retry tests where Chatwoot queues jobs; expose frontend-visible failures where provider execution cannot be completed.
- Acceptance: successful API responses correspond to durable side effects or explicit frontend-visible pending/failed states.
Phase 5 — Enterprise And Provider Hardening
- Run enterprise smoke across SLA, custom roles, audit logs, agent capacity, assignment policies, Captain/Copilot, limits, CSAT, automation/macros, and reports.
- Validate channel/provider setup and webhook callbacks with signed fixture requests.
- Document feature gates for intentionally disabled provider/LLM/SSO behavior so the frontend receives stable disabled/unsupported states instead of broken screens.
- Acceptance: enterprise/provider screens either work unchanged or render intentional disabled states from Chatwoot-compatible API responses.
Acceptance Matrix
| Gate | Command Or Evidence | Required Result |
|---|---|---|
| Route parity | go run ./cmd/dump_routes then go run ./cmd/route_parity |
0 missing; parameter-compatible route families have focused tests or documented Gin constraints. |
| Static contract | docs/parity/frontend_contract_inventory.md and docs/parity/contract_fixture_coverage.md |
Every frontend API client call is mapped to a GoChat handler/service and smoke/test owner; current inventory has 224 entries and the coverage matrix tracks remaining fixture/smoke evidence. |
| API smoke | scripts/parity_frontend_smoke.sh --api-smoke |
Auth/profile, inbox, conversation/message, CRM, seeded conversation/message/contact/company/article search, widget, CSAT, and dashboard API checks pass on a fresh PostgreSQL/Redis/Meilisearch stack; latest enterprise-browser run refreshed the company/article search additions. Search captures are written to search_conversations.json, search_messages.json, search_contacts.json, search_companies.json, and search_articles.json. |
| Browser smoke | scripts/parity_frontend_smoke.sh --browser-smoke |
Reused Chatwoot/Woochat frontend boots, logs in, validates token, requests conversations, and has no frontend-visible API 4xx/5xx failures in the covered dashboard boot path; latest enterprise-browser report also boots the reused widget entrypoint and passes widget mount/messages/inbox-members/campaigns checks (.tmp/frontend-smoke-live/browser-smoke-report.json, 37 passed checks). |
| Enterprise smoke | scripts/parity_frontend_smoke.sh --enterprise-smoke --no-seed and --enterprise-browser-smoke --no-seed |
Enterprise API and enterprise browser route-request smoke pass for SLA, CSAT, automation, macros, audit, custom roles, capacity, Captain, and Copilot. |
| Go tests | GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./... |
Passed on 2026-06-13 after current code/documentation changes. |
| Diff hygiene | git diff --check |
Passed on 2026-06-13 after current code/documentation changes. |
Tracker Update Recommendations
Update docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md only after this review is accepted, using these rows:
| Tracker Row | Suggested Status | Rationale |
|---|---|---|
| Reused Chatwoot frontend verification | Keep Review; attach passed browser evidence |
API, browser, enterprise API, and enterprise browser smoke now pass, but fixture/realtime/provider live gates remain before claiming full direct-connect parity. |
| Serializer/envelope parity | Keep Review; split into fixture-tested subrows |
Route parity is strong, but frontend direct-connect depends on exact payloads. |
| Route parity | Mark generated evidence refreshed; do not mark exact | 0 missing, but 9 parameter-compatible routes need tests/documented constraints. |
| Realtime parity | Keep Review; attach payload fixture evidence |
Message/conversation mutation, typing/presence, notification, account-cache, browser subscription, and user notification preference fixtures are covered; live browser smoke also verifies the current notification list and profile notification-preference store requests; remaining risk is provider live-smoke coverage without configured external credentials. |
| Search/indexing | Keep Review; retain live Meilisearch gate |
Live enterprise-browser smoke reran the full Meilisearch reindex/search path and captured seeded conversation/message/contact/company/article payloads; company/article hooks assert updated objects reach indexing. |
| Widget/public/help-center | Keep Review; retain browser smoke evidence |
Public/widget flows are highly frontend-visible and include multipart/session/locale edge cases; pre-chat config shape, cw_conversation query and cookie session reuse across config boot, message history, labels, and events, locale redirect/fallback, portal/category/article JSON, dashboard article CRUD payloads, category filters, sitemap URLs, suffix-route markdown/tracking-pixel dispatch, raw markdown content, 1x1 pixel cache/body, view side effects, and widget browser-smoke harness navigation are covered; the latest enterprise browser report passed widget mount, messages, inbox-members, and campaigns checks. |
| Enterprise features | Keep Review; split provider-enabled vs feature-gated behavior |
Frontend should see either working behavior or stable disabled states, never fake success. |
Immediate Next Work Items
- Keep the expanded live enterprise browser smoke as a release gate now that reports/live API v2 shape, value, CSV, auth, store-refresh, CSAT dashboard/public/review-note, custom-role permission, enterprise account literal-path and billing error boundaries, SLA inbox association side effects, Captain document/response frontend filters and response-builder jobs, WhatsApp signed delivery/read/failure status callback, Twilio delivered/read/failed delivery-status callback, TikTok read-receipt callback retry fixture, Facebook page setup/reauthorize callback fixtures, root Instagram/TikTok/Twitter OAuth callback config fixtures, TikTok/LINE/Twilio setup payload/config fixtures, LINE valid/missing/invalid signature webhook fixtures, Telegram setup reauthorization fallback, Facebook/Instagram delivery/read receipt webhook fixtures, background Copilot follow-up job, widget
cw_conversationquery/cookie config/message/labels/events drift, ActiveStorage direct-upload create/complete, and help-center locale/JSON/sitemap/markdown/pixel slices are fixture-covered. - Keep the added notification list/profile preference browser-store smoke as a drift guard; core conversation/message, typing/presence, notification/cache, browser subscription, and user preference contracts are now fixture-covered.
- Keep account actions/contact merge, agent create, agent-bot account, assignable-agent, assignment-policy, agent-capacity, custom-attribute definition, audit-log, automation-rule, campaign, canned-response, bulk-action, Captain/Copilot, and core channel-provider fixtures as drift guards for Woochat CRM/settings/enterprise/channel route changes.
- Keep provider fixtures as drift guards for future payload changes: inbox assignment override, WhatsApp health/status/failure, Twilio delivered/read/failed delivery-status, TikTok read-receipt, Facebook/Instagram delivery/read receipt, Facebook page setup, root OAuth callback config/upsert/error fallback, email OAuth token payload fallback, Linear/Shopify/Notion integration callback error fallback, Dyte meeting/add-participant, Linear runtime operations, Slack create/delete/list-channel routes, generic integration hooks, Telegram setup reauthorization fallback, TikTok setup, LINE setup, and Twilio setup fixtures are now covered.
- Keep live Meilisearch search smoke as a release gate and retain
search_reindex.log,search_conversations.json,search_messages.json,search_contacts.json,search_companies.json, andsearch_articles.jsonevidence under.tmp/frontend-smoke-live/when rerun. - Attach fixture/smoke evidence to
docs/parity/frontend_contract_inventory.mdanddocs/parity/contract_fixture_coverage.mdrows as slices are proven.- Current inventory backlog is 0 rows after closing changelog external-Hub triage, voice, WhatsApp authorization, companies, contact notes, contacts, conversations top-level labels/unread-counts, CSAT reports, custom roles, custom filters, dashboard apps, auth/profile literals from
dashboard/api/endPoints.js, help-center dashboard APIs, inbox conversation/message APIs, and inbox health/member/inbox APIs, Dyte/Linear/Shopify integrations, labels, live reports, macros, MFA, notification subscriptions, notifications, Notion authorization, onboarding, search, SLA policies, applied-SLA reports, SAML settings, summary reports, generic integrations, account literal paths, agent-capacity literal paths, agent bulk-create literal triage, article literal triage, automation literal triage, company literal runtime paths, contacts literal runtime paths, conversations literal label/unread-count paths,endPoints.spec.jslegacy constants, and CSAT reports literal runtime paths, and inbox conversation literal runtime paths, and inbox message literal runtime path, and inbox literal runtime paths, and Dyte/Linear/Slack/generic integrations literal runtime paths, and labels/macros/notifications/reports/search/SLA literal runtime paths, teams/summary-reports/user-notification-settings/webhooks/year-in-review/CSAT public runtime paths, and widget literal runtime paths. - Evidence closure moved from inventory backlog to release gates on 2026-06-13: route dump/parity regeneration,
git diff --check, fullgo test ./..., and live enterprise Woochat/browser smoke all passed.
- Current inventory backlog is 0 rows after closing changelog external-Hub triage, voice, WhatsApp authorization, companies, contact notes, contacts, conversations top-level labels/unread-counts, CSAT reports, custom roles, custom filters, dashboard apps, auth/profile literals from
- Add new provider-disabled/provider-enabled fixture tests only when Woochat introduces new channel setup, callback, or delivery-status payloads.
- Re-run full
go test ./...,go run ./cmd/dump_routes,go run ./cmd/route_parity, andgit diff --checkafter code changes, not just documentation updates.
Non-Goals And Assumptions
- This review does not require changing Woochat/current Chatwoot frontend code.
- This review now covers the Chatwoot/Woochat SAML settings API contract, but does not mark end-to-end SSO login, LDAP, or OIDC fully complete; those remain deployment/feature-gated unless scope changes.
- This review does not claim live provider behavior is complete without configured provider smoke evidence.
- This review treats
reference/chatwootas the frontend contract because no separate local Woochat checkout was found.