Implement the ux-first-run change: a state-derived setup checklist on
/operator/setup with a landing region that recedes once required steps
are done, and empty states that distinguish blocked from empty across
operator and member surfaces. Also add production deployment and
environment reference docs, plus a config-key completeness test.
Every configuration key member-console reads: purpose, default, required/optional, and its derived MC_ environment variable override.
Environment Variable Reference
member-console reads configuration through Viper,
layered in this precedence order (highest wins): command-line flag, MC_*
environment variable, mc-config.yaml (or the file passed to --config),
built-in default. internal/config/config_reference_test.go asserts every
configuration key the source code reads is documented on this page.
Derivation rule: every key below is written in mc-config.yaml as its
kebab-case name (e.g. db-dsn). Its environment variable override is
MC_ followed by that name upper-cased with every - replaced by _ (e.g.
MC_DB_DSN). This is a single mechanical rule (cmd/root.go:
viper.SetEnvPrefix("MC") + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))) applied uniformly; the table below states each key once and omits the
env column's value where it is a pure derivation, but always names the env
form so it can be found by search.
Secret keys and -file variants. A key marked secret also accepts a
<key>-file variant (env MC_<KEY>_FILE) whose value is a filesystem path;
at boot, member-console reads the file's contents into the key. Setting both
the direct value and the -file variant for the same key is a fatal
misconfiguration (the process exits before starting any service). This is
how Docker/Podman secrets and Kubernetes-mounted secrets are wired in without
putting secret material in the environment or the config file — see
production-deployment.md.
Core
Key
Env override
Purpose
Default
Required
port
MC_PORT
Port the HTTP server listens on.
8080
Optional
base-url
MC_BASE_URL
Public URL of this console, e.g. https://console.example.com. Also the console's sole CSRF trusted origin — see production-deployment.md.
none
Required
env
MC_ENV
development or production. Controls the CSP upgrade-insecure-requests directive, the CSRF cookie's Secure flag, and JSON vs. text log formatting.
development
Optional
deployment-name
MC_DEPLOYMENT_NAME
Name this deployment presents for itself on the member and operator mastheads, page titles, and OpenGraph tags.
Member Console
Optional (rejected if set to blank/whitespace-only)
support-url
MC_SUPPORT_URL
URL shown in error messages for users to get support.
none
Optional
Database and session store
Key
Env override
Purpose
Default
Required
db-dsn
MC_DB_DSN
PostgreSQL connection string, e.g. postgres://user:pass@host:5432/dbname?sslmode=disable.
none
Required
valkey-addr
MC_VALKEY_ADDR
Valkey/Redis address (host:port) for server-side session storage.
localhost:6379
Required (satisfied by the default unless explicitly cleared)
CSRF and identity (OIDC)
Key
Env override
Purpose
Default
Required
csrf-secret (secret)
MC_CSRF_SECRET
HMAC key signing the anti-CSRF tokens embedded in every page and form. Must be exactly 32 bytes.
none
Required, unless csrf-secret-file is set
csrf-secret-file
MC_CSRF_SECRET_FILE
File path holding csrf-secret.
none
Optional
oidc-idp-issuer-url
MC_OIDC_IDP_ISSUER_URL
OIDC issuer URL, e.g. https://idp.example.com/realms/main.
none
Required
oidc-sp-client-id
MC_OIDC_SP_CLIENT_ID
OIDC client ID registered for this console.
none
Required
oidc-sp-client-secret (secret)
MC_OIDC_SP_CLIENT_SECRET
OIDC client secret.
none
Not enforced by boot validation; set it (or -file) for a confidential OIDC client
Temporal server host:port, e.g. localhost:7233. Leaving it unset disables Temporal, the worker, integration workflows, and every scheduled sweep below.
none
Optional (functionally required for provisioning and scheduled jobs)
temporal-namespace
MC_TEMPORAL_NAMESPACE
Temporal namespace.
default
Required once temporal-host is set
temporal-oauth-token-url
MC_TEMPORAL_OAUTH_TOKEN_URL
OAuth2 token endpoint for Temporal client authentication.
none
Optional; if any temporal-oauth-* key below is set, all three must be
temporal-oauth-client-id
MC_TEMPORAL_OAUTH_CLIENT_ID
OAuth2 client ID for Temporal authentication.
none
Optional; see above
temporal-oauth-client-secret (secret)
MC_TEMPORAL_OAUTH_CLIENT_SECRET
OAuth2 client secret for Temporal authentication.
none
Optional; see above
temporal-oauth-client-secret-file
MC_TEMPORAL_OAUTH_CLIENT_SECRET_FILE
File path holding temporal-oauth-client-secret.
none
Optional
temporal-oauth-scopes
MC_TEMPORAL_OAUTH_SCOPES
OAuth2 scopes for Temporal authentication (comma-separated).
none
Optional
temporal-connect-timeout
MC_TEMPORAL_CONNECT_TIMEOUT
Max time to retry connecting to Temporal at boot before failing.
Members with the capability can point their own domain at a FedWiki site or
other resource; these keys tune that subsystem. All are optional — leaving
domains-connect-target unset disables external domain claims
deployment-wide.
Key
Env override
Purpose
Default
Required
domains-connect-target
MC_DOMAINS_CONNECT_TARGET
DNS target members point external custom domains at (CNAME host or A-record IP). Empty disables external domain claims deployment-wide.
none
Optional
domains-ask-fallback-url
MC_DOMAINS_ASK_FALLBACK_URL
Legacy on-demand-TLS answerer consulted for names unknown to the domains registry. Empty refuses unknown names.
none
Optional
domains-claim-window
MC_DOMAINS_CLAIM_WINDOW
How long a member has to publish the TXT challenge before a pending claim expires.
24h
Optional
domains-pending-cap
MC_DOMAINS_PENDING_CAP
Concurrent pending external domain verifications allowed per workspace.
5
Optional
domains-abandon-budget
MC_DOMAINS_ABANDON_BUDGET
Verifications a workspace may start and abandon under one domain scope, within the abandonment window, before further claims are refused. 0 disables the ledger.
3
Optional
domains-abandon-window
MC_DOMAINS_ABANDON_WINDOW
Rolling window abandoned verifications are counted over.
168h
Optional
domains-scope-labels
MC_DOMAINS_SCOPE_LABELS
Trailing DNS labels forming the scope abandonments are counted under, so sibling names share one scope.
2
Optional
domains-initiation-budget
MC_DOMAINS_INITIATION_BUDGET
New external domain claims allowed per workspace per rolling 24h. 0 disables the cap.
10
Optional
domains-expiry-sweep-interval
MC_DOMAINS_EXPIRY_SWEEP_INTERVAL
Interval between the Temporal-backed domain-claim expiry sweep (backstop for claims whose verification workflow is gone).
15m
Optional
Billing and maintenance sweeps
Key
Env override
Purpose
Default
Required
billing-sweep-interval
MC_BILLING_SWEEP_INTERVAL
Interval between billing scheduled-change sweeps (backstop firing path for due subscription changes).
1h
Optional
webhook-partition-ensure-interval
MC_WEBHOOK_PARTITION_ENSURE_INTERVAL
Interval between core.webhook_events partition-ensure runs, keeping monthly partitions provisioned ahead of need.
24h
Optional
Stripe (optional — only for paid products)
Key
Env override
Purpose
Default
Required
stripe-api-key (secret)
MC_STRIPE_API_KEY
Stripe secret API key.
none
Required together with stripe-webhook-secret to enable billing; both empty leaves it disabled
stripe-api-key-file
MC_STRIPE_API_KEY_FILE
File path holding stripe-api-key.
none
Optional
stripe-webhook-secret (secret)
MC_STRIPE_WEBHOOK_SECRET
Stripe webhook endpoint signing secret.
none
Required together with stripe-api-key
stripe-webhook-secret-file
MC_STRIPE_WEBHOOK_SECRET_FILE
File path holding stripe-webhook-secret.
none
Optional
stripe-mode
MC_STRIPE_MODE
test or live. Controls the operator panel's "view in Stripe" dashboard link URLs.
test
Optional
See stripe.md for the webhook endpoint, subscribed events, and catalog sync.
FedWiki (optional — the FedWiki farm connection)
Key
Env override
Purpose
Default
Required
fedwiki-farm-api-url
MC_FEDWIKI_FARM_API_URL
URL of the FedWiki farm's FarmManager API endpoint, e.g. https://admin.wiki.example.com.
none
Required together with fedwiki-admin-token; both empty leaves the farm connection disabled
fedwiki-admin-token (secret)
MC_FEDWIKI_ADMIN_TOKEN
FarmManager API admin access token.
none
Required together with fedwiki-farm-api-url
fedwiki-admin-token-file
MC_FEDWIKI_ADMIN_TOKEN_FILE
File path holding fedwiki-admin-token.
none
Optional
fedwiki-allowed-domains
MC_FEDWIKI_ALLOWED_DOMAINS
Domains where users can create FedWiki sites (comma-separated), e.g. wiki.example.com,wiki2.example.com.
none
Optional
fedwiki-site-scheme
MC_FEDWIKI_SITE_SCHEME
URL scheme for generated FedWiki site links: http or https.
https
Optional
fedwiki-sync-enabled
MC_FEDWIKI_SYNC_ENABLED
Enable periodic sync of sites from the FedWiki farm.
false
Optional
fedwiki-sync-interval
MC_FEDWIKI_SYNC_INTERVAL
Interval between FedWiki site syncs. Inert while sync is disabled.
1h
Optional
fedwiki-sync-trigger-immediately
MC_FEDWIKI_SYNC_TRIGGER_IMMEDIATELY
Run a sync immediately at startup, in addition to the interval.
true
Optional
fedwiki-swap-cooldown
MC_FEDWIKI_SWAP_COOLDOWN
Cooldown window between FedWiki active-site rotations (swap or archive-then-restore). 0 disables it.
720h (30 days)
Optional
See fedwiki-setup.md for the FarmManager security stack and local dev setup.
Discourse (optional)
Key
Env override
Purpose
Default
Required
discourse-base-url
MC_DISCOURSE_BASE_URL
Base URL of the Discourse instance, e.g. https://forum.example.com.
none
Required together with discourse-api-key; both empty leaves the integration dormant
discourse-api-key (secret)
MC_DISCOURSE_API_KEY
Discourse admin API key (global key, used with discourse-api-username).
none
Required together with discourse-base-url
discourse-api-key-file
MC_DISCOURSE_API_KEY_FILE
File path holding discourse-api-key.
none
Optional
discourse-api-username
MC_DISCOURSE_API_USERNAME
Api-Username header value for Discourse admin API calls.
system
Optional
discourse-linkage-mode
MC_DISCOURSE_LINKAGE_MODE
How persons are matched to Discourse users: email, oidc, or discourseconnect.
oidc
Optional
discourse-auto-create-users
MC_DISCOURSE_AUTO_CREATE_USERS
Create Discourse accounts for entitled persons with no forum user (true/false). The default only finds and links existing users.
false
Optional
discourse-webhook-secret (secret)
MC_DISCOURSE_WEBHOOK_SECRET
Shared secret verifying Discourse webhook signatures. Leave empty to disable the webhook endpoint.
none
Optional
discourse-webhook-secret-file
MC_DISCOURSE_WEBHOOK_SECRET_FILE
File path holding discourse-webhook-secret.
none
Optional
discourse-sync-interval
MC_DISCOURSE_SYNC_INTERVAL
Interval between Discourse group-sync sweeps.
15m
Optional
discourse-sync-trigger-immediately
MC_DISCOURSE_SYNC_TRIGGER_IMMEDIATELY
Run a group-sync sweep immediately at startup.
false
Optional
See discourse-setup.md for forum-side prerequisites and linkage-mode selection.
Integration settings overlay
Every key above that is part of an installed integration's declared spec
(FedWiki, Stripe, Discourse) can also be reviewed and overridden after boot
from the operator Integration Settings UI, without touching mc-config.yaml
or the environment. An override an operator saves there is stored in
core.integration_config_overrides and layered over the environment's value
at the next boot (internal/config.ApplyOverlay); it is not read live, so
a saved override takes effect on restart. Secret-marked keys are never
overridable from this UI — only their presence is shown, never their value
(internal/config/validate.go:180, internal/config.RequiredKeysUnresolved).
This page does not restate each integration's key list a second time for
the UI; the keys are the same ones documented above.
Direct environment reads outside Viper
Variable
Purpose
Default
LOG_LEVEL
Log verbosity, read directly via os.Getenv in internal/logging/logging.go (not a Viper/MC_* key). Accepts any value slog.Level.UnmarshalText parses: debug, info, warn, error (case-insensitive). An unparseable value panics at boot.
info
Test-only environment variables
TEST_DATABASE_URL is read directly (os.Getenv) by the Go test suite's
DB-backed tests; it is not a member-console application configuration key and
has no MC_* form. It, E2E_DATABASE_URL, and POSTGRES_ADMIN_DSN are part
of the test-stack contract documented in test/AGENTS.md
and testing.md, not this reference.