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)
| Interface | Dev (tested in CI) | Deploy |
|---|---|---|
TenantAppJsonStore | MemoryTenantAppJsonStore | PrismaTenantAppJsonStore |
CredentialVault | EncryptedMemoryVault | PrismaCredentialVault (same seal/open crypto) |
| Job queue | MemoryQueue + WorkflowEngine.tick() | pg‑boss worker subscription |
ChangeDetector | SnapshotHashDetector (poll) | same, on a scheduler interval |
LlmClient | MockLlmClient | createAnthropicClient() (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
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 DBMigrations + RLS
prisma migrate deploycreates the tables.prisma db execute --file prisma/rls.sqlenables Row‑Level Security + the tenant policy (Prisma doesn't manage RLS).- 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:
- Polls OData per tenant (
SnapshotHashDetector) onWORKFLOW_POLL_INTERVAL_MS(default 60s). - Enqueues detected changes into pg-boss (same Postgres as Prisma).
- Worker subscription runs
runWorkflowwith vault-backed OData handlers (odata.auth.tokenRef). - Persists runs to
executionand approval pauses toapproval.
Scale on Fly: fly scale count worker=1 --process-group worker (see deploy/fly.toml [processes]).
Live wiring — required env
| Var | Purpose |
|---|---|
DATABASE_URL | Managed Postgres (Neon / Supabase / Fly PG). |
VAULT_KEY | 32‑byte hex (AES‑256) for the credential vault — from a secrets manager, never the DB. openssl rand -hex 32. |
PLATFORM_API_KEYS | Comma‑separated apiKey:tenantId:userId:role entries for auth (e.g. k-demo:demo:admin:admin). |
ANTHROPIC_API_KEY | Enables NL→app.json + the agent. Absent → those endpoints return 501. |
CORS_ORIGIN | Allowed origin for the doc‑site chat UI (default *). |
PORT | Server 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 env | Purpose |
|---|---|
PLATFORM_API_URL | Fly engine URL (e.g. https://samabaasi-platform.fly.dev) |
PLATFORM_API_KEY | One 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 inengine-postgres,prisma generate, run.deploy/fly.toml— HTTPS,/healthcheck, autoscale; secrets viafly secrets set(never committed).- CI runs typecheck/test/build for the workspace; add a deploy job on
mainthat 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.