Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

94 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sequoia-home-web

Standalone Sequoia homepage repo with a Rust frontend, API server, and Discord recruit monitor bot.

What this includes

  • Front page UI (WASM + Trunk)
  • Server API:
    • /api/players
    • /api/players/:username
    • /api/guild
    • /api/scrape-status
    • /api/guild/raid-completions
    • /api/health
  • Background Wynncraft poller for homepage data
  • App-side Postgres migrations (including recruit monitoring tables)
  • Discord bot recruit monitor:
    • 4-day warning alerts (based on Wynncraft guild join time)
    • 7-day escalation alerts (based on Wynncraft guild join time)
    • alert embeds include both current total raids and player raids completed since guild join
    • promoted roles and non-recruit in-game ranks both take precedence over recruit role

Data model

This repo is fully self-managed for homepage data.

  • DATABASE_URL: homepage cache/snapshot Postgres DB
    • player_data
    • player_data_history
    • player_poller_state
    • guild_snapshot
  • guild_metrics
  • scrape_status
  • BOT_DATABASE_URL or APP_DATABASE_URL: recruit monitor tables (can share the same Postgres DB as DATABASE_URL)
  • BOT_ACTIVITY_DATABASE_URL (optional): recruit graid / war history source; point this at sequoia-backend to reuse canonical player snapshots

By default the repo is self-contained. If BOT_ACTIVITY_DATABASE_URL is unset, the bot falls back to the local homepage snapshot tables for graid / war history.

Server behavior

  • Runs two background jobs on startup and on wall-clock schedules (Europe/Stockholm):
    • Guild refresh every 900 seconds (GUILD_POLL_INTERVAL_SECS)
    • Full player sweep every 3600 seconds (PLAYER_FULL_SWEEP_INTERVAL_SECS)
  • Player sweeps are async and bounded (PLAYER_MAX_CONCURRENCY=8, PLAYER_SUCCESSES_PER_MINUTE=30, PLAYER_ATTEMPTS_PER_MINUTE=45) and continue minute-to-minute until the target set is done.
  • Guild membership additions detected in guild refreshes enqueue incremental player sweeps for only newly-added members.
  • Retention pruning runs daily and removes rows older than RETENTION_DAYS from guild_snapshot, guild_metrics, and player_data_history.
  • Cold start responses are stable (200) even before first successful poll:
    • /api/guild returns default empty guild object
    • /api/players returns { "players": {}, "updated_at": null }
    • /api/guild/raid-completions returns 0
    • /api/scrape-status returns the current scheduler/run status JSON

Coolify / production env

You can deploy in two ways:

  • All-in-one stack: docker-compose.coolify.yml (web + bot + db in one resource).
  • Split stacks (recommended for faster bot-only redeploys):
    • docker-compose.coolify.web.yml (web only)
    • docker-compose.coolify.bot.yml (bot only)

Manual values for all-in-one stack (docker-compose.coolify.yml):

  • DISCORD_BOT_TOKEN
  • BOT_ACTIVITY_DATABASE_URL (optional; falls back to BOT_DATABASE_URL/the app DB when empty)
  • BOT_ENABLE_LEGACY_COMMANDS (optional; only needed for the older guide helper commands)
  • RUST_LOG (optional)

Auto-generated by Coolify (do not set manually unless overriding):

  • SERVICE_URL_WEB_3000 / SERVICE_URL_WEB
  • SERVICE_USER_DB / SERVICE_PASSWORD_DB

Manual values for split stacks:

  • Web stack (docker-compose.coolify.web.yml): use .env.coolify.web.example
    • Required: DATABASE_URL
  • Bot stack (docker-compose.coolify.bot.yml): use .env.coolify.bot.example
    • Required: DISCORD_BOT_TOKEN, BOT_DATABASE_URL
    • Optional: BOT_ACTIVITY_DATABASE_URL to reuse the sequoia-backend snapshot database for graid / war history

DATABASE_URL and BOT_DATABASE_URL can point to the same Postgres database. BOT_ACTIVITY_DATABASE_URL can also point at that same DB, or at the existing sequoia-backend Postgres service.

Coolify deployment with Docker Compose

All-in-one stack:

  1. In Coolify, create a Docker Compose resource pointing at this repository.
  2. Set compose file path to docker-compose.coolify.yml.
  3. Add only the manual Discord variables from .env.coolify.example.
  4. Deploy the stack. Coolify should expose the web service (internal port 3000).

Split stacks (recommended to avoid rebuilding frontend for bot-only changes):

  1. Create one Coolify Compose resource with docker-compose.coolify.web.yml.
  2. Create a second Coolify Compose resource with docker-compose.coolify.bot.yml.
  3. Set env vars from .env.coolify.web.example and .env.coolify.bot.example.
  4. Point both resources to the same DB URL if you want shared state.

Split stacks quick bootstrap (recommended):

  1. Export the values you already know:
export DATABASE_URL='postgres://user:password@host:5432/sequoia_web'
export DISCORD_BOT_TOKEN='...'
export BOT_ACTIVITY_DATABASE_URL='postgres://user:password@host:5432/sequoia'
  1. Generate local ready-to-paste env files:
./scripts/coolify-split-setup.sh
  1. Copy values from:
    • .env.coolify.web.local into the web resource env panel
    • .env.coolify.bot.local into the bot resource env panel

Notes:

  • All-in-one stack includes a Postgres container (db) with persistent volume (db_data).
  • Split stacks expect external DB URLs (DATABASE_URL, BOT_DATABASE_URL) from your DB resource.
  • DB resource network defaults:
    • leave Ports Mappings empty (or use 5432:5432 only if Coolify forces a mapping)
    • do not use 3000:5432
    • keep Make it publicly available disabled unless you explicitly need external DB access
  • Compose defaults are tuned for faster startup catch-up (DATABASE_MAX_CONNECTIONS=20, PLAYER_MAX_CONCURRENCY=20, PLAYER_SUCCESSES_PER_MINUTE=90).
  • Docker images use cargo-chef planner/cook layers to cache Rust dependencies between redeploys.
  • Recruit monitor time thresholds use Wynncraft guild join timestamps matched against Discord names (nickname/global name/username token matching).
  • Recruit alert raid metrics:
    • Guild Raids shows the recruit's current total raids from latest player_data.
    • Raids Since Guild Join uses a persisted baseline (taken near Wynncraft join time from player_data_history) and shows unknown when a baseline cannot be determined.
  • Managed bootstrap flow:
    • The bot starts in bootstrap mode until a profile is created from the private management guild.
    • Run /bot-admin profile init <source_guild_id> [wynn_guild_name] in the private management guild.
    • Add source roles with /bot-admin roles add guild_scope:source role_kind:recruit|promoted role_id:<discord-role-id>.
    • Add ops roles with /bot-admin roles add guild_scope:ops role_kind:operator|subscription role:@Role.
    • Add reminder rules with /bot-admin rules add ..., then enable the profile with /bot-admin profile enable.
    • Source-guild roles must be entered as numeric role IDs because Discord slash role pickers only resolve roles from the current guild.
  • Slash commands:
    • /bot-admin ... for profile, role, rule, command, and template management in the private management guild.
    • /notify-reminders [mode] (toggle/on/off/status) for reminder-role signup.
    • /preview-reminder [rule_key] for a test alert preview; when omitted it previews the first enabled rule.
    • /check-unhandled [day] (custom 1-365, default 4) for unhandled recruits.
    • /run-check to run full sync + alert scan on demand.
    • /run-check-here to run full sync + check immediately and post due alert previews in the current channel (no DB write, no role ping).
    • /test-review-thread <target> [rule_key] to post a real test reminder in the current channel, create the review thread, and populate it. target can be a tracked recruit Wynn username or Discord user ID.
    • /player-stats <username> [page] for the paged player history charts.
  • Text command equivalents are available only in the private management guild, and only when enabled for that command:
    • !run-check / !check-now
    • !run-check-here / !check-here
    • !test-review-thread <target> [rule_key] / !test-thread <target> [rule_key]
    • !preview-reminder [rule_key|4|7|warning|escalation]
  • Source guilds do not register management or operator slash commands; management and operator commands live in the private management guild.
  • web and bot both auto-create required tables/schemas on startup.

Post-deploy smoke tests

Run these commands from a machine that can reach your deployed app and database.

# 1) API smoke test
./scripts/deploy-smoke-test.sh api https://your-domain.com

# 2) Recruit monitor DB checks (all guilds)
BOT_DATABASE_URL='postgres://user:pass@host:5432/sequoia_web' \
BOT_ACTIVITY_DATABASE_URL='postgres://user:pass@host:5432/sequoia' \
./scripts/deploy-smoke-test.sh db

# 3) Recruit monitor DB checks (single source guild)
BOT_DATABASE_URL='postgres://user:pass@host:5432/sequoia_web' \
BOT_ACTIVITY_DATABASE_URL='postgres://user:pass@host:5432/sequoia' \
SOURCE_GUILD_ID='123456789012345678' \
./scripts/deploy-smoke-test.sh db

Tip for Coolify: if DB is not exposed publicly, run DB checks in a terminal on the same host/network as the stack.

Local development

  1. Start local databases:
docker compose -f docker-compose.dev.yml up -d app-db sequoia-web-db
  • app-db on localhost:5432 (bot/recruit monitor state)
  • sequoia-web-db on localhost:5434 (homepage cache/snapshots)
  1. Run backend API server:
DATABASE_URL=postgres://sequoia:sequoia@localhost:5434/sequoia_web \
GUILD_POLL_INTERVAL_SECS=900 \
PLAYER_FULL_SWEEP_INTERVAL_SECS=3600 \
SCRAPE_TIMEZONE=Europe/Stockholm \
PLAYER_SUCCESSES_PER_MINUTE=30 \
PLAYER_ATTEMPTS_PER_MINUTE=45 \
PLAYER_MAX_CONCURRENCY=8 \
PLAYER_MAX_RETRIES=2 \
RETENTION_DAYS=90 \
RETENTION_HOUR_LOCAL=0 \
RETENTION_MINUTE_LOCAL=5 \
PORT=3001 \
RUST_LOG=sequoia_home_server=debug \
cargo run --manifest-path server/Cargo.toml
  1. Run frontend:
rustup target add wasm32-unknown-unknown
cargo install trunk --locked
trunk serve

Trunk proxies /api/* to http://127.0.0.1:3001/api/*.

  1. Run recruit monitor bot:
DISCORD_BOT_TOKEN=... \
BOT_DATABASE_URL=postgres://sequoia:sequoia@localhost:5432/sequoia_app \
BOT_ACTIVITY_DATABASE_URL=postgres://sequoia:sequoia@localhost:5434/sequoia_web \
cargo run --manifest-path bot/Cargo.toml

Then, from the private management guild, run /bot-admin profile init <source_guild_id> [wynn_guild_name] and finish setup with the /bot-admin roles, /bot-admin rules, /bot-admin commands, and /bot-admin templates subcommands.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages