feat(agents): align serializer fields

This commit is contained in:
2026-06-06 11:05:34 +08:00
parent ade1a8e0d7
commit b8db9d41f5
3 changed files with 11 additions and 14 deletions
+8 -6
View File
@@ -49,10 +49,10 @@ Hermes task landing checklist:
## Current Baseline
- Current tracking checkpoint: 2026-06-06 after this implementation checkpoint, prepared as `feat(assignment-policies): align chatwoot payloads`.
- Latest implementation checkpoint: this checkpoint, prepared as `feat(assignment-policies): align chatwoot payloads`.
- Current tracking checkpoint: 2026-06-06 after this implementation checkpoint, prepared as `feat(agents): align serializer fields`.
- Latest implementation checkpoint: this checkpoint, prepared as `feat(agents): align serializer fields`.
- Latest documentation/tooling checkpoint: this checkpoint, prepared as `docs: record placeholder smoke audit`; this document is now the active follow-up plan and supersedes `.hermes/plans/*`.
- Worktree status at this documentation checkpoint: Chatwoot assignment policy drift from `routes.rb:306-313`, account assignment policy controllers, nested policy inbox controllers, inbox assignment policy controllers, Jbuilder views, and the reused frontend `assignmentPolicies` API/store is implemented. Phase 6 placeholder audit is refreshed in `docs/parity/placeholder_audit.md`: the only remaining `chatwootParityStub` call sites are public webhook nil-handler guards, not reused dashboard account/contact/conversation/message/inbox, widget, public help-center, public API, or enterprise settings critical paths. B12 harness readiness check passed in `docs/parity/frontend_smoke_report.md`; live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack. Next active implementation slice is B12 live smoke finding, P3.2 account users/invitations drift from fresh reference evidence, or another route/controller/serializer drift opened from current `reference/chatwoot` inspection.
- Worktree status at this implementation checkpoint: P3.2 account agents serializer drift from `app/views/api/v1/models/_agent.json.jbuilder` is implemented. Account agent list/create/show/update responses now expose only the Chatwoot `_agent` fields plus enterprise `custom_role_id`, and no longer leak local `invited_by` or `account_user_id` membership fields. Phase 6 placeholder audit remains in Review; B12 live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack. Next active implementation slice is B12 live smoke finding, remaining P3.2 account users/invitations drift from fresh reference evidence, or another route/controller/serializer drift opened from current `reference/chatwoot` inspection.
- `go test ./...` passes.
- Route dump succeeds with `TOTAL: 906` after adding Chatwoot no-trailing-slash assignment policy routes.
- Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`.
@@ -209,6 +209,7 @@ This ledger records the committed parity checkpoints that future slices should b
| Commit | Scope | Verification summary | Follow-up state |
| --- | --- | --- | --- |
| `feat(agents): align serializer fields` | Advances P3.2 agents serializer parity by matching Chatwoot `app/views/api/v1/models/_agent.json.jbuilder`. GoChat account agent list/create/show/update payloads now return only `id`, `account_id`, `availability_status`, `auto_offline`, `confirmed`, `email`, `provider`, `available_name`, optional `custom_attributes`, `name`, `role`, `thumbnail`, and enterprise `custom_role_id`; local `invited_by` and `account_user_id` fields are no longer emitted. | `go test ./internal/handler/api/v1 -run 'TestAgentHandlerSuite/TestCreateAgent\|TestAgentHandlerSuite/TestListAfterCreate\|TestAgentHandlerSuite/TestGetAgent' -count=1`; `go test ./internal/handler/api/v1 -run AgentHandler -count=1`; `go test ./internal/service ./internal/repository ./internal/router -run Agent -count=1`; sandboxed full `go test ./...` failed only on local socket/miniredis/httptest restrictions; escalated full `go test ./...` passed; `git diff --check`. | Agent serializer field shape moves to Review for current reference evidence; continue remaining P3.2 account users/invitations drift or B12 live smoke. |
| `docs: record placeholder smoke audit` | Documentation/tooling checkpoint for Phase 6 and B12 readiness. Adds `docs/parity/placeholder_audit.md`, classifies remaining `chatwootParityStub` call sites as public webhook nil-handler guards only, refreshes `docs/parity/frontend_smoke_report.md`, and moves Phase 6 placeholder burn-down to Review for the inspected account/contact/conversation/message/inbox/widget/public critical paths. | `rg -n "chatwootParityStub" internal/handler internal/service internal/router internal/channel`; `rg -n "chatwootParityStub" internal/router/router.go | wc -l`; `bash -n scripts/parity_frontend_smoke.sh`; `scripts/parity_frontend_smoke.sh --check`; `scripts/parity_frontend_smoke.sh --print`; `git diff --check`. | Continue B12 live API/browser/enterprise smoke when the full stack is available; otherwise continue the next evidence-backed P2/P3 serializer/controller drift such as P3.2 account users/invitations. |
| `feat(assignment-policies): align chatwoot payloads` | Advances P4.9/Phase 2/3 assignment policy parity by matching Chatwoot `AssignmentPoliciesController`, `AssignmentPolicies::InboxesController`, `Inboxes::AssignmentPoliciesController`, Jbuilder views, frontend `assignmentPolicies` API/store usage, and `routes.rb:306-313`. GoChat now registers no-trailing-slash Chatwoot assignment policy routes, persists Chatwoot assignment policy fields, returns raw array/object payloads, accepts raw and nested request bodies, exposes assigned inbox counts, replaces inbox policy associations, lists policy inboxes as `{ inboxes: [...] }`, and returns empty `200 OK` deletes. | `go test ./internal/handler/api/v1 -run AssignmentPolicy -count=1`; `go test ./internal/service ./internal/repository ./internal/router ./internal/app ./cmd/migrate ./cmd/route_parity -count=1`; sandboxed full `go test ./...` failed only on local socket restrictions, escalated full `go test ./...` passed; `git diff --check`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`. Route dump is `TOTAL: 906`; tracked route parity remains `353 exact, 0 method-compatible, 9 parameter-compatible, 0 missing out of 362`. | Assignment policies move to Review for current reference evidence; continue Phase 6 placeholder audit, B12 live smoke, or the next evidence-backed route/controller/serializer drift. |
| `feat(channels): expose oauth callbacks` | Advances Phase 2/3 root channel callback parity by matching Chatwoot `Twitter::CallbacksController#show`, `Google::CallbacksController#show`, `Microsoft::CallbacksController#show`, `Instagram::CallbacksController#show`, `Tiktok::CallbacksController#show`, and `routes.rb:626/649-652`. GoChat now registers `/twitter/callback`, `/google/callback`, `/microsoft/callback`, `/instagram/callback`, and `/tiktok/callback`; Google/Microsoft callbacks exchange OAuth codes and create/update email inboxes from ID-token mailbox identity; Instagram/TikTok/Twitter callbacks create/update channel inboxes and preserve Chatwoot success/error redirect paths for reused frontend onboarding/settings flows. | `go test ./internal/router -run 'ChannelCallbacks\|IntegrationCallbacks\|RegisterRoutes' -count=1`; `go test ./cmd/route_parity -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`. Route dump is `TOTAL: 900`; tracked route parity is `353 exact, 0 method-compatible, 9 parameter-compatible, 0 missing out of 362`. | Root channel callbacks move to Review for current reference evidence; continue Phase 6 placeholder audit, B12 live smoke, or the next evidence-backed route/controller/serializer drift. |
@@ -244,7 +245,7 @@ This ledger records the committed parity checkpoints that future slices should b
| `feat(campaigns): derive chatwoot scheduling` | Advances P3.7 campaign behavior parity beyond response envelopes by matching Chatwoot `Campaign#ensure_correct_campaign_attributes`, `campaign_params`, and the reused SMS/WhatsApp/live-chat campaign forms. Create no longer requires frontend-absent `campaign_type`; SMS/Twilio/WhatsApp inboxes derive one-off campaigns, persist ISO `scheduled_at`, and default missing schedules to current UTC; web-widget/live-chat inboxes derive ongoing campaigns and clear schedules; update accepts frontend `inbox_id`, `sender_id`, and `scheduled_at`, preserves omitted descriptions, reloads nested inbox/sender data, and validates inbox/sender account scope. | `go test ./internal/handler/api/v1 -run CampaignHandler -count=1`; `go test ./internal/service ./internal/repository -run Campaign -count=1`; full `go test ./...`; `git diff --check`. No route changes; route dump remains `TOTAL: 846`. | Continue Phase 6 placeholder audit or the next named Phase 2/3 drift from reference/smoke evidence. |
| `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 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, and custom-role metadata behind the Chatwoot `_agent` serializer. | `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. |
| `feat(agents): align delete scope` | Advances P3.2 agents/settings parity by matching Chatwoot `AgentsController#fetch_agent` before `destroy`: deletes are scoped through current account membership and return `404` when the target user is not an agent in the account. The local delete path now looks up the `AccountUser` before deletion so cross-account/non-member users are not accidentally deleted. | `go test ./internal/handler/api/v1 -run 'TestAgentHandlerSuite/TestDeleteAgent' -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 duplicate create errors` | Advances P3.2 agents/settings parity by matching Chatwoot's `ActiveRecord::RecordInvalid` handling for duplicate account memberships created through `AgentsController#create`. Re-inviting an existing account member now returns `422 { message: "User has already been taken", attributes: ["user_id"] }` instead of the local `409` conflict envelope, while bulk invite continues to skip duplicate failures like the reference controller. | `go test ./internal/handler/api/v1 -run 'TestAgentHandlerSuite/TestCreateAgentDuplicate' -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. |
@@ -252,7 +253,7 @@ This ledger records the committed parity checkpoints that future slices should b
| `feat(attachments): align list pagination` | Advances Phase 6 dashboard/CRM attachment drift by matching Chatwoot `ConversationsController#attachments`, `Contacts::AttachmentsController#index`, and the shared attachment Jbuilder payloads. Conversation and contact attachment lists now page with the reference fixed 100-row limit from `ATTACHMENT_RESULTS_PER_PAGE`/`RESULTS_PER_PAGE` and ignore reused-frontend `per_page` query values, while retaining newest-first attachment ordering and `{ meta: { total_count }, payload }` responses. | `go test ./internal/handler/api/v1 -run 'Test(ConversationHandlerTestSuite|ContactHandlerCRUDTestSuite)/TestListAttachments' -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 the next named Phase 2/3 or Phase 6 drift from reference/smoke evidence. |
| `feat(profile): align account permissions` | Advances P3.1/P3.2 profile and permission parity by matching Chatwoot `api/v1/models/_user.json.jbuilder`, `AccountUser#permissions`, and the enterprise custom-role prepend used by dashboard route guards. Profile account entries now expose ordinary role permissions as `["administrator"]` or `["agent"]`, and custom-role memberships expose the role's permission keys plus `custom_role` while retaining nested `custom_role` metadata. | `go test ./internal/handler/api/v1 -run ProfileHandler -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 permissions/invitations drift or the next Phase 6 reference/smoke finding. |
| `feat(platform): align account user membership` | Advances P3.2 platform account-user parity by matching `Platform::Api::V1::AccountUsersController`. Platform account-user index/create now return raw AccountUser JSON instead of the local `{ success, data }` envelope, create uses Chatwoot `find_or_initialize_by(user_id).update!` semantics so duplicate membership requests update role instead of failing, and the Chatwoot collection route `DELETE /platform/api/v1/accounts/:account_id/account_users/destroy?user_id=...` is registered while the legacy `/:user_id` alias remains. | `go test ./internal/handler/api/v1 -run PlatformAccountUser -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; `go test ./internal/handler/api/v1 ./internal/repository ./internal/router -count=1`; `go test ./...`; `git diff --check`. Route dump is `TOTAL: 840`; tracked route parity remains `270 exact, 7 parameter-compatible, 0 missing`. | Continue P3.2 permissions/invitations drift or the next Phase 6 reference/smoke finding. |
| `feat(agents): align list ordering` | Advances P3.2 agents/settings parity by matching Chatwoot `AgentsController#index`, which renders `Current.account.users.order_by_full_name`. Account agent lists now order by `lower(users.name) ASC` before pagination while preserving account-user role, availability, auto-offline, inviter, account-user ID, and custom-role metadata. | `go test ./internal/handler/api/v1 -run AgentHandler -count=1`; `go test ./internal/handler/api/v1 ./internal/service ./internal/router -count=1`; `go test ./...`; `git diff --check`. No route changes; route dump remains `TOTAL: 839`. | Continue P3.2 account users/invitations/permissions drift or the next Phase 6 reference/smoke finding. |
| `feat(agents): align list ordering` | Advances P3.2 agents/settings parity by matching Chatwoot `AgentsController#index`, which renders `Current.account.users.order_by_full_name`. Account agent lists now order by `lower(users.name) ASC` before pagination while preserving account-user role, availability, auto-offline, and custom-role data behind the Chatwoot `_agent` serializer. | `go test ./internal/handler/api/v1 -run AgentHandler -count=1`; `go test ./internal/handler/api/v1 ./internal/service ./internal/router -count=1`; `go test ./...`; `git diff --check`. No route changes; route dump remains `TOTAL: 839`. | Continue P3.2 account users/invitations/permissions drift or the next Phase 6 reference/smoke finding. |
| `feat(agents): align update route semantics` | Advances P3.2 agents/settings parity by aligning update with Chatwoot `AgentsController#update` and the reused dashboard `ApiClient.update` path. Agent update now exposes `PATCH /api/v1/accounts/:account_id/agents/:agent_id` alongside the existing `PUT` alias, accepts nested `{ agent: ... }` payloads, preserves `auto_offline` when the field is omitted, and still applies explicit `auto_offline: false` like Rails strong params with `compact`. | `go test ./internal/handler/api/v1 -run AgentHandler -count=1`; `go test ./internal/service -run Agent -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; `go test ./internal/handler/api/v1 ./internal/service ./internal/router -count=1`; `go test ./...`; `git diff --check`. Route dump is `TOTAL: 839`; tracked route parity remains `270 exact, 7 parameter-compatible, 0 missing`. | Continue P3.2 account users/invitations/permissions drift or the next Phase 6 reference/smoke finding. |
| `feat(agents): align bulk invite behavior` | Advances P3.2 agents/onboarding parity by aligning `POST /api/v1/accounts/:account_id/agents/bulk_create` with Chatwoot `AgentsController#bulk_create`. Bulk invite now treats the email list as a best-effort loop: invalid entries are skipped instead of failing the whole request, duplicate failures remain ignored, empty arrays return empty `200 OK`, valid agents in the same request are still created, and the local onboarding step is cleared after the bulk flow. | `go test ./internal/handler/api/v1 -run AgentHandler -count=1`; `go test ./internal/service -run Agent -count=1`; `go test ./internal/handler/api/v1 ./internal/service ./internal/router -count=1`; `go test ./...`; `git diff --check`. | Continue P3.2 account users/invitations/permissions drift or the next Phase 6 reference/smoke finding. |
| `feat(custom-roles): align update route semantics` | Advances B10.3 CustomRole frontend parity by registering Chatwoot's Rails resource `PATCH /api/v1/accounts/:account_id/custom_roles/:id` update route used by the reused `ApiClient.update` path, while keeping the existing `PUT` alias. Custom role updates now distinguish omitted `description` from an explicit empty string, so the enterprise settings form can clear descriptions like `CustomRolesController#update` with strong params. | `go test ./internal/handler/api/v1 -run CustomRole -count=1`; `go test ./internal/service -run CustomRole -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; `go test ./internal/handler/api/v1 ./internal/service ./internal/router -count=1`; `go test ./...`; `git diff --check`. | Continue the next named Phase 2/3 or Phase 6 drift from reference/smoke evidence. |
@@ -1673,7 +1674,7 @@ Frontend-critical API groups to audit first:
| ID | Area | Scope | Status |
| --- | --- | --- | --- |
| P3.1 | Auth/session/profile | Login, logout, current user, profile, availability, notification settings, Devise password reset, and confirmation. | Done; profile account permission arrays and user notification-settings raw payloads now match Chatwoot role/custom-role semantics and dashboard settings store expectations. |
| P3.2 | Accounts/users/teams | Account settings, users, agents, teams, team members, invitations, roles, permissions. | Doing; account show/update/create/cache-key/active-at plus agents/teams/team-member, assignable-agent settings payloads, profile account permission arrays, platform account-user raw/idempotent membership, agents `order_by_full_name` ordering with Chatwoot no-pagination index behavior, agents bulk invite best-effort behavior, and agent update PATCH/`auto_offline`/validation semantics now have focused Chatwoot-style coverage. |
| P3.2 | Accounts/users/teams | Account settings, users, agents, teams, team members, invitations, roles, permissions. | Doing; account show/update/create/cache-key/active-at plus agents/teams/team-member, assignable-agent settings payloads, profile account permission arrays, platform account-user raw/idempotent membership, agents `_agent` serializer fields, `order_by_full_name` ordering with Chatwoot no-pagination index behavior, agents bulk invite best-effort behavior, and agent update PATCH/`auto_offline`/validation semantics now have focused Chatwoot-style coverage. |
| P3.3 | Inboxes/channels | Inbox CRUD, assignable agents, avatars, channel config, business hours, widget config. | Review; assignable-agent payload drift closed, broader inbox serializer drift remains evidence-driven. |
| 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, avatars, and shared attachments. | Doing; company multipart avatar create/update and fixed 25-row company pagination now match the reused dashboard companies store/API path. |
@@ -2365,3 +2366,4 @@ Verification milestone gates:
- 2026-06-06: Root channel callback checkpoint prepared as `feat(channels): expose oauth callbacks`; audited Chatwoot `Twitter::CallbacksController`, `Google::CallbacksController`, `Microsoft::CallbacksController`, `Instagram::CallbacksController`, `Tiktok::CallbacksController`, shared OAuth callback behavior, and routes `626/649-652`. GoChat now exposes `/twitter/callback`, `/google/callback`, `/microsoft/callback`, `/instagram/callback`, and `/tiktok/callback`; callbacks exchange OAuth tokens through configurable provider endpoints, create/update email/social channel inboxes, and redirect successful or failed flows to Chatwoot dashboard inbox agents/settings/new-inbox paths. Focused channel callback/router/route-parity tests and route dump/parity regeneration passed; continue Phase 6 placeholder audit, B12 live smoke, or the next evidence-backed route/controller/serializer drift.
- 2026-06-06: Assignment policy payload checkpoint prepared as `feat(assignment-policies): align chatwoot payloads`; audited Chatwoot account assignment policy controllers, nested assignment-policy inbox controllers, inbox assignment policy controllers, Jbuilder views, reused dashboard assignment policy API/store, and routes `306-313`. GoChat now returns raw Chatwoot assignment policy arrays/objects, accepts raw and nested request bodies, persists Chatwoot policy fields, exposes assigned inbox counts, replaces inbox policy associations, lists policy inboxes as `{ inboxes: [...] }`, and returns empty `200 OK` deletes. Focused AssignmentPolicy tests, service/repository/router/app/migrate/route-parity packages, escalated full `go test ./...`, route dump `TOTAL: 906`, route parity `353 exact, 0 method-compatible, 9 parameter-compatible, 0 missing out of 362`, and `git diff --check` passed; continue Phase 6 placeholder audit, B12 live smoke, or the next evidence-backed drift.
- 2026-06-06: Placeholder/smoke audit checkpoint prepared as `docs: record placeholder smoke audit`; `docs/parity/placeholder_audit.md` now records the `chatwootParityStub` audit and classifies all remaining call sites as public webhook nil-handler guards, with no reused dashboard account/contact/conversation/message/inbox/widget/public critical-path stubs. `scripts/parity_frontend_smoke.sh --check` passed and refreshed `docs/parity/frontend_smoke_report.md`; live API/browser/enterprise smoke remains pending on the full external stack. Continue B12 live smoke when available or the next evidence-backed P2/P3 drift.
- 2026-06-06: P3.2 agent serializer-field checkpoint prepared as `feat(agents): align serializer fields`; audited Chatwoot `AgentsController` Jbuilder views and `app/views/api/v1/models/_agent.json.jbuilder`. Account agent list/create/show/update responses now remove local `invited_by` and `account_user_id` fields and keep only Chatwoot `_agent` fields plus enterprise `custom_role_id`, preserving account-user role, availability, auto-offline, and custom-role behavior behind the serializer. Focused agent handler/service/repository/router tests, escalated full `go test ./...`, and `git diff --check` passed; continue remaining P3.2 account users/invitations drift or B12 live smoke.
+1 -8
View File
@@ -244,14 +244,7 @@ func serializeAgentDetail(agent *repository.AgentDetail, accountID uint) map[str
if agent == nil {
return map[string]any{}
}
payload := serializeAgentUser(&agent.User, accountID, agent.Role, agent.Availability, agent.AutoOffline, agent.CustomRoleID)
if agent.InvitedBy != 0 {
payload["invited_by"] = agent.InvitedBy
}
if agent.AccountUserID != 0 {
payload["account_user_id"] = agent.AccountUserID
}
return payload
return serializeAgentUser(&agent.User, accountID, agent.Role, agent.Availability, agent.AutoOffline, agent.CustomRoleID)
}
func serializeAgentUser(user *model.User, accountID uint, role string, availability string, autoOffline bool, customRoleID uint) map[string]any {
@@ -179,6 +179,8 @@ func (s *AgentHandlerTestSuite) TestCreateAgent() {
assert.Equal(s.T(), "offline", data["availability_status"])
assert.Equal(s.T(), float64(7), data["custom_role_id"])
assert.Contains(s.T(), data, "confirmed")
assert.NotContains(s.T(), data, "invited_by")
assert.NotContains(s.T(), data, "account_user_id")
}
func (s *AgentHandlerTestSuite) TestCreateAgentDefaultsBlankNameFromEmail() {