Lee Kong Si · 李氏总会

Environments

Subdomain topology for development, staging, and production, and which variables each runtime needs.

Topology

Every app has a stable role key in code and a DNS label that depends on the environment. Staging uses the fixed cenvora.dev base; production uses ROOT_DOMAIN, and development uses localhost. The mapping lives in packages/env/src/hosts.ts and is the only place it is defined; apps call hosts(), originFor(), or read publicHosts / serverHosts rather than building URLs by hand.

RoleProductionStagingDevelopment
marketinghttps://www.lee-kong-si.cenvora.devhttps://www.lee-kong-si-test.cenvora.devhttp://localhost:3004
apphttps://app.lee-kong-si.cenvora.devhttps://app.lee-kong-si-test.cenvora.devhttp://localhost:3000
docshttps://docs.lee-kong-si.cenvora.devhttps://docs.lee-kong-si-test.cenvora.devhttp://localhost:3001
platformhttps://platform.lee-kong-si.cenvora.devhttps://platform.lee-kong-si-test.cenvora.devhttp://localhost:3002
partnerhttps://partner.lee-kong-si.cenvora.devhttps://partner.lee-kong-si-test.cenvora.devhttp://localhost:3003
apihttps://api.lee-kong-si.cenvora.devhttps://api.lee-kong-si-test.cenvora.devhttp://localhost:4000

Production uses APP_ENV=production, PROJECT_NAME=lee-kong-si, and ROOT_DOMAIN=cenvora.dev; this deliberately resolves to the six project-scoped Cenvora hosts shown above. Staging uses APP_ENV=staging, PROJECT_NAME=lee-kong-si-test, and the same fixed cenvora.dev base. The six current purpose labels are www, app, docs, platform, partner, and api. A custom non-Cenvora production root uses admin for the platform host; the project-scoped Cenvora convention uses platform in both environments. Future approved purposes such as merchant or user are not current apps or HostRole values.

With PROJECT_NAME=lee-kong-si-test and ROOT_DOMAIN=cenvora.dev, staging yields app.lee-kong-si-test.cenvora.dev. The production Cenvora convention similarly yields app.lee-kong-si.cenvora.dev; a separately owned production registrable domain can still be provided through ROOT_DOMAIN when approved. The staging base is fixed to cenvora.dev. Print the resolved table at any time with:

bun run vigor hosts --env staging
bun run vigor hosts --env production --json

The session cookie domain is .<project>.cenvora.dev in staging, .<ROOT_DOMAIN> in production, and unset on localhost. This lets one login work across the sibling services of the same project. See Authentication.

Other staging projects do not receive that project-domain cookie. This narrower cookie scope is not full security isolation: all projects remain same-site under the shared registrable cenvora.dev domain, and cookie-tossing risks remain. Trust every sibling service within one project, and place mutually untrusted projects on separate registrable domains.

Environment variables

The root .env.example lists every variable. Server-side variables are validated by @vigor/env/server (serverEnv); browser-safe variables carry the NEXT_PUBLIC_ prefix and are validated by @vigor/env/next (nextEnv). The API requires its server configuration at boot. Next.js site builds only need their browser-safe topology and integration variables.

Topology

VariableRuntimeNotes
APP_ENV / NEXT_PUBLIC_APP_ENVAPI, CLI / Next.jsdevelopment, staging, production.
PROJECT_NAME / NEXT_PUBLIC_PROJECT_NAMEAPI, CLI / Next.jsProject DNS label and staging cookie scope.
ROOT_DOMAIN / NEXT_PUBLIC_ROOT_DOMAINAPI, CLI / Next.jsProduction and canonical registrable-domain input, including in staging builds. Use localhost in development and cenvora.dev in staging for clarity; this input does not change the fixed staging placement.
PORTAPIDefaults to 4000.

Data and auth

VariableRuntimeNotes
DATABASE_URLAPI, CLIPostgreSQL connection string. Required.
BETTER_AUTH_SECRETAPIMinimum 32 characters. Intentionally empty in .env.example; generate a unique value with openssl rand -base64 32.
BETTER_AUTH_URLAPIOptional auth-base override; defaults to the API origin for APP_ENV. During a staging cutover, unset it or update it to https://api.<project>.cenvora.dev; a stale override keeps using the old API host.

Email

VariableRuntimeNotes
RESEND_API_KEYAPIMay be empty only in explicit development, where email is logged. Required in test, staging, and production.
EMAIL_FROMAPIDisplay name and address, for example Acme <no-reply@example.com>.

Error logs

VariableRuntimeNotes
ROOTPRINT_URLAPI and Next.js server runtimesRootprint base URL. Server only.
ROOTPRINT_INGEST_KEYAPI and Next.js server runtimesSecret ingest key scoped to otel-logs-v0_9. Server only.
NEXT_PUBLIC_ROOTPRINT_ENABLEDNext.js browserExact true opts into sanitized same-origin /monitoring forwarding; false is the default.

ROOTPRINT_URL and ROOTPRINT_INGEST_KEY are a pair: leaving both blank disables server delivery; setting only one is invalid. Browser code never receives the ingest key.

Feature flags

VariableRuntimeNotes
GROWTHBOOK_API_HOST / NEXT_PUBLIC_GROWTHBOOK_API_HOSTAPI / Next.jsGrowthBook API host.
GROWTHBOOK_CLIENT_KEY / NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEYAPI / Next.jsSDK client key. When set, GrowthBook wins over FLAGS_JSON.
FLAGS_JSON / NEXT_PUBLIC_FLAGS_JSONAPI / Next.jsJSON object of flag values used when no client key is set.

AI and client communication

VariableRuntimeNotes
OPENROUTER_API_KEYAPIServer only. Apps reach models through POST /api/ai/chat.
OPENROUTER_MODEL_FAST, OPENROUTER_MODEL_BALANCED, OPENROUTER_MODEL_STRONGAPIOptional overrides for the model tiers.
AI_DAILY_REQUEST_LIMITAPIChat requests each user may make per UTC day (default 100). Further requests get 429.
AUDIT_RETENTION_DAYSAPIDays to keep audit log entries (default 365); the daily cleanup job deletes older ones.
TRUSTED_PROXIESAPIProxy addresses whose X-Forwarded-For is trusted (default loopback,linklocal,uniquelocal). Used for rate limits and session IPs.
WHATSAPP_ACCESS_TOKEN, WHATSAPP_PHONE_NUMBER_ID, WHATSAPP_CLIENT_RECIPIENTSAPI, CIOptional; disabled when empty.

Misc

VariableRuntimeNotes
MCP_ENABLEDAPIDefaults to true in development and false elsewhere. Set it to override.
MCP_TOKENAPIBearer token (32+ characters) required for /mcp outside development. The API fails at startup if MCP is enabled without it.
APP_VERSIONAnyOptional release override reported with Rootprint error logs.

Per-environment checklist

  • Development: copy .env.example to .env, generate BETTER_AUTH_SECRET, keep both Rootprint server values blank, and keep NEXT_PUBLIC_ROOTPRINT_ENABLED=false.
  • Staging: set APP_ENV=staging and NEXT_PUBLIC_APP_ENV=staging, match PROJECT_NAME and NEXT_PUBLIC_PROJECT_NAME, and use cenvora.dev for both root-domain variables unless retaining a production domain for canonical metadata. Host generation always uses cenvora.dev for staging. Use a unique BETTER_AUTH_SECRET and, when approved, the staging Rootprint URL/key pair and GrowthBook client key. Browser reporting remains opt-in.
  • Production: set both app-environment variables to production and both root-domain variables to the project's production domain. Generate different auth and ingest secrets; staging and production must never share them or their data stores.

On this page