Skip to content

feat(contacts): cover full public API for MCP, move logic into business services - #1093

Open
realcodesiman wants to merge 2 commits into
mainfrom
feat/contacts-public-api-mcp
Open

feat(contacts): cover full public API for MCP, move logic into business services#1093
realcodesiman wants to merge 2 commits into
mainfrom
feat/contacts-public-api-mcp

Conversation

@realcodesiman

Copy link
Copy Markdown
Contributor

Summary

  • Adds the remaining contacts public-API surface — bulk operations, export/export-file status, refresh-profile, and notes/sequences/inboxes/filter-fields (each as its own feature) — so MCP and other workspace-token callers can fully manage contacts, not just read/write the core fields.
  • Moves logic that previously lived only inside server-action inner functions (create/update/delete contact, tag attach/detach/replace, custom-field apply, message send, contact import) into packages/business services and packages/database repositories, so the public API handler and the private server action call the exact same code path instead of diverging copies.
  • Fixes two real bugs surfaced by that duplication: refresh-profile returned 401 for token callers because the old code path required a browser session; contacts_createNotecontacts_listNotes in the same MCP session could see a stale note because nothing invalidated the notes cache on write.

Changes

  • New public routers: contact-notes, contact-sequences, contact-inboxes, contact-filter (each with its own api/public.ts + schema/public.ts), composed into features/contacts/api/public.ts; plus contacts/api/public/{bulk,export,refresh-profile,tags,custom-fields}.ts.
  • New business services/repos: contact/create-with-inbox.ts, contact/update-fields.ts, contact-export/service.ts, message/create-outgoing.ts, database/repositories/contact/, database/repositories/media-library-file/.
  • Server actions (create-contact, delete-contact, add/remove/update-contact-tag, add-contact-custom-field, update-contact-field, create-message, create-tag, delete-tag, import-contacts, create-webhook, create-flow, create-trigger, create-automated-response) now delegate to the shared business service instead of holding their own copy of the logic.
  • Removed dead code: features/contacts/server/** (legacy ad-hoc business layer), queries/public-find-contact.ts, folders/actions/utils.ts, unused tag store provider files.
  • New Drizzle migration adding contact email/phone/workspace indexes (packages/database/drizzle/20260905151444_...).
  • Doc updates: .agents/skills/{orpc-api,feature-scaffold}/SKILL.md (submodule composition pattern, server/ directory ban), docs/developer/workspace-api-tokens.md (accurate endpoint-to-scope table and test list).

Test plan

  • pnpm lint
  • pnpm --filter @chatbotx.io/database check-types && test
  • pnpm --filter @chatbotx.io/business check-types && test
  • pnpm --filter builder check-types && test (418 files / 2684 tests green, snapshot unchanged)
  • pnpm --filter worker check-types && test
  • Manual: chatbotx-mcp-servercontacts_refreshProfile, contacts_createNotecontacts_listNotes immediately after, contacts_create with a mismatched inbox channel (expect 400, not 500)

…ss services

Adds the remaining contacts public-API surface (bulk ops, export, refresh
profile, notes/sequences/inboxes/filter-fields as their own features) so
MCP and other workspace-token callers can fully manage contacts. In the
process, moves business logic that lived only in server-action inner
functions (create/update/delete contact, tag attach/detach/replace,
custom-field apply, message send, contact import) into
packages/business services and packages/database repositories, so the
public API and the action call the same code path instead of duplicating
it — fixing a refresh-profile 401 caused by a stray session check and a
stale contact-notes cache that never invalidated on write.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…invalidation, close public API gaps

Closes the review findings on the contacts public API/MCP surface: a
workspace-A token could enroll contacts into a workspace-B sequence
(sequential bigint ids, never validated); tag writes invalidated cache tags
nothing ever reads, so renamed/deleted tags and stale contact tag lists
persisted for up to 24h; and the custom-field update path silently dropped
writes to fields 51+ in workspaces with more than 50 custom fields.

Also makes bulk endpoints report skipped ids instead of a blind 204,
surfaces channel-send enqueue failures instead of swallowing them, restores
the sequential (not concurrent) pre-auth rate-limit gate, adds read caching
now that invalidation is correct, and removes dead code left behind by the
original PR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant