A survey of the twenty notebooks on disk found general facts that no tracked page stated; the maintainer struck the weak rows and the rest are written into their owning pages in each page's own words. The design-system page gains the hidden-navigation figures that replaced a dangling survey pointer, the reason the anatomy is parts and lint, the record-table grouping and single-tint rules, and when a surface earns row editing. The first-contact process gains a code-verification phase, the transcript lane for models without vision, the three kinds of honesty-audit drift and the click-path guardrail. The operator conventions gain guards-before-writes, error state over empty state, copy that states the real effect, toasts that report counts and the PostForm rule. The Stripe, FedWiki, identifiers, IA, testing, model and environment pages each gain their facts, the integration guide stops telling authors to hand-write a page title, issues.md logs the placeholder security contact, milestones.md records the Codeberg terms clause and CONTRIBUTING.md notes that the module path is the forge URL. One claimed fact was checked against the code and not written: the mass-mutation preview does not run the commit loop in a rolled-back transaction.
17 KiB
title, audience, summary
| title | audience | summary | ||
|---|---|---|---|---|
| Environment Variable Reference |
|
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.
Type. Every key's value is one of a closed set: string, url
(absolute, http or https, with a host), duration (a Go duration
string, e.g. 1h30m; never negative), int, bool (true/false), list
(comma-separated), or an enum's members joined by |. duration, greater than zero marks a duration key whose own consumer replaces a saved zero
with its default silently, so zero is refused rather than accepted and
ignored (design D6, typed-config-keys). Every declared integration key's
Type column is checked against its declaration by
internal/config/config_reference_test.go; core keys are filled by hand
from internal/config/validate.go's (ValidateStart) checks.
Core
| Key | Type | Env override | Purpose | Default | Required |
|---|---|---|---|---|---|
port |
string | MC_PORT |
Port the HTTP server listens on. | 8080 |
Optional |
base-url |
url | MC_BASE_URL |
Public URL of this console, e.g. https://console.example.com; http or https. Its origin is the console's sole cross-origin trusted origin, and its scheme decides the session cookie's Secure flag, the CSP upgrade-insecure-requests directive, and the Strict-Transport-Security header (all on for https, off for http); see production-deployment.md. |
none | Required |
env |
string | MC_ENV |
Environment label. development selects text log formatting; any other value selects JSON. Nothing security-relevant hangs off it. |
development |
Optional |
deployment-name |
string | 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 |
url | MC_SUPPORT_URL |
URL shown in error messages for users to get support. | none | Optional |
Database and session store
| Key | Type | Env override | Purpose | Default | Required |
|---|---|---|---|---|---|
db-dsn |
url (postgres) | MC_DB_DSN |
PostgreSQL connection string, e.g. postgres://user:pass@host:5432/dbname?sslmode=disable. Use this or db-dsn-file, never both. Treated as a secret: never logged; the boot log names host, port, database and user only. |
none | One of this or db-dsn-file |
db-dsn-file |
path | MC_DB_DSN_FILE |
File holding the PostgreSQL DSN, read at startup. | none | One of this or db-dsn |
valkey-addr |
string | MC_VALKEY_ADDR |
Valkey/Redis address (host:port) for server-side session storage. |
localhost:6379 |
Required (satisfied by the default unless explicitly cleared) |
valkey-username |
string | MC_VALKEY_USERNAME |
ACL username for the session store, when it uses one. | none | Optional |
valkey-password |
string | MC_VALKEY_PASSWORD |
Password for the session store. Use this or valkey-password-file, never both. |
none | Required (the store must not be reachable unauthenticated) |
valkey-password-file |
path | MC_VALKEY_PASSWORD_FILE |
File holding the session-store password, read at startup. | none | One of this or valkey-password |
valkey-tls |
bool | MC_VALKEY_TLS |
Connect to the session store over TLS. | false |
Optional |
valkey-tls-skip-verify |
bool | MC_VALKEY_TLS_SKIP_VERIFY |
Do not verify the session store's TLS certificate. Self-signed stores only; logs a warning at every boot. | false |
Optional |
CSRF and identity (OIDC)
| Key | Type | Env override | Purpose | Default | Required |
|---|---|---|---|---|---|
csrf-secret (secret) |
secret (32 bytes) | 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 |
string | MC_CSRF_SECRET_FILE |
File path holding csrf-secret. |
none | Optional |
oidc-idp-issuer-url |
url | MC_OIDC_IDP_ISSUER_URL |
OIDC issuer URL, e.g. https://idp.example.com/realms/main. |
none | Required |
oidc-idp-account-url |
url | MC_OIDC_IDP_ACCOUNT_URL |
URL of the identity provider's self-service account console, opened by the shell's Identity and Access control. OpenID discovery defines no such URL, so providers other than Keycloak set it here. | {oidc-idp-issuer-url}/account (Keycloak's shape) |
Optional |
oidc-sp-client-id |
string | MC_OIDC_SP_CLIENT_ID |
OIDC client ID registered for this console. | none | Required |
oidc-sp-client-secret (secret) |
string | MC_OIDC_SP_CLIENT_SECRET |
OIDC client secret. | none | Not enforced by boot validation; set it (or -file) for a confidential OIDC client |
oidc-sp-client-secret-file |
string | MC_OIDC_SP_CLIENT_SECRET_FILE |
File path holding oidc-sp-client-secret. |
none | Optional |
See identity-provider-setup.md for configuring the IdP side of this exchange.
Temporal
| Key | Type | Env override | Purpose | Default | Required |
|---|---|---|---|---|---|
temporal-host |
string | MC_TEMPORAL_HOST |
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 |
string | MC_TEMPORAL_NAMESPACE |
Temporal namespace. | default |
Required once temporal-host is set |
temporal-oauth-token-url |
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 |
string | MC_TEMPORAL_OAUTH_CLIENT_ID |
OAuth2 client ID for Temporal authentication. | none | Optional; see above |
temporal-oauth-client-secret (secret) |
string | MC_TEMPORAL_OAUTH_CLIENT_SECRET |
OAuth2 client secret for Temporal authentication. | none | Optional; see above |
temporal-oauth-client-secret-file |
string | MC_TEMPORAL_OAUTH_CLIENT_SECRET_FILE |
File path holding temporal-oauth-client-secret. |
none | Optional |
temporal-oauth-scopes |
list | MC_TEMPORAL_OAUTH_SCOPES |
OAuth2 scopes for Temporal authentication (comma-separated). | none | Optional |
temporal-connect-timeout |
duration | MC_TEMPORAL_CONNECT_TIMEOUT |
Max time to retry connecting to Temporal at boot before failing. | 90s |
Optional |
See temporal-authorization-setup.md for configuring the IdP side of Temporal's own JWT authorization.
Custom domains (external domain claims)
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 | Type | Env override | Purpose | Default | Required |
|---|---|---|---|---|---|
domains-connect-target |
string | 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 |
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 |
duration | MC_DOMAINS_CLAIM_WINDOW |
How long a member has to publish the TXT challenge before a pending claim expires. | 24h |
Optional |
domains-pending-cap |
int | MC_DOMAINS_PENDING_CAP |
Concurrent pending external domain verifications allowed per workspace. | 5 |
Optional |
domains-abandon-budget |
int | 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 |
duration | MC_DOMAINS_ABANDON_WINDOW |
Rolling window abandoned verifications are counted over. | 168h |
Optional |
domains-scope-labels |
int | 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 |
int | MC_DOMAINS_INITIATION_BUDGET |
New external domain claims allowed per workspace per rolling 24h. 0 disables the cap. |
10 |
Optional |
domains-expiry-sweep-interval |
duration | 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 | Type | Env override | Purpose | Default | Required |
|---|---|---|---|---|---|
billing-sweep-interval |
duration | MC_BILLING_SWEEP_INTERVAL |
Interval between billing scheduled-change sweeps (backstop firing path for due subscription changes). | 1h |
Optional |
webhook-partition-ensure-interval |
duration | 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 | Type | Env override | Purpose | Default | Required |
|---|---|---|---|---|---|
stripe-api-key (secret) |
string | 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 |
string | MC_STRIPE_API_KEY_FILE |
File path holding stripe-api-key. |
none | Optional |
stripe-webhook-secret (secret) |
string | MC_STRIPE_WEBHOOK_SECRET |
Stripe webhook endpoint signing secret. | none | Required together with stripe-api-key |
stripe-webhook-secret-file |
string | MC_STRIPE_WEBHOOK_SECRET_FILE |
File path holding stripe-webhook-secret. |
none | Optional |
See stripe.md for the webhook endpoint, subscribed events, and catalog sync.
FedWiki (optional; the FedWiki farm connection)
| Key | Type | Env override | Purpose | Default | Required |
|---|---|---|---|---|---|
fedwiki-farm-api-url |
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) |
string | MC_FEDWIKI_ADMIN_TOKEN |
FarmManager API admin access token. | none | Required together with fedwiki-farm-api-url |
fedwiki-admin-token-file |
string | MC_FEDWIKI_ADMIN_TOKEN_FILE |
File path holding fedwiki-admin-token. |
none | Optional |
fedwiki-allowed-domains |
list | 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 |
http|https | MC_FEDWIKI_SITE_SCHEME |
URL scheme for generated FedWiki site links: http or https. |
https |
Optional |
fedwiki-sync-enabled |
bool | MC_FEDWIKI_SYNC_ENABLED |
Enable periodic sync of sites from the FedWiki farm. | false |
Optional |
fedwiki-sync-interval |
duration, greater than zero | MC_FEDWIKI_SYNC_INTERVAL |
Interval between FedWiki site syncs. Inert while sync is disabled. | 1h |
Optional |
fedwiki-sync-trigger-immediately |
bool | MC_FEDWIKI_SYNC_TRIGGER_IMMEDIATELY |
Run a sync immediately at startup, in addition to the interval. | true |
Optional |
fedwiki-swap-cooldown |
duration | 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 | Type | Env override | Purpose | Default | Required |
|---|---|---|---|---|---|
discourse-base-url |
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) |
string | 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 |
string | MC_DISCOURSE_API_KEY_FILE |
File path holding discourse-api-key. |
none | Optional |
discourse-api-username |
string | MC_DISCOURSE_API_USERNAME |
Api-Username header value for Discourse admin API calls. |
system |
Optional |
discourse-linkage-mode |
email|oidc|discourseconnect | MC_DISCOURSE_LINKAGE_MODE |
How persons are matched to Discourse users: email, oidc, or discourseconnect. |
oidc |
Optional |
discourse-auto-create-users |
false|true | 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) |
string | MC_DISCOURSE_WEBHOOK_SECRET |
Shared secret verifying Discourse webhook signatures. Leave empty to disable the webhook endpoint. | none | Optional |
discourse-webhook-secret-file |
string | MC_DISCOURSE_WEBHOOK_SECRET_FILE |
File path holding discourse-webhook-secret. |
none | Optional |
discourse-sync-interval |
duration, greater than zero | MC_DISCOURSE_SYNC_INTERVAL |
Interval between Discourse group-sync sweeps. | 15m |
Optional |
discourse-sync-trigger-immediately |
bool | 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. The overlay is read once, during
single-threaded boot, so an override that no longer parses has no running
value to fall back on and boot fails, naming the key. PostgreSQL's split,
fatal at start and ignored with a log entry at reload, is the rule to copy
if the overlay ever gains a reload path. 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 | Type | Purpose | Default |
|---|---|---|---|
LOG_LEVEL |
debug|info|warn|error | Log verbosity, read directly via os.Getenv in internal/logging/logging.go (not a Viper/MC_* key). Accepts any value slog.Level.UnmarshalText parses (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.