Skip to content

Configuration (env)

All configuration arrives through environment variables. The backend uses the platform-core config model; the sample file is backend/internal/config/.env.example.

Never commit secrets

backend/internal/config/.env*, the root .env and backend.env are gitignored. When you add a variable, document its name in the README and here — never its value.

Core

Variable Example Notes
PORT 8080 API listen port
ENVIRONMENT production Enables strict mode
DEBUG false Verbose logging
ALLOWED_ORIGINS https://geregeapp.mn CORS allow-list (comma separated; * only in dev)
TRUSTED_PROXIES 10.0.0.0/8 IP ranges whose X-Forwarded-For is trusted

With TRUSTED_PROXIES empty

X-Forwarded-For is not trusted at all (fail-safe). Behind a reverse proxy you must set it, or rate limiting will treat every user as one IP.

Database and Redis

Variable Notes
DB_POSTGRE_DSN / DB_POSTGRE_URL Connection string
DB_POSTGRE_DRIVER Driver name
DB_MAX_OPEN_CONNS · DB_MAX_IDLE_CONNS · DB_CONN_MAX_LIFE_MINS Pool
REDIS_HOST · REDIS_PASS · REDIS_EXPIRED Redis and TTL

Two hard requirements in production

  1. The DSN must use sslmode=verify-full.
  2. The API must connect as a non-superuser role — otherwise RLS does not apply and the boot guard refuses to start.

The compose stack deliberately runs ENVIRONMENT=development: the internal database has no TLS.

JWT and session

Variable Notes
JWT_SECRET ≥32 characters. Changing it invalidates every session
JWT_EXPIRED · JWT_REFRESH_EXPIRED Access / refresh lifetimes
JWT_ISSUER Usually the app domain. Changing it invalidates all tokens
BCRYPT_COST Hash cost (no passwords, but used for internal hashes)
OTP_MAX_ATTEMPTS OTP attempts during super-admin onboarding

eID (relying party)

Variable Notes
EID_BASE_URL eID Mongolia /v3 base
EID_RP_UUID · EID_RP_SECRET RP credentials
EID_RP_NAME Display name of the RP
EID_CALLBACK_URL Callback address
EID_CERT_LEVEL Required certificate level
EID_DISPLAY_TEXT Text shown on the phone

Signing

Variable Notes
SIGN_SIGNER_CERT_FILE · SIGN_SIGNER_KEY_FILE Required in production — the persistent Document-Signer
SIGN_RELAY_TOKEN Sign-relay token for third-party RPs (empty = disabled)

Gerege SSO — client side

Settings for this app acting as a relying party of sso.gerege.mn:

Variable Example Notes
SSO_ISSUER https://sso.gerege.mn Defaults to this when empty
SSO_CLIENT_ID · SSO_CLIENT_SECRET Empty disables the SSO flow
SSO_REDIRECT_URI https://geregeapp.mn/sso/callback Must match the registration exactly
SSO_SCOPE openid profile email Add nationalid to receive the national ID
SSO_NATIVE_CLIENT_ID Mobile (PKCE, public) client
SSO_EID_PROXY_BASE_URL https://sso.gerege.mn/rp/eid Fetch the eID console through the SSO proxy

OIDC provider — issuer side

Variable Notes
OAUTH_ISSUER e.g. https://geregeapp.mn. The provider mounts only when set
SSO_STATE_KEY HMAC key for login/consent state (≥32 bytes)
SSO_FIRSTPARTY_CLIENTS Clients that skip consent
SSO_ADMIN_API_KEYS · SSO_ADMIN_SUBS Access to /admin/api/v1

AI (Gemini)

Variable Notes
GEMINI_API_KEY Without it /ai/* returns a genuine 500
GEMINI_MODEL Chat / STT / translation (gemini-2.5-flash)
GEMINI_TTS_MODEL TTS model
GEMINI_EMBED_MODEL Empty = the client auto-selects
GEMINI_VOICE Prebuilt voice (Kore)
GEMINI_API_BASE Override for proxies / tests
AI_SCOPE_PROMPT Scope fallback when the DB layer is empty

Third parties and storage

Variable Notes
GOOGLE_CLIENT_ID · GOOGLE_CLIENT_SECRET Google linking (empty hides the button)
INTEGRATION_ENC_KEY ≥16 bytes. Encrypts OAuth tokens and super-admin TOTP
VERIFY_API_BASE · VERIFY_API_KEY · VERIFY_CHANNEL Gerege Verify
VERIFY_OPTIONAL true lets flows continue without Verify
XYP_API_BASE · XYP_CLIENT_ID · XYP_CLIENT_SECRET State registry lookups
CORE_API_BASE · CORE_API_TOKEN Gerege Core (USER FIND / ORG FIND)
GSPACE_HOST · GSPACE_PORT · GSPACE_USER · GSPACE_PASSWORD SFTP
GSPACE_HOST_KEY Host key pin — protects against MITM
GSPACE_BASE_PATH · GSPACE_QUOTA_BYTES Directory, per-user quota

Never rotate INTEGRATION_ENC_KEY once set

It encrypts super-admin TOTP secrets and integration OAuth tokens. Rotating it breaks both, irrecoverably.

Miscellaneous

Variable Notes
SUPERADMIN_EMAIL Bootstraps the first super admin
RELAY_DEMO_MODE Relay simulator (generates demo responses)

Observability

Variable Notes
OTEL_EXPORTER otlp · stdout · empty
OTEL_SAMPLE_RATIO Trace sampling
OBSERVABILITY_TOKEN Bearer gating /metrics and /swagger in production

Frontend

Variable Notes
BACKEND_URL The internal address the BFF calls

The name api can collide on a shared network

With several stacks on one Docker network, http://api:8080 may resolve to a different container and every /api/v1/* turns into a 404. Pin BACKEND_URL to the full container name (e.g. http://gerege-app-mn-api-1:8080).

Configuration guards

These run at boot:

Guard What it checks
RLS enforceability In production the DB role is not a superuser / BYPASSRLS
TLS In production the DSN uses sslmode=verify-full
Key lengths JWT_SECRET ≥32, SSO_STATE_KEY ≥32, INTEGRATION_ENC_KEY ≥16
Document-Signer Certificate and key present in production
CORS * forbidden in production

Any violation makes the API refuse to start — it never quietly degrades.