Deployment
Lumio uses release-driven deployment. Container images are built and pushed only when a GitHub Release is published -- there are no automatic image builds on branch pushes. The workflow lives in .github/workflows/release-images.yml.
Release Strategy
Every deploy starts with a GitHub Release. The release tag encodes which app to deploy and the version:
{app}@{version}
The workflow parses the tag, determines the target app, runs Bazel tests, builds the image, and pushes it to the container registry.
How to Deploy
- Go to GitHub Releases for the repository.
- Click Draft a new release.
- Create a tag following the
{app}@{version}format. - Mark the release as a pre-release if the image should receive
betatags instead oflatest. - Publish the release.
Tag examples:
api@2026.5.3
twitch-bot@2026.5.1
web@2026.5.2
discord-bot@2026.5.1
Image Tags
The workflow generates multiple tags per image based on whether the release is marked as a pre-release.
Production (stable release)
| Tag | Example | Description |
|---|---|---|
{version} | 2026.5.3 | Exact version |
{major.minor} | 2026.5 | Floating minor tag |
latest | latest | Most recent stable release |
{short_sha} | a1b2c3d | 7-character commit SHA |
{full_sha} | a1b2c3d... | Full 40-character commit SHA |
Pre-release (beta)
| Tag | Example | Description |
|---|---|---|
{version} | 2026.5.3-beta.1 | Exact pre-release version |
beta | beta | Floating beta tag |
{short_sha} | a1b2c3d | 7-character commit SHA |
{full_sha} | a1b2c3d... | Full 40-character commit SHA |
A version string containing beta, alpha, or rc is also treated as a pre-release regardless of the GitHub Release checkbox.
Deployable Apps
| App | Type | Tag Prefix | Build Tool |
|---|---|---|---|
api | Rust binary | api@ | Bazel |
bot-module-worker | Rust binary | bot-module-worker@ | Bazel |
twitch-bot | Rust binary | twitch-bot@ | Bazel |
youtube-bot | Rust binary | youtube-bot@ | Bazel |
kick-bot | Rust binary | kick-bot@ | Bazel |
trovo-bot | Rust binary | trovo-bot@ | Bazel |
discord-bot | Rust binary | discord-bot@ | Bazel |
web | Next.js | web@ | Docker |
admin | Next.js | admin@ | Docker |
id | Next.js | id@ | Docker |
Rust binaries are built with Bazel (bazel run //apps/{app}:{app}_push) and produce minimal Alpine-based images via rules_img. Next.js apps are built with traditional Dockerfiles (docker/{app}.Dockerfile).
Bulk Deploys
Three special tag prefixes deploy multiple apps at once:
| Tag Prefix | Deploys |
|---|---|
all@{version} | All 10 apps (7 Rust + 3 Next.js) |
all-rust@{version} | All 7 Rust apps |
all-web@{version} | All 3 Next.js apps |
Example: publishing a release tagged all@2026.5.3 builds and pushes every app image.
Manual Dispatch
For emergency deploys or rebuilds without creating a release, the workflow supports workflow_dispatch with two inputs:
| Input | Description |
|---|---|
app | Which app to deploy (dropdown: all, all-rust, all-web, or any individual app) |
tag | The image tag to apply |
This is useful when the release flow is unavailable or when retagging an existing build.
Container Registry
All images are pushed to GitHub Container Registry (GHCR):
ghcr.io/{org}/lumio/{app}
For example:
ghcr.io/zaflun/lumio/api:2026.5.3
ghcr.io/zaflun/lumio/twitch-bot:latest
ghcr.io/zaflun/lumio/web:beta
Authentication uses the GITHUB_TOKEN provided by GitHub Actions with packages: write permission.
Environments
Branch and tag mapping determines which environment receives a deploy:
| Branch / Tag | Environment |
|---|---|
next | Staging |
main | Production preview |
Release tag (e.g., api@2026.5.3) | Production |
See the Installation guide for the full domain table per environment.
Security Audit
A nightly security audit runs via .github/workflows/security-audit.yml (cron: 0 3 * * * UTC). It scans both dependency ecosystems and reports to Discord:
| Check | Tool | Scope |
|---|---|---|
| Rust dependencies | cargo audit | All advisories |
| npm dependencies | pnpm audit | High and critical severity |
Alert flow:
- Individual vulnerability alerts fire immediately via Discord webhook (
DISCORD_SECURITY_WEBHOOK_URL). - A daily summary always posts -- either "All clear" (green) or "Action required" (yellow) with vulnerability counts.
The workflow also supports manual workflow_dispatch for on-demand scans.