Skip to content

Deployment

Turning the tested in‑memory platform into a deployed, operated one — adapters + ops + secrets, no new features. Every stateful interface has a tested in‑memory implementation and a deploy adapter behind the same interface, validated by the same contract suite.

The swap (in‑memory → Postgres)

InterfaceDev (tested in CI)Deploy
TenantAppJsonStoreMemoryTenantAppJsonStorePrismaTenantAppJsonStore
CredentialVaultEncryptedMemoryVaultPrismaCredentialVault (same seal/open crypto)
Job queueMemoryQueue + WorkflowEngine.tick()pg‑boss worker subscription
ChangeDetectorSnapshotHashDetector (poll)same, on a scheduler interval
LlmClientMockLlmClientcreateAnthropicClient() (Claude)

The Postgres adapters live in deploy/engine-postgres (a standalone package, kept out of the monorepo so Prisma's postinstall doesn't touch it). They pass the same @samabaasi/engine/contracts suite the in‑memory impls pass — so the swap is correct‑by‑contract, especially the tenant‑isolation cases.

Setup

bash
cd deploy/engine-postgres
npm install
npx prisma generate
export DATABASE_URL=postgres://user:pass@host:5432/app
export VAULT_KEY=$(openssl rand -hex 32)
export PLATFORM_API_KEYS="k-demo-admin:demo:admin:admin"
npm run migrate          # prisma migrate deploy + applies rls.sql
npm run build && npm start   # dist/server.mjs
DATABASE_URL=$DATABASE_URL VAULT_KEY=$VAULT_KEY npm test   # contract suite vs real DB

Migrations + RLS

  1. prisma migrate deploy creates the tables.
  2. prisma db execute --file prisma/rls.sql enables Row‑Level Security + the tenant policy (Prisma doesn't manage RLS).
  3. The app connects as a non‑superuser role; adapters call set_config('app.current_tenant', …) per transaction. Migrations run as a separate owner.

Queue in production (pg‑boss)

The dev model is poll→drain in‑process. In production deploy/engine-postgres/src/worker.mjs:

  1. Polls OData per tenant (SnapshotHashDetector) on WORKFLOW_POLL_INTERVAL_MS (default 60s).
  2. Enqueues detected changes into pg-boss (same Postgres as Prisma).
  3. Worker subscription runs runWorkflow with vault-backed OData handlers (odata.auth.tokenRef).
  4. Persists runs to execution and approval pauses to approval.

Scale on Fly: fly scale count worker=1 --process-group worker (see deploy/fly.toml [processes]).

Live wiring — required env

VarPurpose
DATABASE_URLManaged Postgres (Neon / Supabase / Fly PG).
VAULT_KEY32‑byte hex (AES‑256) for the credential vault — from a secrets manager, never the DB. openssl rand -hex 32.
PLATFORM_API_KEYSComma‑separated apiKey:tenantId:userId:role entries for auth (e.g. k-demo:demo:admin:admin).
ANTHROPIC_API_KEYEnables NL→app.json + the agent. Absent → those endpoints return 501.
CORS_ORIGINAllowed origin for the doc‑site chat UI (default *).
PORTServer port (default 4000).

Doc site (Netlify) — chat UI BFF

The App builder page on platform-site proxies to the engine via a Netlify Function so the API key never reaches the browser:

Netlify envPurpose
PLATFORM_API_URLFly engine URL (e.g. https://samabaasi-platform.fly.dev)
PLATFORM_API_KEYOne key from PLATFORM_API_KEYS (editor or admin)

See App builder for local dev (.env in platform-site/).

A real OData executor replaces the mock in the workflow handlers + agent tool executor — it injects the per‑tenant credential from the vault at egress, never exposing it to the model or client.

Containers & host

  • deploy/Dockerfile — multi‑stage: build the workspace packages, layer in engine-postgres, prisma generate, run.
  • deploy/fly.toml — HTTPS, /health check, autoscale; secrets via fly secrets set (never committed).
  • CI runs typecheck/test/build for the workspace; add a deploy job on main that builds the image and deploys after the security gate.

Status

  • Written: schema, RLS, Postgres adapters, shared contract suite, Dockerfile, fly.toml, runbook.
  • Owner/deploy: provision Postgres → prisma generate + migrate + run the contract suite green → set secrets → stand up the pg‑boss worker + real OData executor → security review → deploy.

See the Security model for the pre‑launch gate.

Released under the MIT License.