Files
2026-11-14 09:56:45 +00:00

284 lines
17 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
# Every variable this app reads, what it is for, who sets it on ConusAI Cloud, and what a local run
# puts here. Nothing is read at build time, so one image serves every environment (there is no
# NEXT_PUBLIC_* value in this file by design, spec §6.4). A test fails when a variable the code reads
# is missing from this file (test/env-example.test.ts).
#
# Two ways to run it locally, and they need different things from this file:
#
# pnpm dev
# needs NO .env at all, and reads none. It starts Postgres in Docker, the fake platform, the
# migrate job, the demo data, the worker and the web shell on this machine, with the values it
# prints. A value you want different is a variable in your shell, not in this file: DEV_WEB_PORT,
# DEV_PLATFORM_PORT and DEV_POSTGRES_PORT move the ports; POSTGRES_URL, POSTGRES_READER_URL and
# POSTGRES_MIGRATE_URL (all three) use a Postgres of your own.
#
# cp .env.example .env && docker compose -f compose.yaml -f compose.dev.yaml up --build
# needs this file as it is, plus AUTH_SESSION_SECRET (below). The same stack as containers.
#
# On ConusAI Cloud the platform injects the "platform" and "Postgres" groups, and you set the
# "sign-in" group and anything under "this app" in the project's settings.
# ---------------------------------------------------------------------------------------------
# The platform (injected into every service; @conusai-kit/platform parses it at boot and the app
# refuses to start without the first four, naming the one that is missing)
# ---------------------------------------------------------------------------------------------
# The platform API, ending in /api. The AI gateway, OCR, Blob, audit and usage are all reached here.
CONUSAI_API_URL=http://platform:4010/api
# The deployment token. A secret: never in an image, a log or an error message.
CONUSAI_API_TOKEN=dev-token
# The project this deployment is.
CONUSAI_PROJECT_ID=1
# The ConusAI organization that owns the deployment: usage is metered against it. Required in
# production; a development run uses "dev".
CONUSAI_ORG_ID=dev
# Optional business modules require the real platform-injected numeric organization and
# environment IDs. They refuse service dispatch when these are missing; other app pages stay usable.
CONUSAI_ENVIRONMENT_ID=
# Reserved optional Cloud identity from the authenticated installed release policy.
# Empty stays unavailable. Standalone adoption must verify the descriptor independently.
# These identify Cloud, while CONUSAI_RELEASE below identifies this application's source.
CONUSAI_PLATFORM_RELEASE_DESCRIPTOR=
CONUSAI_PLATFORM_SOURCE_COMMIT=
# Platform-injected organization slug for slug-scoped usage billing. The app also applies this organization's
# branding from the platform (brand-kit BK12); empty, the app keeps the kit's default theme.
CONUSAI_ORG_SLUG=
# Platform-injected workspace and project slugs: the knowledge service's routes name them, with the
# organization's. A development run that uses knowledge against the fake platform sets all three.
CONUSAI_WORKSPACE_SLUG=
CONUSAI_PROJECT_SLUG=
# The address the app is served at, with no trailing slash. The sign-in redirect URIs derive from it.
CONUSAI_PUBLIC_URL=http://127.0.0.1:3000
# The release being run (the commit), reported with every error and log line.
CONUSAI_RELEASE=dev
# production, preview or a named environment. Without it: production in a production run, else development.
CONUSAI_ENVIRONMENT=
# ---------------------------------------------------------------------------------------------
# Convex profile only. The backup sidecar needs an admin key; keep this secret out of source control.
# ---------------------------------------------------------------------------------------------
# The Convex provider injects these exact names into linked services. The admin key is server-only:
# it deploys app functions and lets the Next BFF attach trusted identities; never prefix it NEXT_PUBLIC.
CONVEX_SELF_HOSTED_URL=http://127.0.0.1:53210
CONVEX_SELF_HOSTED_ADMIN_KEY=
# For local development, generate the key
# with `docker exec <backend-container> ./generate_admin_key.sh`.
# Scheduled export cadence and number of newest archives retained. Defaults: 24 hours and 30.
CONVEX_BACKUP_INTERVAL_HOURS=24
CONVEX_BACKUP_RETENTION=30
# Optional Convex CLI executable and working directory overrides for the backup sidecar.
CONVEX_CLI=
CONVEX_APP_DIR=
# Development and tests ONLY: use the fake platform of @conusai-kit/testing instead of the real one.
# The app refuses this switch in a production run (anything but NODE_ENV=development or test), and
# refuses it when CONUSAI_API_URL is not on this machine or the compose network. `pnpm dev` sets it.
CONUSAI_FAKE_PLATFORM=1
# development or test. Unset means production, the safe way round.
NODE_ENV=development
# ---------------------------------------------------------------------------------------------
# Observability (spec §9.5). Errors need a DSN; logs and traces need the platform's OTLP endpoint.
# Without them the app runs, sends nothing, and says so in one log line at start-up.
# ---------------------------------------------------------------------------------------------
# The project DSN errors are sent to. Public by design (it identifies a project, it grants no read).
CONUSAI_DSN=
# Set together by the platform when the environment has OTLP instrumentation. The exporter authenticates
# with CONUSAI_API_TOKEN, so the headers variable is rarely needed.
OTEL_EXPORTER_OTLP_ENDPOINT=
OTEL_EXPORTER_OTLP_PROTOCOL=
OTEL_EXPORTER_OTLP_HEADERS=
# The service name in logs and traces. Default: app-web or app-worker.
OTEL_SERVICE_NAME=
# The release when CONUSAI_RELEASE is unset (the platform derives it from the commit).
OTEL_SERVICE_VERSION=
# debug, info, warn or error. Default info.
LOG_LEVEL=
# ---------------------------------------------------------------------------------------------
# Postgres: the three logins of a linked managed database (data-services DS21). web and worker never
# see the owner's URL; only the migrate job does. dev/postgres-roles.sql creates them locally.
# ---------------------------------------------------------------------------------------------
# The runtime role, bound by row-level security. web, worker and migrate.
POSTGRES_URL=postgresql://appdev_app:appdev_app@postgres:5432/appdev
# The global reader: the three reads that belong to no organization. web, worker and migrate.
POSTGRES_READER_URL=postgresql://appdev_reader:appdev_reader@postgres:5432/appdev
# The owner. The migrate job alone.
POSTGRES_MIGRATE_URL=postgresql://appdev_owner:appdev_owner@postgres:5432/appdev
# The mariadb and mongodb profiles instead (profiles/<name>/README.md): one login, no RLS roles,
# and the BullMQ queue on Valkey. Empty on the postgres profile; the platform injects them for a
# linked MariaDB, MongoDB (created with replica_set) and Redis/Valkey service.
# The MariaDB login. web, worker and migrate of the mariadb profile.
MARIADB_URL=
# The MongoDB replica-set URL. web, worker and migrate of the mongodb profile.
MONGODB_URL=
# The Valkey of the job queue. web and worker of the mariadb and mongodb profiles.
REDIS_URL=
# ---------------------------------------------------------------------------------------------
# Sign-in (spec §7). On ConusAI Cloud the project's identity link injects every OIDC_* variable and
# AUTH_PROVIDER_GENERATION; you set AUTH_SESSION_SECRET. Choose the issuer by the service you link:
# `identity` (managed Zitadel) or `better-auth` (managed Better Auth). Both feed the same oidc adapter,
# so AUTH_PROVIDER stays oidc (README.md, "Sign-in"). Locally, set the OIDC_* group yourself, or use
# AUTH_DEV_LOGIN.
# ---------------------------------------------------------------------------------------------
# At least 32 bytes of random secret; the key the session cookie is sealed with. Generate one with
# node -e "console.log(require('node:crypto').randomBytes(32).toString('base64url'))"
AUTH_SESSION_SECRET=replace-me-with-32-bytes-of-random-secret
# The one sign-in authority: oidc (default; the OIDC_* variables below) or convex-better-auth (the
# app-embedded Better Auth adapter: the BETTER_AUTH_* variables below; `kit template:prune --auth oidc`
# removes it from an app that does not use it). Better Auth mode refuses every OIDC_* variable and
# AUTH_DEV_LOGIN (blank both), and needs AUTH_IDENTITY_NAMESPACE instead.
AUTH_PROVIDER=
# Better Auth only: the stable namespace its users are mapped under, e.g. better-auth:notes-production.
# Never an issuer URL. Leave it empty for oidc, whose namespace is OIDC_ISSUER.
AUTH_IDENTITY_NAMESPACE=
# kit:convex-better-auth:begin
# Better Auth only: this app's Better Auth Convex deployment (better-auth/, deployed by the migrate job,
# or the convex-deploy job on the Convex profile). On ConusAI Cloud the project's `better-auth` Convex
# link injects these three (runtime-only); set them here for local development. Its URL, where the web server validates every
# request's session and the revocation relay reads the outbox, and its site URL, where Better Auth's
# routes are (the app's /api/auth forwards to them).
BETTER_AUTH_CONVEX_URL=
BETTER_AUTH_CONVEX_SITE_URL=
# Better Auth only: the deployment's admin key. Server-side only (web, the worker and the deploy job;
# on the Convex profile the deploy job also installs it, with the URL and the namespace, in the app's
# own Convex deployment, whose account actions end a deleted person's Better Auth account): it never
# validates a person, and never reaches a browser.
BETTER_AUTH_CONVEX_ADMIN_KEY=
# Better Auth only: Better Auth's own secret, at least 32 random characters. The deploy job alone
# holds it and installs it in the Better Auth deployment; the web server never sees it.
BETTER_AUTH_SECRET=
# Better Auth only: how often, in milliseconds, the web server delivers the revocation outbox (a
# sign-out elsewhere, a revoked device, a disabled or deleted account). Default 2000.
BETTER_AUTH_RELAY_INTERVAL_MS=
# kit:convex-better-auth:end
# An OIDC issuer (managed Identity, managed Better Auth -- whose issuer ends in /api/auth -- or any
# other) and this app's client. All three, or none. In development, none renders the pages signed out and
# sign-in refuses until a provider is configured. A production start with none is refused: every route
# answers 503 and /api/ready says what to set.
OIDC_ISSUER=
OIDC_WEB_CLIENT_ID=
# The API resource audience this app's API accepts in an access token. Never the client id: the boot
# refuses OIDC_AUDIENCE equal to OIDC_WEB_CLIENT_ID.
OIDC_AUDIENCE=
# Optional RFC 8707 resource URI from the selected identity link, forwarded at sign-in/exchange/refresh.
# Managed Better Auth sets it; it must equal OIDC_AUDIENCE, or the boot refuses it.
OIDC_RESOURCE=
# Only for a confidential client; the default public client uses PKCE and needs none.
OIDC_WEB_CLIENT_SECRET=
# Optional server-only resource-status credential, limited to this link's audience. Set both or neither.
OIDC_INTROSPECTION_CLIENT_ID=
OIDC_INTROSPECTION_CLIENT_SECRET=
# Optional server-only policy-bridge URL a managed provider (Better Auth) supplies with that credential.
# Without it, status uses the issuer's advertised introspection endpoint. Requires the credential.
OIDC_RESOURCE_STATUS_URL=
# Optional server-only issuer backchannel a managed provider (Better Auth) supplies: its address on this
# app's private network. The server sends its own OIDC requests there; the issuer and every browser URL
# stay OIDC_ISSUER. Needed where the app cannot reach its own public issuer (a single-host install).
OIDC_BACKCHANNEL_URL=
# Optional introspection claim an active answer must carry (managed Zitadel: the project-roles claim).
# Requires the credential.
OIDC_INTROSPECTION_REQUIRED_CLAIM=
# The managed identity link's server-only admission credential and the link's id, both injected by the
# link: an invitation then asks the platform to admit the invited address as `user` (ADR-062). Set both
# or neither; without them an invitation still works and admission is skipped (the log says why).
OIDC_ADMISSION_TOKEN=
OIDC_LINK_ID=
# Scopes asked of the provider. Default: openid profile email offline_access.
OIDC_SCOPES=
# Monotonic active-link generation. Existing links use 1; every provider cutover/rollback uses a new value.
AUTH_PROVIDER_GENERATION=
# Plain-HTTP discovery, outside production only (a local provider).
OIDC_ALLOW_INSECURE=
# 1 lets anyone in by e-mail address, with no identity provider. Refused at boot in production.
AUTH_DEV_LOGIN=1
# Whether any signed-in person may create an organization (true, the default). false: only a person
# the identity link grants the app-access role `admin` may (ADR-062 decision 5); everyone else joins by
# invitation.
APP_ORGANIZATION_SELF_SERVICE=
# true: one deployment, one organization. The first person founds it and everybody after is invited, and the
# app opens in its default workspace; an administrator may add more from the scope switcher. Default false.
APP_SINGLE_ORGANIZATION=
# 1 drops the Secure flag from the session cookie, for http://127.0.0.1. Refused at boot in production.
AUTH_INSECURE_COOKIES=1
# The session cookie's name. Default conusai_session.
AUTH_COOKIE_NAME=
# Session lifetime in seconds: idle 12 h and absolute 14 days by default.
AUTH_SESSION_IDLE_SECONDS=
AUTH_SESSION_ABSOLUTE_SECONDS=
# ---------------------------------------------------------------------------------------------
# This app
# ---------------------------------------------------------------------------------------------
# How many days a finished agent run (its step log and its conversation) is kept before the hourly sweep
# deletes it (modules/agent). A whole number from 1 to 3650; 90 when blank.
AGENT_RUN_RETENTION_DAYS=
# The model the AI gateway is asked for when a document is read (modules/documents).
AI_MODEL=
# Which search backend the knowledge module uses. "platform" is the default and the only one: the
# platform's knowledge service owns chunking, embeddings and the vector store, and the deployment token
# needs `knowledge.collections:use` (conusai.json asks for it). Any other value stops the app at start.
KNOWLEDGE_BACKEND=
# The embeddings model `platform.models.embed` asks the gateway for, for a module of yours that embeds
# text itself. Retrieval does not read it; the platform injects no default.
AI_EMBEDDING_MODEL=
# The kinds of page the documents extraction never asks the model about: a comma list of text, table,
# drawing, scan, empty. Without it, drawings and empty pages are left out and reported on the document.
# An empty value reads every page.
DOCUMENTS_EXCLUDED_PAGE_CLASSES=
# Where the worker writes the heartbeat its healthcheck reads. Default /tmp/worker-heartbeat.
WORKER_HEARTBEAT_FILE=
# kit:guides:begin
# The guides module's publish credential: a short-lived `guides:publish-code` token the platform
# hands the migrate service alone, for a deployment a member started, and revokes when the deploy
# job ends. Never set it yourself; without it the migrate job skips publishing code guides and says so.
CONUSAI_GUIDES_PUBLISH_TOKEN=
# The deployment's provenance JSON sent with it (deployment_id, source_revision, generation,
# requested_by), set by the platform beside the token.
CONUSAI_GUIDES_DEPLOYMENT=
# kit:guides:end
# kit:support:begin
# The support module's channel: the public key (spk_...) of a Support channel in this app's project,
# created in the console under Support -> Channels. It grants nothing by itself; widget sessions are
# minted with the deployment token (`support:widget-sessions`). Empty: no launcher.
CONUSAI_SUPPORT_CHANNEL=
# kit:support:end
# ---------------------------------------------------------------------------------------------
# `pnpm dev` and `pnpm e2e` (scripts/dev.mjs, e2e/support/stack.ts)
# ---------------------------------------------------------------------------------------------
# The ports they use on this machine. Defaults: web 3000, fake platform 4010, Postgres 55433; the
# end-to-end run uses 3100 and 55432 so it can run beside a development stack.
DEV_WEB_PORT=
DEV_PLATFORM_PORT=
DEV_POSTGRES_PORT=
# Optional private directory for verify-shell.mjs screenshots and bounded browser diagnostics.
# Development verification only; use disposable fixtures and protect captured evidence.
CONUSAI_BROWSER_EVIDENCE_DIR=
E2E_WEB_PORT=
E2E_POSTGRES_PORT=
# `production` builds the web shell for production for that run (e2e/support/stack.ts). Empty: development.
E2E_BUILD_MODE=
# ---------------------------------------------------------------------------------------------
# Shutdown (apps/web/server.mjs, read when it runs directly: compose.yaml does not pass them)
# ---------------------------------------------------------------------------------------------
# On SIGTERM, how long the web server waits, in milliseconds, for the requests in flight, then for the runtime's drain.
# Defaults 10000 and 8000: together they stay inside compose.yaml's stop_grace_period of 20 seconds.
SHUTDOWN_REQUESTS_MS=
SHUTDOWN_FLUSH_MS=
# Assigned by the E2E global setup from the simulated deployment’s organization; leave unset for the app.
E2E_USAGE_ORGANIZATION=