|
|
|
@@ -49,12 +49,12 @@ Hermes task landing checklist:
|
|
|
|
|
|
|
|
|
|
## Current Baseline
|
|
|
|
|
|
|
|
|
|
- Current tracking checkpoint: 2026-06-07 P3.68 contact filter payload parity, prepared as `feat(contacts): align filter payloads`.
|
|
|
|
|
- Latest implementation checkpoint: this checkpoint, prepared as `feat(contacts): align filter payloads`.
|
|
|
|
|
- Latest documentation/tooling checkpoint: this tracker update records Chatwoot `Contacts::FilterService` payload behavior for standard, additional, label, date, and custom contact attributes. No route artifacts change.
|
|
|
|
|
- Current tracking checkpoint: 2026-06-07 P3.69 contact resolved-scope parity, prepared as `feat(contacts): align resolved scope`.
|
|
|
|
|
- Latest implementation checkpoint: this checkpoint, prepared as `feat(contacts): align resolved scope`.
|
|
|
|
|
- Latest documentation/tooling checkpoint: this tracker update records Chatwoot `Contact.resolved_contacts` behavior for contact index, filter, and export scopes. No route artifacts change.
|
|
|
|
|
- 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: contact filter payload conditions now follow Chatwoot `Contacts::FilterService` for `name`, `email`, `phone_number`, `identifier`, `blocked`, additional attributes `country_code`, `city`, `company_name`, contact labels, `created_at`, `last_activity_at`, query-operator validation, and account-scoped contact custom attributes with null-inclusive `not_equal_to`. Existing P3.64-P3.67 conversation filter payload parity, P3.63 search message-order parity, P3.62 trimmed search payload fields, P3.61 sender-name, P3.60 numeric message-type parity, and prior report/profile/channel/contact checkpoints remain implemented. Live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack.
|
|
|
|
|
- Next executable implementation checkpoint: continue Phase 2/3 drift audit for remaining message filters, conversation permission-filter depth, contact filter frontend/reference drift such as frontend-only `referer`, or the next reused-frontend mismatch; or run B12 live smoke when the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack is available. Re-run Phase 6 placeholder audit after future route/smoke changes.
|
|
|
|
|
- Worktree status at this implementation checkpoint: contact index, filter, and export scopes now follow Chatwoot `Contact.resolved_contacts`: default CRM surfaces include only contacts with email, phone number, or identifier, while `crm_v2` accounts include only `contact_type = lead`. Existing P3.68 contact filter payload parity, P3.64-P3.67 conversation filter payload parity, P3.63 search message-order parity, P3.62 trimmed search payload fields, P3.61 sender-name, P3.60 numeric message-type parity, and prior report/profile/channel/contact checkpoints remain implemented. Live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack.
|
|
|
|
|
- Next executable implementation checkpoint: continue Phase 2/3 drift audit for remaining contact search/global-search resolved-contact drift, message filters, conversation permission-filter depth, contact filter frontend/reference drift such as frontend-only `referer`, or the next reused-frontend mismatch; or run B12 live smoke when the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack is available. Re-run Phase 6 placeholder audit after future route/smoke changes.
|
|
|
|
|
- `go test ./...` passes when run outside the restricted socket sandbox for the latest implementation baseline; the latest docs/tooling checkpoint verified `scripts/parity_frontend_smoke.sh --check` with workspace-local temp/cache dirs after `/tmp` was full.
|
|
|
|
|
- Route dump succeeds with `967` registered routes after profile MFA route tracking.
|
|
|
|
|
- Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`.
|
|
|
|
@@ -156,6 +156,7 @@ This table is the shortest authoritative handoff view. If an older lower section
|
|
|
|
|
|
|
|
|
|
| Priority | Workstream | Current state | Next checkpoint | Commit close rule |
|
|
|
|
|
| --- | --- | --- | --- | --- |
|
|
|
|
|
| 0 | P3.69 contact resolved-scope parity | Implemented for reused CRM contact index/filter/export flows: GoChat now applies Chatwoot `Contact.resolved_contacts` before listing, advanced filtering, and export selection. Default CRM scope keeps contacts with email, phone number, or identifier; `crm_v2` scope keeps only `contact_type = lead`. | Keep in Review; reopen from B12 CRM smoke or fresh reference evidence for contact search/global search resolved-scope drift, CRM v2 feature-flag serialization, or import paths creating unexpected contact types. | Focused contact repository and handler tests, contact regression tests, full `go test ./...`, and `git diff --check` must pass. No route artifacts change. |
|
|
|
|
|
| 0 | P3.68 contact filter payload parity | Implemented for reused CRM contact advanced filters: `POST /contacts/filter` now accepts Chatwoot `{ payload: [...] }` conditions for standard contact fields, additional contact attributes, labels, dates, query operators, and account-scoped contact custom attributes. | Keep in Review; reopen from B12 CRM filter smoke or fresh reference evidence for frontend-only `referer`, exact PostgreSQL JSON/date casting drift, or contact `base_relation` CRM v2 resolved-contact scope. | Focused contact filter handler tests, contact repository/service/handler regression tests, full `go test ./...`, and `git diff --check` must pass. No route artifacts change. |
|
|
|
|
|
| 0 | P3.67 conversation filter standard-operator parity | Implemented for reused dashboard advanced conversation filters: `{ payload: [...] }` now covers Chatwoot standard conversation operators for labels, presence checks, display-id contains, and date comparisons/days-before on `created_at` and `last_activity_at`. | Keep in Review; reopen from B12 filter smoke or fresh reference evidence for message filters, contact custom attributes inside conversation filters, or full `Conversations::PermissionFilterService` depth. | Focused conversation filter handler tests, full `go test ./...`, and `git diff --check` must pass. No route artifacts change. |
|
|
|
|
|
| 0 | P3.66 conversation filter attribute parity | Implemented for reused dashboard advanced conversation filters: `{ payload: [...] }` now supports Chatwoot conversation additional attributes from `filter_keys.yml` and account-scoped conversation custom attributes, including text/list/link case handling and `not_equal_to` matching rows where the custom attribute is absent. | Keep in Review; reopen from B12 filter smoke or fresh reference evidence for message filters, contact custom attributes inside conversation filters, or full `Conversations::PermissionFilterService` depth. | Focused conversation filter handler tests, full `go test ./...`, and `git diff --check` must pass. No route artifacts change. |
|
|
|
|
@@ -231,6 +232,7 @@ These rows are the executable development plan from this point forward. A checkp
|
|
|
|
|
|
|
|
|
|
| ID | Owner files | Reference files | Work to land | Exit gate |
|
|
|
|
|
| --- | --- | --- | --- | --- |
|
|
|
|
|
| P3.69 contact resolved-scope parity | `internal/repository/contact_repo.go`, `internal/repository/contact_repo_test.go`, `internal/handler/api/v1/contact_handler_crud_test.go` | `reference/chatwoot/app/models/contact.rb#resolved_contacts`, `reference/chatwoot/spec/models/contact_spec.rb`, `reference/chatwoot/app/controllers/api/v1/accounts/contacts_controller.rb#index/#filter`, `reference/chatwoot/app/jobs/account/contacts_export_job.rb`, `reference/chatwoot/app/services/contacts/filter_service.rb#base_relation` | Contact list, advanced filter, and export queries now share Chatwoot's resolved-contact base relation. Without `crm_v2`, anonymous contacts lacking email, phone number, and identifier are excluded from CRM index/filter/export surfaces. With `crm_v2`, only `contact_type = lead` is included, so lead-only contacts remain visible while customer/visitor records are hidden from those scopes. | Review by `feat(contacts): align resolved scope`; focused repository tests assert default resolved scope, CRM v2 lead-only scope, and export resolved scope; handler tests assert list scope and CRM v2 list behavior; full `go test ./...` and `git diff --check`. No route artifacts change. |
|
|
|
|
|
| P3.68 contact filter payload parity | `internal/repository/contact_repo.go`, `internal/handler/api/v1/contact_handler.go`, `internal/handler/api/v1/contact_handler_crud_test.go` | `reference/chatwoot/app/services/contacts/filter_service.rb`, `reference/chatwoot/app/services/filter_service.rb`, `reference/chatwoot/app/helpers/filters/filter_helper.rb`, `reference/chatwoot/app/services/filters/custom_attribute_filter_helper.rb`, `reference/chatwoot/lib/filters/filter_keys.yml`, `reference/chatwoot/app/javascript/dashboard/components-next/filter/contactProvider.js` | Contact filter now accepts the reused CRM `{ payload: [...] }` body, validates `query_operator`, returns raw `422 { error }` for payload validation failures, normalizes phone numbers and case-insensitive values like Chatwoot, supports standard contact fields, additional attributes `country_code`, `city`, `company_name`, labels, date comparisons/days-before, and account-scoped contact custom attributes with null-inclusive `not_equal_to`. Backend reference excludes frontend-only `referer`, so it remains a tracked drift candidate rather than a silently accepted local extension. | Review by `feat(contacts): align filter payloads`; focused contact filter handler tests assert standard/additional filters, labels plus date filters, custom-attribute `not_equal_to` null inclusion, and invalid attribute errors; full `go test ./...` and `git diff --check`. No route artifacts change. |
|
|
|
|
|
| P3.67 conversation filter standard-operator parity | `internal/service/conversation_service.go`, `internal/handler/api/v1/conversation_handler_crud_test.go` | `reference/chatwoot/lib/filters/filter_keys.yml`, `reference/chatwoot/app/services/filter_service.rb#filter_operation`, `reference/chatwoot/app/services/filter_service.rb#tag_filter_query`, `reference/chatwoot/app/services/filter_service.rb#lt_gt_filter_query`, `reference/chatwoot/app/services/conversations/filter_service.rb` | Conversation filter payload now supports Chatwoot standard filter operators beyond the P3.64 basics: `assignee_id`, `inbox_id`, `team_id`, and `campaign_id` support equality plus present/absent checks; `display_id` supports contains/does-not-contain through text casting; `labels` uses account tag joins with equal/not-equal/present/absent semantics; `created_at` and `last_activity_at` support greater-than, less-than, and days-before. | Review by `feat(conversations): align standard filters`; focused filter handler tests assert presence filters, label joins, display-id contains with date filters, last-activity days-before, full `go test ./...`, and `git diff --check`. No route artifacts change. |
|
|
|
|
|
| P3.66 conversation filter attribute parity | `internal/service/conversation_service.go`, `internal/handler/api/v1/conversation_handler_crud_test.go` | `reference/chatwoot/lib/filters/filter_keys.yml`, `reference/chatwoot/app/helpers/filters/filter_helper.rb#handle_additional_attributes`, `reference/chatwoot/app/services/filters/custom_attribute_filter_helper.rb`, `reference/chatwoot/app/services/filter_service.rb#filter_operation`, `reference/chatwoot/app/services/conversations/filter_service.rb` | Conversation filter payload now supports additional-attribute keys `browser_language`, `conversation_language`, `referer`, and `mail_subject` with Chatwoot operator sets, dialect-aware JSON extraction, case-insensitive contains checks, and account-scoped conversation custom attribute definitions. Custom `not_equal_to` includes conversations where the custom attribute key is absent, matching Chatwoot's appended `IS NULL` behavior. | Review by `feat(conversations): align filter attributes`; focused filter handler tests assert additional-attribute equality, additional-attribute contains, and custom-attribute `not_equal_to` null inclusion; full `go test ./...` and `git diff --check` must pass. No route artifacts change. |
|
|
|
|
@@ -324,6 +326,7 @@ This ledger records the committed parity checkpoints that future slices should b
|
|
|
|
|
|
|
|
|
|
| Commit | Scope | Verification summary | Follow-up state |
|
|
|
|
|
| --- | --- | --- | --- |
|
|
|
|
|
| `feat(contacts): align resolved scope` | Advances P3.69 with Chatwoot contact resolved-scope parity. Contact index, filter, and export queries now apply `Contact.resolved_contacts`: non-CRM-v2 scopes require email, phone number, or identifier; CRM v2 scopes require `contact_type = lead`. | `go test ./internal/repository -run 'ContactRepo_FindByAccount\|ContactRepo_FindAllForExport' -count=1`; `go test ./internal/handler/api/v1 -run 'ContactHandlerCRUDTestSuite/TestList_ChatwootResolvedContacts\|ContactHandlerCRUDTestSuite/TestFilter_ChatwootPayloadCustomAttribute' -count=1`; `go test ./internal/repository ./internal/service ./internal/handler/api/v1 -run 'Contact.*(Filter\|List\|Search\|Export\|Label)\|ContactHandlerCRUDTestSuite/Test(Filter\|Labels\|List\|Search\|Export)\|ContactService\|ContactRepo' -count=1`; `go test ./...`; `git diff --check`. No route artifacts change. | Move P3.69 to Review; continue Phase 2/3 drift audit for contact search/global-search resolved scope, frontend-only `referer`, message filters, Phase 6 placeholder audit, or B12 live smoke. |
|
|
|
|
|
| `feat(contacts): align filter payloads` | Advances P3.68 with Chatwoot contact filter payload parity. `POST /contacts/filter` now understands `{ payload: [...] }` conditions for standard fields, additional attributes, labels, dates, query-operator chains, and account-scoped contact custom attributes; payload errors return raw `422 { error }`, and contact equality uses scalar `=`/`!=` semantics matching `Contacts::FilterService`. | `go test ./internal/handler/api/v1 -run 'ContactHandlerCRUDTestSuite/TestFilter' -count=1`; `go test ./internal/repository ./internal/service ./internal/handler/api/v1 -run 'Contact.*(Filter\|List\|Search\|Export\|Label)\|ContactHandlerCRUDTestSuite/Test(Filter\|Labels\|List\|Search\|Export)\|ContactService\|ContactRepo' -count=1`; `go test ./...`; `git diff --check`. No route artifacts change. | Move P3.68 to Review; continue Phase 2/3 drift audit for frontend-only `referer`, message filters, conversation permission-filter depth, Phase 6 placeholder audit, or B12 live smoke. |
|
|
|
|
|
| `feat(conversations): align standard filters` | Advances P3.67 with Chatwoot conversation filter standard-operator parity. Payload filters now cover presence operators for assignee/inbox/team/campaign fields, display-id contains/does-not-contain through text casts, account tag joins for labels, and date/days-before comparisons for `created_at` plus Unix-second `last_activity_at`. | `go test ./internal/handler/api/v1 -run 'ConversationCrudTestSuite/TestFilter' -count=1`; `go test ./internal/repository ./internal/service ./internal/handler/api/v1 -run 'ConversationRepo_(GetMeta\|ListForFinder)\|Conversation.*(Meta\|List\|Search\|Filter)\|ConversationCrudTestSuite/Test(Filter\|Search\|List)\|ConversationService' -count=1`; `go test ./...`; `git diff --check`. No route artifacts change. | Move P3.67 to Review; continue Phase 2/3 drift audit for message filters, contact custom attributes inside conversation filters, Phase 6 placeholder audit, or B12 live smoke. |
|
|
|
|
|
| `feat(conversations): align filter attributes` | Advances P3.66 with Chatwoot conversation filter additional/custom attribute parity. Payload filters now cover `browser_language`, `conversation_language`, `referer`, and `mail_subject` through JSON extraction and Chatwoot operator sets, and custom conversation attributes are resolved through account-scoped definitions with text/list/link lowercasing plus null-inclusive `not_equal_to`. | `go test ./internal/handler/api/v1 -run 'ConversationCrudTestSuite/TestFilter' -count=1`; `go test ./internal/repository ./internal/service ./internal/handler/api/v1 -run 'ConversationRepo_(GetMeta\|ListForFinder)\|Conversation.*(Meta\|List\|Search\|Filter)\|ConversationCrudTestSuite/Test(Filter\|Search\|List)\|ConversationService' -count=1`; `go test ./...`; `git diff --check`. No route artifacts change. | Move P3.66 to Review; continue Phase 2/3 drift audit for message filters, contact custom attributes inside conversation filters, Phase 6 placeholder audit, or B12 live smoke. |
|
|
|
|
@@ -2653,3 +2656,4 @@ Verification milestone gates:
|
|
|
|
|
- 2026-06-07: P3.66 conversation filter attribute checkpoint prepared as `feat(conversations): align filter attributes`; audited Chatwoot `filter_keys.yml`, `Filters::FilterHelper#handle_additional_attributes`, `Filters::CustomAttributeFilterHelper`, `FilterService#filter_operation`, and `Conversations::FilterService`. GoChat payload filters now support conversation additional attributes (`browser_language`, `conversation_language`, `referer`, `mail_subject`) and account-scoped conversation custom attributes, including case-normalized text/list/link comparisons and `not_equal_to` matching absent custom-attribute keys. Focused filter handler tests passed; full `go test ./...` and `git diff --check` passed. No route artifacts change.
|
|
|
|
|
- 2026-06-07: P3.67 conversation filter standard-operator checkpoint prepared as `feat(conversations): align standard filters`; audited Chatwoot `filter_keys.yml`, `FilterService#tag_filter_query`, `#filter_operation`, `#lt_gt_filter_query`, and `Conversations::FilterService`. GoChat payload filters now support presence operators for assignee/inbox/team/campaign fields, label equal/not-equal/present/absent through account tag joins, `display_id` contains/does-not-contain through text casts, and date/days-before comparisons for `created_at` and Unix-second `last_activity_at`. Focused filter handler tests passed; full `go test ./...` and `git diff --check` passed. No route artifacts change.
|
|
|
|
|
- 2026-06-07: P3.68 contact filter payload checkpoint prepared as `feat(contacts): align filter payloads`; audited Chatwoot `Contacts::FilterService`, base `FilterService`, `Filters::FilterHelper`, `CustomAttributeFilterHelper`, contact `filter_keys.yml`, and reused `contactProvider.js`. GoChat contact filters now accept frontend `{ payload: [...] }` bodies for standard fields, additional attributes, labels, dates, query operators, and account-scoped contact custom attributes; errors return raw `422 { error }`, phone/case normalization follows the reference, and contact equality uses scalar `=`/`!=`. Focused contact filter tests passed; full `go test ./...` and `git diff --check` passed. No route artifacts change.
|
|
|
|
|
- 2026-06-07: P3.69 contact resolved-scope checkpoint prepared as `feat(contacts): align resolved scope`; audited Chatwoot `Contact.resolved_contacts`, contact model specs, contacts index/filter controller paths, contacts export job, and `Contacts::FilterService#base_relation`. GoChat contact index, advanced filter, and export scopes now exclude anonymous contacts without email/phone/identifier unless `crm_v2` is enabled, and CRM v2 accounts now show only `contact_type = lead` in those CRM surfaces. Focused repository and handler tests passed; full `go test ./...` and `git diff --check` passed. No route artifacts change.
|
|
|
|
|