Self-hoster setup + env-var reference in README; CLAUDE.md convention to keep it current #114

Closed
opened 2026-06-18 13:58:47 +00:00 by james · 0 comments
Owner

The repo's self-hoster-facing setup is scattered across README.md, CLAUDE.md, Dockerfile, docs/ci.md, docs/oidc-self-hoster-guide.md, and the ADR set. A self-hoster reading the README today doesn't see:

  • That DATABASE_URL defaults to sqlite:./data/carol.db and accepts Postgres URLs.
  • That CAROL_STORAGE_ROOT controls blob storage (added under #21 / ADR-0018).
  • That APP_URL is needed under a reverse proxy (added by #103).
  • That REGISTRATION_POLICY accepts open | invite | admin-approval but only open is implemented today.
  • That OIDC_<NAME>_* provider configuration goes in env, not a config file (ADR-0017).
  • That the container exposes PORT / HOSTNAME and ships with NEXT_TELEMETRY_DISABLED=1.

A quick grep over the source today (process.env.[A-Z_]+) confirms the user-facing surface is: APP_URL, CAROL_STORAGE_ROOT, DATABASE_URL, REGISTRATION_POLICY, plus the Dockerfile ENV defaults and the dynamic OIDC_<NAME>_* set. None of those names appear in the README.

Without a single source of truth, every new feature ticket either re-documents the same info or quietly relies on the contributor reading the source — exactly the failure mode the env-var sprawl creates.

Scope

  • Main README.md gains:
    • Configuration section — every self-hoster-facing env var: default, allowed values, what it controls, when the default works and when it doesn't. Group by concern (data, storage, auth, OIDC, ops). The audit pass should walk process.env.* in lib/, app/, db/, proxy.ts, instrumentation.ts, and the Dockerfile.
    • Self-hosted deployment snippet — minimal podman run / compose with the data-directory volume mount called out and the minimum env vars to start.
    • Local development — the existing npm install flow stays, plus a note on overriding env vars locally (shell export or .env.local).
  • CLAUDE.md gains a convention bullet (under Conventions — these are load-bearing) saying: every PR that adds, removes, or changes a self-hoster-facing env var must update the README's Configuration table in the same commit. No user-facing env var lives only in the source. CI-runner / test-only env vars (BASE_REF, FORGEJO_*, GITHUB_*, PR_NUMBER, TEST_POSTGRES_URL, NEXT_RUNTIME) are explicitly out — they belong with the workflow or test that uses them.
  • Avoid duplication. CLAUDE.md's Stack defaults and Working in this repo sections currently restate some of this. After the README lands as the source of truth, those bullets should link to the README rather than repeat the values.

Acceptance criteria

  • README.md has a Configuration section listing every self-hoster-facing env var with default + brief description, grouped by concern.
  • README.md has a self-hosted deployment snippet that names the data-directory volume and shows the minimum env vars to start the container.
  • CLAUDE.md adds the convention bullet that ties future env-var changes to README updates.
  • grep -rohE 'process\.env\.[A-Z_]+' lib/ app/ db/ proxy.ts instrumentation.ts | sort -u shows no name that isn't either in the README table or explicitly marked as internal in the audit notes inside this PR's description.
  • No env-var values are duplicated between README.md and CLAUDE.md / docs/* — the deeper docs link to the README's table rather than restate it.

Out of scope

  • A CI check that enforces the convention (greps process.env.* and fails if anything isn't in the README table). Worth a follow-up ticket if drift turns out to be real; the convention bullet is the soft enforcement first.
  • A .env.example file. Useful but follow-up — the README table is the source of truth first; a checked-in example file is the second-order convenience.
  • Reformatting existing operational deep-dives (docs/ci.md, docs/oidc-self-hoster-guide.md). Those stay as references; the README is the "where do I start?" entry point and should link into them, not absorb them.
The repo's self-hoster-facing setup is scattered across `README.md`, `CLAUDE.md`, `Dockerfile`, `docs/ci.md`, `docs/oidc-self-hoster-guide.md`, and the ADR set. A self-hoster reading the README today doesn't see: - That `DATABASE_URL` defaults to `sqlite:./data/carol.db` and accepts Postgres URLs. - That `CAROL_STORAGE_ROOT` controls blob storage (added under #21 / ADR-0018). - That `APP_URL` is needed under a reverse proxy (added by #103). - That `REGISTRATION_POLICY` accepts `open | invite | admin-approval` but only `open` is implemented today. - That `OIDC_<NAME>_*` provider configuration goes in env, not a config file (ADR-0017). - That the container exposes `PORT` / `HOSTNAME` and ships with `NEXT_TELEMETRY_DISABLED=1`. A quick grep over the source today (`process.env.[A-Z_]+`) confirms the user-facing surface is: `APP_URL`, `CAROL_STORAGE_ROOT`, `DATABASE_URL`, `REGISTRATION_POLICY`, plus the Dockerfile `ENV` defaults and the dynamic `OIDC_<NAME>_*` set. None of those names appear in the README. Without a single source of truth, every new feature ticket either re-documents the same info or quietly relies on the contributor reading the source — exactly the failure mode the env-var sprawl creates. ## Scope - **Main `README.md`** gains: - **Configuration** section — every self-hoster-facing env var: default, allowed values, what it controls, when the default works and when it doesn't. Group by concern (data, storage, auth, OIDC, ops). The audit pass should walk `process.env.*` in `lib/`, `app/`, `db/`, `proxy.ts`, `instrumentation.ts`, and the Dockerfile. - **Self-hosted deployment** snippet — minimal `podman run` / compose with the data-directory volume mount called out and the minimum env vars to start. - **Local development** — the existing `npm install` flow stays, plus a note on overriding env vars locally (shell export or `.env.local`). - **`CLAUDE.md`** gains a convention bullet (under *Conventions* — these are load-bearing) saying: every PR that adds, removes, or changes a self-hoster-facing env var must update the README's *Configuration* table in the same commit. No user-facing env var lives only in the source. CI-runner / test-only env vars (`BASE_REF`, `FORGEJO_*`, `GITHUB_*`, `PR_NUMBER`, `TEST_POSTGRES_URL`, `NEXT_RUNTIME`) are explicitly out — they belong with the workflow or test that uses them. - **Avoid duplication.** `CLAUDE.md`'s *Stack defaults* and *Working in this repo* sections currently restate some of this. After the README lands as the source of truth, those bullets should link to the README rather than repeat the values. ## Acceptance criteria - [ ] `README.md` has a *Configuration* section listing every self-hoster-facing env var with default + brief description, grouped by concern. - [ ] `README.md` has a self-hosted deployment snippet that names the data-directory volume and shows the minimum env vars to start the container. - [ ] `CLAUDE.md` adds the convention bullet that ties future env-var changes to README updates. - [ ] `grep -rohE 'process\.env\.[A-Z_]+' lib/ app/ db/ proxy.ts instrumentation.ts | sort -u` shows no name that isn't either in the README table or explicitly marked as internal in the audit notes inside this PR's description. - [ ] No env-var values are duplicated between `README.md` and `CLAUDE.md` / `docs/*` — the deeper docs link to the README's table rather than restate it. ## Out of scope - A CI check that enforces the convention (greps `process.env.*` and fails if anything isn't in the README table). Worth a follow-up ticket if drift turns out to be real; the convention bullet is the soft enforcement first. - A `.env.example` file. Useful but follow-up — the README table is the source of truth first; a checked-in example file is the second-order convenience. - Reformatting existing operational deep-dives (`docs/ci.md`, `docs/oidc-self-hoster-guide.md`). Those stay as references; the README is the "where do I start?" entry point and should *link* into them, not absorb them.
james closed this issue 2026-06-18 15:30:49 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
james/carol#114
No description provided.