Development
For the first-party web architecture, rendering model, authentication boundaries, and packaging behavior, see First-party frontend.
Run the local stack:
podman compose -f deploy/compose.yaml up --build
The local stack starts Roosty with serve --with-migrations --with-worker, so migrations run before the server begins listening. It starts four durable worker loops; set ROOSTY_WORKER_CONCURRENCY=0 to size the worker pool from the process’s available logical CPUs.
The local stack uses Caddy with an internal development certificate so Roosty and Elk can run over HTTPS. Your browser may ask you to accept the local certificate.
The local deployment also starts Elk, an external Mastodon-compatible web client:
https://localhost:4001
Elk is configured for Roosty as a single-instance client using roosty.localhost:4000.
If Elk keeps trying an old saved instance, open https://localhost:4001/reset once to clear its local browser state.
To smoke-test Elk’s server-side login handoff to Roosty:
deploy/test-elk-login.sh
To run migrations manually instead:
podman compose -f deploy/compose.yaml exec roosty /usr/local/bin/roosty migrate
Bootstrap the first administrator:
podman compose -f deploy/compose.yaml exec roosty /usr/local/bin/roosty admin bootstrap --username admin --email admin@example.com
Reset a local user’s password and print a temporary replacement:
podman compose -f deploy/compose.yaml exec roosty /usr/local/bin/roosty admin reset-password --username admin
The local application listener is exposed through Caddy on https://roosty.localhost:4000. When ROOSTY_INFRA_LISTEN_ADDR is set, infrastructure endpoints are served only from that listener:
http://localhost:3001/healthz
http://localhost:3001/readyz
http://localhost:3001/metrics
Roosty stores uploaded media in the roosty-media compose volume. Elk stores local client settings in the elk-data compose volume. The backend does not serve, package, or embed Elk.
Durable-job retention
Worker processes remove successfully completed jobs after 24h and permanently failed jobs after
30d by default. Override these non-zero humantime durations with
ROOSTY_SUCCESSFUL_JOB_RETENTION and ROOSTY_PERMANENTLY_FAILED_JOB_RETENTION. Cleanup runs in
bounded batches and is safe when multiple worker processes share the database.
Streaming controls
Streaming uses PostgreSQL for ordered, best-effort fan-out between server processes. The local bounded channel remains the immediate delivery path, so a database publication failure does not delay the publishing request. Retained events are recovery metadata rather than a permanent message queue.
| Environment variable | Default | Validation |
|---|---|---|
|
|
Positive integer, per process. |
|
|
Non-zero |
|
|
Non-zero |
|
|
Non-zero duration greater than the ping interval. |
|
|
Non-zero |
Configuration is read at startup. Stalled sends and clients that do not send
any frames (including pong frames) before the idle deadline are disconnected.
/readyz requires both database access and an initialized PostgreSQL listener.
The /metrics output includes active/rejected sockets, send timeouts, idle
disconnects, lagged receivers, listener reconnects, and failed cross-process
publications.
Scheduled status controls
Scheduled statuses are published by the durable worker pool. Limits are enforced transactionally per account so they remain consistent when multiple Roosty processes share a database.
| Environment variable | Default | Validation |
|---|---|---|
|
|
Non-zero |
|
|
Positive integer per account. |
|
|
Positive integer per account and UTC day. |