OmegaBot is structured so the same backend can power Discord and a future web UI. Game logic, progression, events, and profiles live in shared services; Discord commands and the web API both call these services.
- Setting up the website
- Architecture
- User accounts
- Events
- Posts / social feed
- Persistent games
- Game API layer
- Web API
- Leaderboards
- Achievements
- Profiles
- Real-time (SSE)
- Implemented features (roadmap done)
Follow these steps to run the Web API and optionally connect a frontend.
- Same as the Discord bot: Node.js 18+ (22 LTS recommended),
npm install, and a working SQLite database. - The Web API uses the same database as the bot (
DATABASE_PATH). Run migrations if needed (they run on bot/API startup).
DATABASE_PATH— Path to your SQLite DB (e.g.data/omegabot.db). Same as the bot so profiles, games, and events are shared.WEB_API_PORT(optional) — Port for the HTTP server. Default:4000.
No Discord token is required to run the API alone. To use the bot and website together, run the bot as usual and run the API in a separate process (or same machine, different port).
cd OmegaBot
npm run build
npm run apiOr run the built server directly:
node dist/web/server.jsThe server listens on http://localhost:4000 (or your WEB_API_PORT). You can hit endpoints with curl, e.g.:
curl http://localhost:4000/api/profile/YOUR_USER_ID
curl "http://localhost:4000/api/leaderboard?scope=users&limit=10"- Use any frontend (React, Vue, static HTML, etc.) that can call the API.
- Base URL:
http://localhost:4000in development, or your deployed API URL in production. - Auth: Use
WEB_API_KEY(X-API-Key header) or Discord OAuth (/auth/discord→ callback sets session cookie). See User accounts and env vars in Environment Setup.
- Run the API as a separate process (e.g. systemd, Docker, or PaaS). Point
DATABASE_PATHto the same DB the bot uses (or a copy if you run bot and API on different machines and sync data). - Put a reverse proxy (e.g. nginx, Caddy) in front for HTTPS and optional rate limiting.
- Frontend can be served from the same host (static files) or a separate domain; ensure CORS is configured if the frontend origin differs from the API.
Discord Bot (commands, buttons, embeds)
│
▼
Shared services (games, progression, platform)
│
Database (SQLite)
│
▼
Web API (HTTP JSON)
│
▼
Future web frontend
- Discord remains the primary client; commands stay thin and call services.
- Web API is an optional HTTP server that exposes the same data for a browser client.
- Real-time: SSE at
GET /api/sse?gameId=...or?eventId=...streams live game/event updates.
- Table:
platform_users(migration010_platform_users.sql):user_id(UUID),discord_id(unique),username,avatar_url,created_at,updated_at. - Service:
services/platform/userService.tsgetOrCreateByDiscord(discordId, username?, avatarUrl?)— ensure a platform user for a Discord account; update name/avatar.getPlatformUser(userIdOrDiscordId)— fetch by internal id or Discord id.resolveDiscordId(userIdOrDiscordId)— resolve to a Discord id for use with existing game/progression tables (keyed by Discord id).
- Discord OAuth:
GET /auth/discordredirects to Discord;GET /auth/discord/callbackexchanges the code, callsgetOrCreateByDiscord, creates a session, and sets a cookie. SetDISCORD_OAUTH_CLIENT_ID,DISCORD_OAUTH_CLIENT_SECRET, and optionallyDISCORD_OAUTH_REDIRECT_URI,WEB_APP_URL.
- Tables:
events,event_participants(migration011_events.sql). - Service:
services/platform/eventsService.ts- Create, get, list (by status), join, get participants, update status.
- Discord:
/event create,/event update,/event join,/event list,/event results. - Web: GET/POST/PATCH events, join via API; SSE for live event updates.
- Tables:
posts,post_likes(migration012_posts.sql). - Service:
services/platform/postsService.ts- Create, get, list (global or by author), like, unlike.
- API:
POST /api/posts(auth),GET /api/posts,GET /api/posts/:id(with comments),GET/POST /api/posts/:id/comments. Optional Discord cross-post later.
- Sessions:
game_sessions(see Games development); statusactive|finished|abandoned. - Service:
services/games/sessionManager.ts+services/games/gameEngine.tsgetGameState(gameId)— for API/Discord.applyGameMove(gameId, userId, payload)— e.g. Connect 4 column; returns{ ok, winner?, draw? }.
- Games started on Discord can be continued on the web (and vice versa) by calling the same services.
services/games/gameEngine.ts— facade for state and moves; used by web API and can be used by Discord.services/games/progressionEngine.ts— XP, levels, progression result.services/games/sessionManager.ts— persistent sessions, expiry, status.- Commands (e.g. Connect 4) already use these or equivalent logic; the web API calls
gameEngineandsessionManager.
Optional HTTP server: src/web/server.ts. Start with npm run api (or node dist/web/server.js). Set WEB_API_PORT (default 4000) and DATABASE_PATH as needed. The server calls initDatabase() and the same services as the bot. For full setup steps, see Setting up the website above.
| Method | Path | Description |
|---|---|---|
| GET | /api/profile/:userId |
Profile (xp, level, games, wins, achievements, daily streak). userId = platform user_id or Discord id. |
| GET | /api/leaderboard |
Usage leaderboard. Query: scope=users or commands, limit. |
| GET | /api/leaderboard?game=slots |
Per-game leaderboard (e.g. game=slots, game=daily). |
| GET | /api/events |
List events. Query: status=active or ended, limit. |
| GET | /api/events/:id |
Single event + participants. |
| POST | /api/events/:id/join |
Body: { "userId": "..." }. Join event. |
| GET | /api/games/state/:gameId |
Game state (board, turn, status, expiresAt). |
| POST | /api/games/move |
Body: { "gameId", "userId", "col" }. Apply move (e.g. Connect 4). |
| GET | /api/sse |
Query: gameId=... or eventId=.... Server-Sent Events stream for live updates. |
| GET | /auth/discord |
Redirect to Discord OAuth. |
| GET | /auth/discord/callback |
OAuth callback; sets session cookie and redirects to WEB_APP_URL. |
| GET | /api/posts |
List posts. Query: authorId, limit. |
| POST | /api/posts |
Create post (auth). Body: content, optional attachments, optional userId (when using API key). |
| GET | /api/posts/:id |
Single post with comments. |
| GET | /api/posts/:id/comments |
List comments. Query: limit. |
| POST | /api/posts/:id/comments |
Add comment (auth). Body: content, optional userId. |
| POST | /api/events |
Create event (auth). Body: title, description?, startTime/start_time, endTime/end_time, status?. |
| PATCH | /api/events/:id |
Update event (auth). Body: title?, description?, startTime?, endTime?, status?. |
| GET | /api/achievements |
List all achievement definitions (id, name, description, emoji, category). |
Responses are JSON (except SSE). Auth: Authorization: Bearer <sessionId>, cookie session_id (after Discord OAuth), or X-API-Key (set WEB_API_KEY). Write endpoints (POST posts, POST/PATCH events, POST comments) require auth.
- Usage:
leaderboardService.getUsageLeaderboard({ scope: "users"|"commands", limit })— from fun usage store. - Per-game:
leaderboardService.getGameLeaderboard(gameType, { limit })— e.g. slots, daily; extend for more games. - Scopes: Global (default), weekly (
?window=weekly), server (?guildId=...). Usage is logged tousage_log(migration 014) withguild_idwhen recording from Discord.
- Definitions:
commands/games/achievements/definitions.ts(id, title, description, xpReward, icon, checkFn). - Unlock state: Stored implicitly via game stats and progression; profile and achievements embed use the same checks.
- Web:
GET /api/profile/:userIdincludesachievements(array of{ id, name, description, emoji, category, unlocked }).GET /api/achievementsreturns all definitions.
- Service:
services/platform/profileService.ts—getProfile(userIdOrDiscordId). - Returns: username, avatarUrl, xp, level, gamesPlayed, wins, winRate, achievements, daily streak.
- Discord:
/profile viewuses the same data (via profileHelpers + progression + gameStats). - Web:
GET /api/profile/:userIdreturns the same shape.
- Services are stateless and keyed by id; a WebSocket or SSE layer can subscribe to “game updates” or “event updates” and push from the same service layer.
- Sessions are in-memory; WebSocket could be added later for bidirectional use.
The following are implemented:
- Discord OAuth:
GET /auth/discordandGET /auth/discord/callback; session cookie; env:DISCORD_OAUTH_CLIENT_ID,DISCORD_OAUTH_CLIENT_SECRET,DISCORD_OAUTH_REDIRECT_URI,WEB_APP_URL. - Auth middleware: Session (cookie or
Authorization: Bearer <sessionId>) and API key (X-API-Key,WEB_API_KEY). Write endpoints require auth;userIdfrom session or body when using API key. - POST /api/posts and GET /api/posts: Create (auth), list with
authorId,limit. Comments:post_commentstable (migration 013),GET /api/posts/:id/comments,POST /api/posts/:id/comments(auth). - Event create/update:
POST /api/events,PATCH /api/events/:id(auth). Discord:/event create,/event update,/event join,/event list,/event results. - Weekly leaderboard:
GET /api/leaderboard?window=weekly. Date range:from,to(Unix ms). Server leaderboard:?guildId=.... Usage is logged tousage_log(migration 014) withguild_idwhen recording from Discord. - SSE:
GET /api/sse?gameId=...or?eventId=...streams live updates when a move or event join occurs. - Achievement badges:
GET /api/achievementsreturns all definitions.GET /api/profile/:userIdincludesachievements: { id, name, description, emoji, category, unlocked }[].