FKCFKC·OmniChannelSign in
Home/Developers/Architecture

Architecture & End-to-End Walkthrough

A technical overview of FKC-OmniChannel: its Shopify sales-channel role, the data-routing path from each connected channel through the ticket lifecycle, webhooks, security, and a step-by-step reviewer walkthrough.

Sales channelMerchant helpdesk / inboxNext.js on Cloudflare WorkersAdmin API 2025-10Channel API 2026-04
01

App overview & sales-channel role

FKC-OmniChannel unifies inbound customer conversations from WhatsApp, Instagram, Facebook Messenger, web chat, email and SMS into one merchant inbox, layered with AI-assisted replies and automated workflows. Inside that inbox, agents need to recommend, link to and sell the merchant's Shopify products without leaving the ticket — which is why the app is registered as a Shopify sales channel, not just an admin extension.

On install, the app provisions a modern Publication via channelCreate (Channel API 2026-04). Merchants then see “FKC-Omnichannel” in the standard product publication picker alongside Online Store and POS, and choose which products are eligible to be surfaced inside customer chats. When an agent or the AI shares a product, the app generates a Storefront cart permalink so any resulting order is attributed back to the FKC publication.

02

System topology

Two deployed surfaces, deliberately split so that webhook delivery, OAuth, message processing and storage all live on Cloudflare while the embedded admin UI lives on a Node host.

┌───────────────────────────────────────────────┐
│  Shopify Admin (embedded iframe, App Bridge)  │
│  shop.fkc-omnichannel.com — React Router      │
└──────────────┬────────────────────────────────┘
               │ App Bridge / authenticated session
               ▼
┌───────────────────────────────────────────────┐
│  apps/web — Cloudflare Worker (Next.js)        │
│   • OAuth start + callback                     │
│   • /api/webhooks/shopify  (HMAC, topic-routed)│
│   • /api/webhooks/meta     (WhatsApp / IG / FB)│
│   • Inbox UI, AI agent, workflow engine        │
│  Storage:                                      │
│   D1  — workspaces, conversations, audit log   │
│   R2  — media attachments (images, voice)      │
│   Vectorize — KB embeddings (per workspace)    │
│   KV  — sessions, rate-limits, dedupe keys     │
└───────────────────────────────────────────────┘
        ▲                ▲                ▲
   Meta Graph API   WhatsApp Cloud     OpenAI
   (IG, Messenger)  API (WABA)         (per-workspace key)
03

End-to-end data routing

Every inbound message follows the same five-stage pipeline regardless of the originating channel:

 1. INGEST     POST /api/webhooks/<channel>  ← HMAC / signature verified
                ↓ idempotency key written to KV
 2. NORMALISE  Channel adapter → canonical Message DTO
 3. RESOLVE    Match/create Contact + open/attach Conversation
 4. PERSIST    Prisma write to D1 · attachments to R2
                ↓ Durable Object fan-out to live inbox
 5. AUTOMATE   Workflow engine evaluates triggers
                AI Sales Agent drafts a suggested reply
                ↓ Agent sends → outbound adapter (Meta / WABA / SMTP)

The same path applies in reverse: an agent reply is written to D1 first, then dispatched to the originating channel, and any platform-specific message ID is stored back on the row so delivery and read receipts can be correlated.

04

Ticket / conversation lifecycle

The unit of work in the inbox is a Conversation (a.k.a. ticket) with a deterministic state machine:

    open ──assign──► assigned ──reply──► waiting_customer
     ▲                  │                     │
     │                  └─ customer replies ──┘
     └────── reopen ──── resolved ◄───────────┘
                           │
                           └── auto-close after N days idle

AI assistance never changes ticket state on its own — it only drafts a reply that an agent reviews. The send action is the state transition. Every state change writes an immutable audit entry with actor, before, after, and source (manual / workflow / webhook).

05

Shopify integration surface

  • Channel config extension declares type = "channel_config" so the channel appears in the publication picker immediately on install.
  • Modern Publication — the install callback calls channelCreate (Channel API 2026-04) to provision the Publication, required for the channel to be selectable.
  • Embedded admin UI — React Router framework, App Bridge and Polaris, for in-admin connection management.
  • Cart permalinks & attribution built using the Storefront Access Token for the FKC publication, so orders are attributed to this sales channel.
  • Order & product webhooks land on /api/webhooks/shopify, routed by the x-shopify-topic header.
06

Webhooks & verification

POST /api/webhooks/shopify is a single unified handler for every subscribed topic:

 1. Read raw body  (bytes, not parsed — required for HMAC)
 2. Verify         X-Shopify-Hmac-Sha256  ← reject 401 on mismatch
 3. Dedupe         KV.put(X-Shopify-Webhook-Id)  ← 24h no-op window
 4. Route          switch (X-Shopify-Topic) { ... }
                     app/uninstalled  → revoke tokens
                     orders/create    → attach to conversation
                     customers/redact → enqueue GDPR delete job
                     shop/redact      → wipe shop + child rows
 5. Persist        Audit log entry for every privacy webhook
 6. Respond        200 { ok: true } within ~5s budget

Non-Shopify channels use the same shape: /api/webhooks/meta verifies X-Hub-Signature-256 against the Meta app secret; HMAC mismatches return 401 and are logged.

07

OAuth scopes & why each is needed

read_products         show catalog in the product picker
read_orders           display recent orders in the context panel
read_customers        match a conversation to a Shopify customer
write_draft_orders    create a draft order for a custom quote in chat
read_inventory        show "in stock / N left" beside products
read_publications     list publications when registering the channel
write_publications     publish/unpublish products to the FKC channel
read_product_listings  required by the channelCreate mutation
read_content          ground AI answers in the merchant's own policies
read_price_rules      surface active discounts the AI may mention
08

Security, secrets & data handling

  • Transport. All public endpoints are HTTPS-only via Cloudflare (HSTS preload).
  • Token storage. Every channel access token is encrypted at rest with AES-GCM using a per-deployment master key held in Worker Secrets, never written to D1 in plaintext.
  • Sessions. NextAuth cookies — HttpOnly, Secure, SameSite=Lax; records in KV with short TTL.
  • Webhook integrity. Every provider webhook is HMAC- or signature-verified on the raw body before any database access.
  • Tenant isolation. Every query carries the workspace ID; row-level filters and a request-scoped context enforce it server-side.
  • Audit log. Security-sensitive actions write immutable audit entries.
  • No model training. Customer message content is never used to train third-party models; AI calls run with the merchant's own API key.
09

GDPR / mandatory privacy webhooks

  • customers/data_request — enqueues an export job; we email the export to the shop owner within 30 days.
  • customers/redact — deletes the matching contact and all associated messages, attachments and PII across D1 and R2.
  • shop/redact — fired 48h after uninstall; cascades a full delete of the workspace integration row, cached products, conversations and the encrypted token blob.

Public user-facing data deletion: see Data Deletion.

10

Reviewer walkthrough & test path

  1. Install. From the App Store listing, install on a development store. OAuth completes and the channel record + modern Publication are provisioned automatically.
  2. Verify channel registration. In Admin → Products → Publishing, confirm “FKC-Omnichannel” is listed alongside Online Store and POS; publish at least one product to it.
  3. Trigger an inbound message. A new conversation appears in the inbox in real time via Durable Object fan-out, in the open state.
  4. Demonstrate routing. Assign, reply, and observe the transition to waiting_customer; audit entries appear under Activity.
  5. Share a product in chat using the in-conversation picker and send a cart permalink.
  6. Complete checkout. orders/create fires, is HMAC-verified, attributed to the conversation, and appears inline.
  7. Resolve the conversation; a follow-up inbound message reopens it automatically.
  8. Uninstall. app/uninstalled wipes the token within seconds; shop/redact (T+48h) cascades the rest.