Skip to content

Architecture

How the Labs64.IO modules fit together — the request path, the module map, and the extension points available today.

Mental model

Labs64.IO is a set of independent, polyglot services — Java/Spring Boot, Python/FastAPI, Vue — that sit behind one gateway and one auth plane. Every module is deployed from one chart library, and every module boundary is an OpenAPI-first contract: the API spec is written first, server and client code is generated from it, and the contract — not the implementation — is what other services and teams depend on.

No module reaches into another module's process or database. Everything crosses a boundary either as a REST call through the gateway, or as an event on the message bus. That's the whole model — the rest of this page walks through it.

The request path

Every request, regardless of which module it targets, crosses the same edge before it reaches application code.

Labs64.IO request and event pathA client request enters through Traefik, which forwards it to traefik-authproxy for ForwardAuth. The authproxy verifies the token and asks the central Cerbos PDP for an authorization decision, then routes the request to the target module. That module publishes domain events to RabbitMQ, which AuditFlow consumes and routes onward to configured sinks. Client Traefik gateway traefik-authproxy ForwardAuth /auth Cerbos PDP authz decision Module On success, authproxy sets trusted headers: X-Auth-User, X-Auth-Scopes, X-Auth-Tenant, X-Request-ID Module RabbitMQ AuditFlow Sinks (own persistence) Request path Event path (per-tenant pipelines) Unmatched routes fail closed (403)

Traefik receives every request and forwards it to traefik-authproxy at /auth before routing it anywhere else. The authproxy verifies the OIDC/JWT token on the request, then asks the central Cerbos PDP for the authorization decision — policy evaluation is centralized, not duplicated per module.

On success, the authproxy emits the trusted header contract that every upstream module relies on: X-Auth-User, X-Auth-Scopes, X-Auth-Tenant (set to - when the request is tenant-less), and X-Request-ID. All four are set on every 2xx response, and Traefik's authResponseHeaders always overwrite whatever a client supplied, so a module can trust these headers without re-validating them. Routes that don't match a known policy fail closed — they're rejected, not silently allowed through.

Module map

5 modules exist today. Each is a separate repository, ships independently, and communicates with the others only through REST calls that cross the gateway above, or through events over RabbitMQ into AuditFlow.

ModuleStatusWhat it owns
AuditFlowBetaPublish once, route anywhere, lose nothing
Auth GatewayBetaOne authenticated edge for every module
CheckoutAlphaWhitelabel checkout and order workflow
Payment GatewayAlphaOne API across multiple payment providers
Customer PortalAlphaSelf-service portal for your customers

AuditFlow is the one exception to "REST through the gateway": it is reached only by consuming events published to RabbitMQ by the other modules, plus its own pipeline configuration — it does not expose a public write API that other modules call synchronously.

Database-per-service

Each module owns its own logical database, or databases — every module except AuditFlow, which owns no persistent store of its own. Audit events live in each tenant's configured sinks, which are the systems of record. Everywhere a database does exist, credentials are never shared between services, and no module connects directly to another module's schema. If one module needs data that another module owns, it asks for it across the gateway as a REST call, or reacts to an event — it never reaches into the other service's storage.

Tenancy

AuditFlow's pipeline model is the reference implementation for tenant isolation across the ecosystem. Every pipeline belongs to exactly one tenant, and an event is routed only through the pipeline set owned by that event's tenant — there is no global pipeline list and no fall-through to another tenant's pipelines. Events that arrive with no tenant context belong to a reserved _platform pseudo-tenant, so tenant-less traffic is still isolated rather than silently merged into a shared bucket.

Observability

Observability is infrastructure-owned, not something each service builds for itself. Runtime auto-instrumentation — the OTel Java Agent for Java services, opentelemetry-instrument for Python services — attaches at deploy time and ships traces, logs, and metrics through an OTel Collector to Tempo (traces), Loki (logs), and Prometheus (metrics), visualized in Grafana.

Services carry no OpenTelemetry SDK and do no instrumentation bootstrap of their own. The exact same container image runs with or without observability — it's toggled purely by deployment configuration, so instrumentation can never drift from the code it's watching.

Extension points available today

This is the complete list of ways to extend the platform without forking a module. If it isn't on this list, it isn't available yet.

  • AuditFlow transformer plugins — a transformers/<name>.py file implementing transform(input_data: dict) -> dict.
  • AuditFlow sink plugins — a sinks/<name>.py file implementing process(event_data: dict, properties: dict) -> dict.
  • Runtime plugin mountstransformers_bootstrap/ and sinks_bootstrap/, mounted in via a ConfigMap volume so plugins can be added without rebuilding the image.
  • Payment Gateway PSP SPI — a new Maven module under payment-gateway-providers/<name>/ implementing PaymentProvider, and optionally ProviderCheckoutSupport and/or ProviderWebhookSupport.
  • Pipelines as configuration — a per-tenant tenants/<tenantId>.yaml file, or a labelled ConfigMap, defines which sinks a tenant's events route through.
  • Pipeline condition operators — the operators available for matching and routing events within a pipeline definition.
  • Helm values overlays — on the published charts, for environment-specific configuration without patching the chart itself.

Go deeper

The pages below cover each architectural property in more depth, and the docs repository has the full technical reference.