PrimeBrickPrimeBrick
  • Docs
  • Contact
  • MIT License
  • Documentation
  • MCP Server
  • API Catalog
  • Services
  • Libraries
PrimeBrickPrimeBrick

© 2026 PrimeBrick. MIT License. v3.11.2

github
Backend
    Roles and PermissionsWorking Together on the Same RecordManaging ModulesSigning In and MFA
    Generated
    Manual
    Developer Guide
      OverviewArchitectureAPI ConventionsEntity metadata contractEntity CRUD PipelineEntities and CRUD conventionsModule Navigation MetadataService RegistryMCP GatewayThe Service ProxyRotating Secrets EngineTranslationsAuthenticationRBACEnvironment ConfigurationCollaboration & Visual Merge
Frontend
Microservices
powered by Zudoku
Developer Guide

Environment Configuration

The Primebrick Backend reads configuration from two sources:

  1. Environment variables — see the strict split below
  2. config_entries database table — runtime auth settings (OIDC, Redis, gateway)

Environment variables are loaded once at startup via dotenv/config. The config_entries table is read at runtime and can be updated via the admin API without restarting.

The env contract — read this first (CRITICAL)

The .env file is a closed set: it may contain ONLY the database bootstrap pair DATABASE_URL + DATABASE_SCHEMA. assertDbEnv() crashes the boot on ANY other key in the file — including a misspelled DB_*/DATABASE_* name (fail-loud, never silently ignored).

A closed set of platform variables (NODE_ENV, E2E/debug knobs) is supplied at process launch or via Docker ENV — never in .env, never hardcoded, never in config_entries. Everything else — URLs, ports, secrets — lives in the config_entries table (nats_url included: the BE connects inside startServiceLifecycle(), after initDal()).

Quick start

Create .env with ONLY the DB pair:

TerminalCode
# .env — the ONLY two keys allowed in this file DATABASE_URL=postgres://primebrick:primebrick_dev@127.0.0.1:5432/primebrick DATABASE_SCHEMA=public

The defaults work out-of-the-box with the dockerized infrastructure from infra/docker-compose.postgres.yml.

Required variables (.env — closed set)

VariableDescriptionDefault
DATABASE_URLPostgreSQL connection string(none — required)
DATABASE_SCHEMADeclared schema domain — CSV or JSON array (public,system,custom). [0] is the owned schema(none — required)

The backend crashes on startup if either is missing or empty, or if the .env file contains any other key.

Platform variables (process env — never .env, never config)

VariableDescriptionImpacts
NODE_ENVproduction via Docker ENV or process launch — never .env, never hardcoded, never config_entriesproduction → session cookies carry Secure (HTTPS-only); allowedTrust accepts only release-signed DB patches. Any other value (or unset) → plain-HTTP dev cookies + dev/release patch trust.

The HTTP port is fixed (3001, src/index.ts) — not configurable. nats_url, frontend_url, OIDC/Casdoor values and every other runtime setting live in config_entries (table below). UUID columns always default to gen_random_uuid() (pgcrypto — hardcoded in the DAL entity decorator, no override).

Debug toggles (process env only — dev/test only, never .env)

PB_<MODULE>_FORCE_EMPTY / PB_<MODULE>_FORCE_ERROR (1 to enable) — consumed by DomainService.list to force empty/error states for E2E. E2E_ADMIN_USERNAME / E2E_ADMIN_PASSWORD carry the ephemeral test actor minted per run by the FE E2E harness. Do not enable in production.

(Demo customers seed via pnpm run db:seed:customers, not an env flag.)

Database-stored configuration

Most auth-related configuration is stored in the config_entries table, not in environment variables. This allows runtime updates via the admin API without restarting the server.

Each config row has a type column that drives typed coercion at the API boundary and Frontend widget selection. The type vocabulary includes string, text, boolean, bigint, number, money, badge, list, url, secret, json, date, datetime, and time. See the Config tables guide for the full vocabulary.

Config rows marked reserved = true cannot have their type or type_config changed — only the value is editable. This protects built-in settings from being re-typed in a way that would break the system. Non-reserved rows allow value, type, and type_config updates.

Config keyDescription
auth_modeSTANDALONE (API verifies JWTs via OIDC) or GATEWAY (trusted proxy injects identity headers) — validated at boot
auth_roles_pathDotted JWT path used to extract roles from any token shape (e.g. roles, realm_access.roles) — mandatory in all modes
idp_type, idp_endpoint, idp_organization, idp_client_id, idp_client_secretCasdoor™ IDP connection (login, org sync, user resolution)
redis_urlRedis connection URL for caching and sessions
oidc_issuer_urlOIDC issuer URL (defaults to Casdoor endpoint)
oidc_client_idOIDC client ID
oidc_client_secretOIDC client secret
oidc_audienceOptional OIDC audience check (STANDALONE mode)
service_client_shield_secretShared secret protecting service-to-service calls (client shield); value auto-rotated by the secret engine — this row is only the static fallback
service_client_shield_secret_header, gateway_public_secret, gateway_public_secret_header, gateway_header_*GATEWAY mode: shield secrets + the user-identity header names injected by the trusted proxy — all mandatory when auth_mode=GATEWAY
enable_mfa, enable_webauthn, passkey_required, enable_email_verification_checkAuth feature flags (type: boolean)
password_policyPassword policy rules for self-service changes
invitation_expiry_daysInvitation expiry in days (type: bigint)
mfa_challenge_token_ttl_secondsMFA token TTL in seconds (type: bigint)
mfa_challenge_signing_secretHMAC secret signing MFA challenges — auto-generated if empty

To update a config value, use the admin API:

TerminalCode
curl -X PUT http://localhost:3001/api/v1/entities/config_entry/<uuid> \ -H "Authorization: Bearer <admin-jwt>" \ -H "Content-Type: application/json" \ -d '{"value": "redis://redis:6379", "version": 1}'

Local development setup

Prerequisites

  1. Docker Desktop running
  2. PostgreSQL + pgvector — start with:
    TerminalCode
    docker compose -f infra/docker-compose.postgres.yml up -d
  3. Casdoor — included in the same compose file, starts automatically

Steps

  1. Create .env with ONLY the DB pair (see "The env contract" above):

    TerminalCode
    DATABASE_URL=postgres://primebrick:primebrick_dev@127.0.0.1:5432/primebrick DATABASE_SCHEMA=public
  2. Apply database migrations:

    TerminalCode
    pnpm run db:migrate
  3. Set up Casdoor (creates the builtin client, admin user, and roles):

    TerminalCode
    pnpm run setup:casdoor
  4. Start the dev server:

    TerminalCode
    pnpm run dev
  5. Verify health:

    TerminalCode
    curl http://localhost:3001/api/v1/health

Production checklist

  • NODE_ENV=production via Docker ENV (image) or process launch — never .env
  • Set DATABASE_URL + DATABASE_SCHEMA in .env (the only keys allowed there)
  • Update config_entries with production values: nats_url, idp_*/oidc_* (production Casdoor), frontend_url, Redis, and gateway settings
  • Remove or disable all debug toggles
Last modified on October 28, 2026
RBACCollaboration & Visual Merge
On this page
  • The env contract — read this first (CRITICAL)
  • Quick start
  • Required variables (.env — closed set)
  • Platform variables (process env — never .env, never config)
  • Debug toggles (process env only — dev/test only, never .env)
  • Database-stored configuration
  • Local development setup
    • Prerequisites
    • Steps
  • Production checklist