efa8990c0defca0a5f26384d15e1004faa4de64a
Stoat Admin
Stoat Admin is a lightweight self-hosted moderation and invite dashboard for a Stoat chat instance. It runs as a separate Podman Compose stack, joins the Stoat network to talk to MongoDB directly, and is intended to be reachable only over WireGuard.
Features
- Single-admin login with Argon2id password hashing and SQLite-backed sessions
- Invite creation, revocation, and acceptance tracking
- User listing, lookup, ban, unban, and scheduled deletion actions
- Dashboard stats for users, pending invites, and recent bans
pnpmworkspace with Turborepo coordinating cross-package tasks- Example Podman Compose, s6 service directories, and GitHub Actions workflows
Project Layout
.
├── api/ # Express + TypeScript backend
├── web/ # Vite + React + TypeScript frontend
├── deploy/s6/ # Example s6 service directories and systemd unit
├── compose.yml # Production-oriented compose file
├── compose.override.example.yml
├── docs/ # Design and task references
└── .env.example
Prerequisites
- Node 22+
pnpmvia Corepack- Turborepo is installed through the workspace dependencies
- A Stoat deployment with MongoDB reachable on the shared container network
invite_only = truein Stoat'sRevolt.toml- Podman or Docker-compatible compose support
- WireGuard or another private network boundary for admin access
Quick Start
- Enable
pnpm:
corepack enable
- Install dependencies:
COREPACK_HOME=/tmp/corepack pnpm install
- Copy the environment template and fill in the real values:
cp .env.example .env
- Seed the admin account from the root workspace:
COREPACK_HOME=/tmp/corepack pnpm seed -- --username admin --password '<strong-password>'
- Run both packages together through Turborepo:
COREPACK_HOME=/tmp/corepack pnpm dev
Useful targeted variants:
COREPACK_HOME=/tmp/corepack pnpm dev:api
COREPACK_HOME=/tmp/corepack pnpm dev:web
Configuration
| Variable | Description |
|---|---|
MONGODB |
MongoDB connection string for the Stoat database |
RESEND_API_KEY |
Resend API key for invite delivery |
RESEND_FROM_EMAIL |
Sender address for invite messages |
SESSION_SECRET |
Express session signing secret |
INSTANCE_URL |
Public Stoat URL used in invite links |
INSTANCE_NAME |
Human-readable instance name used in copy |
ADMIN_API_PORT |
Listen port for admin-api |
ADMIN_WEB_ORIGIN |
Exact browser origin allowed by CORS |
ADMIN_BIND_IP |
Compose bind IP for admin services |
ADMIN_WEB_PORT |
Host port for the frontend |
ADMIN_WEB_API_URL |
API base URL baked into the frontend build |
Deployment
The repo ships with a standalone compose.yml that expects an external stoat_default network. Update the network name if your Stoat stack uses a different one.
For supervised deployments:
- Install
s6 - Copy
deploy/s6/stoatanddeploy/s6/stoat-admininto/etc/s6-services - Adjust service paths and network names
- Copy
deploy/s6/s6-services.serviceinto/etc/systemd/system/ - Enable the unit:
sudo systemctl daemon-reload
sudo systemctl enable --now s6-services
Common operations:
s6-svc -r /etc/s6-services/stoat-admin
s6-svc -d /etc/s6-services/stoat-admin
s6-svc -u /etc/s6-services/stoat-admin
s6-svstat /etc/s6-services/stoat-admin
tail -f /var/log/s6/stoat-admin/current | s6-tai64nlocal
Development Notes
- The backend uses SQLite for admin credentials, audit logs, and invite metadata, and MongoDB for Stoat state.
- The frontend talks directly to the API with cookie-based auth and TanStack Query.
- Root task orchestration is handled by Turborepo through turbo.json.
- The current repo state is a first implementation slice based on the design docs in docs/stoat-admin-design.md and docs/stoat-admin-tasks.md.
Contributing
Keep infrastructure-specific values out of committed files. Prefer changes that preserve the split between the standalone admin stack and the main Stoat stack.
Languages
TypeScript
86.4%
Shell
6.2%
JavaScript
3.8%
Dockerfile
1.3%
CSS
1.2%
Other
1.1%