Files
2GT-RichandClaude Opus 5 e10f7ba568 docs: split reference material into docs/, keeping the README a shop window (v0.23.4-beta)
Documentation only — no functional change.

The README was carrying two jobs for two different readers. Its Reference section was
the single largest block at 154 lines, and nobody deciding whether to try the project
reads an InfluxDB environment variable table — while the people who need it were
scrolling past the pitch to reach it.

Split along that seam: anything you would read before installing stays in the README,
anything you would read after installing moves to docs/.

  README.md              430 lines   sell, prove, install, feature overview
  docs/change-guard.md   193         safety system, settings, guard states
  docs/architecture.md   116         data stores, polling model, module layout
  docs/capsman.md         84         role model, radio matching, current limits
  docs/alerting.md        81         rules, channels, webhooks, maintenance windows
  docs/api.md             77         scoped tokens, preflight, scripting
  docs/configuration.md   76         environment, secrets, rotation, TLS
  docs/sso-oidc.md        71         identity provider setup and behaviour
  docs/README.md          20         index

In-repo rather than a documentation site, deliberately. A change to Change Guard's
semantics can edit its documentation in the same commit as the code — which, given how
often that behaviour has been refined recently, is the property that actually matters.
A static site generator can point at docs/ later without moving a file.

The Change Guard pitch stays on the front page: the problem framing, the verified
recovery timeline and the quoted prediction warning are what make someone care, and a
reference page is the wrong home for them.

Three sections are new rather than relocated, written because the split exposed the gaps:

  - architecture.md did not exist. It now records why there are three data stores, the
    polling cadences, and which modules are pure functions over a snapshot and why.
  - Scoped API tokens shipped without usage documentation. api.md shows preflighting a
    change from a script and reading the guard block afterwards.
  - change-guard.md records why ip-on-bridge-port is informational rather than critical
    on RouterOS 7 — reasoning that previously existed only in a commit message.

Every internal anchor and cross-file link verified to resolve, including anchors into
other documents. No content dropped, checked by keyword comparison against the previous
single file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 12:26:18 -07:00

3.5 KiB

Configuration

← Documentation index

Environment variables

Set in .env at the project root. Changing any of these requires a container restart.

Variable Default Description
JWT_SECRET auto-generated & persisted Signs session tokens. Set it to pin your own value.
ENCRYPTION_KEY auto-generated & persisted Encrypts device passwords at rest. Set it to pin your own value.
CORS_ORIGIN localhost defaults Comma-separated browser origins allowed to call the API. Required in production.
DB_PASSWORD mikrotik_secure_pw PostgreSQL password
INFLUXDB_TOKEN mytoken123456789 InfluxDB admin token
INFLUXDB_ORG mikrotik-manager InfluxDB organization
INFLUXDB_BUCKET metrics InfluxDB bucket for time-series data
INFLUXDB_ADMIN_PASSWORD admin_password_123 InfluxDB admin UI password
HTTP_PORT 80 Host port for HTTP (redirects to HTTPS)
HTTPS_PORT 443 Host port for HTTPS

Never commit .env. It is already listed in .gitignore.

For a production deployment the only variable you genuinely must set is CORS_ORIGIN. Both secrets generate themselves safely — see below.

Secret management (self-healing)

JWT_SECRET and ENCRYPTION_KEY are managed automatically so that a fresh install is secure by default and an upgrade never strands existing data.

  • Set to a strong value in the environment — that value is used, and you stay in control.
  • Unset, or left at an old default — the backend generates a strong secret once, persists it to the app_data volume (SECRETS_DIR, default /app/data), and reuses it on every boot.

Secrets live outside the database deliberately: a database dump alone cannot reveal the key protecting the credentials stored inside it.

Upgrading is non-breaking

Existing ciphertext is decrypted through a legacy-key fallback — including previous shipped defaults — and transparently re-encrypted under the current key by a background sweep. Nothing needs to be re-entered.

Rotating the JWT secret off a public default invalidates sessions signed with it. Users simply log in again once.

Key rotation

Set a new ENCRYPTION_KEY (or delete the persisted secret to force regeneration) and restart. Old rows keep decrypting through the fallback and are re-encrypted forward automatically.

If the persisted secret and every prior key are lost, ciphertext encrypted under that key cannot be recovered. Re-enter device credentials, or restore from a backup.

Settings stored in the database

These are edited in the Settings UI and take effect without a restart:

Area Settings Documented in
Change Guard change_guard_enabled, change_guard_mode, change_guard_timeout_sec Change Guard
Config Health config_health_enabled, config_health_interval_min Change Guard
Polling fast / slow / log intervals, MAC scan, spectral and AP scan cadence Settings → Polling
Config snapshots config_snapshot_enabled, config_snapshot_interval_min, config_snapshot_retention Settings → Config History
NetFlow collector address and port, version, retention, top-N clients Settings → NetFlow
Alerting rules, thresholds, cooldowns, channels Alerting

TLS

A self-signed certificate is generated on first run. Replace it under Settings → TLS Certificate by uploading a certificate and private key; nginx terminates TLS and redirects HTTP to HTTPS.