Files
gochat/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md
T

468 lines
38 KiB
Markdown

# Chatwoot Parity Development Plan
Updated: 2026-06-04
## Goal
Build GoChat as a Go backend that can directly reuse the frontend from `reference/chatwoot`. The backend API, data contracts, side effects, permissions, and runtime behavior must match the local `reference/chatwoot` repository first. Existing docs are secondary when they conflict with the reference implementation.
## Confirmed Decisions
- Frontend: reuse Chatwoot frontend directly. Backend compatibility is mandatory.
- Baseline: `reference/chatwoot` is the source of truth for routes, controllers, models, serializers, jobs, and service behavior.
- Immediate order: keep `go test ./...` green first, then deepen Chatwoot behavior parity.
- Search: final implementation must use Meilisearch. DB/LIKE search is not acceptable as the final engine.
- Enterprise scope: exclude SSO/SAML/LDAP/OIDC. Include the remaining paid features already present in planning and code: SLA, Audit, CustomRole, AgentCapacity, Captain/Copilot, CSAT, InboxLimit, automation, macros, assignment policies, and related limits/workflows.
## Current Baseline
- `go test ./...` passes.
- Route dump succeeds with `TOTAL: 791`.
- 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.
- 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.
## Execution Snapshot
| Phase | Name | Status | Blocking gaps |
| --- | --- | --- | --- |
| Phase 0 | Test and route baseline | Done | none |
| Phase 1 | Meilisearch search engine | Review | live Meilisearch integration and document-shape parity still need reference verification |
| Phase 2 | Route and controller parity audit | Doing | Ruby/Bundler unavailable, so Chatwoot route extraction currently uses static `routes.rb` fallback |
| Phase 3 | Data and serializer parity | Planned | needs route-gap priorities from Phase 2 |
| Phase 4 | Enterprise feature completion | Planned | excluded SSO family must stay out of scope; all other enterprise features remain included |
| Phase 5 | Background jobs and integrations | Planned | durable worker choice and job parity are open |
| Phase 6 | Core placeholder burn-down | Planned | placeholders must be converted into real Chatwoot-compatible behavior |
| Phase 7 | Verification harness | Planned | route/JSON/frontend smoke harness not complete |
## Tracking Artifacts
| Artifact | Purpose | Update rule |
| --- | --- | --- |
| `docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md` | Master execution plan and status ledger. | Update in every parity commit. |
| `docs/parity/gochat_routes.txt` | Generated Go route inventory. | Regenerate after every route change. |
| `docs/parity/route_parity.md` | Generated tracked route comparison against `reference/chatwoot/config/routes.rb`. | Regenerate after every route-tracking or route-registration change. |
| `cmd/route_parity` | Static route parity generator. | Extend whenever a new Chatwoot route group enters the tracked critical set. |
| `.hermes/plans/2025-05-24-global-search-meilisearch.md` | Original Meilisearch implementation plan. | Mine for context only; this document is now the active tracker. |
| `.hermes/plans/2026-05-24-automation-macro-csat.md` | Original automation, macro, and CSAT implementation plan. | Mine for context only; this document is now the active tracker. |
| `docs/requirements/*.md` | Reference notes extracted from Chatwoot modules. | Use as helper material after checking `reference/chatwoot` directly. |
## Immediate Execution Queue
This is the ordered queue for the next implementation slices. Do not skip the route and test gates even when working on deeper business behavior.
| Order | Work item | Primary phase | Done when | Status |
| --- | --- | --- | --- | --- |
| Q1 | Expand tracked route parity to Captain/Copilot, assignment policies, widget, public inbox/contact/conversation, public CSAT, v2 reports, summary reports, and live reports. | Phase 2 | `cmd/route_parity` tracks these groups and `docs/parity/route_parity.md` lists every missing/mismatched route. | Done |
| Q2 | Patch route aliases discovered by Q1, especially Chatwoot widget/public paths such as `/api/v1/widget/...` versus existing `/widget/...`. | Phase 2 | Missing tracked routes return to zero or are explicitly documented with implementation tasks. | Done |
| Q3 | Add route boot regression coverage for wildcard conflict groups before expanding more Rails-style resources. | Phase 2 | Router tests cover nested dynamic resources that previously risked Gin conflicts. | Done |
| Q4 | Start serializer parity fixtures for auth/session, conversations/messages, contacts/companies, inboxes, notifications, and search. | Phase 3 | Each area has at least one reference fixture and Go response test. | Doing |
| Q5 | Review Meilisearch document shape and endpoint payloads against Chatwoot frontend consumers. | Phase 1 and Phase 3 | Search remains Meilisearch-first and payload mismatches are fixed or tracked. | Todo |
| Q6 | Burn down enterprise gaps in this order: SLA, assignment policy and capacity, CSAT, automation/macros, Audit, CustomRole, InboxLimit, Captain/Copilot. | Phase 4 and Phase 5 | Each feature passes route, persistence, auth, side-effect, response, and test checks. | Todo |
| Q7 | Add frontend smoke harness using the reused Chatwoot frontend once core API flows boot end-to-end. | Phase 7 | Login, inbox list, conversation list/detail, message send, contact view, and widget init run without frontend adapters. | Todo |
## Phase 0: Test And Route Baseline
Status: done.
Checklist:
- [x] Fix `internal/handler/api/v1` route param mismatches around `:account_id`, `:id`, and resource IDs.
- [x] Fix malformed test routes that conflict with Gin wildcard rules.
- [x] Add defensive handling for zero-value services in handler edge tests.
- [x] Align handler error responses where tests encode the expected Chatwoot-compatible status category.
- [x] Keep platform routes bootable and dumpable.
- [x] Verify `go test ./...`.
- [x] Verify `go run ./cmd/dump_routes`.
Verification commands:
```bash
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./...
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/dump_routes
```
## Phase 1: Meilisearch Search Engine
Status: review.
Source material:
- `.hermes/plans/2025-05-24-global-search-meilisearch.md`
- `reference/chatwoot` search controllers, models, and indexing behavior
- Current local packages under `internal/search`, `internal/handler/api/v1/search_handler.go`, and entity repositories
Checklist:
- [x] Define a stable `SearchEngine` interface for Meilisearch-backed search and indexing.
- [x] Add search config for engine, host, API key, and index prefix.
- [x] Implement Meilisearch client wrapper with index bootstrapping and settings.
- [x] Define per-entity documents for conversations, messages, contacts, companies, articles, and help-center content as required by Chatwoot frontend behavior.
- [x] Wire create/update/delete hooks from services into indexing.
- [x] Add batch reindex command for existing data.
- [x] Keep DB search only as explicit development fallback, not as final production mode.
- [x] Add tests with a mocked search engine and integration hooks that can run without a live Meilisearch instance.
- [x] Document required Meilisearch environment variables and local startup flow.
Acceptance:
- Global search endpoint and entity search endpoints return Chatwoot-compatible payloads.
- Search results are account-scoped.
- Search indexing survives entity updates and deletes.
- `go test ./...` stays green.
Tracking table:
| ID | Task | Target files | Reference source | Status |
| --- | --- | --- | --- | --- |
| P1.1 | Add `SearchConfig` with engine, host, API key, index prefix, env binding, and defaults. | `internal/config/config.go`, `configs/config.yaml`, config tests | `.hermes/plans/2025-05-24-global-search-meilisearch.md` | Done |
| P1.2 | Add stable engine contract for search, indexing, deletes, batch indexing, and close. | `internal/search/engine.go` | Chatwoot global/entity search behavior | Done |
| P1.3 | Implement Meilisearch engine wrapper, index naming, bootstrap, sortable/filterable/searchable settings. | `internal/search/engine_meili.go` | Chatwoot search models/services | Review |
| P1.4 | Keep existing DB search as explicit dev fallback only. Production config must prefer Meilisearch. | `internal/search/engine_db.go`, `internal/search/search_service.go` | User decision on Meilisearch | Done |
| P1.5 | Define documents and serializers for conversations, messages, contacts, companies, articles, and help-center content. | `internal/search/engine.go` | `reference/chatwoot` models/serializers | Review |
| P1.6 | Wire create/update/delete hooks from entity services into async or synchronous indexing boundary. | `internal/service/*`, `internal/search/search_service.go`, `internal/app/bootstrap.go` | Chatwoot callbacks/jobs | Done |
| P1.7 | Add batch reindex command and account/entity filters. | `cmd/reindex_search` | Chatwoot reindex/search tasks | Done |
| P1.8 | Add mocked engine tests and service integration tests without requiring live Meilisearch. | `internal/search/engine_test.go`, `internal/config/config_test.go` | Existing test style | Done |
| P1.9 | Document Meilisearch env vars and local startup flow. | this doc, ops docs if needed | Hermes plan | Done |
Meilisearch local flow:
```bash
docker run --rm -p 7700:7700 -e MEILI_MASTER_KEY=gochat_dev getmeili/meilisearch:latest
GOCHAT_SEARCH_ENGINE=meilisearch GOCHAT_SEARCH_HOST=http://localhost:7700 GOCHAT_SEARCH_API_KEY=gochat_dev go run ./cmd/reindex_search -types all
```
Search environment variables:
| Variable | Default | Notes |
| --- | --- | --- |
| `GOCHAT_SEARCH_ENGINE` | `meilisearch` | Use `db` only for explicit local fallback. |
| `GOCHAT_SEARCH_HOST` | `http://localhost:7700` | Meilisearch endpoint. |
| `GOCHAT_SEARCH_API_KEY` | empty | Set to Meilisearch master/search key when enabled. |
| `GOCHAT_SEARCH_INDEX_PREFIX` | `gochat_` | Prefixes indexes such as `gochat_conversations`. |
| `GOCHAT_SEARCH_TIMEOUT_SECONDS` | `5` | HTTP timeout for search/index requests. |
## Phase 2: Route And Controller Parity Audit
Status: doing.
Checklist:
- [x] Dump Chatwoot route source declarations from `reference/chatwoot/config/routes.rb`.
- [x] Dump GoChat routes with `cmd/dump_routes`.
- [x] Build a first tracked route parity table covering method, path, controller, source, and route status.
- [x] Prioritize first frontend-critical API v1 account routes used by the Chatwoot web app.
- [ ] Extend parity table with auth scope, request params, response serializer, and handler implementation status.
- [x] Patch first-batch route names and wildcard params where Gin constraints require different internal names, while preserving external URLs.
- [x] Add regression tests for the contact conversations relation route added in this slice.
- [x] Expand route boot regression coverage for tracked Gin wildcard/param conflict groups.
Acceptance:
- Route gap report is generated and checked in.
- All currently implemented routes boot without panic.
- Missing frontend-critical routes have tickets or implementation tasks.
Tracking table:
| ID | Task | Artifact | Status |
| --- | --- | --- | --- |
| P2.1 | Generate Chatwoot route dump from `reference/chatwoot`. | `docs/parity/chatwoot_routes_static.md` | Review |
| P2.2 | Generate GoChat route dump with `cmd/dump_routes`. | `docs/parity/gochat_routes.txt` | Done |
| P2.3 | Produce route parity table: method, path, controller/handler, auth, request params, serializer, status. | `docs/parity/route_parity.md` | Review |
| P2.4 | Mark frontend-critical gaps from Chatwoot web app route usage. | `docs/parity/route_parity.md` | Done |
| P2.5 | Convert existing placeholders/stubs into tracked feature tasks instead of hidden debt. | this doc and gap report | Doing |
| P2.6 | Add route boot regression tests for Gin wildcard/param conflicts. | `internal/router/router_test.go` | Done |
| P2.7 | Track Captain/Copilot route group from `routes.rb:62-89`. | `cmd/route_parity`, `docs/parity/route_parity.md` | Done |
| P2.8 | Track assignment policies and inbox assignment policy routes from `routes.rb:306-313`. | `cmd/route_parity`, router | Done |
| P2.9 | Track widget API routes from `routes.rb:442-472`; keep `/api/v1/widget` as the Chatwoot-compatible surface. | `cmd/route_parity`, router widget mount | Done |
| P2.10 | Track public API routes from `routes.rb:569-585`, including public inbox contacts, conversations, messages, and CSAT survey. | `cmd/route_parity`, public handlers | Done |
| P2.11 | Track v2 reports, summary reports, and live reports from `routes.rb:479-513`. | `cmd/route_parity`, reports handlers | Done |
Current Phase 2 route findings:
| Type | Count | Required action |
| --- | --- | --- |
| Exact tracked critical routes | 251 | 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. |
Expanded tracked groups now covered by route parity:
| Area | Coverage |
| --- | --- |
| Agents and assignable agents | CRUD/bulk-create route coverage for `agents`, plus `assignable_agents#index`. |
| Canned responses | index/create/update/destroy account routes. |
| Custom attributes and custom filters | index/show/create/update/destroy account routes. |
| Labels and team membership | labels CRUD plus teams and team_members collection actions. |
| Notifications | account-scoped notifications, notification_settings, unread_count, read_all, destroy_all, snooze, unread. |
| Inbox members | Chatwoot account-scoped `inbox_members` create/show/update/destroy routes. |
| Inbox member actions | agent_bot, set_agent_bot, sync_templates, health, register_webhook, reset_secret, avatar. |
| Captain/Copilot | Assistants, assistant inboxes/scenarios, assistant responses, bulk actions, copilot threads/messages, custom tools, documents, preferences, and tasks. |
| Assignment policies | Account assignment policies, nested inbox bindings, and inbox assignment policy routes. |
| 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. |
New route groups tracked in this slice:
| Area | Chatwoot source | Current Go surface observed | Expected action |
| --- | --- | --- | --- |
| Captain/Copilot | `reference/chatwoot/config/routes.rb:62-89` | Many `/api/v1/accounts/:account_id/captain/...` routes already existed. | Added tracked critical set; route parity is exact. |
| Assignment policies | `reference/chatwoot/config/routes.rb:306-313` | `/assignment_policies` and local `/assignment_policies_v2` routes exist. | Added tracked route set and aligned singular inbox assignment delete route. |
| Widget API | `reference/chatwoot/config/routes.rb:442-472` | GoChat exposed many routes only under `/widget`. | Added `/api/v1/widget` aliases; behavior parity remains tracked under Phase 3/6. |
| Public API | `reference/chatwoot/config/routes.rb:569-585` | GoChat had public CSAT conversation routes. | Added public inbox/contact/conversation/message route surface and Chatwoot public CSAT path. |
| Reports v2 | `reference/chatwoot/config/routes.rb:479-513` | GoChat had report-style routes under `/api/v1/accounts`. | Added exact v2 `/api/v2/accounts/:account_id/...` report paths. |
Closed tracked critical route gaps in this slice:
| Method | Path | Chatwoot controller | Implementation note |
| --- | --- | --- | --- |
| GET | `/api/v1/accounts/:account_id/contacts/:contact_id/conversations` | `api/v1/accounts/contacts/conversations#index` | Added contact conversation relation endpoint returning Chatwoot `payload` shape, optional `inbox_id`, and latest-20 ordering. |
| POST | `/api/v1/accounts/:account_id/contacts/export` | `api/v1/accounts/contacts#export` | Added Chatwoot async request path returning `200 OK`; existing CSV download route remains for local compatibility. |
| POST | `/api/v1/accounts/:account_id/conversations/:conversation_id/toggle_priority` | `api/v1/accounts/conversations#toggle_priority` | Added Chatwoot action path returning `200 OK`. |
Closed Rails update method gaps:
| Expected | Existing GoChat route | Implementation note |
| --- | --- | --- |
| `PUT /api/v1/accounts/:account_id/conversations/:conversation_id` | `PATCH /api/v1/accounts/:account_id/conversations/:conversation_id` | Added PUT alias to the same update handler. |
| `PUT /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id` | `PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/messages/:message_id` | Added PUT alias to the same update handler. |
Phase 2 commands:
```bash
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/dump_routes > docs/parity/gochat_routes.txt
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/route_parity
```
## Phase 3: Data And Serializer Parity
Status: planned.
Checklist:
- [ ] Compare key Chatwoot serializers/entities with Go response payloads.
- [ ] Align account, user, inbox, conversation, message, contact, company, team, label, canned response, campaign, help center, and notification payload shapes.
- [ ] Verify timestamps, IDs, enum strings, nested objects, pagination metadata, and error envelopes.
- [ ] Add fixture-driven tests for payload compatibility.
Acceptance:
- Chatwoot frontend can consume the payloads without adapter code.
- Serializer deviations are documented only where GoChat intentionally differs.
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.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.5 | Contacts/companies | CRUD, merge, labels, notes, custom attributes, import/export, conversations relation. | Todo |
| 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 |
| P3.8 | Widget/public APIs | Widget init, campaigns, config, contact, conversations, messages, direct uploads, public inbox flow, public CSAT. | Doing |
| P3.9 | Search payloads | Global search and entity search documents backed by Meilisearch. | Review |
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 |
| S3 | Contacts and companies | `reference/chatwoot/app/controllers/api/v1/accounts/contacts*`, `companies*` | fixture tests for list/show/search/merge/relation payloads | Todo |
| 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 |
| S6 | Reports and CSAT | `reference/chatwoot/app/controllers/api/v1/accounts/reports*`, `csat_survey_responses*` | fixture tests for report filters and CSAT metrics/list | Todo |
| S7 | Widget/public | `reference/chatwoot/app/controllers/api/v1/widget*`, `public/api/v1*` | widget smoke fixtures and public flow tests | Doing |
| S8 | Search | `reference/chatwoot` search controllers plus frontend search client | Meilisearch-backed search response fixtures | Todo |
Serializer comparison rules:
- Compare against `reference/chatwoot` serializers/entities before changing Go responses.
- Prefer fixture-driven tests for exact JSON shape, enum strings, pagination metadata, and error envelopes.
- Preserve Chatwoot field names even if Go internal naming differs.
## Phase 4: Enterprise Feature Completion
Status: doing.
Excluded:
- SSO
- SAML
- LDAP
- OIDC
Included checklist:
- [ ] SLA policies and SLA event tracking.
- [ ] Audit logs and admin-readable audit endpoints.
- [ ] Custom roles and permission checks.
- [ ] Agent capacity and assignment limits.
- [ ] Assignment policies and auto-assignment compatibility.
- [ ] Captain/Copilot assistant, custom tools, scenarios, documents, responses, and inbox bindings.
- [ ] CSAT survey response flow, metrics, filters, and review notes.
- [ ] Inbox limits and account/inbox usage enforcement.
- [ ] Automation rules, macros, execution logs, and action side effects.
Acceptance:
- Each included feature has routes, persistence, authorization, tests, and Chatwoot-compatible response behavior.
- Unsupported SSO family features are explicitly disabled or omitted without breaking frontend navigation for enabled features.
Enterprise tracking table:
| ID | Feature | Existing Go surface | Required next work | Status |
| --- | --- | --- | --- | --- |
| P4.1 | SLA policies/events | `internal/model/sla_policy.go`, `internal/model/sla_event.go`, `internal/service/sla_policy_service.go`, `internal/service/sla_event_service.go`, `internal/handler/api/v1/sla_policy_handler.go` | Compare with Chatwoot SLA behavior; wire lifecycle events and breach tracking; add frontend payload tests. | Todo |
| P4.2 | Audit logs | `internal/model/audit.go`, `internal/service/audit_service.go`, `internal/repository/audit_repo.go`, `internal/handler/api/v1/audit_handler.go` | Ensure every mutating enterprise/core action emits audit events and filters match Chatwoot. | Todo |
| P4.3 | Custom roles/permissions | `internal/model/custom_role.go`, `internal/service/custom_role_service.go`, `internal/middleware/role_check.go`, `internal/handler/api/v1/custom_role_handler.go` | Align permission keys, inherited roles, authorization failures, and admin UX payloads. | Todo |
| P4.4 | Agent capacity | `internal/model/agent_capacity_policy.go`, `internal/service/agent_capacity_policy_service.go`, `internal/handler/api/v1/agent_capacity_handler.go`, `internal/autoassignment/*` | Enforce capacity in assignment path and auto-assignment; add limit tests. | Todo |
| P4.5 | Inbox limits | `internal/model/inbox_limit.go`, `internal/service/inbox_limit_service.go`, `internal/repository/inbox_limit_repo.go`, `internal/handler/api/v1/inbox_limit_handler.go` | Enforce account/inbox usage limits and frontend-compatible responses. | Todo |
| P4.6 | Captain/Copilot | `internal/model/captain_models.go`, `internal/model/copilot_models.go`, `internal/service/captain_*`, `internal/service/copilot_*`, `internal/handler/api/v1/captain_*`, `internal/handler/api/v1/copilot_handler.go` | Complete assistant, tools, scenarios, documents, responses, inbox bindings, suggestions, and streaming compatibility. | Todo |
| P4.7 | CSAT | `internal/csat/*`, `internal/automation/csat_survey_*`, `internal/handler/api/v1/csat_*`, `internal/service/csat_metrics_service.go` | Wire resolve-triggered survey send, public update flow, metrics, review notes, filters. | Todo |
| P4.8 | Automation and macros | `internal/automation/*`, `internal/handler/api/v1/automation_rule_handler.go`, `internal/handler/api/v1/macro_handler.go` | Finish action side effects, execution logs, webhook/email transcript delivery, and rule trigger coverage. | Todo |
| P4.9 | Assignment policies | `internal/autoassignment/*`, `internal/automation/agent_bot_rule_listener.go` | Match Chatwoot assignment policy behavior and availability/capacity rules. | Todo |
Enterprise acceptance gates:
| Feature | Required gates before `Done` | Reference notes |
| --- | --- | --- |
| SLA | Field names and units match Chatwoot; `only_during_business_hours` exists; applied SLA state machine is wired; breach events create notifications; delete/update statuses match Rails behavior. | `docs/verification/SLA_ASSIGNMENT_POLICY_V2_COMPATIBILITY_REPORT.md`, `docs/requirements/M11-enterprise-features.md` |
| Audit | Mutating account resources emit audit records with actor, IP, request UUID, auditable type/id, associated account, and changes; admin list pagination matches Chatwoot. | `docs/requirements/M11-enterprise-features.md` |
| CustomRole | Permission keys match Chatwoot; `AccountUser` permission resolution honors custom roles; deleting a role nullifies users; admin-only policy is enforced. | `docs/requirements/M1-accounts-and-users.md`, `docs/requirements/M11-enterprise-features.md` |
| AgentCapacity and InboxLimit | Assignment and auto-assignment respect per-inbox conversation limits; account/inbox limits are enforced in create paths and surfaced to frontend. | `docs/requirements/M1-accounts-and-users.md`, `docs/requirements/M5-team-and-assignment.md` |
| Assignment policies | V2 route and payload shape match Chatwoot; policy selection is applied during manual and automatic assignment; availability and capacity interact correctly. | `reference/chatwoot/config/routes.rb:306-313` |
| CSAT | Resolve event sends survey once; widget/WhatsApp/Twilio paths are modeled where supported; public submit/update honors lock window; metrics and download filters match Chatwoot. | `.hermes/plans/2026-05-24-automation-macro-csat.md`, `docs/requirements/M7-reporting-and-csat.md` |
| Automation and macros | Conditions/actions match Chatwoot; macro execute side effects are real; execution logs and async webhook/email transcript actions are durable and retryable. | `.hermes/plans/2026-05-24-automation-macro-csat.md`, `docs/requirements/M6-automation-and-templates.md` |
| Captain/Copilot | Assistant, tools, documents, responses, scenarios, inbox bindings, copilot threads/messages, tasks, streaming, and LLM/tool-call behavior are implemented or explicitly feature-gated. | `docs/requirements/M10-captain-and-copilot.md` |
Excluded tracking table:
| Feature | Decision | Required handling |
| --- | --- | --- |
| SSO | Excluded | Do not prioritize implementation. Existing surfaces should not block core frontend use. |
| SAML | Excluded | Do not expand beyond already present code unless needed to disable safely. |
| LDAP | Excluded | Omit from parity scope. |
| OIDC | Excluded | Omit from parity scope. |
## Phase 5: Background Jobs And Integrations
Status: planned.
Known hotspots:
- `internal/worker/worker.go` is still mostly placeholder.
- `internal/automation/action_service.go` has pending webhook/email transcript work.
- `internal/automation/csat_survey_listener.go` has pending CSAT enable/send behavior.
- `internal/auth/webhook_registry.go` has pending signature verification for Facebook/WhatsApp.
- `internal/service/analytics_service.go` has placeholder analytics paths.
Checklist:
- [ ] Map Chatwoot jobs/listeners to Go worker responsibilities.
- [ ] Implement durable job dispatch for automation, CSAT, notifications, webhooks, and search indexing.
- [ ] Add retry and failure logging for external calls.
- [ ] Add tests for job enqueueing and idempotency.
Acceptance:
- User-visible side effects do not depend on synchronous handler-only execution.
- Failed background work is observable and retryable.
Tracking table:
| ID | Task | Current hotspot | Status |
| --- | --- | --- | --- |
| P5.1 | Choose and wire durable job runner compatible with current Go stack. | `internal/worker/worker.go`, `internal/channel/dispatcher.go` | Todo |
| P5.2 | Move search indexing into retryable jobs where Chatwoot uses callbacks/jobs. | search services and worker | Todo |
| P5.3 | Implement automation webhook delivery with retry, timeout, and logs. | `internal/automation/action_service.go` | Todo |
| P5.4 | Implement email transcript delivery once email infrastructure is available. | `internal/automation/action_service.go` | Todo |
| P5.5 | Complete CSAT survey send listener and idempotency. | `internal/automation/csat_survey_listener.go`, `internal/csat/listener.go` | Todo |
| P5.6 | Complete webhook signature verification for Facebook/WhatsApp/Twilio/provider paths. | `internal/auth/webhook_registry.go`, channel providers | Todo |
| P5.7 | Replace placeholder analytics with real report builders/queries. | `internal/service/analytics_service.go`, reporting services | Todo |
## Phase 6: Core Product Placeholder Burn-down
Status: planned.
Purpose: route parity is not enough; existing handlers that return placeholder JSON must be converted into real Chatwoot-compatible behavior before the frontend can be reused directly.
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. | Todo |
| 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 |
| P6.6 | Widget/public APIs | `docs/ROUTE_GAP_ANALYSIS.md`, widget/channel provider code, `chatwootParityStub` routes | Implement init/config, campaigns, events, contact, conversations, messages, cable token, direct uploads, public inbox flows, and public CSAT with Chatwoot contracts. | Doing |
| P6.7 | Webhook ingress | `internal/router/router.go`, `internal/handler/webhook/*`, channel providers | Replace generic placeholder with provider-specific verified ingestion and dispatch. | Todo |
## Phase 7: Verification Harness
Status: planned.
Checklist:
- [ ] Add repeatable command to compare Chatwoot and GoChat route dumps.
- [ ] Add fixture-based JSON parity tests for major frontend endpoints.
- [ ] Add Meilisearch mock tests and optional integration test mode gated by env vars.
- [ ] Add frontend smoke path using reused Chatwoot frontend once backend boot flow is ready.
- [ ] Keep a generated gap report in `docs/parity/` with date, reference commit, Go commit, and pass/fail summary.
Required verification before each feature commit:
```bash
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./...
env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/dump_routes
```
Verification milestone gates:
| Gate | Command or artifact | Required before |
| --- | --- | --- |
| V1 | `env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go test ./...` | Every commit that changes Go code. |
| V2 | `env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/dump_routes > docs/parity/gochat_routes.txt` | Every route/router/handler registration change. |
| V3 | `env GOCACHE=/tmp/gochat-gocache GOMODCACHE=/tmp/gochat-gomodcache go run ./cmd/route_parity` | Every tracked route or route generator change. |
| V4 | JSON fixture parity tests for touched endpoint family. | Every serializer or handler payload change. |
| V5 | Optional live Meilisearch integration test gated by env var. | Search behavior changes that claim Meilisearch compatibility. |
| V6 | Reused Chatwoot frontend smoke flow. | Before declaring frontend reuse viable. |
## Task Status Legend
- `Todo`: not started or only skeleton exists.
- `Doing`: implementation is underway in the current working tree.
- `Review`: code is implemented and needs parity/test verification.
- `Done`: committed, tested, and linked to the matching `reference/chatwoot` behavior.
- `Blocked`: needs a decision, missing dependency, or reference behavior cannot yet be reproduced.
## Ongoing Tracking Rules
- Every parity task should name the matching file or behavior in `reference/chatwoot`.
- Every route change should keep `cmd/dump_routes` passing.
- Every phase must keep `go test ./...` green before moving on.
- Test-only route fixes should be limited to malformed tests. Production route changes must preserve external Chatwoot-compatible URLs.
- New search work must target Meilisearch first.
- Update this document in the same commit as each completed parity slice: change task status, add verification command output summary, and link the touched `reference/chatwoot` behavior.
- Do not count a feature as done because a model/handler exists; it is done only when route behavior, persistence, authorization, side effects, response shape, and tests are covered.
- Keep `.codegraph/` and other generated local analysis artifacts out of product commits unless explicitly requested.
## Progress Log
- 2026-06-04: Baseline stabilized and committed as `42cdab8 chore: stabilize chatwoot parity baseline`; `go test ./...` passed and route dump reported `TOTAL: 704`.
- 2026-06-04: Phase 1 search foundation added: Meilisearch config/env defaults, `SearchEngine` contract, Meilisearch HTTP wrapper with bootstrap/settings, DB fallback adapter, document builders, reindex command, and no-live-Meilisearch tests. Verified `go test ./...` in unsandboxed mode because miniredis/httptest need local sockets; route dump still reports `TOTAL: 704`.
- 2026-06-04: Phase 1 indexing hooks wired for conversations, messages, contacts, companies, and articles. Create/update/delete paths now call the service-layer `SearchIndexer` boundary, bootstrap injects the Meilisearch-backed search service, and unit tests cover each entity hook path.
- 2026-06-04: Phase 2 route parity tracking added. Ruby/Bundler are unavailable in this workspace, so `cmd/route_parity` records static Chatwoot route DSL declarations from `reference/chatwoot/config/routes.rb`, consumes `cmd/dump_routes` output, and writes `docs/parity/route_parity.md`. First tracked critical route summary: 76 exact, 2 method-compatible, 0 parameter-compatible, 3 missing out of 81; GoChat route dump remains `TOTAL: 704`.
- 2026-06-04: First tracked Phase 2 route gaps closed. Added Chatwoot-compatible contact conversations, contact export POST, conversation `toggle_priority`, and PUT aliases for conversation/message updates; fixed contact handlers to accept `:account_id` as well as legacy `:id`. Regenerated parity report: 81 exact, 0 method-compatible, 0 parameter-compatible, 0 missing out of 81; route dump now reports `TOTAL: 709`.
- 2026-06-04: Expanded Phase 2 route parity from 81 to 138 tracked frontend-critical account routes. Added account-scoped notification routes, `notification_settings` PUT alias, and Chatwoot account-level `inbox_members` create/show/update/destroy handlers. Regenerated parity report: 138 exact, 0 method-compatible, 0 parameter-compatible, 0 missing out of 138; route dump now reports `TOTAL: 723`.
- 2026-06-04: Expanded Phase 2 route parity from 138 to 251 tracked frontend-critical routes. Added tracking and route-level coverage for Captain/Copilot, assignment policies, `/api/v1/widget`, public inbox/contact/conversation/message APIs, public CSAT survey, and `/api/v2` reports. Regenerated parity report: 251 exact, 0 method-compatible, 0 parameter-compatible, 0 missing out of 251; route dump now reports `TOTAL: 791`. Added router boot regression coverage for Captain static/dynamic routes, widget collection routes, public nested message routes, and v2 reports.
- 2026-06-04: Started Phase 3/6 widget behavior parity for the reused Chatwoot frontend. `/api/v1/widget/config` now returns Chatwoot-style `website_channel_config`, contact pubsub token, and global config; `/api/v1/widget/messages` accepts `X-Auth-Token` and nested `message.content`, returns Chatwoot message shape, and exposes latest messages as `{payload, meta}`; `/api/v1/widget/contact` and core conversation actions now route to real handlers instead of parity stubs. Legacy `/widget/*` response compatibility is preserved. Focused widget/service/router tests pass.
- 2026-06-04: Continued Phase 3/6 widget behavior parity. Replaced more `/api/v1/widget` stubs with handlers for `campaigns`, `events`, `inbox_members`, `labels`, and label removal. Inbox member payload now follows Chatwoot `{payload: [...]}` shape; campaigns return enabled inbox campaigns with trigger rules; events validate website/contact token context and return `204`; labels mutate the latest widget conversation only when the label exists in the account. Added focused widget handler coverage for available agents, events, and label add/remove. Remaining widget stubs: message update, transcript, `contact/set_user`, and Dyte participant integration; public inbox/contact/conversation/message routes are still placeholder-backed.
- 2026-06-04: Completed the remaining `/api/v1/widget` stub burn-down. Message update now persists submitted email/form values and identifies the contact; `contact/set_user` validates identifier HMAC, supports verified contact identification, and returns `widget_auth_token` when the contact context changes; conversation transcript returns Chatwoot-compatible status behavior around missing conversations; Dyte participant endpoint validates integration messages and returns a meeting token payload. Added model/repository support for contact inbox HMAC verification and identifier lookup. Public inbox/contact/conversation/message routes remain the next P6.6 placeholder group.