feat(crm): queue contact bulk actions
This commit is contained in:
@@ -49,11 +49,11 @@ Hermes task landing checklist:
|
||||
|
||||
## Current Baseline
|
||||
|
||||
- Current tracking checkpoint: 2026-06-07 P3.102 enterprise account limits and billing-route parity, prepared as `feat(enterprise): align account limits API`.
|
||||
- Latest implementation checkpoint: this checkpoint, prepared as `feat(enterprise): align account limits API`.
|
||||
- Latest documentation/tooling checkpoint: this tracker update records the enterprise account API route expansion, Chatwoot account-limit payload shape, deletion toggle side effects, and regenerated route parity artifacts.
|
||||
- Current tracking checkpoint: 2026-06-07 P3.103 contact bulk-action parity, prepared as `feat(crm): queue contact bulk actions`.
|
||||
- Latest implementation checkpoint: this checkpoint, prepared as `feat(crm): queue contact bulk actions`.
|
||||
- Latest documentation/tooling checkpoint: this tracker update records Chatwoot contact bulk action enqueueing, label add/remove side effects, delete side effects, and raw empty `200 OK` account bulk-action responses.
|
||||
- Plan landing status: complete for the current known Hermes plans and user-confirmed scope. Future work should update this file directly instead of opening a parallel tracker.
|
||||
- Worktree status at this implementation checkpoint: the reused dashboard enterprise account client routes from `reference/chatwoot/app/javascript/dashboard/api/enterprise/account.js` and `routes.rb:523-527` are registered under `/enterprise/api/v1/accounts/:account_id/*`. `limits` returns Chatwoot-shaped `{ id, limits }` usage data, `toggle_deletion` writes/removes Chatwoot deletion custom attributes, `subscription` records the local customer-creation guard, and checkout/top-up endpoints return explicit billing-provider errors instead of missing routes. This retains P6.1 webhook placeholder burn-down, P3.101 WhatsApp call route-parameter parity, P3.100 dashboard app route-parameter parity, and prior checkpoints. Live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack.
|
||||
- Worktree status at this implementation checkpoint: reused dashboard contact bulk actions from `ContactsIndex.vue` and `api/bulkActions.js` now enqueue Chatwoot-shaped contact jobs on the `medium` queue, normalize lower-case `type`, allow empty `ids` like the reference controller/job path, return empty `200 OK`, add/remove contact labels account-scoped, and soft-delete only selected contacts in the current account. This retains P3.102 enterprise account route parity, P6.1 webhook placeholder burn-down, P3.101 WhatsApp call route-parameter parity, P3.100 dashboard app route-parameter parity, and prior checkpoints. Live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack.
|
||||
- Next executable implementation checkpoint: continue Phase 2/3 drift audit for the next reused-frontend mismatch, or run B12 live smoke when the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack is available. Re-run Phase 6 placeholder audit after future route/smoke changes.
|
||||
- `go test ./...` passes when run outside the restricted socket sandbox for the latest implementation baseline; the latest docs/tooling checkpoint verified `scripts/parity_frontend_smoke.sh --check` with workspace-local temp/cache dirs after `/tmp` was full.
|
||||
- Route dump succeeds with `972` registered routes after enterprise account route tracking.
|
||||
@@ -156,6 +156,7 @@ This table is the shortest authoritative handoff view. If an older lower section
|
||||
|
||||
| Priority | Workstream | Current state | Next checkpoint | Commit close rule |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 0 | P3.103 contact bulk actions | Implemented for reused CRM contact index actions: `POST /api/v1/accounts/:account_id/bulk_actions` now normalizes Chatwoot `type`, accepts Contact payloads without requiring `action_name`, enqueues durable `contact:bulk_action` jobs on the `medium` queue, returns empty `200 OK`, applies label add/remove account-scoped through `contact_labels`/`tags`, soft-deletes only current-account selected contacts, and treats unknown contact operations as no-op success like `Contacts::BulkActionService`. | Keep in Review; reopen from B12 contacts smoke or fresh reference evidence for exact Pundit authorization, label serializer, deleted-association cleanup, or notification side effects beyond the inspected controller/service/frontend contract. | Focused BulkActionHandler tests passed; focused conversation maintenance contact bulk-action worker tests passed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change. |
|
||||
| 0 | P3.102 enterprise account limits and billing routes | Implemented for reused enterprise account frontend calls: `GET/POST /enterprise/api/v1/accounts/:account_id/{limits,checkout,subscription,toggle_deletion,topup_checkout}` are now registered and tracked from `routes.rb:523-527`; `limits` returns Chatwoot-shaped usage data for agents, Captain documents/responses, and default-plan conversation/non-web-inbox counts; `toggle_deletion` mutates `marked_for_deletion_at` and `marked_for_deletion_reason`; `subscription` persists the `is_creating_customer` guard when no Stripe customer exists; checkout/top-up return explicit billing-provider errors instead of missing routes. | Keep in Review; reopen from B12 enterprise account smoke or fresh reference evidence for actual Stripe session creation, cloud-env gating, plan-config defaults, or account deletion notification/cancellation jobs beyond the local persisted boundary. | Focused EnterpriseAccountHandler tests passed; route dump/parity artifacts regenerated to `TOTAL: 972` and `435 exact, 0 method-compatible, 9 parameter-compatible, 0 missing out of 444`; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. |
|
||||
| 0 | P6.1 webhook placeholder fallback burn-down | Implemented for Phase 6 placeholder cleanup: `chatwootParityStub` and the unused webhook placeholder helper are removed from product code. Public webhook nil-handler guards now return explicit `503 { error: "webhook provider unavailable", message: "webhook handler is not configured" }` responses instead of `501 not implemented` placeholder bodies, while wired provider handlers still own real Telegram, WhatsApp, TikTok, LINE, Twilio, Twitter, Instagram, and Shopify behavior. | Keep in Review; reopen from placeholder audit or webhook smoke if a frontend/provider-reachable route returns placeholder/not-implemented content or if a provider handler is missing from normal bootstrap. | Focused router tests cover route boot and nil-handler fallback body/status; placeholder audit refreshed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change. |
|
||||
| 0 | P3.101 WhatsApp call route parameter parity | Implemented for reused WhatsApp call controls: account-level show/accept/reject/terminate/upload-recording routes now register Chatwoot's `:id` parameter name from `routes.rb:237-242`, while the handler still accepts legacy `:call_id` mounts. Route parity improves from `425 exact / 14 parameter-compatible` to `430 exact / 9 parameter-compatible` with no missing critical routes. AgentCapacity nested route names stay parameter-compatible in the main Gin router because Gin cannot register `/:id` policy members and `/:agent_capacity_policy_id` nested siblings under the same prefix without a wildcard conflict; the nested handlers now tolerate both parameter-name families. | Keep in Review; reopen from B12 WhatsApp calling smoke or fresh reference evidence for route/action payload drift beyond the inspected enterprise controller/frontend call API contract. | Focused WhatsAppCallHandler, AgentCapacityHandler, and router tests passed; route dump/parity artifacts regenerated; full `go test ./...` passed outside the restricted socket sandbox after retrying the known `internal/worker` SQLite in-memory flake; `git diff --check` passed. |
|
||||
@@ -391,6 +392,7 @@ This ledger records the committed parity checkpoints that future slices should b
|
||||
|
||||
| Commit | Scope | Verification summary | Follow-up state |
|
||||
| --- | --- | --- | --- |
|
||||
| `feat(crm): queue contact bulk actions` | Advances P3.103/P5.12 with Chatwoot contact bulk-action parity. GoChat now accepts reused frontend Contact bulk payloads for label add/remove and delete, normalizes `type` like the Rails controller, enqueues `contact:bulk_action` on the `medium` queue when a WorkerPool is configured, returns empty `200 OK`, and replays account-scoped label/delete side effects through durable workers. | Focused BulkActionHandler tests and conversation maintenance worker contact bulk-action tests passed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change. | Move P3.103 to Review; continue Phase 2/3 drift audit, Phase 6 placeholder audit, or B12 live smoke. |
|
||||
| `fix(routes): align dashboard app ids` | Advances P3.100 with exact Chatwoot dashboard app member route parameter parity. GoChat now registers `GET/PATCH/PUT/DELETE /api/v1/accounts/:account_id/dashboard_apps/:id`, keeps handler compatibility with legacy local `:dashboard_app_id`, and regenerates route parity artifacts. | Focused DashboardAppHandler and router tests passed; route dump/parity regenerated to `TOTAL: 967` and `425 exact, 0 method-compatible, 14 parameter-compatible, 0 missing out of 439`; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. | Move P3.100 to Review; continue reducing remaining parameter-compatible rows or run B12 live smoke. |
|
||||
| `feat(conversations): align destroy job` | Advances P3.99 with Chatwoot conversation destroy parity. GoChat now returns empty `200 OK` for `DELETE /conversations/:conversation_id`, wires a durable low-priority `conversation:delete_object` job into the WorkerPool, and lets that job perform the existing soft-delete/event/search cleanup while retaining a synchronous fallback without workers. | Focused ConversationService delete/job tests and ConversationHandler delete response tests passed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change. | Move P3.99 to Review; continue Phase 2/3 drift audit, Phase 6 placeholder audit, or B12 live smoke. |
|
||||
| `feat(conversations): align transcript delivery` | Advances P3.98 with Chatwoot conversation transcript delivery parity. GoChat now adds the Chatwoot `accounts.limits` field, uses account email transcript availability/rate helpers, maps dashboard transcript disabled/rate-limited responses to raw `402`/empty `429`, delivers transcript emails through the fakeable SMTP boundary, increments outbound-email counters, and filters transcript content to public incoming/outgoing chat messages. Automation `send_email_transcript` now no-ops when disabled and stops recipient fan-out at the configured rate limit. | Focused Account model, ConversationService, ConversationHandler, and ActionService transcript tests passed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change. | Move P3.98 to Review; continue Phase 2/3 drift audit, Phase 6 placeholder audit, or B12 live smoke. |
|
||||
@@ -2123,7 +2125,7 @@ Tracking table:
|
||||
| P5.9 | Queue inbound provider webhook processing where Chatwoot defers work. | `webhooks/*_events_job.rb`, `webhooks/*_delivery_job.rb` | webhook handlers, provider services | Provider HTTP ack behavior remains Chatwoot-compatible while persistence/dispatch runs through retryable jobs with signature validation preserved. | Review by `feat(webhook): queue incoming messages` |
|
||||
| P5.10 | Queue outbound message delivery and delivery-status updates. | `send_reply_job.rb`, provider delivery/status jobs | message send/channel services, delivery status handler | Outgoing message creation and provider delivery are separated; retries update message/delivery status exactly once. | Review by `feat(messages): queue send replies` and `feat(messages): queue delivery statuses` |
|
||||
| P5.11 | Queue Captain document sync, crawl, response building, embeddings, and Copilot responses. | Captain document/crawl/response/embedding/Copilot/conversation jobs | `internal/service/captain_document_service.go`, `internal/service/copilot_service.go`, `internal/service/captain_conversation_service.go`, Captain/Copilot services | Existing fakeable disabled/failure gates run under durable jobs; document statuses, Copilot message persistence, and Captain conversation replies survive worker restart. | Review by `feat(captain): queue document syncs`, `feat(captain): queue document crawl jobs`, `feat(captain): queue response embedding jobs`, and `feat(captain): queue copilot response jobs` |
|
||||
| P5.12 | Queue conversation maintenance jobs. | `trigger_scheduled_items_job.rb`, `campaigns/trigger_oneoff_campaign_job.rb`, `conversations/resolution_job.rb`, `reopen_snoozed_conversations_job.rb`, `update_message_status_job.rb`, `bulk_actions_job.rb` | conversation service/handlers | Auto-resolution, snooze reopen, status updates, and bulk actions are scheduled/retryable with idempotent tests. | Review by `feat(conversations): queue maintenance jobs`, `feat(conversations): queue message status updates`, and `feat(conversations): queue bulk actions` |
|
||||
| P5.12 | Queue conversation and contact maintenance jobs. | `trigger_scheduled_items_job.rb`, `campaigns/trigger_oneoff_campaign_job.rb`, `conversations/resolution_job.rb`, `reopen_snoozed_conversations_job.rb`, `update_message_status_job.rb`, `bulk_actions_job.rb`, `contacts/bulk_action_job.rb` | conversation/contact service handlers | Auto-resolution, snooze reopen, status updates, conversation bulk actions, and contact label/delete bulk actions are scheduled/retryable with account-scoped tests. | Review by `feat(conversations): queue maintenance jobs`, `feat(conversations): queue message status updates`, `feat(conversations): queue bulk actions`, and `feat(crm): queue contact bulk actions` |
|
||||
| P5.13 | Replace placeholder analytics/report builders that need background aggregation. | reporting jobs/services and report controllers | `internal/service/analytics_service.go`, `internal/service/analytics_query_helpers.go`, `internal/service/reporting_rollup_worker.go`, reporting services | P5.13a derives live/bot/conversation summary/matrix/distribution/outgoing-count report values from persisted rows; P5.13b adds lazy cached rollup freshness, durable `reporting:rollup_day` jobs, and `/reports` metric timeseries index parity. | Review by `feat(reports): derive analytics aggregates` and `feat(reports): add analytics timeseries rollups`; remaining report work should be created as drift slices when frontend/reference exposes additional metrics |
|
||||
|
||||
P5.1 current checkpoint:
|
||||
@@ -2788,3 +2790,4 @@ Verification milestone gates:
|
||||
- 2026-06-07: P3.101 WhatsApp call route-parameter checkpoint prepared as `fix(routes): align whatsapp call ids`; audited Chatwoot `routes.rb:237-242` and the reused account WhatsApp call route family. GoChat now registers account-level WhatsApp call show/action routes with Chatwoot's `:id` parameter name, preserves legacy `:call_id` handler compatibility, and makes AgentCapacity nested handlers accept both Chatwoot `:agent_capacity_policy_id`/`:id` and local Gin-compatible `:id`/`:user_id`/`:limit_id` parameter names. The main router keeps AgentCapacity nested route names parameter-compatible because Gin rejects wildcard-name changes below the existing policy `/:id` member route. Focused WhatsAppCallHandler, AgentCapacityHandler, and router tests passed; route dump/parity regenerated to `TOTAL: 967` and `430 exact, 0 method-compatible, 9 parameter-compatible, 0 missing out of 439`; full `go test ./...` passed outside the restricted socket sandbox after retrying the known `internal/worker` SQLite in-memory flake; `git diff --check` passed.
|
||||
- 2026-06-07: P6.1 webhook placeholder fallback checkpoint prepared as `fix(webhooks): replace parity stubs`; refreshed the Phase 6 placeholder audit and burned down the remaining `chatwootParityStub` nil-handler fallbacks in `internal/router/router.go`. Public webhook routes now return explicit `503 webhook provider unavailable` JSON when a provider handler is not configured instead of `501 not implemented` placeholder bodies, and the unused placeholder helper is removed. Focused router tests cover boot and nil-handler fallback behavior; placeholder audit shows no `chatwootParityStub` product-code matches; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change.
|
||||
- 2026-06-07: P3.102 enterprise account limits checkpoint prepared as `feat(enterprise): align account limits API`; audited Chatwoot enterprise `AccountsController#limits/#toggle_deletion/#subscription/#checkout/#topup_checkout`, `BillingHelper`, `Enterprise::Account::PlanUsageAndLimits`, reused dashboard `api/enterprise/account.js`, and `routes.rb:523-527`. GoChat now registers the enterprise account route family under `/enterprise/api/v1/accounts/:account_id`, returns Chatwoot-shaped account limit payloads, persists scheduled deletion custom attributes, records subscription customer-creation guards, and exposes explicit local billing-provider errors for checkout/top-up paths. Focused EnterpriseAccountHandler tests passed; route dump/parity regenerated to `TOTAL: 972` and `435 exact, 0 method-compatible, 9 parameter-compatible, 0 missing out of 444`; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed.
|
||||
- 2026-06-07: P3.103 contact bulk-action checkpoint prepared as `feat(crm): queue contact bulk actions`; audited Chatwoot `BulkActionsController`, `Contacts::BulkActionJob`, `Contacts::BulkActionService`, reused dashboard `api/bulkActions.js`, and `ContactsIndex.vue` label/delete callers. GoChat account bulk actions now accept Contact payloads for label add/remove and delete, normalize lower-case type values, enqueue durable `contact:bulk_action` jobs on the `medium` queue, return empty `200 OK`, replay account-scoped contact label add/remove through tags/contact_labels, soft-delete only selected current-account contacts, and preserve no-op success for unknown contact bulk payloads. Focused BulkActionHandler and conversation maintenance worker contact bulk-action tests passed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change.
|
||||
|
||||
Reference in New Issue
Block a user