● internal

Dodeka

Organization management platform for a Star Citizen gaming org, with Discord OAuth, real-time SSE, and hierarchical RBAC.

pythonjavascriptflaskdiscordreactsserbac

Dodeka was an organization management platform built for a Star Citizen gaming org. The goal was to replace a collection of spreadsheets, Discord threads, and manual processes with a single cohesive web application: one place for member records, recruitment, events, ship fleets, certifications, and operations documents. It ran as a Flask 3 backend serving a React 18 SPA, with Discord OAuth handling authentication and JWT sessions with silent refresh managing the browser session lifetime.

The feature surface was wide: role-based hierarchical permissions gating every action at the API layer, a multi-stage recruitment pipeline, an event calendar with two-way Discord RSVP via reaction sync, ship fleet management with RSI API price sync, medals and certifications, and requisition forms routed through Discord notifications.

The org disbanded before the platform reached its full intended scope, so the live instance is no longer running. The codebase stands as a portfolio showcase of breadth and API integration: 287 commits, Python 48%, JavaScript 32%.

Architecture

The backend is Flask 3 with SQLAlchemy and Alembic for schema management. Discord OAuth 2.0 handles the full authentication flow: the user authorizes through Discord, the backend exchanges the code for tokens, fetches the guild member record to verify org membership, and issues a short-lived JWT with a refresh token stored in an HttpOnly cookie. Silent refresh runs in the React client so sessions extend without prompting the user.

Real-time updates use Server-Sent Events rather than WebSockets. A Flask SSE endpoint holds the connection open and pushes update events as they are generated. The cross-worker propagation problem (Flask workers are independent processes) is solved by routing events through a shared Redis pub/sub channel: any worker that handles a state change publishes to Redis, and the SSE workers each subscribe and forward to their connected clients. A Discord reaction on an event, for example, triggers the bot gateway, writes to the database, publishes to Redis, and updates every open browser tab within a second without those tabs polling.

The discord.py gateway bot runs as a separate process. It handles reaction add/remove events for RSVP sync and fires outbound notifications for requisitions and recruitment status changes. Bot credentials and guild configuration are injected at startup via environment variables; the bot and API share only the database and Redis, not any in-process state.

Google Docs SOP rendering fetches documents via the Google Docs API at request time and converts them to HTML for in-app display, keeping runbooks in the tool officers already used without requiring them to leave the platform.

The application runs as a Docker Compose stack: Flask API, discord.py bot, Redis, and PostgreSQL. A GitLab CI pipeline covers lint and pytest on each push, with the deploy step pushing the image and restarting services via SSH.