Architecture

Lua inside Nginx, PostgreSQL underneath

OpsAPI is a Lapis application running inside OpenResty's Nginx workers, so there's no separate app server. Every request takes the same layered path, every business row carries its workspace, and a deployment loads only the modules its preset names.

The whole system

Clients reach one API through the edge. Inside the container a request passes six layers; outside it, PostgreSQL holds the data and a few services do the rest.

OpsAPI system overview: clients, edge, the OpsAPI container and its servicesCLIENTSAdmin dashboardNext.jsYour web appsJava, PHP, Node, …Mobile appsGoogle/Apple ID tokenServers, scriptsAPI keys, TS SDKEdge proxyTLS, routingby host nameOPSAPI CONTAINER · OPENRESTYNginx workersLua runs in-processbefore_filterpublic list, JWT checkMiddlewareworkspace + permissionsRoutesloaded per featureQuerieslogic, validation, SQLModelsthin table wrappersSERVICESPostgreSQLevery table, per tenantRediscross-pod eventsMinIO / S3files and mediaKafkaaudit and outboxLLM providerOllama or hostedPrometheusscrapes /metricsExternal APIsGoogle, Apple, Stripe, HMRC
Dashed lines are connections the API makes as needed. Redis, MinIO, Kafka and the LLM provider are optional: a minimal deployment needs only PostgreSQL.

The stack

LayerWhatWhy
RuntimeOpenResty (Nginx + LuaJIT)Lua runs in the worker processes: no proxy hop to an app server
FrameworkLapisRouting, models and migrations for Lua
DatabasePostgreSQL (with pgvector)One database per deployment; workspaces separate tenants inside it
DashboardNext.js (App Router), React, ZustandMenu and permissions come from the API
Cache and eventsRedisChat and notifications across pods
FilesMinIO or S3Uploads, PDFs and media
EventsKafkaAudit trail and outbox
AIOllama or a hosted modelClassification, extraction and chat agents
MonitoringPrometheus, Grafana/metrics on every pod

Where things live in the repository

PathContents
lapis/The API: app.lua, routes/, queries/, models/, middleware/, migrations/, helper/, lib/
opsapi-dashboard/The Next.js admin dashboard
projects/Pluggable project modules with their own routes and migrations
sdk/typescript/The @opsapi/client TypeScript SDK
devops/Helm charts, Kubernetes manifests, the demo stack
start.shLocal and server orchestration: compose, migrations, admin seed
website/This site

Deep dives

Each technote takes one part of the system and draws it out.

Technote · 29 October 2026

SAML single sign-on per workspace

Each workspace connects its own SAML 2.0 identity provider. How the sign-in round trip works, what OpsAPI checks in every response, and why an IdP can only vouch for its own workspace.

securityssosamlidentity
Read →
Technote · 28 October 2026

Keeping admin dashboards off the internet: VPN and zero-trust access

Customer apps are public; the dashboards that run the platform shouldn’t be. How to put OpsAPI admin, the edge admin, the vault UI, Grafana and the Kubernetes API behind a VPN or ZTNA broker, with OpsAPI sign-in and roles still on top.

zero trustsecurityvpnsre
Read →
Technote · 28 October 2026

Webhooks: sending workspace events to your own systems

How OpsAPI turns business changes into signed HTTP deliveries, how retries and ordering work, how to verify a request, and how the CMS “website update” webhook refreshes a static site.

webhookseventsintegrationscms
Read →
Technote · 28 October 2026

Single sign-on for any app: the OpsAPI sign-in flow

How a Java app and a PHP app share one sign-in through OpsAPI: the hosted sign-in page, the nonce, the token hand-back and the one call that proves who the user is.

ssoauthsecurityjava
Read →
Technote · 28 October 2026

One request through OpsAPI: from nginx worker to PostgreSQL

What happens between a request arriving and the JSON going back: the global before_filter, the public allow-list, JWT and API-key checks, feature-gated routes, the middleware chain, the routes → queries → models layering and the two response envelopes.

architectureluaopenrestylapis
Read →
Technote · 28 October 2026

Building a safe public demo login

Publishing a password for a real admin dashboard without leaking anyone's data or letting visitors break it: a separate workspace, a read-only role and a reset job.

securityrbacdemoprivacy
Read →
Technote · 28 October 2026

PROJECT_CODE: one codebase, many products

How one environment variable decides which modules a deployment has: the presets, combining codes, why core is always on, and why every module must be gated in both app.lua and migrations.lua.

architecturedeploymentmigrationsdevops
Read →
Technote · 28 October 2026

Extending OpsAPI: plugins and consumer products

How a folder of Lua files becomes a first-class OpsAPI module with routes, RBAC, dashboard pages, events, jobs and its own migrations, and how an external product ships its schema in its own image built FROM bwalia/opsapi.

pluginsextensibilitymigrationsdevops
Read →
Technote · 28 October 2026

Seeing inside OpsAPI: probes, metrics, errors and audit trails

The three health endpoints and what each one is for, the Prometheus metrics, the error envelope with its correlation id, sign-in and activity records, the Kafka outbox, and why the error catalog had to move into the core.

observabilityprometheusgrafanasre
Read →
Technote · 28 October 2026

Workspaces and roles: how OpsAPI keeps tenants apart

How a request is tied to one workspace, what membership and module.action permissions decide, where platform admins and owners fit, and which of the three access layers is actually a hard boundary.

multi-tenancyrbacsecuritynamespaces
Read →
Technote · 28 October 2026

The modules map: what each PROJECT_CODE switches on

Every business module behind its feature flag, which deployment presets include which, how a preset decides what routes and tables exist, and how to call it all from TypeScript.

modulesproject_codearchitecturesdk
Read →
Technote · 28 October 2026

Running OpsAPI on Kubernetes: the Helm chart, piece by piece

What the OpsAPI chart creates, how secrets reach the pods, why migrations run as a pre-upgrade Job, how a rollout drains without dropping requests, and the start-up race we hit on a fast node.

kuberneteshelmdevopssre
Read →
Technote · 28 October 2026

Filing a UK tax return through HMRC Making Tax Digital

The six-step “File your tax” wizard, the HMRC endpoints and API versions behind it, the sandbox behaviour that is expensive to rediscover, and what production needs.

hmrcmtdtaxintegrations
Read →
Technote · 28 October 2026

From DNS to pod: the edge in front of OpsAPI

How a request for an OpsAPI host travels: a DNS-only CNAME, an edge PoP that terminates TLS and picks a rule, the cluster ingress and the pod. Plus how opsapi.org itself is a GitHub Pages site behind the same edge.

edgednstlswslproxy
Read →