No description
Find a file
2026-09-24 00:57:37 -06:00
.githooks (ai,tool): Format staged changes on commit 2026-09-15 12:42:25 -06:00
.sqlx (feat): Add file streaming endpoint for OG asset variants 2026-09-15 17:25:40 -06:00
migrations (feat): Add boolean column to asset variant to mark as OG target per asset 2026-09-15 15:50:36 -06:00
src (fix) increase parallelism on testing, make db url optional 2026-09-24 00:57:37 -06:00
tests (fix): Move get account endpoint out from behind auth rate limiter 2026-09-19 00:54:40 -06:00
ui (feat): invalite the layout on rendering the logout page 2026-09-19 01:09:30 -06:00
.gitignore (ui): Set up a few dumb tests 2026-09-16 23:42:50 -06:00
build.rs (fix): Prevent SVGs from being uploaded 2026-09-13 18:16:16 -06:00
Cargo.lock (fix): Correct requesting to stag for log in, use multipart instead of 2026-09-16 20:14:39 -06:00
Cargo.toml (fix): Correct requesting to stag for log in, use multipart instead of 2026-09-16 20:14:39 -06:00
justfile (fix) increase parallelism on testing, make db url optional 2026-09-24 00:57:37 -06:00
README.md (fix) increase parallelism on testing, make db url optional 2026-09-24 00:57:37 -06:00
todo.md (fix): Correct a few smaller issues 2026-09-15 19:41:17 -06:00

Environment Variables

Loaded from the process environment, falling back to a .env file in the working directory if one is present.

Required

The application exits at startup if any of these is unset.

Variable Type Description
S3_ENDPOINT URL Address of the S3 instance. Must be reachable by anyone viewing the UI, or presigned URLs will not resolve.
S3_BUCKET string Bucket name. Checked with HeadBucket at startup, so an unreachable or missing bucket fails fast.
S3_ACCESS_KEY string S3 access key.
S3_SECRET_KEY secret string S3 secret key.
SESSION_PRIVATE_KEY base64 string Signing and encryption key for session cookies. Must decode to at least 64 bytes — generate with openssl rand -base64 64.
STAG_CLIENT_ID string OAuth client id issued by stag. Also the expected aud on identity tokens.
STAG_CLIENT_SECRET secret string OAuth client secret. Also the HS256 key identity tokens are verified against.

Required only on first run

Read only when the database holds no root administrator, so they are needed on an empty database and ignored on every later start. Leaving them set is harmless.

Variable Type Description
AUTH_ROOT_ADMINISTRATOR_USER_STAG_ID i64 The sub of the stag identity that becomes the root administrator. Startup fails if it will not parse.
AUTH_ROOT_ADMINISTRATOR_USER_EMAIL string Email for the root administrator record.
AUTH_ROOT_ADMINISTRATOR_USER_DISPLAY string Display name. Optional even on first run — defaults to the email.

Optional

Variable Type Default Description
DATABASE_URL SQLite URL sqlite://<PATH TO FILE>. The file is created if missing; WAL and foreign keys are enabled on connect. Defaults to sqlite://deers-io.db
BIND_ADDRESS socket address 127.0.0.1:5000 Address the server listens on. Use 0.0.0.0:<port> to accept traffic from outside the host.
SECURE_COOKIES true | false true Sets the Secure flag on session cookies. Only turn it off for local HTTP development — browsers drop secure cookies over plain HTTP.
TRUST_PROXY_HEADERS true | false false Whether to believe X-Real-IP when rate limiting. Enable only behind a proxy that sets it; otherwise a client can forge a fresh rate-limit bucket per request.
CORS_ALLOWED_ORIGINS comma-separated origins unset e.g. https://deers.io,https://www.deers.io. When unset the CORS layer is not installed at all, so browsers apply same-origin rules.
RUST_LOG tracing filter warn,deers_io=info,tower_http=info Standard EnvFilter syntax. Avoid trace in production — the HTTP client logs request bodies at that level, which would include the stag client secret.

Notes on parsing

  • SECURE_COOKIES and TRUST_PROXY_HEADERS accept only the exact strings true and false. Any other value is ignored and the default applies, so a typo such as TRUE or 1 fails silently and leaves the safer setting in place.
  • CORS_ALLOWED_ORIGINS panics at startup on a value that is not a valid header, rather than skipping it.
  • SESSION_PRIVATE_KEY panics at startup if it decodes to fewer than 64 bytes.
  • Changing SESSION_PRIVATE_KEY invalidates every existing session.

Accounts

Every account in this application is a full administrator. There are no roles: any authenticated user can create, edit, and delete every commission, person, and character, and can invite further users who are also full administrators. Invites cannot currently be revoked and users cannot be removed, so only invite people you would trust with direct access to the database.

The root administrator is the account seeded on first run. It is marked by users.is_root_administrator, and the schema permits exactly one such row.

Development

Register the git hooks after cloning:

git config core.hooksPath .githooks

The pre-commit hook runs cargo check and cargo clippy, and verifies that the .sqlx offline query cache matches the queries being committed. A stale cache builds fine for anyone holding a migrated dev.db and fails for everyone else, CI and fresh clones included. Installing sqlx-cli is required for the check:

cargo install sqlx-cli

Testing

Run everything with cargo test. No database setup is needed: #[sqlx::test] applies migrations/ to a throwaway database (under target/sqlx/) for every test, and hands it over as a SqlitePool argument. No environment variables are needed either — integration tests build the router from fixtures rather than from the environment, and never reach S3 or stag.

Unit tests live next to the code they cover, in a #[cfg(test)] mod tests at the bottom of the file.

tests/ holds integration tests, which link the crate as an external caller and therefore only see its public API. They are split by area — people.rs, characters.rs, commissions.rs, authentication.rs — with public_api.rs holding the cross-cutting router behaviour: authentication coverage across every mutating route, fallbacks, body limits, and rate limiting. Shared fixtures, including the HTTP test client and the fakes for S3 and stag, live in src/util/test_support.rs.