feat(campaigns): align chatwoot payloads
This commit is contained in:
@@ -16,12 +16,12 @@ Build GoChat as a Go backend that can directly reuse the frontend from `referenc
|
||||
|
||||
## Current Baseline
|
||||
|
||||
- Current tracking checkpoint: 2026-06-06 after `d49aafd feat(agents): align index pagination`, with this implementation checkpoint prepared as `feat(notification-settings): align chatwoot payloads`.
|
||||
- Latest implementation checkpoint: this checkpoint, prepared as `feat(notification-settings): align chatwoot payloads`.
|
||||
- Current tracking checkpoint: 2026-06-06 after `4b2c1a9 feat(notification-settings): align chatwoot payloads`, with this implementation checkpoint prepared as `feat(campaigns): align chatwoot payloads`.
|
||||
- Latest implementation checkpoint: this checkpoint, prepared as `feat(campaigns): align chatwoot payloads`.
|
||||
- Latest documentation-only checkpoint: `8b378c7 docs: refresh parity tracker baseline`; this document is now the active follow-up plan and supersedes `.hermes/plans/*`.
|
||||
- Worktree status at this implementation checkpoint: User notification settings now match Chatwoot `NotificationSettingsController#show/#update` and `show.json.jbuilder`: account-scoped `GET/PATCH /notification_settings` accepts the reused frontend no-trailing-slash URL, update accepts nested `notification_settings`, and both actions return the raw notification-setting object without local `{ success, data }` or `notification_setting` wrappers. Agent index pagination already matches Chatwoot `AgentsController#index`, which renders `Current.account.users.order_by_full_name` without `.page/.per`: reused frontend `page/per_page` query values are ignored and the endpoint returns the full account-agent array ordered by full name. Agent update blank-name validation already matches Chatwoot `User#update!` plus `RequestExceptionHandler#render_record_invalid`: explicit blank `agent[name]` returns `422 { message: "Name can't be blank", attributes: ["name"] }` and leaves the user name unchanged. Agent delete/create/bulk-create drifts, account attachment pagination, profile account permissions, platform account-user membership, B10.3 CustomRole frontend update, contacts pagination/active payloads, conversation transcript, and custom-attribute response drifts are already closed. The fresh placeholder audit found remaining `chatwootParityStub` routes only in webhook handler-not-injected fallbacks, not in the reused dashboard account/contact/conversation/message/inbox critical path. P3.6 custom filters/custom attribute definitions and label CRUD are already in Review. B11.1a-B11.3e Captain/Copilot slices remain in Review; B12.1/B12.2/B12.3 smoke harnesses remain in Review; P5 durable job work through P5.13b is in Review. Next active implementation slice is the next named Phase 2/3 or Phase 6 drift from fresh reference/smoke evidence.
|
||||
- Worktree status at this implementation checkpoint: Account campaigns now match the reused dashboard `campaigns` store and Chatwoot `CampaignsController`/Jbuilder contract for the core CRUD path: index returns a raw unpaginated array, show/create/update return raw campaign objects with `id` mapped from `display_id`, nested inbox/sender data, parsed JSON `audience/trigger_rules/template_params`, create returns `200 OK`, delete returns empty `200 OK`, PATCH update is registered for `ApiClient.update`, and no-trailing-slash index/create routes are registered for `ApiClient` URLs. User notification settings already match Chatwoot `NotificationSettingsController#show/#update` and `show.json.jbuilder`: account-scoped `GET/PATCH /notification_settings` accepts the reused frontend no-trailing-slash URL, update accepts nested `notification_settings`, and both actions return the raw notification-setting object without local `{ success, data }` or `notification_setting` wrappers. Agent index/update/delete/create/bulk-create drifts, account attachment pagination, profile account permissions, platform account-user membership, B10.3 CustomRole frontend update, contacts pagination/active payloads, conversation transcript, and custom-attribute response drifts are already closed. The fresh placeholder audit found remaining `chatwootParityStub` routes only in webhook handler-not-injected fallbacks, not in the reused dashboard account/contact/conversation/message/inbox critical path. P3.6 custom filters/custom attribute definitions and label CRUD are already in Review. B11.1a-B11.3e Captain/Copilot slices remain in Review; B12.1/B12.2/B12.3 smoke harnesses remain in Review; P5 durable job work through P5.13b is in Review. Next active implementation slice is the next named Phase 2/3 or Phase 6 drift from fresh reference/smoke evidence.
|
||||
- `go test ./...` passes.
|
||||
- Route dump succeeds with `TOTAL: 843` after adding no-trailing-slash notification-settings route aliases for the reused frontend.
|
||||
- Route dump succeeds with `TOTAL: 846` after adding no-trailing-slash campaign index/create aliases and the frontend-used campaign PATCH update route.
|
||||
- Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`.
|
||||
- Tracked frontend-critical route audit covers 277 Chatwoot routes: 270 exact, 0 method-compatible, 7 parameter-compatible, 0 missing. The 7 parameter-compatible routes are Gin-internal parameter-name differences for nested AgentCapacityPolicy users/inbox limits; the external URL shape is equivalent.
|
||||
- `/api/v1/widget` stubs are burned down and public inbox/contact/conversation/message core flows are backed by real handlers.
|
||||
@@ -87,7 +87,7 @@ This table is the shortest authoritative handoff view. If an older lower section
|
||||
|
||||
| Priority | Workstream | Current state | Next checkpoint | Commit close rule |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Phase 2/3 drift | Tracked route parity is 0 missing for the current critical set; notification list/action serializers, user notification-settings raw payloads, Devise password reset/confirmation payloads, CRM shared attachment payloads plus fixed 100-row attachment pagination, account/settings payloads, assignable-agent payloads, agent index full-list behavior, agent create/update/delete defaults/errors/scope, label CRUD payloads, custom filters, and custom attribute definitions now match the inspected Chatwoot frontend contract. | Continue Phase 6 placeholder audit, then open the next named serializer/controller drift slice from reference/smoke evidence. | Regenerate parity artifacts when routes change and add endpoint-family fixture tests. |
|
||||
| 1 | Phase 2/3 drift | Tracked route parity is 0 missing for the current critical set; notification list/action serializers, user notification-settings raw payloads, campaigns raw payload/display-id routes, Devise password reset/confirmation payloads, CRM shared attachment payloads plus fixed 100-row attachment pagination, account/settings payloads, assignable-agent payloads, agent index full-list behavior, agent create/update/delete defaults/errors/scope, label CRUD payloads, custom filters, and custom attribute definitions now match the inspected Chatwoot frontend contract. | Continue Phase 6 placeholder audit, then open the next named serializer/controller drift slice from reference/smoke evidence. | Regenerate parity artifacts when routes change and add endpoint-family fixture tests. |
|
||||
| 2 | Phase 6 placeholder audit | Widget/public/webhook critical placeholders are burned down; inbox WhatsApp health/register-webhook and sync-template drift are closed; fresh `rg` audit shows only webhook nil-handler fallbacks still call `chatwootParityStub`; dashboard conversation transcript response drift is closed. | Continue targeted account/contact/conversation/message/inbox drift from reference/smoke evidence. | `rg` placeholder audit is recorded and no reused-frontend blocker is ownerless. |
|
||||
| 3 | B12 optional live smoke | API/browser/enterprise smoke commands are checked in; live runs need PostgreSQL, Redis, Meilisearch, Vite, and Chrome. | Run full live smoke when environment is available and map failures to the board. | `docs/parity/frontend_smoke_report.md` records pass/fail and linked owners. |
|
||||
| 4 | B9.3 delayed automation actions | Current reference exposes no delayed automation action params; scheduled-item work is already P5.12; `send_email_to_team` is durable and `add_sla` mutates conversation/applied SLA state. | Keep automation drift closed if future reference/smoke exposes delayed params or unsupported action shapes. | Automation worker/action fixtures verify queued team email replay, retry visibility through worker jobs, and SLA action idempotency. |
|
||||
@@ -143,6 +143,7 @@ This ledger records the committed parity checkpoints that future slices should b
|
||||
|
||||
| Commit | Scope | Verification summary | Follow-up state |
|
||||
| --- | --- | --- | --- |
|
||||
| `feat(campaigns): align chatwoot payloads` | Advances P3.7 campaign/settings parity by matching Chatwoot `CampaignsController#index/show/create/update/destroy`, `_campaign.json.jbuilder`, and the reused dashboard `campaigns` API/store. Account campaigns now return raw arrays/objects instead of local success/data/meta envelopes, ignore frontend `page/per_page`, use `display_id` as the external `id`, resolve show/update/delete/start/stop through display ID with legacy primary-key fallback, serialize nested inbox/sender data plus parsed JSON `audience`, `trigger_rules`, and `template_params`, create returns `200 OK`, delete returns empty `200 OK`, and the frontend-used no-trailing-slash index/create plus `PATCH` update routes are registered. | `go test ./internal/handler/api/v1 -run CampaignHandler -count=1`; `go test ./internal/service ./internal/repository -run Campaign -count=1`; `go test ./internal/handler/api/v1 ./internal/service ./internal/repository ./internal/router -run 'Campaign\|Router' -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; `go test ./...`; `git diff --check`. Route dump is `TOTAL: 846`; tracked route parity remains `270 exact, 7 parameter-compatible, 0 missing`. | Continue Phase 6 placeholder audit or the next named Phase 2/3 drift from reference/smoke evidence. |
|
||||
| `feat(notification-settings): align chatwoot payloads` | Advances P3.1 auth/profile settings parity by matching Chatwoot `NotificationSettingsController#show/#update`, `show.json.jbuilder`, and reused dashboard `userNotificationSettings` store/API. Account notification-settings show/update now return the raw object with `id`, `user_id`, `account_id`, `all_email_flags`, `selected_email_flags`, `all_push_flags`, and `selected_push_flags`; the local `{ success, data: { notification_setting } }` wrapper is removed, nested update params are retained, and no-trailing-slash route aliases are registered for the frontend `ApiClient` URL. | `go test ./internal/handler/api/v1 -run NotificationSetting -count=1`; `go test ./internal/service -run NotificationSetting -count=1`; `go test ./internal/handler/api/v1 ./internal/service ./internal/router -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; `go test ./...`; `git diff --check`. Route dump is `TOTAL: 843`; tracked route parity remains `270 exact, 7 parameter-compatible, 0 missing`. | Continue Phase 6 placeholder audit or the next named Phase 2/3 drift from reference/smoke evidence. |
|
||||
| `feat(agents): align index pagination` | Advances P3.2 agents/settings parity by matching Chatwoot `AgentsController#index`, which assigns `@agents = agents` from `Current.account.users.order_by_full_name.includes(...)` without pagination. Account agent lists now ignore reused-frontend `page/per_page` query values, return the full account-agent array, and retain `lower(users.name) ASC` ordering plus account-user role, availability, auto-offline, inviter, account-user ID, and custom-role metadata. | `go test ./internal/handler/api/v1 -run 'TestAgentHandlerSuite/TestList' -count=1`; `go test ./internal/service ./internal/repository -run Agent -count=1`; `go test ./internal/handler/api/v1 ./internal/service ./internal/repository -count=1`; `go test ./...`; `git diff --check`. No route changes; route dump remains `TOTAL: 840`. | Continue P3.2 agents/account-user drift or the next Phase 6 reference/smoke finding. |
|
||||
| `feat(agents): align update validation errors` | Advances P3.2 agents/settings parity by matching Chatwoot `AgentsController#update`, `User#update!`, and `RequestExceptionHandler#render_record_invalid`. Explicit blank `agent[name]` updates now return `422 { message: "Name can't be blank", attributes: ["name"] }` and preserve the existing user name instead of silently ignoring the invalid value with a `200 OK`. | `go test ./internal/handler/api/v1 -run 'TestAgentHandlerSuite/TestUpdateAgent' -count=1`; `go test ./internal/service -run Agent -count=1`; `go test ./internal/handler/api/v1 ./internal/service ./internal/repository -count=1`; `go test ./...`; `git diff --check`. No route changes; route dump remains `TOTAL: 840`. | Continue P3.2 agents/account-user drift or the next Phase 6 reference/smoke finding. |
|
||||
@@ -1575,7 +1576,7 @@ Frontend-critical API groups to audit first:
|
||||
| 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, and shared attachments. | Doing |
|
||||
| P3.6 | Labels/custom attributes/custom filters | Create/update/list behavior and exact response shapes. | Doing; label CRUD is in Review with Chatwoot `title/description/color/show_on_sidebar` payloads and raw/list response contracts, while custom attributes/custom filters remain evidence-driven follow-ups. |
|
||||
| P3.7 | Notifications/reports/help center/campaigns | Frontend-visible payloads and pagination/error envelopes. | Doing; notifications and reports now have focused Chatwoot payload fixtures, help center/campaigns remain broader audit scope. |
|
||||
| P3.7 | Notifications/reports/help center/campaigns | Frontend-visible payloads and pagination/error envelopes. | Doing; notifications, reports, and account campaign CRUD now have focused Chatwoot payload fixtures, while help center and deeper campaign side effects remain broader audit scope. |
|
||||
| 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 |
|
||||
|
||||
@@ -2084,6 +2085,7 @@ Verification milestone gates:
|
||||
|
||||
## Progress Log
|
||||
|
||||
- 2026-06-06: P3.7 campaigns checkpoint prepared as `feat(campaigns): align chatwoot payloads`; audited Chatwoot `CampaignsController`, campaign Jbuilder views, `_campaign.json.jbuilder`, and the reused dashboard campaigns API/store. Account campaigns now return raw Chatwoot arrays/objects, ignore `page/per_page`, use `display_id` as API `id`, resolve route IDs by display ID with legacy primary-key fallback, serialize nested inbox/sender data and parsed campaign JSON fields, accept object/array campaign params, return `200 OK` for create/delete, and register frontend-used no-trailing-slash index/create plus `PATCH` update routes. Focused campaign handler tests, service/repository campaign tests, combined handler/service/repository/router tests, route dump/parity, full `go test ./...`, and `git diff --check` passed; continue Phase 6 placeholder audit or the next named Phase 2/3 drift.
|
||||
- 2026-06-06: P3.1 notification-settings checkpoint prepared as `feat(notification-settings): align chatwoot payloads`; audited Chatwoot `NotificationSettingsController#show/#update`, `notification_settings/show.json.jbuilder`, and the reused dashboard `userNotificationSettings` API/store. Account-scoped notification settings now return the raw Jbuilder object with flag arrays instead of the local success/data wrapper, keep nested `notification_settings` update params, and register no-trailing-slash GET/PATCH/PUT route aliases for the frontend client URL. Focused handler/service tests, combined handler/service/router tests, route dump/parity, full `go test ./...`, and `git diff --check` passed; continue Phase 6 placeholder audit or the next named Phase 2/3 drift.
|
||||
- 2026-06-06: P3.2 agent index-pagination checkpoint prepared as `feat(agents): align index pagination`; audited Chatwoot `AgentsController#index`, `agents`, and `User.order_by_full_name`. Account agent lists now ignore reused-frontend `page/per_page` query values and return the full account-agent array like Chatwoot's unpaginated `@agents = agents`, while preserving lowercased full-name ordering and account-user metadata. Focused list tests, service/repository agent tests, combined handler/service/repository tests, full `go test ./...`, and `git diff --check` passed; continue P3.2 agents/account-user drift or the next Phase 6 reference/smoke finding.
|
||||
- 2026-06-06: P3.2 agent update-validation checkpoint prepared as `feat(agents): align update validation errors`; audited Chatwoot `AgentsController#update`, `User` name presence validation, and `RequestExceptionHandler#render_record_invalid`. Explicit blank `agent[name]` updates now return Chatwoot `422 { message, attributes }`, preserve the existing user name, and continue to allow omitted names plus explicit `auto_offline: false`. Focused update tests, service agent tests, combined handler/service/repository tests, full `go test ./...`, and `git diff --check` passed; continue P3.2 agents/account-user drift or the next Phase 6 reference/smoke finding.
|
||||
|
||||
@@ -145,6 +145,7 @@ GET /api/v1/accounts/:account_id/automation_rules/
|
||||
GET /api/v1/accounts/:account_id/automation_rules/:automation_id
|
||||
GET /api/v1/accounts/:account_id/banners
|
||||
GET /api/v1/accounts/:account_id/cache_keys
|
||||
GET /api/v1/accounts/:account_id/campaigns
|
||||
GET /api/v1/accounts/:account_id/campaigns/
|
||||
GET /api/v1/accounts/:account_id/campaigns/:campaign_id
|
||||
GET /api/v1/accounts/:account_id/canned_responses/
|
||||
@@ -450,6 +451,7 @@ PATCH /api/v1/accounts/:account_id/agent_bot_inboxes/:agent_bot_inbox_id/status
|
||||
PATCH /api/v1/accounts/:account_id/agent_capacity_policies/:id
|
||||
PATCH /api/v1/accounts/:account_id/agent_capacity_policies/:id/inbox_limits/:limit_id
|
||||
PATCH /api/v1/accounts/:account_id/agents/:agent_id
|
||||
PATCH /api/v1/accounts/:account_id/campaigns/:campaign_id
|
||||
PATCH /api/v1/accounts/:account_id/channels/facebook_channel/:fb_id
|
||||
PATCH /api/v1/accounts/:account_id/companies/:company_id
|
||||
PATCH /api/v1/accounts/:account_id/contacts/:contact_id
|
||||
@@ -516,6 +518,7 @@ POST /api/v1/accounts/:account_id/automation_rules/
|
||||
POST /api/v1/accounts/:account_id/automation_rules/:automation_id/clone
|
||||
POST /api/v1/accounts/:account_id/automation_rules/:automation_id/toggle_active
|
||||
POST /api/v1/accounts/:account_id/bulk_actions
|
||||
POST /api/v1/accounts/:account_id/campaigns
|
||||
POST /api/v1/accounts/:account_id/campaigns/
|
||||
POST /api/v1/accounts/:account_id/campaigns/:campaign_id/start
|
||||
POST /api/v1/accounts/:account_id/campaigns/:campaign_id/stop
|
||||
@@ -841,4 +844,4 @@ PUT /public/api/v1/csat_survey/:id
|
||||
PUT /public/api/v1/inboxes/:inbox_id/contacts/:contact_id
|
||||
PUT /public/api/v1/inboxes/:inbox_id/contacts/:contact_id/conversations/:conversation_id/messages/:message_id
|
||||
PUT /widget/direct_uploads/:upload_uuid
|
||||
TOTAL: 843
|
||||
TOTAL: 846
|
||||
|
||||
Reference in New Issue
Block a user