feat: update documentation for architecture, runtime scenarios, and deployment strategies

This commit is contained in:
2026-05-17 16:54:00 +02:00
parent a402c7b0bb
commit 168f4ea13c
5 changed files with 176 additions and 135 deletions
+24 -22
View File
@@ -2,32 +2,34 @@
## Technology Decisions
| Decision | Choice | Rationale |
| ---------------- | -------------------- | --------------------------------------------------------------------------------------- |
| Bot framework | Discord.js (Node.js) | Mature library, strong type support, rich event model |
| Database | PostgreSQL | Reliable, supports JSONB for flexible user state, well-suited for mileage/role tracking |
| Frontend (Admin) | React | Team familiarity, rich ecosystem for dashboards |
| Hosting | Coolify | Easy deployment for Node.js with Nixpacks. |
| Auth | Discord OAuth2 | No custom auth needed, seamless web/bot integration |
| Decision | Choice | Rationale |
| -------------- | ----------------------------------------- | -------------------------------------------------------------------------------------- |
| Bot runtime | Node.js + TypeScript + discord.js | Strong ecosystem, typed Discord interactions, shared language across backend/dashboard |
| Persistence | PostgreSQL (`pg`) | Reliable relational storage for mileage, schedules, and settings |
| Admin API | Express | Lightweight routing and middleware model for operational endpoints |
| Dashboard | React + Vite + TypeScript | Fast iteration and typed API integration |
| Authentication | Bearer token (admin API) + Discord OAuth2 | Secure machine-to-machine admin calls plus user identity bridge |
| Deployment | Coolify + Gitea Actions | Simple CI/CD path with webhook-triggered production rollout |
## Top-Level Decomposition
## Architectural Strategy
The system follows a **modular monolith** pattern with clear separation:
System uses modular monolith strategy in single backend process:
- **Core Bot** — command handlers, event listeners, Discord Gateway logic
- **Content Syndicator** — polling adapters for YouTube/IG/TikTok, webhook dispatch
- **Event Manager** — FIFO queue for stage/speaker management
- **Mileage Engine** — scoring logic, persistence, state sync with web app
- **Admin API** — RESTful endpoints for bot config, content scheduling, analytics
- Bot core orchestrates Discord gateway and command/event handling.
- Domain services encapsulate call-sheet onboarding, tour queue, mileage, and dailies.
- Operational interfaces exposed through Admin API and OAuth bridge.
- Shared configuration layer centralizes environment parsing and validation.
- Separate dashboard SPA consumes API without direct DB access.
## Key Quality Goals
## Quality Strategies
- **Availability** — Stateless bot instances scale horizontally behind load balancer
- **Consistency** — Write-ahead logging for mileage transactions; periodic state reconciliation with web app
- **Extensibility** — Adapter pattern for content sources: implement interface, register, deploy
- Availability: graceful startup/shutdown, service initialization guards, process-level health endpoint.
- Consistency: transactional mileage writes, strict DB row guards, idempotent schedule updates.
- Security: token-based admin auth, OAuth code exchange on server side, no token logging.
- Extensibility: adapter interface for new dailies sources and isolated service modules.
- Operability: CI checks (lint/build/test) for bot and dashboard before deploy trigger.
## Organizational Decisions
## Trade-offs
- One-person or small-team development per project scope
- CI/CD via Gitea Actions: lint → test → deploy
- Feature toggles for admin dashboard rollout
- In-memory OAuth sessions reduce complexity but require re-authentication after process restart.
- Modular monolith minimizes operational overhead now, while preserving service boundaries for future extraction.
+47 -33
View File
@@ -3,39 +3,53 @@
## Whitebox Overall System (Level 1)
```txt
┌──────────────────────────────────────────────────────┐
│ omo-bot │
├──────────────────────────────────────────────────────┤
┌──────────────────┐ ┌─────────────────────────┐
Command Layer │ │ Event Listener Layer │
│ /sign-up, /map │ │ member_join, reaction │
│ └────────┬─────────┘ └───────────┬─────────────┘
┌──────────────────────────────────────────────┐
│ Service Layer
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Event │ │ Mileage │ │ Content
│ │ Manager │ │ Engine │ │ Syndicator
│ └──────────┘ └──────────┘ └──────────────┘ │
└───────────────────┬──────────────────────────┘
┌──────────────────────────────────────────────┐
│ │ Data / Persistence Layer │ │
PostgreSQL DB + Discord API Wrapper
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────
┌────────────────────────────────────────────────────────────
omo-bot
├────────────────────────────────────────────────────────────
Discord Gateway Runtime
├─ Command handlers (/ping, /call-sheet, /sign-up, /dailies)
├─ Reaction/member event handlers
│ └─ Service orchestration (`startBot`)
Core Services
├─ Call Sheet Service
├─ Tour Schedule Engine
├─ Mileage Engine
├─ Dailies Service (adapters + dispatcher)
├─ OAuth Bridge Service
│ └─ Configuration Database Service
Interfaces
├─ Admin API (Express)
└─ Health endpoint
└──────────────────────────────┬─────────────────────────────┘
────────────────────────────
│ PostgreSQL + Discord APIs │
└────────────────────────────┘
```
### Black Box Descriptions
## Building Blocks and Responsibilities
| Building Block | Responsibility |
| ------------------ | ------------------------------------------------------------------------------------------ |
| Command Layer | Register and handle slash commands (`/sign-up`, `/map`, `/help`); validate permissions |
| Event Listener | Subscribe to Discord Gateway events (member join, reaction add, voice state change) |
| Event Manager | Manage FIFO queue for voice/stage speakers; schedule "Tour Stop" events via Discord API |
| Mileage Engine | Score user interactions, persist to DB, trigger role upgrades, sync with web app |
| Content Syndicator | Poll YouTube/IG/TikTok APIs; format rich embeds; dispatch to Discord channels via webhooks |
| Admin API | Expose REST endpoints for dashboard (configuration, content schedule, engagement stats) |
| DB Layer | PostgreSQL connection pool, migrations, query builders |
| Building Block | Responsibility |
| ------------------------------- | ---------------------------------------------------------------------------------- |
| `src/bot.ts` | Runtime bootstrap, command registration, service lifecycle, graceful shutdown |
| `src/call-sheet.ts` | Reaction-role onboarding, grouped role exclusivity, welcome flow hooks |
| `src/tour-schedule.ts` | Queue state, join/leave/advance operations, stage speaker management |
| `src/mileage.ts` | Event scoring, persistence, mileage aggregation, role tier synchronization |
| `src/dailies/service.ts` | Polling scheduler, adapter orchestration, webhook dispatch loop |
| `src/oauth-bridge.ts` | Discord OAuth code exchange, user fetch, temporary session cache, optional sync |
| `src/configuration-database.ts` | Settings/schedules CRUD and engagement snapshot persistence |
| `src/admin-api.ts` | Authenticated operational endpoints for config, queue, stats, OAuth, and config DB |
| `admin-dashboard/src/*` | Browser UI for OAuth connect flow, API calls, and analytics views |
## Level 2 (Admin API)
Admin API route groups:
- Health and runtime config (`/health`, `/admin/config`)
- Tour schedule operations (`/admin/schedule`, `/admin/schedule/clear`)
- Engagement statistics (`/admin/stats`, `/admin/db/engagement/latest`)
- Configuration DB CRUD (`/admin/db/settings`, `/admin/db/schedules`)
- OAuth bridge session flow (`/admin/oauth/discord/exchange`, `/admin/oauth/session/:sessionId`)
+36 -21
View File
@@ -1,28 +1,43 @@
# Runtime View
## Scenario: User Signs Up for Open Mic
## Scenario: `/sign-up join` to Stage Queue
1. User runs `/sign-up` in voice channel
2. Command Layer validates user has `@ComedyFan` role
3. Event Manager adds user to FIFO queue
4. When previous speaker leaves stage (voice state change), Event Manager pops queue
5. Bot grants temporary speaker permission via voice channel API
6. Announcement sent to `#stage-door` channel
7. Mileage Engine awards +50 miles for participation
1. User invokes `/sign-up join`.
2. Command handler validates guild/context and required permissions.
3. Tour schedule engine appends user to guild queue if not already present.
4. Engine returns queue position and current queue snapshot.
5. Bot replies ephemerally with confirmation and position.
6. If configured, queue announcement message is sent to target channel.
## Scenario: Content Auto-Post
## Scenario: Advance Next Performer
1. CRON job triggers Content Syndicator every 15 min
2. Syndicator polls YouTube Data API for new uploads on channel
3. New video detected → fetches metadata + thumbnail
4. Syndicator builds rich embed (title, description, thumbnail, link)
5. Embed posted to `#screenings` channel via Discord webhook
6. Mileage Engine awards +10 miles to channel subscribers
1. Moderator invokes `/sign-up next`.
2. Tour schedule engine pops head of FIFO queue.
3. If stage channel integration is enabled, bot resolves member and promotes stage speaker.
4. Confirmation response includes promoted user and remaining queue length.
5. Optional announcement is sent to configured channel.
## Scenario: Admin Updates Bot Restart
## Scenario: Mileage Award on Interaction
1. Bot receives SIGTERM from hosting platform
2. Graceful shutdown initiated: close Gateway connection, flush pending DB writes
3. Bot process restarts
4. On startup: reconnect to Discord Gateway, rehydrate in-memory state from DB
5. Mileage state is consistent — no data loss
1. Discord interaction event reaches runtime handler.
2. Bot resolves guild/member context and chooses mileage event type.
3. Mileage engine calculates points from configured event map.
4. Transaction persists event row and upserts total user mileage.
5. Role-tier thresholds are evaluated and missing roles are granted.
6. Runtime stores an engagement snapshot in configuration DB for dashboard consumption.
## Scenario: Dashboard OAuth Connect
1. Browser redirects user to Discord OAuth authorize URL.
2. Dashboard callback receives authorization code.
3. Dashboard posts code to `POST /admin/oauth/discord/exchange`.
4. OAuth bridge exchanges code for Discord token, fetches user, creates local session.
5. API returns `sessionId`; dashboard fetches session details from `/admin/oauth/session/:sessionId`.
6. Optional backend sync call propagates session to openmicodyssey.com.
## Scenario: Graceful Shutdown
1. Process receives SIGINT/SIGTERM.
2. Runtime stops HTTP server and Discord client.
3. Service tear-down closes DB pools and cancels dailies intervals.
4. Process exits with clean status after shutdown promises resolve.
+41 -38
View File
@@ -3,44 +3,47 @@
## Infrastructure Overview
```txt
┌─────────────┐ ┌──────────────────────────────────────┐
Discord │◄─────►│ Coolify
│ Gateway │ WSS │
│ + REST API │ │ ┌──────────────────────────────┐
└─────────────┘ │ │ omo-bot (Node.js process)
│ - Command handlers
│ - Event listeners
- Mileage engine │
│ └─────────────────────────────┘
│ ▼ │
│ ┌──────────────────────────────┐
│ │ PostgreSQL (local) │
- User profiles │
│ │ - Mileage scores │ │
│ │ - Event schedules │ │
│ │ - Content cache │ │
│ └──────────────────────────────┘
│ ┌──────────────────────────────┐ │
│ │ Admin API / Dashboard │ │
│ │ (React SPA) │ │
│ │ admin.openmicodyssey.com │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────┘
OAuth2 │
┌─────────────────────┐
│ openmicodyssey.com │
│ (Web Application) │
└─────────────────────┘
┌─────────────HTTPS/WSS ┌───────────────────────────────────┐
│ Discord APIs │◄───────────────────►│ Coolify deployment
└──────────────┘ │ ┌───────────────────────────────┐
│ │ Backend container │
│ │ - Discord gateway runtime
- Admin API (Express) │ │
- Dailies pollers
│ └──────────────┬────────────────┘
└───────────────────────────────────┘
───────────────────┐
│ PostgreSQL
│ mileage + config
└───────────────────┘
┌──────────────────────────┐ HTTPS ┌─────────────────────────────┐
│ Admin Dashboard (SPA) │◄───────────►│ Admin API + OAuth bridge
│ React/Vite static deploy │ │ │
└──────────────────────────┘ ─────────────────────────────
```
## Environments
## CI/CD Pipeline
| Environment | Host | Bot Instance | DB | Purpose |
| ----------- | ---------------- | ------------ | ---------------- | ---------------------------- | ---------------------- |
| Development | Local machine | 1 process | Local Postgres | Feature development, testing |
| Staging | Coolify | 1 instance | Staging Postgres | Integration | Pre-release validation |
| Production | Coolify (scaled) | 2+ instances | Production (HA) | Live community server |
Source file: `.gitea/workflows/ci-cd.yml`
1. Bot job: install dependencies, run lint, build, and test.
2. Dashboard job: install dependencies in `admin-dashboard`, run lint/build.
3. Deploy job: on `main`, trigger Coolify webhook (optionally authenticated with token).
## Environment Matrix
| Environment | Runtime | Database | Notes |
| ----------------- | --------------------------------- | -------------------------------------- | ------------------------------------------- |
| Local development | Node.js process via `npm run dev` | Local/Postgres dev instance | Fast iteration, manual command registration |
| CI | Ephemeral runner | Test/dev DB or mocked integration path | Quality gates before deployment |
| Production | Coolify-managed container(s) | Managed PostgreSQL | Webhook-triggered deployment from Gitea |
## Deployment Risks and Mitigations
- Risk: bot restarts clear in-memory OAuth sessions.
Mitigation: dashboard re-auth flow and short-lived session design.
- Risk: DB connectivity interruptions.
Mitigation: startup validation + retry behavior on mileage writes.
+28 -21
View File
@@ -1,32 +1,39 @@
# Cross-cutting Concepts
## Logging & Monitoring
## Configuration and Validation
- Structured logging (JSON) to stdout — visible in Coolify logs and via `docker logs`
- Log levels: DEBUG (dev), INFO (prod), ERROR (alert-worthy)
- Key metrics exposed via Prometheus endpoint: commands/sec, webhook latency, active users
- Central config parsing in `src/config.ts` with typed getters and validation.
- Required environment variables fail fast at startup.
- Feature toggles gate optional services (admin API, dailies, OAuth sync).
## Error Handling
## Persistence Strategy
- Command handlers: try/catch → ephemeral error reply to user + logged
- Content pollers: exponential backoff on API failures, alert after 3 consecutive failures
- Mileage writes: retry (3x, 50ms backoff) before logging as failed
- PostgreSQL used for both high-volume mileage events and operational configuration.
- Schema initialization runs inside service startup (`init` methods).
- Strict null and row count checks protect runtime behavior under `exactOptionalPropertyTypes`.
## Configuration
## Security Model
- Environment variables via `.env` file (dev) or Coolify secrets (prod), keep example in `.env.example`
- Config schema validated on startup — bot exits on missing required vars
- Admin API uses bearer token authentication middleware.
- Health endpoint can be optionally public for infrastructure probes.
- OAuth bridge performs code exchange server-side and stores ephemeral sessions in memory.
- Secrets are environment-based and excluded from logs.
## Security
## Error Handling and Resilience
- Bot token stored in env variable, never logged
- OAuth2 tokens short-lived; refresh flow managed by web app
- Admin dashboard routes guarded by Discord OAuth2 role check (`@Producer` or `@Director`)
- All external API calls over HTTPS
- Command handlers and API handlers return explicit user-safe errors.
- Mileage persistence applies bounded retries for transient DB failures.
- Dailies polling loop logs and continues on adapter-specific errors.
- Shutdown hooks close HTTP/Discord/DB resources to avoid orphaned connections.
## Conventions
## Integration Concepts
- Slash command names: kebab-case
- Event handler naming: `on<EventName>` pattern
- Database table names: snake_case, plural
- PRs require passing lint + tests before merge
- Discord integration points: slash commands, reactions, stage channels, role management.
- Dashboard integration points: REST API JSON contracts and OAuth callback/session flow.
- External content integration: adapter contract + webhook dispatcher for dailies.
## Testing and Quality Gates
- Jest + ts-jest for command and integration-like flows.
- ESLint flat config for src and tests.
- CI requires lint, build, and tests for backend plus lint/build for dashboard.