Skip to content

Architecture overview

Vitni is a modular monolith with independently built web, API, and worker applications in one pnpm workspace.

Browser ── Nuxt web/BFF ── REST + OpenAPI ── NestJS API ── PostgreSQL
│ │ ├── tenant data + RLS
└── OIDC discovery ── configured provider └── encrypted email outbox
│
Cloudflare Worker ── Hyperdrive ── Neon ── Resend HTTPS API
Self-hosted Node worker ── PostgreSQL ── SMTP relay
  • Nuxt web app: customer and holder pages, sign-in session, and same-origin API proxy.
  • NestJS API: organization, membership, issuer, achievement, pathway, credential, and public document routes.
  • PostgreSQL: tenant records, migration-managed schema, row-level security, and the encrypted email outbox.
  • Worker: hosted scheduled email delivery through an HTTPS provider; local and self-hosted SMTP delivery is optional and off by default.
  • OIDC provider: local development uses Keycloak; hosted prelaunch uses ZITADEL; self-hosted operators can configure another OIDC-compatible issuer.
  • Credential package: credential serialization, signing, status, and verification behavior shared by services.

An organization is the tenant root. Tenant-owned records have an organization ID, and PostgreSQL row-level security is forced. The API sets the authenticated user and active organization in a transaction before tenant queries. The API, migration process, and worker use separate database roles. Public credential, issuer, and status-list reads are narrowly scoped to a requested public document.

Recipients do not become issuer-organization members by default. The holder claim flow is separate and requires sign-in with the verified email that received the claim link.

Each organization receives one issuer profile and signing-key lifecycle. Publishing establishes its stable issuer identifier. Issuance stores an immutable signed credential; revocation updates a signed Bitstring Status List. Public verification checks proof, expiry, and revocation status.

The repository’s canonical runtime and tenant-isolation note is docs/architecture.md. The implementation inventory and current delivery status are in docs/feature-inventory.md and docs/implementation-status.md. These records remain authoritative as the product evolves.