From 330f875f954bd1617a989381d4193add80177912 Mon Sep 17 00:00:00 2001 From: Rogee Date: Fri, 5 Jun 2026 07:50:14 +0800 Subject: [PATCH] docs: record applied sla reports checkpoint --- docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md | 50 +++++++++++++----------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md b/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md index 024b32bb..01a78370 100644 --- a/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md +++ b/docs/CHATWOOT_PARITY_DEVELOPMENT_PLAN.md @@ -16,13 +16,13 @@ Build GoChat as a Go backend that can directly reuse the frontend from `referenc ## Current Baseline -- Latest implementation checkpoint: `213bf2b feat(sla): make sla breach events idempotent`. -- Latest documentation checkpoint before this update: `85da0be docs: record applied sla persistence checkpoint`. -- Worktree status at this planning checkpoint: clean after the matching implementation checkpoint; next active slice is B7 applied-SLA report/list payload parity. +- Latest implementation checkpoint: `4f85ef1 feat(sla): align applied sla reports`. +- Latest documentation checkpoint before this update: `0c6cf1d docs: record sla breach lifecycle checkpoint`. +- Worktree status at this planning checkpoint: clean after the matching implementation checkpoint; next active slice is B7 SLA business-hours and notification parity review. - `go test ./...` passes. -- Route dump succeeds with `TOTAL: 829` after adding Chatwoot-compatible nested AgentCapacityPolicy users and inbox-limit routes. +- Route dump succeeds with `TOTAL: 830` after adding the Chatwoot-compatible applied-SLA index route. - Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`. -- Tracked frontend-critical route audit covers 274 Chatwoot routes: 267 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. +- 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. - 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. @@ -35,7 +35,7 @@ Build GoChat as a Go backend that can directly reuse the frontend from `referenc | Phase 1 | Meilisearch search engine | Review | B6 payload parity, optional live gate, and DB-fallback hardening are implemented; an actual live Meilisearch run is optional and environment-dependent | | Phase 2 | Route and controller parity audit | Doing | Ruby/Bundler unavailable, so Chatwoot route extraction currently uses static `routes.rb` fallback | | Phase 3 | Data and serializer parity | Doing | JSON fixture coverage is partial and still endpoint-family based | -| Phase 4 | Enterprise feature completion | Doing | B7 assignment capacity, SLA policy CRUD payload parity, applied-SLA conversation persistence, and idempotent SLA breach events are implemented; applied-SLA report/list payload parity remains active | +| Phase 4 | Enterprise feature completion | Doing | B7 assignment capacity, SLA policy CRUD payload parity, applied-SLA conversation persistence, idempotent SLA breach events, and applied-SLA report/list payload parity are implemented; business-hours/notification depth remains active | | Phase 5 | Background jobs and integrations | Planned | durable worker choice and job parity are open | | Phase 6 | Core placeholder burn-down | Doing | account/contact/conversation/message/inbox placeholder groups remain broad | | Phase 7 | Verification harness | Planned | search live gate and reused-frontend smoke harness are not complete | @@ -99,12 +99,13 @@ This ledger records the committed parity checkpoints that future slices should b | `95224fa feat(sla): align sla policy payloads` | Completed B7.2 SLA policy CRUD payload parity for the reused Chatwoot frontend: create/show/update now return `{ payload: sla_policy }`, index returns `{ payload: [...] }`, destroy returns empty `200 OK`, and the SLA policy serializer emits only the fields from Chatwoot's enterprise SLA policy partial. | `go test ./internal/handler/api/v1 -run SlaPolicy -count=1`; `go test ./internal/service -run Sla -count=1`; `go test ./internal/handler/api/v1 -count=1`; `go test ./...`; `git diff --check`. No route changes; route dump remains `TOTAL: 829`. | Continue B7.3 with applied-SLA persistence for new/open conversations, then B7.4 timer/breach lifecycle. | | `a11bb96 feat(sla): persist applied sla on conversations` | Completed the first B7.3 applied-SLA persistence slice: conversation create/update now accept Chatwoot enterprise `sla_policy_id`, validate account ownership and replacement/removal rules, create one `applied_slas` row when a policy is attached, keep status-only updates idempotent for existing SLA conversations, and serialize `applied_sla` in conversation payloads using Chatwoot's applied-SLA partial fields. | `go test ./internal/service -run 'ConversationService_.*Sla\|ConversationService_Update\|ConversationService_Create' -count=1`; `go test ./internal/handler/api/v1 -run 'ConversationCrudTestSuite/Test(Update_WithSlaPolicy\|Update_Success\|Create_Success)' -count=1`; `go test ./internal/service -run 'Conversation\|AppliedSla\|Sla' -count=1`; `go test ./internal/handler/api/v1 -run 'ConversationCrudTestSuite\|SlaPolicy' -count=1`; `go test ./internal/service -count=1`; `go test ./internal/handler/api/v1 -count=1`; `go test ./...`; `git diff --check`. No route changes; route dump remains `TOTAL: 829`. | Continue B7.4 with idempotent SLA event/timer lifecycle and then B7.5 applied-SLA report/list payload parity. | | `213bf2b feat(sla): make sla breach events idempotent` | Completed B7.4 timer/breach lifecycle core parity: SLA thresholds now use Chatwoot seconds units, FRT/NRT/RT checks treat the exact threshold as breached, missed events are idempotent by `applied_sla_id`, `event_type`, and `meta`, NRT events store the last incoming message ID in `meta`, and resolved active/active-with-misses applied SLAs transition to `hit` or `missed`. | `go test ./internal/service -run 'AppliedSlaService\|ConversationService_Create_AppliesSlaPolicy' -count=1`; `go test ./internal/handler/api/v1 -run 'SlaPolicy\|ConversationCrudTestSuite/TestUpdate_WithSlaPolicy' -count=1`; `go test ./internal/service -run 'AppliedSla\|Sla\|Conversation' -count=1`; `go test ./internal/handler/api/v1 -run 'SlaPolicy\|ConversationCrudTestSuite' -count=1`; `go test ./internal/service -count=1`; `go test ./internal/handler/api/v1 -count=1`; `go test ./...`; `git diff --check`. No route changes; route dump remains `TOTAL: 829`. | Continue B7.5 with applied-SLA report/list payload parity, then review notifications/business-hours depth. | +| `4f85ef1 feat(sla): align applied sla reports` | Completed B7.5 applied-SLA report/list payload parity for the reused Chatwoot SLA reports screen: added `GET /api/v1/accounts/:account_id/applied_slas`, aligned the index `{ payload, meta }` shape, filtered missed reports by date/inbox/team/SLA policy/label/assignee, returned Chatwoot applied-SLA/conversation/SLA-event fields, changed metrics to raw `total_applied_slas`, `number_of_sla_misses`, and `hit_rate`, and changed download to the breached-conversation CSV. | `go test ./internal/service -run 'SlaPolicyService_.*AppliedSla\|AppliedSlaReport' -count=1`; `go test ./internal/handler/api/v1 -run 'SlaPolicyHandler_.*AppliedSla' -count=1`; `go test ./internal/service -count=1`; `go test ./internal/handler/api/v1 -count=1`; `go run ./cmd/dump_routes > docs/parity/gochat_routes.txt`; `go run ./cmd/route_parity`; `go test ./...`; `go test ./cmd/route_parity -count=1`; `git diff --check`. Route dump is now `TOTAL: 830`; route parity tracks 277 routes with 270 exact, 7 parameter-compatible, and 0 missing. | Continue B7 with business-hours timer math and SLA notification delivery review before closing the SLA package. | ## Next Slice Contract -Completed implementation slice: B5.1-B5.5 now cover inbox serializer shape, Chatwoot frontend create/update binding, working-hours persistence, out-of-office behavior, inbox member assignment payload/mutation semantics, channel-specific config depth, AgentCapacityPolicy/InboxCapacityLimit API data contracts, and dedicated Email/Twilio/LINE channel route response shapes. B6 is now in Review after `a16c23c` and `f08c743`: Chatwoot search response envelopes, frontend query params, Meilisearch sender filters, mocked hit serialization, env-gated live Meilisearch validation, release-mode DB fallback rejection, and reindex Meilisearch-only guard are covered. B7 has started with `a98dc2c`, `95224fa`, `a11bb96`, and `213bf2b`, enforcing per-inbox capacity limits, aligning SLA policy CRUD payloads, persisting applied SLA records, and making core FRT/NRT/RT breach events idempotent. B3 and B4 remain in review for deeper side effects and browser validation. +Completed implementation slice: B5.1-B5.5 now cover inbox serializer shape, Chatwoot frontend create/update binding, working-hours persistence, out-of-office behavior, inbox member assignment payload/mutation semantics, channel-specific config depth, AgentCapacityPolicy/InboxCapacityLimit API data contracts, and dedicated Email/Twilio/LINE channel route response shapes. B6 is now in Review after `a16c23c` and `f08c743`: Chatwoot search response envelopes, frontend query params, Meilisearch sender filters, mocked hit serialization, env-gated live Meilisearch validation, release-mode DB fallback rejection, and reindex Meilisearch-only guard are covered. B7 has started with `a98dc2c`, `95224fa`, `a11bb96`, `213bf2b`, and `4f85ef1`, enforcing per-inbox capacity limits, aligning SLA policy CRUD payloads, persisting applied SLA records, making core FRT/NRT/RT breach events idempotent, and aligning the applied-SLA reports API. B3 and B4 remain in review for deeper side effects and browser validation. -Next implementation slice: continue B7 with applied-SLA report/list payload parity. +Next implementation slice: continue B7 with business-hours timer math and SLA notification delivery review. | Step | Required result | Reference source | Verification | | --- | --- | --- | --- | @@ -114,8 +115,9 @@ Next implementation slice: continue B7 with applied-SLA report/list payload pari | N4 | Keep SLA policy CRUD payload review as current SLA API baseline. | `reference/chatwoot/enterprise/app/controllers/api/v1/accounts/sla_policies_controller.rb`, SLA policy Jbuilder views, dashboard SLA store/API. | Done by `95224fa`; create/show/update/index/delete payloads match the frontend-consumed Chatwoot shape. | | N5 | Keep applied-SLA persistence as current conversation SLA baseline. | `reference/chatwoot/enterprise/app/models/enterprise/concerns/conversation.rb`, `AppliedSla#push_event_data`, applied-SLA model partial. | Done by `a11bb96`; `sla_policy_id` attach creates exactly one applied SLA and conversation payloads include Chatwoot-style `applied_sla`. | | N6 | Keep SLA timer and breach lifecycle as current SLA lifecycle baseline. | `reference/chatwoot/enterprise/app/services/sla/evaluate_applied_sla_service.rb`, `SlaEvent`, SLA processing jobs. | Done by `213bf2b`; active applied SLAs create idempotent FRT/NRT/RT miss events, transition to `active_with_misses`, `hit`, or `missed`, and preserve status on repeated evaluation. | -| N7 | Add applied-SLA report/list payload parity. | `reference/chatwoot/enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb`, applied-SLA index/metrics/download views, dashboard SLA reports client. | Account-side applied-SLA list/report filters return frontend-compatible payloads and metrics/download shapes. | -| N8 | Update this tracker after every implementation checkpoint. | This document. | `git diff --check`; `go test ./...` for Go changes. | +| N7 | Keep applied-SLA report/list payload parity as the current SLA reports baseline. | `reference/chatwoot/enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb`, applied-SLA index/metrics/download views, dashboard SLA reports client. | Done by `4f85ef1`; account-side applied-SLA list/report filters return frontend-compatible payloads and metrics/download shapes. | +| N8 | Review business-hours timer math and SLA notification delivery. | `Sla::EvaluateAppliedSlaService`, `SlaEvent#create_notifications`, business-hours helpers/jobs. | SLA timers respect `only_during_business_hours`, and breach notifications are emitted with Chatwoot-compatible actors/types or explicitly tracked as a remaining job gap. | +| N9 | Update this tracker after every implementation checkpoint. | This document. | `git diff --check`; `go test ./...` for Go changes. | Current B2 profile checkpoint: @@ -172,7 +174,7 @@ Current B5 inbox/channel checkpoint: - Inbox show/create/update/reset-secret style responses now render raw Chatwoot inbox payloads rather than raw Go models; delete returns `Your inbox deletion request will be processed in some time.` and avatar delete returns an empty `200 OK`. - Local channel slugs are serialized to frontend-required Rails channel class names such as `Channel::WebWidget`, `Channel::Api`, `Channel::Telegram`, and `Channel::TwilioSms`. - Channel-specific fields stored in `channel_config` are surfaced in the inbox payload for web widget, API, Telegram, Facebook/Instagram/TikTok, Twilio, Email, and WhatsApp-style keys. -- Added the frontend-used `PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id` route alias; the current route dump is now `TOTAL: 829` after later capacity routes, and tracked route parity remains regenerated with zero missing tracked routes. +- Added the frontend-used `PATCH /api/v1/accounts/:account_id/inboxes/:inbox_id` route alias; the current route dump is now `TOTAL: 830` after later capacity and applied-SLA report routes, and tracked route parity remains regenerated with zero missing tracked routes. - Chatwoot dashboard create/update request bodies now bind through the generic inbox route for JSON, urlencoded forms, and multipart FormData. The binder accepts top-level inbox settings, nested `channel[...]`, `channel[selected_feature_flags][]`, and nested `csat_config[...]` values generated by `buildInboxData`. - Create/update now persists greeting/email collection/CSAT/auto-assignment/timezone/post-resolve/single-conversation/sender/business settings, stores channel-specific fields in `channel_config`, generates web widget `website_token`/`hmac_token`, generates API `secret`/`hmac_token`/identifier, and derives a Telegram inbox name when the frontend omits `name`. - Inbox create/update now follows Chatwoot's `OutOfOffisable` schedule lifecycle: default seven-day working hours are created for new inboxes, `working_hours` updates persist the weekly relation, empty string time fields from the frontend are normalized, open-all-day rows are expanded to `00:00`-`23:59`, and the serializer returns `weekly_schedule` shape from the relation. @@ -301,7 +303,8 @@ Active B7 task board: | B7.2 | Align SLA policy CRUD payloads and validation. | `sla_policies_controller.rb`, SLA frontend store/API, SLA policy views/entities. | Done | `95224fa`; handler tests prove Chatwoot request wrapper, raw `{ payload }`/list shapes, validation, and empty `200 OK` delete status. | | B7.3 | Persist applied SLA on new/open conversations. | Chatwoot applied SLA model/services and conversation create/status callbacks. | Done | `a11bb96`; `sla_policy_id` create/update creates one applied SLA, validates policy/account/replacement rules, and serializes conversation `applied_sla`. | | B7.4 | Implement SLA timer and breach lifecycle. | First response, next response, resolution targets, business-hours behavior, SLA events/notifications. | Done | `213bf2b`; lifecycle tests cover FRT/NRT miss idempotency, NRT message meta, hit, missed, and active-with-misses transitions. | -| B7.5 | Add SLA report/list payload parity. | `applied_slas` routes, SLA report frontend. | Todo | Account-side applied-SLA list/report filters return frontend-compatible payloads. | +| B7.5 | Add SLA report/list payload parity. | `applied_slas` routes, SLA report frontend. | Done | `4f85ef1`; account-side applied-SLA index/metrics/download filters return frontend-compatible payloads and breached-conversation CSV. | +| B7.6 | Review business-hours timer math and SLA notifications. | Business-hours helpers, SLA event notification creation, processing jobs. | Todo | `only_during_business_hours` timers and SLA breach notifications match Chatwoot or have explicit deferred job gaps. | B7 execution breakdown: @@ -312,11 +315,12 @@ B7 execution breakdown: | B7.3a | Determine applied-SLA policy attachment behavior from Chatwoot callbacks/services and map it to Go conversation create/update/open flows. | `Enterprise::Concerns::Conversation`, `Enterprise::Api::V1::Accounts::ConversationsController#permitted_update_params`, `AppliedSLA`. | Service tests prove explicit `sla_policy_id` attachment, account validation, replacement rejection, and no duplicate applied SLA rows. | Done by `a11bb96` | | B7.3b | Persist `applied_slas` and link `conversations.sla_policy_id` when a conversation enters an SLA-covered state. | Applied SLA model and serializer views. | Conversation create/update tests assert `applied_slas`, `conversations.sla_policy_id`, initial active status, and frontend `applied_sla` payload fields. | Done by `a11bb96` | | B7.4a | Implement first-response, next-response, and resolution target state transitions with idempotent SLA events. | `Sla::EvaluateAppliedSlaService`, `SlaEvent`, SLA processing jobs and event model. | Lifecycle tests cover active, hit, missed, active-with-misses, NRT `message_id` meta, exact-threshold breach behavior, and duplicate-event prevention. | Done by `213bf2b` | -| B7.5a | Add the Chatwoot account applied-SLA index route and handler if the Go route surface is missing it. | `reference/chatwoot/enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb#index`, dashboard SLA reports client. | Route artifacts are regenerated only if a route is added; handler tests prove `GET /api/v1/accounts/:account_id/applied_slas` returns the expected envelope. | Todo | -| B7.5b | Align applied-SLA index filters and pagination. | `AppliedSlasController#index`, `applied_slas/index.json.jbuilder`, frontend SLA reports filters. | Tests cover `status`, `sla_policy_id`, `inbox_id`, `team_id`, `assigned_agent_id`, `label_list`, `since`, `until`, and Chatwoot's missed scope semantics (`missed` plus `active_with_misses`). | Todo | -| B7.5c | Align applied-SLA list item serializers. | `api/v1/models/_applied_sla.json.jbuilder`, `_sla_event.json.jbuilder`, conversation/report Jbuilder views. | Tests assert `applied_sla`, `conversation`, `sla_events`, SLA policy names/descriptions/threshold fields, Unix timestamps, event `meta`, and no local response envelope. | Todo | -| B7.5d | Align applied-SLA metrics and download payloads used by the frontend reports. | `applied_slas_controller.rb#metrics/#download`, `metrics.json.jbuilder`, dashboard reports API. | Handler/service tests assert metric keys, hit/miss math, shared filters, CSV/download shape, and frontend field names. | Todo | -| B7.5e | Update this tracker and commit immediately after the applied-SLA report/list implementation checkpoint. | This document. | Commit ledger row, B7 status changes, verification commands, and route counts if changed. | Todo | +| B7.5a | Add the Chatwoot account applied-SLA index route and handler if the Go route surface is missing it. | `reference/chatwoot/enterprise/app/controllers/api/v1/accounts/applied_slas_controller.rb#index`, dashboard SLA reports client. | Route artifacts are regenerated only if a route is added; handler tests prove `GET /api/v1/accounts/:account_id/applied_slas` returns the expected envelope. | Done by `4f85ef1` | +| B7.5b | Align applied-SLA index filters and pagination. | `AppliedSlasController#index`, `applied_slas/index.json.jbuilder`, frontend SLA reports filters. | Tests cover `sla_policy_id`, `inbox_id`, `team_id`, `assigned_agent_id`, `label_list`, `since`, `until`, and Chatwoot's missed scope semantics (`missed` plus `active_with_misses`). | Done by `4f85ef1` | +| B7.5c | Align applied-SLA list item serializers. | `api/v1/models/_applied_sla.json.jbuilder`, `_sla_event.json.jbuilder`, conversation/report Jbuilder views. | Tests assert `applied_sla`, `conversation`, `sla_events`, SLA policy names/descriptions/threshold fields, Unix timestamps, event `meta`, and no local response envelope. | Done by `4f85ef1` | +| B7.5d | Align applied-SLA metrics and download payloads used by the frontend reports. | `applied_slas_controller.rb#metrics/#download`, `metrics.json.jbuilder`, dashboard reports API. | Handler/service tests assert metric keys, hit/miss math, shared filters, CSV/download shape, and frontend field names. | Done by `4f85ef1` | +| B7.5e | Update this tracker and commit immediately after the applied-SLA report/list implementation checkpoint. | This document. | Commit ledger row, B7 status changes, verification commands, and route counts if changed. | Done by this documentation checkpoint | +| B7.6a | Audit and implement remaining business-hours timer math and SLA notifications. | `Sla::EvaluateAppliedSlaService`, `SlaEvent#create_notifications`, SLA processing jobs. | Focused lifecycle/notification tests cover business-hours policies and notification fan-out. | Todo | B7.5 implementation notes: @@ -410,7 +414,7 @@ Remaining slice landing plan: | Slice | First implementation checkpoint | Follow-up checkpoints | Done classification rule | | --- | --- | --- | --- | | B6 | Compare current Meilisearch document fields and global/entity search payloads against Chatwoot frontend consumers. | Add optional live Meilisearch integration gate, tighten account-scoped filters, and document DB fallback as development-only. | Done only after mocked tests and live-shape review prove search payloads work without DB-only assumptions. | -| B7 | Done: assignment capacity enforcement, SLA policy CRUD payload parity, applied-SLA conversation persistence, and idempotent SLA breach lifecycle. Next: applied-SLA report/list payload parity. | Business-hours timer math, deeper notification delivery, capacity-aware assignment policy binding, report/list payloads. | Done only after report/list payloads and remaining business-hours/notification checks are covered. | +| B7 | Done: assignment capacity enforcement, SLA policy CRUD payload parity, applied-SLA conversation persistence, idempotent SLA breach lifecycle, and applied-SLA report/list payload parity. Next: business-hours and notification depth. | Business-hours timer math, deeper notification delivery, and capacity-aware assignment policy binding review. | Done only after remaining business-hours/notification checks are covered or explicitly deferred with job boundaries. | | B8 | Account-side CSAT list/metrics/review-note payload parity. | Resolve-triggered survey send idempotency, report/download filters, public/update lock regression, channel-specific send hooks. | Done only after account APIs, public APIs, and resolve listener agree on one message-linked response model. | | B9 | Macro execution side effects for labels, status, assignee/team, priority, private notes, and attachments. | Automation rule condition/action parity, execution logs, webhook delivery retry, email transcript delivery, stop-on-match semantics. | Done only after actions mutate real conversations and async external actions are retryable or explicitly feature-gated. | | B10 | Audit list payload and audit writer boundary for representative mutating core resources. | CustomRole permission-key parity, AccountUser permission resolution, InboxLimit enforcement in inbox/channel creation paths. | Done only after authorization tests prove admin-only surfaces and non-admin denial shapes match Chatwoot. | @@ -549,7 +553,7 @@ Current Phase 2 route findings: | Type | Count | Required action | | --- | --- | --- | -| Exact tracked critical routes | 267 | Keep covered while expanding audit scope. | +| Exact tracked critical routes | 270 | Keep covered while expanding audit scope. | | Method-compatible update routes | 0 | First tracked batch now has exact Rails-compatible method coverage. | | Parameter-compatible routes | 7 | Nested AgentCapacityPolicy user/inbox-limit routes use Gin-internal parameter names while preserving external path shape. | | Missing tracked critical routes | 0 | Current tracked frontend-critical route set has no route-level gaps. | @@ -568,6 +572,7 @@ Expanded tracked groups now covered by route parity: | Captain/Copilot | Assistants, assistant inboxes/scenarios, assistant responses, bulk actions, copilot threads/messages, custom tools, documents, preferences, and tasks. | | Assignment policies | Account assignment policies, nested inbox bindings, and inbox assignment policy routes. | | Agent capacity policies | Account policy CRUD plus nested users and inbox capacity limits from `routes.rb:123-127`. | +| Applied SLA reports | Account applied-SLA index, metrics, and download routes from `routes.rb:228-231`. | | Widget API | Chatwoot `/api/v1/widget/*` route surface plus legacy `/widget/*` compatibility. | | Public API | Public inbox contact/conversation/message routes and public CSAT survey route. | | Reports v2 | `/api/v2/accounts/:account_id` summary reports, reports, and live reports. | @@ -686,7 +691,7 @@ Enterprise tracking table: | ID | Feature | Existing Go surface | Required next work | Status | | --- | --- | --- | --- | --- | -| P4.1 | SLA policies/events | `internal/model/sla_policy.go`, `internal/model/sla_event.go`, `internal/service/sla_policy_service.go`, `internal/service/applied_sla_service.go`, `internal/service/sla_event_service.go`, `internal/handler/api/v1/sla_policy_handler.go` | SLA policy CRUD, applied-SLA conversation attach, and idempotent core breach lifecycle are done; next align applied-SLA reports, business-hours timers, and notification delivery. | Doing | +| P4.1 | SLA policies/events | `internal/model/sla_policy.go`, `internal/model/sla_event.go`, `internal/service/sla_policy_service.go`, `internal/service/applied_sla_service.go`, `internal/service/sla_event_service.go`, `internal/handler/api/v1/sla_policy_handler.go` | SLA policy CRUD, applied-SLA conversation attach, idempotent core breach lifecycle, and applied-SLA reports are done; next align business-hours timers and notification delivery. | Doing | | P4.2 | Audit logs | `internal/model/audit.go`, `internal/service/audit_service.go`, `internal/repository/audit_repo.go`, `internal/handler/api/v1/audit_handler.go` | Ensure every mutating enterprise/core action emits audit events and filters match Chatwoot. | Todo | | P4.3 | Custom roles/permissions | `internal/model/custom_role.go`, `internal/service/custom_role_service.go`, `internal/middleware/role_check.go`, `internal/handler/api/v1/custom_role_handler.go` | Align permission keys, inherited roles, authorization failures, and admin UX payloads. | Todo | | P4.4 | Agent capacity | `internal/model/agent_capacity_policy.go`, `internal/service/agent_capacity_policy_service.go`, `internal/handler/api/v1/agent_capacity_handler.go`, `internal/autoassignment/*` | First align AgentCapacityPolicy API, serializers, nested users, and `InboxCapacityLimit` data contracts; then enforce capacity in manual/auto assignment. | Review | @@ -700,7 +705,7 @@ Enterprise work package breakdown: | Package | Subtasks | Must verify | Status | | --- | --- | --- | --- | -| SLA | Policy CRUD parity, conversation SLA assignment, first-response/next-response/resolution timers, business-hours handling, breach events, notifications. | Policy payloads, applied-SLA attach, seconds-based thresholds, core state transitions, and breach idempotency are covered; report payloads, business hours, and notifications remain. | Doing | +| SLA | Policy CRUD parity, conversation SLA assignment, first-response/next-response/resolution timers, business-hours handling, breach events, notifications. | Policy payloads, applied-SLA attach, seconds-based thresholds, core state transitions, breach idempotency, and report payloads are covered; business hours and notifications remain. | Doing | | Assignment and capacity | Assignment policy CRUD, inbox policy binding, round-robin/availability/capacity selection, manual assignment limits, fallback behavior. | Manual and automatic assignment respect policy, availability, team/inbox membership, and limits. | Review | | CSAT account side | Survey send on resolve, response list, metrics, filters, downloads, review notes, resend/idempotency, public lock already implemented. | Account API payload fixtures, metrics math, 14-day lock, one response per CSAT message. | Todo | | Automation rules | Condition/action parity, event listener coverage, delayed actions, execution logs, stop-on-match behavior, webhook and transcript actions. | Rule trigger tests for conversation/contact/message events and durable retry for external actions. | Todo | @@ -714,7 +719,7 @@ Enterprise acceptance gates: | Feature | Required gates before `Done` | Reference notes | | --- | --- | --- | -| SLA | Field names and units match Chatwoot; `only_during_business_hours` exists; policy CRUD payloads match the enterprise Jbuilder views; applied SLA is created when `sla_policy_id` is attached; FRT/NRT/RT breach events are idempotent; remaining report/business-hours/notification behavior matches Rails. | `docs/verification/SLA_ASSIGNMENT_POLICY_V2_COMPATIBILITY_REPORT.md`, `docs/requirements/M11-enterprise-features.md` | +| SLA | Field names and units match Chatwoot; `only_during_business_hours` exists; policy CRUD payloads match the enterprise Jbuilder views; applied SLA is created when `sla_policy_id` is attached; FRT/NRT/RT breach events are idempotent; report index/metrics/download payloads match Rails; remaining business-hours/notification behavior matches Rails. | `docs/verification/SLA_ASSIGNMENT_POLICY_V2_COMPATIBILITY_REPORT.md`, `docs/requirements/M11-enterprise-features.md` | | Audit | Mutating account resources emit audit records with actor, IP, request UUID, auditable type/id, associated account, and changes; admin list pagination matches Chatwoot. | `docs/requirements/M11-enterprise-features.md` | | CustomRole | Permission keys match Chatwoot; `AccountUser` permission resolution honors custom roles; deleting a role nullifies users; admin-only policy is enforced. | `docs/requirements/M1-accounts-and-users.md`, `docs/requirements/M11-enterprise-features.md` | | AgentCapacity and InboxLimit | Assignment and auto-assignment respect per-inbox conversation limits; account/inbox limits are enforced in create paths and surfaced to frontend. | `docs/requirements/M1-accounts-and-users.md`, `docs/requirements/M5-team-and-assignment.md` | @@ -922,3 +927,4 @@ Verification milestone gates: - 2026-06-05: B7 SLA policy payload checkpoint committed as `95224fa feat(sla): align sla policy payloads`; SLA policy create/show/update now return `{ payload: sla_policy }`, index returns `{ payload: [...] }`, destroy returns empty `200 OK`, and the serializer is limited to Chatwoot's enterprise SLA policy fields. Focused SLA policy handler tests, SLA service tests, handler package tests, full `go test ./...`, and `git diff --check` passed. Next B7 checkpoint is applied-SLA persistence for new/open conversations. - 2026-06-05: B7 applied-SLA persistence checkpoint committed as `a11bb96 feat(sla): persist applied sla on conversations`; conversation create/update now accepts `sla_policy_id`, validates SLA policy account ownership plus Chatwoot replacement/removal rules, creates exactly one active `applied_slas` record, keeps status-only updates idempotent for existing SLA conversations, and includes Chatwoot-style `applied_sla` payload fields in conversation responses. Focused conversation/SLA service and handler tests, full `go test ./...`, and `git diff --check` passed. Next B7 checkpoint is SLA timer/breach lifecycle with idempotent FRT/NRT/RT events. - 2026-06-05: B7 SLA breach lifecycle checkpoint committed as `213bf2b feat(sla): make sla breach events idempotent`; SLA thresholds now use Chatwoot seconds units, exact-threshold checks count as breached, FRT/NRT/RT miss events are idempotent by applied SLA, event type, and meta, NRT events store last incoming `message_id`, and resolved applied SLAs transition to `hit` or `missed`. Focused applied-SLA lifecycle tests, handler SLA/conversation tests, full `go test ./...`, and `git diff --check` passed. Next B7 checkpoint is applied-SLA report/list payload parity. +- 2026-06-05: B7 applied-SLA reports checkpoint committed as `4f85ef1 feat(sla): align applied sla reports`; account applied-SLA index/metrics/download now match Chatwoot's reports controller and frontend SLA reports API, including missed-only table/download semantics, shared filters, `{ payload, meta }` index shape, raw metrics keys, and breached-conversation CSV. Focused applied-SLA service/handler tests, service and handler package tests, full `go test ./...`, route dump `TOTAL: 830`, route parity `270 exact, 7 parameter-compatible, 0 missing`, `go test ./cmd/route_parity -count=1`, and `git diff --check` passed. Next B7 checkpoint is business-hours timer math and SLA notification delivery review.