Overview
What dashboard is
The dashboard is a small website that gives Discord server
admins an easy UI for managing the
apoptotic Discord bot. Instead of memorizing
slash-command syntax, admins sign in with Discord, pick the guild they want to
manage, and edit AutoMod rules, configure log channels, browse audit history,
and adjust permissions through a friendly web interface. Everything the
dashboard can do, a slash command can also do — but admins generally prefer
clicking.
Stack
Architecture
The dashboard is a standalone Rust + Axum service running on its own VM with
rustls TLS. It is not a workspace member — it has its own
Cargo.toml with a [workspace] opt-out — but it
follows the same conventions as the other web services: clean URL middleware,
structured logging, and a static-file ServeDir for the front-end
assets.
Front-end is hand-written HTML + CSS + a small amount of vanilla JavaScript.
There is no client-side framework. State that the user sees — current rules,
log channel selections, audit entries — is fetched on demand by simple
fetch() calls against the dashboard's own JSON endpoints, which in
turn proxy to the bot.
Auth
Discord OAuth + role gating
Sign-in is Discord OAuth (scope: identify). After the OAuth round
trip, the dashboard knows the user's Discord ID and lists the guilds they are
a member of where the bot is also installed. Selecting a guild starts a session
keyed to that guild, and every API call from then on is checked twice:
- Membership. The user must be in the target guild.
- Role. The user must hold the configured admin role(s) for that guild.
Both checks are re-validated server-side on every request rather than trusted
from the session cookie. If a user gets demoted in Discord while the dashboard
tab is open, the next click is rejected.
API Proxy
Talking to the bot
The dashboard does not own any of the configuration data. Every read or write
is forwarded to the bot's internal REST API, configured at startup via
DC_BOT_API_URL. This keeps a single source of truth: the bot is
the authoritative store for AutoMod rules, log channel mappings, leveling
settings, and so on. The dashboard is just a friendly face for the same data
a slash command would mutate.
The proxy is intentionally narrow. The dashboard exposes specific endpoints for
specific operations rather than a generic pass-through, so each operation can
enforce the role check that matches its blast radius.
UX
Design decisions
- One guild at a time. The whole UI is scoped to the currently selected guild — there is no "all guilds" super-view that risks acting on the wrong one.
- Optimistic UI is off. Edits show a spinner until the bot confirms; the alternative leads to confused admins when a permission check fails server-side.
- Audit visibility. Every change made through the dashboard is logged through the bot's normal audit pipeline, with a marker that says it came from the web UI rather than a slash command.
- No analytics tracking. The dashboard ships without analytics scripts; access patterns are observable in the standard request log.
Co-location
Why it ships next to the bot
The dashboard and the bot run on the same VM. They are separate
binaries with separate systemd units, but co-locating them keeps the latency
between the dashboard and the bot's REST API negligible and avoids exposing the
bot's internal API to the public network. The dashboard talks to the bot over
loopback; the public endpoint is the dashboard alone.
Roadmap
Where it's going
The dashboard is intentionally minimal — it grows surface only when a real admin
asks for it. Near-term priorities: richer audit-log filters, an inline tester
for AutoMod regex rules, and a "preview" mode that shows what an AutoMod
configuration would have caught against the last 24 hours of messages without
actually taking any action.
Related
Read more