Configuration Reference
All Platform-Kernel services read configuration exclusively from
environment variables at startup. There is no .env file loading at
runtime (Architectural Decision AD-1). Defaults are compiled into each
service's internal/config/config.go.
The table below is the authoritative reference for all services. Columns: Variable · Service · Default · Description.
Global / Shared Variables
Variables consumed by multiple services:
| Variable | Services | Default | Description |
|---|---|---|---|
DATABASE_URL | IAM, Data Layer, Billing, Money, Files, Notify, Module Registry, Domain Resolver | (See below) | PostgreSQL connection DSN. Required — startup aborts if unset. |
VALKEY_URL | IAM, Gateway, Data Layer | localhost:6379 | Valkey address (host:port). Unified across all services. |
VALKEY_PASSWORD | IAM, Data Layer | (empty) | Valkey AUTH password. Empty disables auth (dev only). |
KAFKA_BROKERS | Gateway, Event Bus, Billing, Money, Audit | localhost:9092 | Comma-separated Kafka broker addresses. |
VAULT_ADDR | IAM, Gateway, Domain Resolver | http://vault:8200 | HashiCorp Vault HTTP address. |
VAULT_TOKEN | IAM, Gateway, Domain Resolver | kernel-dev-root-token | Vault root or AppRole service token. Rotated every 90 days in prod. |
LOG_LEVEL | All services | info | Log level: debug, info, warn, error. |
LOG_JSON | All services | true | If true, emits structured JSON via slog.NewJSONHandler. |
DATABASE_URL Default:
postgres://localhost:5432/platform?sslmode=disable
Gateway (services/gateway/)
| Variable | Description |
|---|---|
GATEWAY_HOST | Listen address. Default: 0.0.0.0 |
GATEWAY_PORT | HTTP listen port (mapped to 8051 on host in Docker). Default: 8080 |
GATEWAY_GRPC_PORT | gRPC listen port. Default: 50051 |
GATEWAY_SHUTDOWN_TIMEOUT | Graceful shutdown window. Go duration string (e.g. 30s). Default: 30s |
IAM_URL | IAM service HTTP address (internal Docker: http://iam:8080). Default: http://localhost:8081 |
IAM_GRPC_ADDR | IAM service gRPC address. Used by Gateway for token validation. Default: iam:50050 |
DATA_LAYER_URL | Data Layer HTTP address. Do not use host-mapped port. Default: http://localhost:8080 |
DATA_LAYER_GRPC_ADDR | Data Layer gRPC address. Default: data-layer:50052 |
BILLING_URL | Billing gRPC address (no http:// prefix — raw gRPC). Default: localhost:50055 |
BILLING_GRPC_ADDR | Billing gRPC address (Docker service name). Default: billing:50055 |
NOTIFY_GRPC_ADDR | Notify gRPC address. Default: notify:50054 |
MODULE_REGISTRY_GRPC_ADDR | Module Registry gRPC address. Default: module-registry:50060 |
JWT_PUBLIC_KEY | Base64-encoded PEM ECDSA P-256 public key for token validation. Default: (required) |
JWT_ISSUER | Expected iss claim in incoming JWTs. Default: platform-kernel |
JWT_AUDIENCE | Expected aud claim in incoming JWTs. Default: platform-kernel |
CORS_ALLOWED_ORIGINS | Comma-separated origin whitelist. No wildcard. MUST be set in prod. Default: (empty — deny all) |
CORS_ALLOWED_METHODS | Comma-separated allowed HTTP methods. Default: (See below) |
CORS_ALLOWED_HEADERS | Allowed request headers. Default: (See below) |
CORS_MAX_AGE | Preflight cache duration in seconds. Default: 3600 |
RATE_LIMIT_RPS | Per-IP sustained request rate (token bucket). Default: 10000 |
RATE_LIMIT_BURST | Per-IP burst headroom. Default: 20000 |
RATE_LIMIT_WINDOW | Sliding window duration for RATE_LIMIT_MAX_REQUESTS. Default: 60s |
RATE_LIMIT_MAX_REQUESTS | Global hard cap per window (Valkey-backed). Default: 1000000 |
BILLING_CACHE_TTL | Billing plan cache TTL. Go duration string. Default: 15m |
OPENAPI_RESPONSE_VALIDATION | Enable OpenAPI response contract validation (perf cost in prod). Default: false |
CORS Defaults:
CORS_ALLOWED_METHODS=GET,POST,PUT,PATCH,DELETE,OPTIONS
CORS_ALLOWED_HEADERS=Accept,Authorization,Content-Type,X-Request-ID,X-Tenant-ID
IAM Service (services/iam/)
| Variable | Description |
|---|---|
PORT | HTTP listen port (mapped to 8050:8080 in Docker). Default: 8081 |
IAM_GRPC_PORT | gRPC listen port. Default: 50050 |
DATABASE_URL | PostgreSQL DSN. Reads platform_kernel database. Default: (required) |
VALKEY_URL | Valkey address. Used for session cache and dedup. Default: localhost:6379 |
VALKEY_PASSWORD | Valkey AUTH password. Default: (empty) |
JWT_PRIVATE_KEY | Base64-encoded PEM ECDSA P-256 private key for token signing. Default: (required) |
JWT_ACCESS_TTL_MIN | Access token lifetime in minutes. Default: 15 |
JWT_REFRESH_TTL_DAYS | Refresh token lifetime in days. Default: 7 |
DELEGATION_TOKEN_TTL | Delegation token TTL in seconds. Clamped to [MinTTL, MaxTTL]. Default: 3600 |
AUTH_REFRESH_GRACE_WINDOW_SEC | Race-protection grace window for token refresh (seconds). Default: 10 |
MFA_ENCRYPTION_KEY | Hex-encoded AES-256 key (64 chars) for TOTP secret encryption. Default: (required in prod) |
ARGON2_MEMORY | Argon2id memory cost in KB (OWASP recommended: 64 MB). Default: 65536 |
ARGON2_ITERATIONS | Argon2id time cost (OWASP recommended). Default: 3 |
ARGON2_PARALLELISM | Argon2id threads. Must be ≤ host vCPU count. Default: 4 |
ARGON2_KEY_LENGTH | Argon2id output key length in bytes. Default: 32 |
ARGON2_SALT_LENGTH | Argon2id salt length in bytes. Default: 16 |
OIDC_ISSUER | OIDC discovery iss URL. Set to the public Gateway URL in prod. Default: http://localhost:8081 |
OIDC_RSA_PRIVATE_KEY | PEM-encoded RSA-2048 key for OIDC RS256 token signing. Default: (required for OIDC) |
OIDC_SECRET_ROTATION_GRACE_HOURS | Hours the old client_secret remains valid post-rotation (kernel-spec §1397). Default: 24 |
VAULT_ADDR | Vault address for JWT key retrieval. Default: http://vault:8200 |
VAULT_TOKEN | Vault auth token. Default: (required) |
VAULT_INIT_TIMEOUT_SEC | Max seconds to wait for Vault on startup before os.Exit(1). Default: 120 |
VAULT_RETRY_INITIAL_MS | Initial retry backoff for Vault connection (ms). Default: 250 |
VAULT_RETRY_MAX_MS | Max retry backoff for Vault connection (ms). Default: 16000 |
VAULT_WATCH_INTERVAL_SEC | JWT signing key rotation poll interval (seconds). Default: 30 |
Data Layer (services/data-layer/)
| Variable | Default | Description |
|---|---|---|
DATABASE_URL | (required) | PostgreSQL DSN. Required — startup aborts if unset. |
PORT | 8080 | HTTP listen port. |
DATA_LAYER_GRPC_PORT | 50052 | gRPC listen port. |
VALKEY_URL | localhost:6379 | Valkey address. Used for query result caching and dedup. |
VALKEY_PASSWORD | (empty) | Valkey AUTH password. |
DB_MAX_OPEN_CONNS | 25 | PostgreSQL max open connections per service instance. |
DB_MAX_IDLE_CONNS | 5 | PostgreSQL max idle connections. |
DB_CONN_MAX_LIFETIME | 5m | Max connection lifetime (Go duration). |
DB_CONN_MAX_IDLE_TIME | 1m | Max idle connection time (Go duration). |
DATA_MAX_RECORD_SIZE_BYTES | 1048576 | Max record size (1 MB). Rejected at ingress. |
DATA_MAX_JSONB_SIZE_BYTES | 262144 | Max JSONB field size (256 KB). |
DATA_MAX_TABLES_PER_MODULE | 50 | Max dynamic tables a module can create. |
Billing Service (services/billing/)
| Variable | Default | Description |
|---|---|---|
DATABASE_URL | (required) | PostgreSQL DSN. |
BILLING_GRPC_PORT | 50055 | gRPC listen port. |
KAFKA_BROKERS | localhost:9092 | Kafka brokers for billing event publishing. |
DB_MAX_OPEN_CONNS | 25 | PostgreSQL pool: max open connections. |
DB_MAX_IDLE_CONNS | 5 | PostgreSQL pool: max idle connections. |
DB_CONN_MAX_LIFETIME_MIN | 5 | Connection max lifetime in minutes. |
DB_CONN_MAX_IDLE_TIME_MIN | 1 | Connection max idle time in minutes. |
BILLING_CACHE_TTL_MIN | 15 | In-memory billing plan cache TTL (minutes). |
BILLING_GRACE_PERIOD_DAYS | 7 | Subscription grace period after payment failure. |
BILLING_SUSPEND_PERIOD_DAYS | 30 | Days after grace period before account suspension. |
BILLING_CRYPTO_WIPE_PERIOD_DAYS | 30 | Days after suspension before GDPR wipe. |
BILLING_TRIAL_DAYS | 14 | Default trial plan duration. |
BILLING_TRIAL_WARNING_DAYS | 3 | Days before trial expiry to send warning. |
Audit Service (services/audit/)
| Variable | Default | Description |
|---|---|---|
AUDIT_HOST | 0.0.0.0 | HTTP listen address. |
AUDIT_HTTP_PORT | 8094 | HTTP port (health + REST). |
AUDIT_GRPC_PORT | 50059 | gRPC listen port. |
CLICKHOUSE_ADDR | localhost:9000 | ClickHouse native TCP address. |
CLICKHOUSE_DATABASE | platform_audit | ClickHouse database name. |
CLICKHOUSE_USERNAME | kernel | ClickHouse user. |
CLICKHOUSE_PASSWORD | (empty) | ClickHouse password. Required in prod. |
CLICKHOUSE_MAX_OPEN_CONNS | 10 | ClickHouse connection pool size. |
CLICKHOUSE_MAX_IDLE_CONNS | 5 | ClickHouse idle connections. |
CLICKHOUSE_CONN_MAX_LIFETIME | 10m | ClickHouse connection max lifetime (Go duration). |
CLICKHOUSE_DIAL_TIMEOUT | 5s | ClickHouse connection timeout. |
KAFKA_AUDIT_TOPIC | platform.audit.events | Kafka topic consumed by Audit service. |
KAFKA_AUDIT_CONSUMER_GROUP | audit-clickhouse-writer | Kafka consumer group ID. |
KAFKA_BATCH_TIMEOUT | 100ms | Kafka batch flush timeout. |
KAFKA_MAX_ATTEMPTS | 3 | Kafka producer retry attempts. |
WAL_REPLAY_INTERVAL | 30s | PostgreSQL WAL fallback replay interval. |
WAL_RETENTION_DAYS | 7 | WAL fallback retention before purge. |
AUDIT_HOT_DAYS | 90 | ClickHouse hot storage retention (days). |
AUDIT_COLD_YEARS | 7 | S3 Glacier cold storage retention (years). |
Event Bus (services/event-bus/)
| Variable | Default | Description |
|---|---|---|
EVENT_BUS_GRPC_PORT | 50053 | gRPC listen port. |
KAFKA_BROKERS | localhost:9092 | Kafka broker addresses. |
VALKEY_ADDR | valkey:6379 | Valkey address (used for dedup cache). |
KAFKA_RETENTION_HOURS | 168 | Event topic retention (7 days). |
KAFKA_AUDIT_RETENTION_HOURS | 720 | Audit topic retention (30 days). |
Notify Service (services/notify/)
| Variable | Default | Description |
|---|---|---|
NOTIFY_GRPC_PORT | 50054 | gRPC listen port. |
VALKEY_ADDR | valkey:6379 | Valkey for replay buffer and session cache. |
NOTIFY_RATE_LIMIT_PER_TENANT | 100 | Max notifications per minute per tenant. |
NOTIFY_WS_MAX_CONNECTIONS_PER_TENANT | 1000 | Max concurrent WebSocket connections per tenant. |
WS_REPLAY_BUFFER_SIZE | 100 | WebSocket disconnect replay buffer (messages). |
WS_REPLAY_BUFFER_TTL_SEC | 3600 | Replay buffer TTL (1 hour). |
NOTIFY_HISTORY_RETENTION_DAYS | 90 | Notification history retention in PostgreSQL. |
Files Service (services/files/)
| Variable | Default | Description |
|---|---|---|
FILES_GRPC_PORT | 50057 | gRPC listen port. |
VALKEY_ADDR | valkey:6379 | Valkey for dedup and rate limiting. |
FILES_MAX_IMAGE_SIZE_MB | 10 | Max upload image size in MB. |
FILES_STAGING_TTL_HOURS | 24 | Staging bucket TTL before AV scan expiry. |
FILES_SOFT_DELETE_RETENTION_DAYS | 30 | Recycle bin retention before permanent deletion. |
FILES_ORPHAN_SCAN_INTERVAL_HOURS | 24 | Orphaned file cleanup scan interval. |
S3_ENDPOINT | (required) | S3-compatible endpoint (e.g. http://seaweedfs:8333). |
S3_BUCKET | platform-files | Primary S3 bucket name. |
S3_ACCESS_KEY | (required) | S3 access key ID. |
S3_SECRET_KEY | (required) | S3 secret access key. |
S3_REGION | us-east-1 | S3 region (SeaweedFS ignores this; required by AWS SDK). |
Money Service (services/money/)
| Variable | Default | Description |
|---|---|---|
MONEY_GRPC_PORT | 50058 | gRPC listen port. |
KAFKA_BROKERS | localhost:9092 | Kafka brokers for money event publishing. |
VALKEY_ADDR | valkey:6379 | Valkey for idempotency key dedup. |
MONEY_HOLD_TTL_HOURS | 72 | Default wallet hold TTL (3 days). Max: 7 days. |
MONEY_MAX_HOLDS_PER_WALLET | 100 | Max concurrent holds per wallet. |
MONEY_REVERSAL_MAX_AGE_DAYS | 365 | Max age for transaction reversals (1 year). |
MONEY_HOLD_CLEANUP_INTERVAL_SEC | 60 | Background hold expiration ticker interval. |
Module Registry (services/module-registry/)
| Variable | Default | Description |
|---|---|---|
MODULE_REGISTRY_GRPC_PORT | 50060 | gRPC listen port. |
VALKEY_ADDR | valkey:6379 | Valkey for module manifest cache. |
DATABASE_URL | (required) | PostgreSQL DSN. |
Integration Hub (services/integration-hub/)
| Variable | Default | Description |
|---|---|---|
INTEGRATION_GRPC_PORT | 50056 | gRPC listen port. |
INTEGRATION_RATE_LIMIT_PER_SEC | 100 | Max outgoing requests per second per provider. |
Domain Resolver (services/domain-resolver/)
| Variable | Default | Description |
|---|---|---|
DOMAIN_RESOLVER_GRPC_PORT | 50061 | gRPC listen port. |
DATABASE_URL | (required) | PostgreSQL DSN (reads platform_domain database). |
VAULT_ADDR | http://vault:8200 | Vault address for TLS certificate storage. |
VAULT_TOKEN | (required) | Vault auth token. |
DOMAINS_MAX_PER_TENANT | 5 | Max custom domains per tenant. |
DOMAINS_VERIFY_TTL_HOURS | 72 | DNS verification TTL before challenge expiry. |
DOMAINS_SSL_RENEW_DAYS_BEFORE | 30 | Days before TLS cert expiry to trigger renewal. |
Feature Flags (services/integration-hub/ — GoFeatureFlag)
| Variable | Default | Description |
|---|---|---|
FEATURE_FLAGS_PORT | 1031 | GoFeatureFlag HTTP port. |
FLAGS_MAX_PER_TENANT | 0 | Max feature flags per tenant (0 = unlimited). |
Production .env.example
Copy and fill before first deployment. Store secrets in Vault — never commit this file with real values.
# ── Database ──────────────────────────────────────────────────
DATABASE_URL=postgres://kernel:CHANGE_ME@postgres:5432/platform_kernel?sslmode=require
# ── Cache ─────────────────────────────────────────────────────
VALKEY_URL=valkey:6379
VALKEY_PASSWORD=CHANGE_ME
# ── Kafka ─────────────────────────────────────────────────────
KAFKA_BROKERS=kafka-0:9092,kafka-1:9092,kafka-2:9092
# ── HashiCorp Vault ───────────────────────────────────────────
VAULT_ADDR=https://vault.internal:8200
VAULT_TOKEN=CHANGE_ME
# ── IAM / JWT ─────────────────────────────────────────────────
# ES256 ECDSA P-256 — generate with: openssl ecparam -name prime256v1 -genkey | base64
JWT_PRIVATE_KEY=BASE64_PEM_HERE
JWT_PUBLIC_KEY=BASE64_PEM_HERE
MFA_ENCRYPTION_KEY=64_HEX_CHARS_HERE
# ── OIDC (if provider feature enabled) ────────────────────────
OIDC_ISSUER=https://api.yourdomain.com
OIDC_RSA_PRIVATE_KEY=PEM_RSA2048_HERE
# ── Gateway ───────────────────────────────────────────────────
CORS_ALLOWED_ORIGINS=https://app.yourdomain.com,https://admin.yourdomain.com
JWT_ISSUER=platform-kernel
JWT_AUDIENCE=platform-kernel
# ── S3 ────────────────────────────────────────────────────────
S3_ENDPOINT=https://s3.yourdomain.com
S3_BUCKET=platform-files
S3_ACCESS_KEY=CHANGE_ME
S3_SECRET_KEY=CHANGE_ME
# ── ClickHouse ────────────────────────────────────────────────
CLICKHOUSE_ADDR=clickhouse:9000
CLICKHOUSE_PASSWORD=CHANGE_ME
See Also
- Requirements — software and hardware prerequisites
- Docker Compose Setup — full local stack deployment
- Vault Setup — JWT key generation and rotation
- Kubernetes Deployment — production secret injection via Vault Secrets Operator