Skip to content

POS Adapter Architecture Plan

Overview

POS Adapters transform data between external POS systems (Deliverect, Revel, Atlas Kitchen, Lightspeed) and Cata's Standard API. Each adapter is a set of JavaScript transformation scripts — one per integration topic — stored centrally and executed at runtime via a JS engine (goja).

Key Principles

  • One script per POS per topic — shared across all tenants using that POS
  • Scripts stored in centraldb — not per-tenant (a Deliverect transform is the same for everyone)
  • AI-generated, human-reviewed — Claude generates candidate scripts, humans approve before activation
  • Runtime execution in Go — goja (pure Go JS engine), no CGo dependency

The 7 Adapter Topics

# Topic Direction Cata Endpoint Description
1 test_connection Cata → POS POST .../provider-connections/{slug}/test Verify credentials work
2 list_remote_outlets Cata → POS GET .../provider-connections/{slug}/remote-outlets Fetch POS locations for dropdown
3 sync_outlet POS → Cata POST /api/v1/outlets/sync Import or map POS locations to Cata outlets
4 sync_products POS → Cata POST /api/v1/products/sync Flat product sync (products + modifier groups + options)
5 order_dispatch Cata → POS External POS order API Transform Cata order → POS order format on OrderPaid event
6 order_status_update POS → Cata Cata webhook endpoint (POST /api/v1/inbound/{provider}/order-status) Transform POS status webhook → Cata order status update
7 snooze_items Cata → POS External POS API Temporarily disable/enable items on the POS system

Topic Details

1. SyncOutlet — Two modes: - Import: POS location → create new Cata outlet - Map: POS location → link to existing outlet (match by name)

2. SyncProducts — Flat only: - Pull all products from POS as flat list - Map: Product → Modifier Groups → Modifier Options (one level) - Ignore POS menu tree / categories / sections — Cata owns menu composition via Menu V2

3. OrderDispatch — Outbound: - Triggered by OrderPaid event from kds-management-service - Cata order format → adapter script → external POS createOrder API - Prices in Cata are decimals (15.50) — script converts to cents if POS requires

4. OrderStatusUpdate — Inbound: - External POS sends webhook to Cata - Adapter transforms POS status values → Cata order status (PENDING/ACCEPTED/PREPARING/READY/COMPLETED/CANCELLED) - Must follow Status Transition Diagram (see pos-adapter-guidelines.md) - Special case: COMPLETED → COMPLETED = ACK only (Cata auto-completes after X min)

Database Schema

-- centraldb (shared, not per-tenant)
CREATE TABLE centraldb.`adapter_scripts` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `provider` varchar(50) NOT NULL,
  `topic` enum('test_connection','list_remote_outlets','sync_outlet','sync_products','order_dispatch','order_status_update') NOT NULL,
  `version` varchar(20) NOT NULL,
  `status` enum('candidate','active','deprecated','archived') NOT NULL DEFAULT 'candidate',
  `script` mediumtext NOT NULL,
  `metadata` json DEFAULT NULL,
  `created_by` varchar(100) DEFAULT NULL,
  `reviewed_by` varchar(100) DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_active_script` (`provider`, `topic`, `status`),
  KEY `idx_provider_topic` (`provider`, `topic`)
);

Constraints: Only one active script per provider + topic at any time.

Status: Table already created in centraldb.

TODO — Revisions: Add revision column (int, auto-increment per provider+topic) to support version history, diff between revisions, and rollback. Current table uses version string — migrate to numeric revision tracking when building the UI.

Example data:

| provider   | topic               | version | status    |
|------------|---------------------|---------|-----------|
| deliverect | sync_outlet         | 1.0.0   | active    |
| deliverect | sync_products       | 1.0.0   | active    |
| deliverect | order_dispatch      | 1.0.0   | active    |
| deliverect | order_status_update | 1.0.0   | active    |
| revel      | sync_outlet         | 1.0.0   | candidate |
| revel      | sync_products       | 1.0.0   | candidate |

Script Lifecycle

candidate → (human review in UI) → active
candidate → (rejected) → archived
active → (new version generated) → deprecated → archived

AI Agent Generation Pipeline

┌─────────────────────────────────────────────────┐
│  POS Adapter Manager UI                         │
│                                                 │
│  [Select Provider: Deliverect ▼]                │
│  [Select Topic: SyncProducts ▼]                 │
│  [Generate Script]                              │
│       │                                         │
│       ▼                                         │
│  n8n Workflow                                   │
│  ┌─────────────────────────────────────────┐    │
│  │ 1. Fetch latest Cata openapi.yml        │    │
│  │ 2. Load POS knowledge for this provider │    │
│  │ 3. Load Guideline Principles            │    │
│  │ 4. Call Claude API                      │    │
│  │ 5. Save script as "candidate"           │    │
│  └─────────────────────────────────────────┘    │
│       │                                         │
│       ▼                                         │
│  JS Code Editor (Monaco/CodeMirror)             │
│  ┌─────────────────────────────────────────┐    │
│  │ // @provider deliverect                 │    │
│  │ // @topic sync_products                 │    │
│  │ function transform(input) {             │    │
│  │   return { products: ... };             │    │
│  │ }                                       │    │
│  └─────────────────────────────────────────┘    │
│                                                 │
│  [Test with Sample] [Save Draft] [Activate]     │
└─────────────────────────────────────────────────┘

Claude Inputs

Input Source Description
Cata Standard API openapi.yml (auto-fetched from repo) Target format — what the transform must produce
Guideline Principles docs/guides/pos-adapter-guidelines.md Rules for field mapping, price format, null handling, etc.
POS Knowledge Per-provider context store (TBD) API docs, sample payloads, field mappings for the specific POS

POS Knowledge Management (Open — Needs Discussion)

How to maintain context that Claude needs for each POS adapter:

Option Description Pros Cons
API doc links Claude fetches POS docs at generation time Always up-to-date Docs may be behind auth
Uploaded context docs PDF/markdown stored in DB or GCS per provider Full control Manual maintenance
Sample payload pairs Input (POS) → expected output (Cata) examples Best accuracy, testable Need to collect per POS
Hybrid Docs + samples + links Best coverage More complexity

Decision needed: Which approach (or combination) to use for each POS.

Runtime Execution

Inbound (POS → Cata):
  HTTP request from POS
    → identify provider (from store_credentials or webhook config)
    → load active script from centraldb.adapter_scripts
    → goja.RunString(script) with POS payload as input
    → validate output against Cata Standard API
    → call internal Cata endpoint (SyncOutlet / SyncProducts / OrderStatusUpdate)

Outbound (Cata → POS):
  OrderPaid event
    → load Cata order
    → identify provider (from store_credentials)
    → load active script for order_dispatch
    → goja.RunString(script) with Cata order as input
    → POST transformed payload to external POS API

Script Interface

Every transform script must export a transform function:

/**
 * @param {object} input - Source payload (POS format for inbound, Cata format for outbound)
 * @param {object} context - Runtime context (provider, tenantId, storeId, etc.)
 * @returns {object} - Transformed payload
 */
function transform(input, context) {
  // ... transformation logic
  return output;
}

UI Features (POS Adapter Manager)

Feature Description
Provider list List all POS providers with script status per topic (4 indicators)
Script editor Monaco/CodeMirror JS editor with syntax highlighting
Generate Trigger n8n → Claude to generate candidate script
Test Run script against sample payload, show input/output side-by-side
Diff view Compare candidate vs current active version
Activate Promote candidate → active (deprecates previous active)
Version history List all versions per provider + topic with status
Execution logs View recent transform executions with success/failure

Target POS Systems

Provider Status Priority
Deliverect First target — sample payloads already available High
Revel Systems API-pull based Medium
Atlas Kitchen Webhook with payload Medium
Lightspeed Webhook + pull Low

Implementation Phases

Phase 1: Foundation

  • [ ] Create centraldb.adapter_scripts table
  • [ ] Build goja runtime wrapper (load script, execute transform, validate output)
  • [ ] CRUD API for adapter scripts (/api/v1/adapter-scripts/*)
  • [ ] Wire into existing SyncOutlet / SyncProducts / OrderDispatch flows

Phase 2: AI Generation

  • [ ] n8n workflow: Claude generates transform scripts
  • [ ] POS knowledge store (start with uploaded context docs)
  • [ ] Test runner: validate script against sample payloads

Phase 3: UI

  • [ ] POS Adapter Manager page (provider list, script status)
  • [ ] JS code editor (Monaco)
  • [ ] Test panel (input/output side-by-side)
  • [ ] Activate/archive workflow
  • [ ] Version history and diff view

Phase 4: Production Rollout

  • [ ] Deliverect adapter (all 4 topics)
  • [ ] Execution logging and monitoring
  • [ ] Error alerting (failed transforms)
  • [ ] Revel / Atlas / Lightspeed adapters

Per-Provider Guides