|
|
|
@@ -49,15 +49,15 @@ Hermes task landing checklist:
|
|
|
|
|
|
|
|
|
|
## Current Baseline
|
|
|
|
|
|
|
|
|
|
- Current tracking checkpoint: 2026-06-06 conversation reporting events checkpoint, prepared as `feat(conversations): expose reporting events`.
|
|
|
|
|
- Latest implementation checkpoint: this checkpoint, prepared as `feat(conversations): expose reporting events`.
|
|
|
|
|
- Latest documentation/tooling checkpoint: this tracker update for P3.21 plus the landed parity tracker history; this document is the active follow-up plan and supersedes `.hermes/plans/*`.
|
|
|
|
|
- Current tracking checkpoint: 2026-06-06 account reporting events checkpoint, prepared as `feat(reporting): align account events`.
|
|
|
|
|
- Latest implementation checkpoint: this checkpoint, prepared as `feat(reporting): align account events`.
|
|
|
|
|
- Latest documentation/tooling checkpoint: this tracker update for P3.22 plus the landed parity tracker history; this document is the active follow-up plan and supersedes `.hermes/plans/*`.
|
|
|
|
|
- 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: conversation reporting events from `reference/chatwoot/config/routes.rb:166`, enterprise `Api::V1::Accounts::ConversationsController#reporting_events`, and `enterprise/app/views/api/v1/models/_reporting_event.json.jbuilder` are implemented. `GET /api/v1/accounts/:account_id/conversations/:conversation_id/reporting_events` is now tracked and routed, resolves conversations by display ID with legacy ID fallback, scopes reporting events by account and conversation, orders by `created_at ASC`, and returns the raw Chatwoot reporting-event array with nullable relation keys preserved. Live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack.
|
|
|
|
|
- Worktree status at this implementation checkpoint: account reporting events from `reference/chatwoot/config/routes.rb:234`, enterprise `Api::V1::Accounts::ReportingEventsController#index`, and its index Jbuilder are implemented. `GET /api/v1/accounts/:account_id/reporting_events` now returns Chatwoot `{ payload, meta }`, filters by optional Unix `since/until`, `inbox_id`, `user_id`, and `name`, orders by `created_at DESC`, paginates at 25 rows per page, and reuses the `_reporting_event` raw serializer. Live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack.
|
|
|
|
|
- `go test ./...` passes.
|
|
|
|
|
- Route dump succeeds with `TOTAL: 933` after adding the enterprise conversation reporting events route.
|
|
|
|
|
- Route dump succeeds with `TOTAL: 933`; P3.22 changes account reporting-events behavior and expands tracked route parity without adding a new Go route.
|
|
|
|
|
- Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`.
|
|
|
|
|
- Tracked frontend-critical route audit covers 386 Chatwoot routes: 373 exact, 0 method-compatible, 13 parameter-compatible, 0 missing. The 13 parameter-compatible routes are Gin-internal parameter-name differences for nested AgentCapacityPolicy users/inbox limits, dashboard app member `:id` names, plus the public article `.md`/`.png` suffixes served through the same external article route dispatcher.
|
|
|
|
|
- Tracked frontend-critical route audit covers 387 Chatwoot routes: 374 exact, 0 method-compatible, 13 parameter-compatible, 0 missing. The 13 parameter-compatible routes are Gin-internal parameter-name differences for nested AgentCapacityPolicy users/inbox limits, dashboard app member `:id` names, plus the public article `.md`/`.png` suffixes served through the same external article route dispatcher.
|
|
|
|
|
- `/api/v1/widget` stubs are burned down and public inbox/contact/conversation/message core flows are backed by real handlers.
|
|
|
|
|
- Handler test stability fixes are committed into the baseline before feature parity work continues.
|
|
|
|
|
- `.codegraph/` is generated indexing output and is not part of tracked product code.
|
|
|
|
@@ -140,7 +140,7 @@ This table is the shortest authoritative handoff view. If an older lower section
|
|
|
|
|
| Priority | Workstream | Current state | Next checkpoint | Commit close rule |
|
|
|
|
|
| --- | --- | --- | --- | --- |
|
|
|
|
|
| 1 | P3.2a invitation/confirmation mail parity | Implemented for current non-SSO reference behavior: profile resend is no longer a TODO-only log, new invited agents and unconfirmed invited profile resends generate reset-password invitation links, normal unconfirmed profile resends generate confirmation links, `users.unconfirmed_email` is modeled for email-update routing, and fakeable/environment SMTP mailers keep default tests offline. | Keep in Review; reopen only if reused frontend smoke or fresh reference evidence exposes additional Devise confirmation states outside excluded SSO/SAML/LDAP/OIDC variants. | Focused profile and agent invitation tests, combined handler/service/repository/router/migrate/app tests, full `go test ./...`, and `git diff --check` passed. |
|
|
|
|
|
| 2 | Phase 2/3 drift | Tracked route parity is 0 missing for the current 386-route critical set; dashboard `/app` shell routes from `routes.rb:19-20`, `.well-known` app association and custom-domain challenge routes from `routes.rb:657-660`, Twilio callback routes from `routes.rb:639-640`, enterprise Twilio voice routes from `routes.rb:643-646`, root Linear/Shopify/Notion OAuth callback routes from `routes.rb:630/634/654`, root Twitter/Google/Microsoft/Instagram/TikTok callback routes from `routes.rb:626/649-652`, assignment policy routes from `routes.rb:306-313`, help-center portal/category/article routes from `routes.rb:385-404`, public help-center portal/sitemap/article/category/search/article-detail routes from `routes.rb:590-601`, enterprise contact outbound voice call from `routes.rb:216`, account agent-bot routes from `routes.rb:94-97`, account webhook routes from `routes.rb:342`, account integration app/hook routes from `routes.rb:345-348`, account Dyte routes from `routes.rb:357-358`, dashboard app routes from `routes.rb:130`, canned response routes from `routes.rb:114`, notification subscription routes from `routes.rb:440`, team/team-member routes from `routes.rb:296-300`, conversation participant routes from `routes.rb:150`, conversation direct upload route from `routes.rb:151`, conversation draft message routes from `routes.rb:152`, conversation inbox assistant route from `routes.rb:165`, and conversation reporting events route from `routes.rb:166` are now explicitly tracked. 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, account agent-bot route/payload/mutation behavior, account webhook payload/mutation behavior, integration app/hook payload behavior, account Dyte create/join payload behavior, dashboard app raw payload/serializer behavior, canned response raw payload/search/delete behavior, notification subscription payload behavior, team update/frontend route behavior, conversation participant route/payload/final-set update behavior, conversation direct upload ActiveStorage behavior, conversation draft message Redis-key-equivalent behavior, conversation inbox assistant Copilot payload behavior, conversation reporting-event raw array behavior, label CRUD payloads, custom filters, custom attribute definitions, contact outbound voice calls, assignment policy CRUD and inbox binding payloads, Twilio inbound/status callbacks, enterprise Twilio voice callbacks, Linear/Shopify/Notion root integration callbacks, Shopify OAuth auth redirects, root channel OAuth callbacks, help-center portal/category/article payloads, dashboard app shell route behavior, app association JSON payloads, Cloudflare custom hostname verification, public widget popular-article lists, public help-center category list/show payloads, public portal show/default-locale payloads, public portal search payloads, public article show/markdown/tracking routes, and public sitemap XML now match the inspected Chatwoot contract. | Continue the next evidence-backed route/controller/serializer drift after conversation reporting-events parity or from B12 findings. | Regenerate parity artifacts when routes change and add endpoint-family fixture tests. |
|
|
|
|
|
| 2 | Phase 2/3 drift | Tracked route parity is 0 missing for the current 387-route critical set; dashboard `/app` shell routes from `routes.rb:19-20`, `.well-known` app association and custom-domain challenge routes from `routes.rb:657-660`, Twilio callback routes from `routes.rb:639-640`, enterprise Twilio voice routes from `routes.rb:643-646`, root Linear/Shopify/Notion OAuth callback routes from `routes.rb:630/634/654`, root Twitter/Google/Microsoft/Instagram/TikTok callback routes from `routes.rb:626/649-652`, assignment policy routes from `routes.rb:306-313`, help-center portal/category/article routes from `routes.rb:385-404`, public help-center portal/sitemap/article/category/search/article-detail routes from `routes.rb:590-601`, enterprise contact outbound voice call from `routes.rb:216`, account agent-bot routes from `routes.rb:94-97`, account webhook routes from `routes.rb:342`, account integration app/hook routes from `routes.rb:345-348`, account Dyte routes from `routes.rb:357-358`, dashboard app routes from `routes.rb:130`, canned response routes from `routes.rb:114`, notification subscription routes from `routes.rb:440`, team/team-member routes from `routes.rb:296-300`, conversation participant routes from `routes.rb:150`, conversation direct upload route from `routes.rb:151`, conversation draft message routes from `routes.rb:152`, conversation inbox assistant route from `routes.rb:165`, conversation reporting events route from `routes.rb:166`, and account reporting events route from `routes.rb:234` are now explicitly tracked. 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, account agent-bot route/payload/mutation behavior, account webhook payload/mutation behavior, integration app/hook payload behavior, account Dyte create/join payload behavior, dashboard app raw payload/serializer behavior, canned response raw payload/search/delete behavior, notification subscription payload behavior, team update/frontend route behavior, conversation participant route/payload/final-set update behavior, conversation direct upload ActiveStorage behavior, conversation draft message Redis-key-equivalent behavior, conversation inbox assistant Copilot payload behavior, conversation reporting-event raw array behavior, account reporting-events payload/filter/pagination behavior, label CRUD payloads, custom filters, custom attribute definitions, contact outbound voice calls, assignment policy CRUD and inbox binding payloads, Twilio inbound/status callbacks, enterprise Twilio voice callbacks, Linear/Shopify/Notion root integration callbacks, Shopify OAuth auth redirects, root channel OAuth callbacks, help-center portal/category/article payloads, dashboard app shell route behavior, app association JSON payloads, Cloudflare custom hostname verification, public widget popular-article lists, public help-center category list/show payloads, public portal show/default-locale payloads, public portal search payloads, public article show/markdown/tracking routes, and public sitemap XML now match the inspected Chatwoot contract. | Continue the next evidence-backed route/controller/serializer drift after account reporting-events parity or from B12 findings. | Regenerate parity artifacts when routes change and add endpoint-family fixture tests. |
|
|
|
|
|
| 3 | Phase 6 placeholder audit | Widget/public/webhook critical placeholders are burned down; inbox WhatsApp health/register-webhook and sync-template drift are closed; refreshed `docs/parity/placeholder_audit.md` shows only webhook nil-handler fallbacks still call `chatwootParityStub`; dashboard conversation transcript/custom-attribute response drift and message retry status drift are closed. | Keep in Review; reopen only if fresh `rg`, route smoke, or B12 finds a frontend-reachable placeholder/stub in account/contact/conversation/message/inbox/widget/public paths. | `rg` placeholder audit and `scripts/parity_frontend_smoke.sh --check` are recorded; no reused-frontend blocker is ownerless. |
|
|
|
|
|
| 4 | P3.9 account agent-bot API | Implemented for the reused dashboard AgentBots settings route with no-trailing-slash routes, PATCH update, raw Jbuilder-style payloads, account mutation scope, system-bot show/list visibility, empty `200 OK` delete, and full reset/avatar action payloads. | Keep in Review; reopen only if live settings smoke exposes avatar upload storage or administrator-secret gating drift. | Focused AgentBot handler tests, service/router focused tests, route dump/parity regeneration, full `go test ./...`, and `git diff --check` passed. |
|
|
|
|
|
| 5 | P3.10 account webhooks API | Implemented for the reused dashboard Webhooks settings route with PATCH update, Chatwoot `{ payload }` list/mutation serializers, nested `{ webhook: ... }` bodies, generated secret, account-scoped mutations, URL/subscription validation, optional inbox serialization, and empty `200 OK` delete. | Keep in Review; reopen only if live settings smoke exposes audit writer or delivery-signature drift beyond the existing delivery service boundary. | Focused webhook handler/service/router tests, migration test, route dump/parity regeneration, full `go test ./...`, and `git diff --check` passed. |
|
|
|
|
@@ -155,6 +155,7 @@ This table is the shortest authoritative handoff view. If an older lower section
|
|
|
|
|
| 14 | P3.19 conversation inbox assistant API | Implemented for reused dashboard Copilot state: `GET /conversations/:conversation_id/inbox_assistant` is tracked and registered, conversation lookup uses display ID with legacy ID fallback, account-scoped `captain_inboxes` binds the inbox to a Captain assistant, and responses are exactly `{ assistant: { id, name } }` or `{ assistant: null }`. | Keep in Review; reopen only if live conversation/Copilot smoke exposes feature-flag, authorization, or serializer drift beyond the inspected enterprise controller/store contract. | Focused ConversationCrud handler tests, service/router/route-parity tests, route dump/parity regeneration, full `go test ./...`, and `git diff --check` passed. |
|
|
|
|
|
| 15 | P3.20 conversation draft messages API | Implemented for Chatwoot's singular draft-message route: `GET/PATCH/PUT/DELETE /conversations/:conversation_id/draft_messages` are tracked and registered without a draft ID, conversation lookup uses display ID with legacy ID fallback, show returns raw `{ has_draft, message }`, update upserts the nested `draft_message.message`, and delete returns empty `200 OK`. | Keep in Review; reopen only if live conversation composer smoke exposes Redis-backed multi-agent or authorization drift beyond the inspected controller/spec contract. | Focused DraftMessage handler/service/repository/router/route-parity tests, route dump/parity regeneration, full `go test ./...`, and `git diff --check` passed. |
|
|
|
|
|
| 16 | P3.21 conversation reporting events API | Implemented for Chatwoot enterprise conversation reporting events: `GET /conversations/:conversation_id/reporting_events` is tracked and registered, conversation lookup uses display ID with legacy ID fallback, events are account/conversation scoped and ordered by `created_at ASC`, and the response is the raw `_reporting_event` array with `id/name/value/value_in_business_hours/event_start_time/event_end_time/account_id/inbox_id/user_id/conversation_id/created_at/updated_at`. | Keep in Review; reopen only if live enterprise conversation analytics smoke exposes pagination, authorization, or serializer drift beyond the inspected enterprise controller/Jbuilder contract. | Focused Conversation handler tests, combined handler/service/repository/router/route-parity tests, route dump/parity regeneration, full `go test ./...`, and `git diff --check` passed. |
|
|
|
|
|
| 17 | P3.22 account reporting events API | Implemented for Chatwoot enterprise account reporting events: `GET /reporting_events` is tracked and returns `{ payload, meta }`, accepts optional Unix `since/until`, `inbox_id`, `user_id`, and `name` filters, orders newest first, paginates at 25 rows per page, and serializes each row through the same `_reporting_event` field shape. | Keep in Review; reopen only if live enterprise reports/audit smoke exposes admin-authorization, includes, or date-range drift beyond the inspected controller/spec contract. | Focused ReportingEvent handler tests, combined handler/service/repository/router/route-parity tests, route parity regeneration, full `go test ./...`, and `git diff --check` passed. |
|
|
|
|
|
| 16 | P6.8 contact outbound voice call | Implemented for the reused dashboard route with Twilio voice-enabled inbox validation, assigned-inbox check, open-conversation reuse, ContactInbox/conversation/call/message persistence, and Chatwoot response shape. | Keep in Review; reopen only if live smoke exposes provider initiation/status-update drift beyond the fakeable persisted boundary. | Focused contact call tests, route dump/parity regeneration, full `go test ./...`, and `git diff --check` passed. |
|
|
|
|
|
| 17 | 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. |
|
|
|
|
|
| 18 | 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. |
|
|
|
|
@@ -191,6 +192,7 @@ These rows are the executable development plan from this point forward. A checkp
|
|
|
|
|
| P3.19 conversation inbox assistant API parity | `internal/router/router.go`, `internal/handler/api/v1/conversation_handler.go`, `internal/service/conversation_service.go`, conversation CRUD/service tests, `cmd/route_parity` | `reference/chatwoot/config/routes.rb:165`, `reference/chatwoot/enterprise/app/controllers/enterprise/api/v1/accounts/conversations_controller.rb`, `reference/chatwoot/app/javascript/dashboard/api/inbox/conversation.js`, `reference/chatwoot/app/javascript/dashboard/store/modules/conversations/actions.js`, conversation store mutation that writes `copilotAssistant` | Conversation inbox assistant now matches the reused dashboard Copilot sidebar contract: `GET /api/v1/accounts/:account_id/conversations/:conversation_id/inbox_assistant` is tracked and registered, resolves conversations by account display ID with legacy ID fallback, joins `captain_inboxes` to `captain_assistants` with account and inbox scope, serializes only assistant `id/name`, and returns `{ assistant: null }` when no assistant is bound. | Review by `feat(conversations): expose inbox assistant`; focused ConversationCrud handler tests cover bound, unbound, and display-ID lookup paths; service/router/route-parity tests pass; route dump/parity regenerated to `TOTAL: 928` and `368 exact, 13 parameter-compatible, 0 missing out of 381`; full `go test ./...` and `git diff --check` passed. |
|
|
|
|
|
| P3.20 conversation draft messages API parity | `internal/router/router.go`, `internal/handler/api/v1/draft_message_handler.go`, `internal/service/draft_message_service.go`, `internal/repository/draft_message_repo.go`, draft message handler tests, `cmd/route_parity` | `reference/chatwoot/config/routes.rb:152`, `reference/chatwoot/app/controllers/api/v1/accounts/conversations/draft_messages_controller.rb`, `reference/chatwoot/spec/controllers/api/v1/accounts/conversations/draft_messages_controller_spec.rb`, `reference/chatwoot/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue` local draft call sites for composer behavior context | Conversation draft messages now match Chatwoot's singular route contract: `GET/PATCH/PUT/DELETE /api/v1/accounts/:account_id/conversations/:conversation_id/draft_messages` are tracked and registered without `:draft_id`, show returns raw `{ has_draft: false }` or `{ has_draft: true, message }`, update accepts nested `{ draft_message: { message } }` and returns empty `200 OK`, delete clears the conversation draft and returns empty `200 OK`, and conversation resolution uses display ID with legacy ID fallback. Legacy local collection/id draft routes remain only compatibility aliases. | Review by `feat(conversations): align draft message route`; focused DraftMessage handler tests cover raw show/no-draft, nested update, empty delete, display-ID lookup, and legacy route compatibility; service/repository/router/route-parity tests pass; route dump/parity regenerated to `TOTAL: 932` and `372 exact, 13 parameter-compatible, 0 missing out of 385`; full `go test ./...` and `git diff --check` passed. |
|
|
|
|
|
| P3.21 conversation reporting events API parity | `internal/router/router.go`, `internal/handler/api/v1/conversation_handler.go`, `internal/service/conversation_service.go`, `internal/repository/reporting_event_repo.go`, conversation handler tests, `cmd/route_parity` | `reference/chatwoot/config/routes.rb:166`, `reference/chatwoot/enterprise/app/controllers/enterprise/api/v1/accounts/conversations_controller.rb`, `reference/chatwoot/enterprise/app/views/api/v1/accounts/conversations/reporting_events.json.jbuilder`, `reference/chatwoot/enterprise/app/views/api/v1/models/_reporting_event.json.jbuilder`, `reference/chatwoot/app/models/reporting_event.rb` | Conversation reporting events now match Chatwoot's enterprise member route boundary: `GET /api/v1/accounts/:account_id/conversations/:conversation_id/reporting_events` is tracked and registered, resolves conversations by account display ID with legacy ID fallback, scopes event rows by account and conversation, orders by `created_at ASC`, and serializes a raw array with nullable `inbox_id`, `user_id`, and `conversation_id` keys preserved. | Review by `feat(conversations): expose reporting events`; focused Conversation handler tests cover raw array shape, ascending order, display-ID lookup, invalid params, and cross-account non-leakage; route dump/parity regenerated to `TOTAL: 933` and `373 exact, 13 parameter-compatible, 0 missing out of 386`; full `go test ./...` and `git diff --check` passed. |
|
|
|
|
|
| P3.22 account reporting events API parity | `cmd/route_parity`, `internal/handler/api/v1/reporting_event_handler.go`, `internal/service/reporting_event_service.go`, `internal/repository/reporting_event_repo.go`, reporting event handler tests | `reference/chatwoot/config/routes.rb:234`, `reference/chatwoot/enterprise/app/controllers/api/v1/accounts/reporting_events_controller.rb`, `reference/chatwoot/enterprise/app/views/api/v1/accounts/reporting_events/index.json.jbuilder`, `reference/chatwoot/enterprise/app/views/api/v1/models/_reporting_event.json.jbuilder`, `reference/chatwoot/spec/enterprise/controllers/api/v1/accounts/reporting_events_controller_spec.rb`, `reference/chatwoot/app/helpers/date_range_helper.rb` | Account reporting events now match Chatwoot's enterprise index boundary: `GET /api/v1/accounts/:account_id/reporting_events` is tracked, returns raw `{ payload, meta: { count, current_page, total_pages } }`, filters by optional Unix timestamp `since/until`, `inbox_id`, `user_id`, and `name`, orders by `created_at DESC`, uses a fixed 25-row page size, and serializes event rows with nullable relation keys preserved. | Review by `feat(reporting): align account events`; focused ReportingEvent handler tests cover payload shape, ordering, combined filters, pagination, and invalid filters; route parity regenerated to `374 exact, 13 parameter-compatible, 0 missing out of 387`; full `go test ./...` and `git diff --check` passed. |
|
|
|
|
|
| P6.8 contact outbound voice call parity | `internal/router/router.go`, `internal/handler/api/v1/contact_handler.go`, `internal/service/contact_service.go`, `internal/model/call.go`, contact handler tests | `reference/chatwoot/config/routes.rb:216`, `reference/chatwoot/enterprise/app/controllers/api/v1/accounts/contacts/calls_controller.rb`, `reference/chatwoot/enterprise/app/services/voice/outbound_call_builder.rb`, `reference/chatwoot/enterprise/app/services/voice/call_message_builder.rb`, `reference/chatwoot/enterprise/app/models/call.rb`, dashboard `api/contacts.js`, `store/modules/contacts/actions.js`, `api/channel/voice/voiceAPIClient.js` | Contact outbound calls now match the Chatwoot enterprise route boundary: account contact lookup, current user's assigned `Channel::TwilioSms` inbox lookup, `voice_enabled` guard, phone-number guard, open display-ID conversation reuse only for same inbox/contact, new ContactInbox/open conversation creation when needed, persisted outgoing Twilio call metadata, linked `voice_call` message content attributes, and raw `{ conversation_id, inbox_id, call_sid, conference_sid }` response. | Review by `feat(contacts): initiate voice calls`; focused contact call tests cover success/reuse/resolved-hint ignored/no-phone/non-voice/unassigned cases; route dump/parity regenerated to `TOTAL: 861` and `299 exact, 7 parameter-compatible, 0 missing out of 306`; full `go test ./...` and `git diff --check` passed. |
|
|
|
|
|
| P6 conversation transcript response parity | `internal/handler/api/v1/conversation_handler.go`, conversation handler tests | `reference/chatwoot/app/controllers/api/v1/accounts/conversations_controller.rb`, dashboard `api/inbox/conversation.js` | Account conversation transcript now follows Chatwoot's controller contract: missing email returns `422 { error: "email param missing" }`, nonblank email schedules through the existing service boundary and returns empty `200 OK`, and invalid-looking but nonblank email values are not rejected by local email format validation. | Review by `feat(conversations): align transcript responses`; focused transcript handler/service tests, combined handler/service/router tests, full `go test ./...`, and `git diff --check` must pass. |
|
|
|
|
|
| P6 conversation custom attributes response parity | `internal/handler/api/v1/conversation_handler.go`, conversation handler tests | `reference/chatwoot/app/controllers/api/v1/accounts/conversations_controller.rb`, `app/views/api/v1/accounts/conversations/custom_attributes.json.jbuilder`, dashboard `api/inbox/conversation.js`, conversation store action | Account conversation custom attribute updates now return Chatwoot `{ custom_attributes: ... }` only, matching the store action that reads `response.data.custom_attributes`, instead of returning the full conversation serializer with unrelated fields. Empty/null JSON serializes as `{}`. | Review by `feat(conversations): align custom attribute response`; focused handler tests, combined handler/service/router tests, full `go test ./...`, and `git diff --check` passed. |
|
|
|
|
@@ -232,6 +234,7 @@ This ledger records the committed parity checkpoints that future slices should b
|
|
|
|
|
|
|
|
|
|
| Commit | Scope | Verification summary | Follow-up state |
|
|
|
|
|
| --- | --- | --- | --- |
|
|
|
|
|
| `feat(reporting): align account events` | Advances P3.22 account reporting-events parity by matching Chatwoot enterprise `Api::V1::Accounts::ReportingEventsController#index`, route `234`, `DateRangeHelper`, request specs, and the `_reporting_event` Jbuilder partial. GoChat now returns `{ payload, meta }` instead of the local success envelope, treats date filtering as optional Unix `since/until`, supports `inbox_id`, `user_id`, and `name` filters, orders by `created_at DESC`, paginates at Chatwoot's fixed 25 rows per page, and tracks the account route in route parity. | `go test ./internal/handler/api/v1 ./internal/service ./internal/repository ./internal/router ./cmd/route_parity -run 'ReportingEvent\|Router\|RouteParity' -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; full `go test ./...`; `git diff --check`. Route dump is `TOTAL: 933`; tracked route parity is `374 exact, 0 method-compatible, 13 parameter-compatible, 0 missing out of 387`. | P3.22 moves to Review for current enterprise account reporting-events evidence; continue Phase 2/3 drift audit, Phase 6 placeholder audit, B12 live smoke, or fresh reference/smoke drift. |
|
|
|
|
|
| `feat(conversations): expose reporting events` | Advances P3.21 conversation reporting-events parity by matching Chatwoot enterprise `Api::V1::Accounts::ConversationsController#reporting_events`, route `166`, and the `_reporting_event` Jbuilder partial. GoChat now registers and tracks `GET /api/v1/accounts/:account_id/conversations/:conversation_id/reporting_events`, resolves conversations by display ID with legacy ID fallback, scopes reporting events by account and conversation, orders by `created_at ASC`, and returns the raw Chatwoot array shape with nullable relation keys preserved. | `go test ./internal/handler/api/v1 ./internal/service ./internal/repository ./internal/router ./cmd/route_parity -run 'ReportingEvent\|Conversation\|Router\|RouteParity' -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; full `go test ./...`; `git diff --check`. Route dump is `TOTAL: 933`; tracked route parity is `373 exact, 0 method-compatible, 13 parameter-compatible, 0 missing out of 386`. | P3.21 moves to Review for current enterprise conversation reporting-event evidence; continue Phase 2/3 drift audit, Phase 6 placeholder audit, B12 live smoke, or fresh reference/smoke drift. |
|
|
|
|
|
| `feat(conversations): align draft message route` | Advances P3.20 conversation draft-message parity by matching Chatwoot `Api::V1::Accounts::Conversations::DraftMessagesController`, route `152`, and its request specs. GoChat now registers and tracks the singular `GET/PATCH/PUT/DELETE /api/v1/accounts/:account_id/conversations/:conversation_id/draft_messages` routes without a draft ID, resolves conversations by display ID with legacy ID fallback, models the Redis key behavior as one effective persisted draft per conversation, returns raw `{ has_draft, message }` show payloads, accepts nested `{ draft_message: { message } }` updates, and returns empty `200 OK` for update/delete. | `go test ./internal/handler/api/v1 ./internal/service ./internal/repository ./internal/router ./cmd/route_parity -run 'DraftMessage\|Router\|RouteParity' -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; full `go test ./...`; `git diff --check`. Route dump is `TOTAL: 932`; tracked route parity is `372 exact, 0 method-compatible, 13 parameter-compatible, 0 missing out of 385`. | P3.20 moves to Review for current conversation draft-message evidence; continue Phase 2/3 drift audit, Phase 6 placeholder audit, B12 live smoke, or fresh reference/smoke drift. |
|
|
|
|
|
| `feat(conversations): expose inbox assistant` | Advances P3.19 conversation inbox assistant parity by matching Chatwoot enterprise `Api::V1::Accounts::ConversationsController#inbox_assistant`, route `165`, and reused dashboard `api/inbox/conversation.js` plus conversation store Copilot assistant state. GoChat now registers and tracks `GET /api/v1/accounts/:account_id/conversations/:conversation_id/inbox_assistant`, resolves conversations by display ID with legacy ID fallback, account-scopes the inbox-to-Captain-assistant join through `captain_inboxes` and `captain_assistants`, returns only assistant `id/name`, and returns `{ assistant: null }` for unbound inboxes. | `go test ./internal/handler/api/v1 ./internal/service ./internal/router ./cmd/route_parity -run 'ConversationCrud\|Conversation\|Router\|RouteParity' -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; full `go test ./...`; `git diff --check`. Route dump is `TOTAL: 928`; tracked route parity is `368 exact, 0 method-compatible, 13 parameter-compatible, 0 missing out of 381`. | P3.19 moves to Review for current conversation Copilot assistant evidence; continue Phase 2/3 drift audit, Phase 6 placeholder audit, B12 live smoke, or fresh reference/smoke drift. |
|
|
|
|
@@ -2425,3 +2428,4 @@ Verification milestone gates:
|
|
|
|
|
- 2026-06-06: P3.19 conversation inbox assistant checkpoint prepared as `feat(conversations): expose inbox assistant`; audited Chatwoot enterprise conversation `inbox_assistant`, route `165`, and reused dashboard conversation API/store Copilot assistant state. GoChat now exposes and tracks `GET /api/v1/accounts/:account_id/conversations/:conversation_id/inbox_assistant`, resolves conversations by display ID with legacy ID fallback, looks up the account-scoped Captain assistant bound to the conversation inbox, and returns `{ assistant: { id, name } }` or `{ assistant: null }`. Focused ConversationCrud handler/service/router/route-parity tests, route dump/parity regeneration (`TOTAL: 928`, `368 exact`, `13 parameter-compatible`, `0 missing out of 381`), full `go test ./...`, and `git diff --check` passed; continue Phase 2/3 drift audit, Phase 6 placeholder audit, or B12 live smoke.
|
|
|
|
|
- 2026-06-06: P3.20 conversation draft message checkpoint prepared as `feat(conversations): align draft message route`; audited Chatwoot singular draft message route/controller/specs. GoChat now exposes and tracks `GET/PATCH/PUT/DELETE /api/v1/accounts/:account_id/conversations/:conversation_id/draft_messages` without a draft ID, resolves conversations by display ID with legacy ID fallback, persists one effective draft per conversation, returns raw `{ has_draft, message }` show payloads, accepts nested `draft_message.message`, and returns empty `200 OK` for update/delete. Focused DraftMessage handler/service/repository/router/route-parity tests, route dump/parity regeneration (`TOTAL: 932`, `372 exact`, `13 parameter-compatible`, `0 missing out of 385`), full `go test ./...`, and `git diff --check` passed; continue Phase 2/3 drift audit, Phase 6 placeholder audit, or B12 live smoke.
|
|
|
|
|
- 2026-06-06: P3.21 conversation reporting events checkpoint prepared as `feat(conversations): expose reporting events`; audited Chatwoot enterprise conversation `reporting_events`, route `166`, and `_reporting_event` Jbuilder serializer. GoChat now exposes and tracks `GET /api/v1/accounts/:account_id/conversations/:conversation_id/reporting_events`, resolves conversations by display ID with legacy ID fallback, scopes raw reporting-event rows by account and conversation, orders by `created_at ASC`, and returns the raw Chatwoot event array with nullable relation keys preserved. Focused Conversation handler tests, route dump/parity regeneration (`TOTAL: 933`, `373 exact`, `13 parameter-compatible`, `0 missing out of 386`), full `go test ./...`, and `git diff --check` passed; continue Phase 2/3 drift audit, Phase 6 placeholder audit, or B12 live smoke.
|
|
|
|
|
- 2026-06-06: P3.22 account reporting events checkpoint prepared as `feat(reporting): align account events`; audited Chatwoot enterprise account reporting events controller/specs, route `234`, `DateRangeHelper`, and `_reporting_event` Jbuilder serializer. GoChat now returns `{ payload, meta }`, accepts optional Unix `since/until`, `inbox_id`, `user_id`, and `name` filters, orders account reporting events by `created_at DESC`, uses fixed 25-row pagination, and tracks the account reporting-events route. Focused ReportingEvent handler tests and route parity regeneration (`TOTAL: 933`, `374 exact`, `13 parameter-compatible`, `0 missing out of 387`) passed; full `go test ./...` and `git diff --check` passed.
|
|
|
|
|