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_scriptstable - [ ] 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
Related Documents¶
- Adapter Script Contracts — universal input/output shapes per topic (test_connection, list_remote_outlets, etc.)
- POS Adapter Transformation Guidelines — field mapping rules, DO/DON'T for AI generation
Per-Provider Guides¶
- Revel Systems — API key auth, test_connection + list_remote_outlets scripts ready
- Deliverect — API key auth, TODO
- Atlas Kitchen — webhook-only, TODO
- Lightspeed — OAuth, TODO