Repository navigation
Expand file tree
/
Copy path.env.example
More file actions
144 lines (133 loc) · 8.9 KB
/
Copy path.env.example
File metadata and controls
144 lines (133 loc) · 8.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# LearnStack — local dev environment variables (single source of truth).
#
# Copy to `.env` at the repo root (NOT committed — `.gitignore` covers it).
# `infra/compose/dev.yml` and `infra/compose/e2e.yml` read this via the
# `${VAR:-default}` interpolation Compose performs at file-parse time
# (every reference has a dev-safe fallback so the stack still boots even
# without `.env`).
#
# It only reaches Compose through an explicit `--env-file .env`. Compose
# resolves its default env file from the project directory — `infra/compose/` —
# not from the cwd, so a bare `docker compose -f infra/compose/dev.yml …` from
# the repo root ignores this file entirely and every value below falls back.
# `make`, `scripts/seed.sh` and the commands in `infra/*/README.md` pass the
# flag; anything you type by hand has to as well.
#
# The Dapr Vault token chain runs through Dapr's own
# `secretKeyRef` + local-env-secret-store indirection — `.env` → compose
# env → daprd's process env → `secretstore-envvar.yaml` (the
# `secretstores.local.env` component named `envvar-secrets`) →
# `secretstore-vault.yaml` `secretKeyRef`. Dapr does not support a
# `{{env.VAR}}` template; the indirection is the only sanctioned shape.
# See `infra/dapr/README.md` § Vault token for the full walk.
#
# Every value below is a **dev-only** default. Production wires the real
# values through `ISecretProvider` against an authenticated Vault cluster
# per Standards 12 § Secrets Management — `.env.example` is the local
# parity, not the production source.
# ─── Postgres (PostgreSQL 18 per ADR-0031) ───────────────────────────────
# The superuser the container boots as. It owns nothing the application uses:
# every LearnStack table is owned by learnstack_migration below, because an
# owner defeats its own Row Level Security policies and every isolation test
# would then pass against policies that constrain nothing.
POSTGRES_USER=learnstack
POSTGRES_PASSWORD=learnstack
POSTGRES_DB=learnstack
# ─── The four database roles (ADR-0003 Amendment 3) ──────────────────────
# Read by infra/compose/postgres-init/02-create-roles.sql through psql's
# \getenv on first boot. Four roles and four separate login credentials;
# the role model is closed and a fifth role requires an ADR. Additional
# application-role sources do not create roles (ADR-0076/0077).
# An unset variable aborts initdb rather than creating a passwordless role.
LEARNSTACK_MIGRATION_PW=learnstack-migration-dev
LEARNSTACK_APP_PW=learnstack-app-dev
LEARNSTACK_PLATFORM_PW=learnstack-platform-dev
LEARNSTACK_OUTBOX_PW=learnstack-outbox-dev
# ─── Baseline connection strings ────────────────────────────────────────
# Double underscore is the .NET environment spelling of `ConnectionStrings:X`.
# These are NOT interchangeable and must not be unified in any environment,
# local development included — see Standards 05 § Database roles.
#
# Migration — `make migrate` and the deploy job ONLY. Never present in
# API or worker runtime configuration: the role owns every
# table, and a runtime that is the owner is the arrangement
# FORCE ROW LEVEL SECURITY exists to defeat.
# Default — ordinary request/job business owners. NOBYPASSRLS.
# PlatformAdmin — resolvable only by PlatformAdminScope. BYPASSRLS.
# OutboxDispatcher — API-owned OutboxProcessor only. Never Seeder or web.
ConnectionStrings__Migration='Host=localhost;Port=5432;Database=learnstack;Username=learnstack_migration;Password=learnstack-migration-dev'
ConnectionStrings__Default='Host=localhost;Port=5432;Database=learnstack;Username=learnstack_app;Password=learnstack-app-dev'
ConnectionStrings__PlatformAdmin='Host=localhost;Port=5432;Database=learnstack;Username=learnstack_platform;Password=learnstack-platform-dev'
ConnectionStrings__OutboxDispatcher='Host=localhost;Port=5432;Database=learnstack;Username=learnstack_outbox_admin;Password=learnstack-outbox-dev'
# API/Seeder startup qualifies the coupled backend-only
# IdentityAuthorization / AuthorizationEvidence sources use the SAME app role.
# Development may derive both only for direct PostgreSQL; other modes require
# both explicit strings. Do not add one alone or expose either to the web.
# docs/standards/05-database.md#authorization-and-evidence-source-ledger owns
# source limits, actual cleanup and the independent PgBouncer backend lanes.
# The selected runtime child receives both keys; restore/build and web do not.
# ─── Keycloak (two realms per ADR-0004 Amendment 1) ──────────────────────
# The Development API defaults to the loopback tenant issuer declared in
# backend/src/LearnStack.Api/appsettings.Development.json. Other deployment modes
# require an explicit canonical HTTPS issuer; the API and authority installer use it.
Authentication__Tenant__Issuer=http://localhost:8080/realms/learnstack
# Global identity uses an explicit stable deployment ID, not a hash of the issuer.
# `make migrate` installs/verifies BOTH explicit keys as one immutable registration.
# This fixed ID is local development data; deployment owners choose their stable ID.
Identity__AuthorityId=019a1929-5450-7bbb-8df1-516e8e002501
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=admin-dev-secret
# Server-only BFF client source. Old local .env files must add it explicitly;
# reconciliation verifies an existing confidential secret and never rotates it.
# Never pass this value to the API, public renderer or .NET Seeder.
KEYCLOAK_WEB_CLIENT_SECRET=learnstack-web-dev-secret
# Optional native tenant BFF (ADR-0070). Explicit false keeps the anonymous demo
# independent of Keycloak. For local watch mode, opt in with true and the issuer
# below; production launch requires an HTTPS issuer and a trusting private CA.
# All present root/web/process values must agree. Private source files are 0600.
LEARNSTACK_BFF_ENABLED=false
# LEARNSTACK_BFF_ISSUER=http://localhost:8080/realms/learnstack
# ─── Vault (-dev mode; token shared with Dapr secret-store component) ────
# Boots the `vault` compose service via `-dev-root-token-id` AND is passed
# into the `dapr-sidecar-api` service env so Dapr's `secretstore-vault.yaml`
# component can resolve `vaultToken` through `secretKeyRef` against the
# local-env secret store (`secretstore-envvar.yaml` → `envvar-secrets`).
# Changing this value updates Vault boot + Dapr auth in one shot.
VAULT_ROOT_TOKEN=learnstack-dev-root-token
# ─── LiveKit (dev key/secret; production rotates via ILiveClassProvider) ─
LIVEKIT_API_KEY=devkey
LIVEKIT_API_SECRET=devsecret-32-byte-min-length-padding-xyz
# ─── Coturn (long-term credentials; production uses use-auth-secret) ─────
COTURN_USER=devuser
COTURN_PASSWORD=devsecret
# ─── SeaweedFS S3 (dev identities; production loads from Vault) ──────────
# These values MUST match `infra/seaweedfs/s3-identities.json` because that
# file is what SeaweedFS actually reads at boot (the binary does not support
# env-var substitution in its identity config). The vars here document the
# canonical credential for the future backend `IStorageProvider` adapter
# (Phase 02b+) and any developer S3 CLI scripts; changing them WITHOUT
# updating the JSON above means the backend tries to talk with a key the
# server has never seen. Production swaps both for Vault-issued credentials.
SEAWEEDFS_ACCESS_KEY=learnstack
SEAWEEDFS_SECRET_KEY=learnstack-dev-secret
# ─── Meilisearch (dev master key; production loads from Vault) ───────────
# Read by the `meilisearch` compose service. Every search request carries it
# as a bearer token; Meilisearch refuses to start in `production` env without
# one. Standards 12 § Development credentials requires the `${VAR:-default}`
# indirection rather than a literal in `dev.yml`.
MEILI_MASTER_KEY=learnstack-dev-master-key
# ─── Backend host (LearnStack.Api, runs on workstation via `dotnet run`) ─
# `dotnet run` reads no `.env`, so these two lines are documentation. The API's launch
# profile, backend/src/LearnStack.Api/Properties/launchSettings.json, sets the same two.
ASPNETCORE_ENVIRONMENT=Development
ASPNETCORE_URLS=http://localhost:5080
# ─── Public renderer (ADR-0053; API and web share this private source) ───
# make public-env fills the empty secret with 32 random bytes encoded as ASCII.
# No TLS/hosts/trust-store changes are automatic. See README Quickstart.
# make public-api loads application/platform-admin/dispatcher DB credentials
# plus network AND secret.
# pnpm dev/start loads these values; an optional web .env.local must match.
LEARNSTACK_PUBLIC_API_ORIGIN=http://127.0.0.1:5080
LEARNSTACK_PUBLIC_HOP_SECRET=
LEARNSTACK_PUBLIC_TLS_CERT=.data/tls/public.pem
LEARNSTACK_PUBLIC_TLS_KEY=.data/tls/public-key.pem