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 ## Technology Decisions
| Decision | Choice | Rationale | | Decision | Choice | Rationale |
| ---------------- | -------------------- | --------------------------------------------------------------------------------------- | | -------------- | ----------------------------------------- | -------------------------------------------------------------------------------------- |
| Bot framework | Discord.js (Node.js) | Mature library, strong type support, rich event model | | Bot runtime | Node.js + TypeScript + discord.js | Strong ecosystem, typed Discord interactions, shared language across backend/dashboard |
| Database | PostgreSQL | Reliable, supports JSONB for flexible user state, well-suited for mileage/role tracking | | Persistence | PostgreSQL (`pg`) | Reliable relational storage for mileage, schedules, and settings |
| Frontend (Admin) | React | Team familiarity, rich ecosystem for dashboards | | Admin API | Express | Lightweight routing and middleware model for operational endpoints |
| Hosting | Coolify | Easy deployment for Node.js with Nixpacks. | | Dashboard | React + Vite + TypeScript | Fast iteration and typed API integration |
| Auth | Discord OAuth2 | No custom auth needed, seamless web/bot 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 - Bot core orchestrates Discord gateway and command/event handling.
- **Content Syndicator** — polling adapters for YouTube/IG/TikTok, webhook dispatch - Domain services encapsulate call-sheet onboarding, tour queue, mileage, and dailies.
- **Event Manager** — FIFO queue for stage/speaker management - Operational interfaces exposed through Admin API and OAuth bridge.
- **Mileage Engine** — scoring logic, persistence, state sync with web app - Shared configuration layer centralizes environment parsing and validation.
- **Admin API** — RESTful endpoints for bot config, content scheduling, analytics - Separate dashboard SPA consumes API without direct DB access.
## Key Quality Goals ## Quality Strategies
- **Availability** — Stateless bot instances scale horizontally behind load balancer - Availability: graceful startup/shutdown, service initialization guards, process-level health endpoint.
- **Consistency** — Write-ahead logging for mileage transactions; periodic state reconciliation with web app - Consistency: transactional mileage writes, strict DB row guards, idempotent schedule updates.
- **Extensibility** — Adapter pattern for content sources: implement interface, register, deploy - 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 - In-memory OAuth sessions reduce complexity but require re-authentication after process restart.
- CI/CD via Gitea Actions: lint → test → deploy - Modular monolith minimizes operational overhead now, while preserving service boundaries for future extraction.
- Feature toggles for admin dashboard rollout
+47 -33
View File
@@ -3,39 +3,53 @@
## Whitebox Overall System (Level 1) ## Whitebox Overall System (Level 1)
```txt ```txt
┌──────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────────
│ omo-bot │ omo-bot
├──────────────────────────────────────────────────────┤ ├────────────────────────────────────────────────────────────
┌──────────────────┐ ┌─────────────────────────┐ Discord Gateway Runtime
Command Layer │ │ Event Listener Layer │ ├─ Command handlers (/ping, /call-sheet, /sign-up, /dailies)
│ /sign-up, /map │ │ member_join, reaction │ ├─ Reaction/member event handlers
│ └────────┬─────────┘ └───────────┬─────────────┘ │ └─ Service orchestration (`startBot`)
Core Services
┌──────────────────────────────────────────────┐ ├─ Call Sheet Service
│ Service Layer ├─ Tour Schedule Engine
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ ├─ Mileage Engine
│ │ Event │ │ Mileage │ │ Content ├─ Dailies Service (adapters + dispatcher)
│ │ Manager │ │ Engine │ │ Syndicator ├─ OAuth Bridge Service
│ └──────────┘ └──────────┘ └──────────────┘ │ │ └─ Configuration Database Service
└───────────────────┬──────────────────────────┘
Interfaces
├─ Admin API (Express)
┌──────────────────────────────────────────────┐ └─ Health endpoint
│ │ Data / Persistence Layer │ │ └──────────────────────────────┬─────────────────────────────┘
PostgreSQL DB + Discord API Wrapper
│ └──────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────── ────────────────────────────
│ PostgreSQL + Discord APIs │
└────────────────────────────┘
``` ```
### Black Box Descriptions ## Building Blocks and Responsibilities
| Building Block | Responsibility | | Building Block | Responsibility |
| ------------------ | ------------------------------------------------------------------------------------------ | | ------------------------------- | ---------------------------------------------------------------------------------- |
| Command Layer | Register and handle slash commands (`/sign-up`, `/map`, `/help`); validate permissions | | `src/bot.ts` | Runtime bootstrap, command registration, service lifecycle, graceful shutdown |
| Event Listener | Subscribe to Discord Gateway events (member join, reaction add, voice state change) | | `src/call-sheet.ts` | Reaction-role onboarding, grouped role exclusivity, welcome flow hooks |
| Event Manager | Manage FIFO queue for voice/stage speakers; schedule "Tour Stop" events via Discord API | | `src/tour-schedule.ts` | Queue state, join/leave/advance operations, stage speaker management |
| Mileage Engine | Score user interactions, persist to DB, trigger role upgrades, sync with web app | | `src/mileage.ts` | Event scoring, persistence, mileage aggregation, role tier synchronization |
| Content Syndicator | Poll YouTube/IG/TikTok APIs; format rich embeds; dispatch to Discord channels via webhooks | | `src/dailies/service.ts` | Polling scheduler, adapter orchestration, webhook dispatch loop |
| Admin API | Expose REST endpoints for dashboard (configuration, content schedule, engagement stats) | | `src/oauth-bridge.ts` | Discord OAuth code exchange, user fetch, temporary session cache, optional sync |
| DB Layer | PostgreSQL connection pool, migrations, query builders | | `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 # Runtime View
## Scenario: User Signs Up for Open Mic ## Scenario: `/sign-up join` to Stage Queue
1. User runs `/sign-up` in voice channel 1. User invokes `/sign-up join`.
2. Command Layer validates user has `@ComedyFan` role 2. Command handler validates guild/context and required permissions.
3. Event Manager adds user to FIFO queue 3. Tour schedule engine appends user to guild queue if not already present.
4. When previous speaker leaves stage (voice state change), Event Manager pops queue 4. Engine returns queue position and current queue snapshot.
5. Bot grants temporary speaker permission via voice channel API 5. Bot replies ephemerally with confirmation and position.
6. Announcement sent to `#stage-door` channel 6. If configured, queue announcement message is sent to target channel.
7. Mileage Engine awards +50 miles for participation
## Scenario: Content Auto-Post ## Scenario: Advance Next Performer
1. CRON job triggers Content Syndicator every 15 min 1. Moderator invokes `/sign-up next`.
2. Syndicator polls YouTube Data API for new uploads on channel 2. Tour schedule engine pops head of FIFO queue.
3. New video detected → fetches metadata + thumbnail 3. If stage channel integration is enabled, bot resolves member and promotes stage speaker.
4. Syndicator builds rich embed (title, description, thumbnail, link) 4. Confirmation response includes promoted user and remaining queue length.
5. Embed posted to `#screenings` channel via Discord webhook 5. Optional announcement is sent to configured channel.
6. Mileage Engine awards +10 miles to channel subscribers
## Scenario: Admin Updates Bot Restart ## Scenario: Mileage Award on Interaction
1. Bot receives SIGTERM from hosting platform 1. Discord interaction event reaches runtime handler.
2. Graceful shutdown initiated: close Gateway connection, flush pending DB writes 2. Bot resolves guild/member context and chooses mileage event type.
3. Bot process restarts 3. Mileage engine calculates points from configured event map.
4. On startup: reconnect to Discord Gateway, rehydrate in-memory state from DB 4. Transaction persists event row and upserts total user mileage.
5. Mileage state is consistent — no data loss 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 ## Infrastructure Overview
```txt ```txt
┌─────────────┐ ┌──────────────────────────────────────┐ ┌─────────────HTTPS/WSS ┌───────────────────────────────────┐
Discord │◄─────►│ Coolify │ Discord APIs │◄───────────────────►│ Coolify deployment
│ Gateway │ WSS │ └──────────────┘ │ ┌───────────────────────────────┐
│ + REST API │ │ ┌──────────────────────────────┐ │ │ Backend container │
└─────────────┘ │ │ omo-bot (Node.js process) │ │ - Discord gateway runtime
│ - Command handlers - Admin API (Express) │ │
│ - Event listeners - Dailies pollers
- Mileage engine │ │ └──────────────┬────────────────┘
│ └─────────────────────────────┘ └───────────────────────────────────┘
│ ▼ │
│ ┌──────────────────────────────┐ ───────────────────┐
│ │ PostgreSQL (local) │ │ PostgreSQL
- User profiles │ │ mileage + config
│ │ - Mileage scores │ │ └───────────────────┘
│ │ - Event schedules │ │
│ │ - Content cache │ │ ┌──────────────────────────┐ HTTPS ┌─────────────────────────────┐
│ └──────────────────────────────┘ │ Admin Dashboard (SPA) │◄───────────►│ Admin API + OAuth bridge
│ React/Vite static deploy │ │ │
│ ┌──────────────────────────────┐ │ └──────────────────────────┘ ─────────────────────────────
│ │ Admin API / Dashboard │ │
│ │ (React SPA) │ │
│ │ admin.openmicodyssey.com │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────┘
OAuth2 │
┌─────────────────────┐
│ openmicodyssey.com │
│ (Web Application) │
└─────────────────────┘
``` ```
## Environments ## CI/CD Pipeline
| Environment | Host | Bot Instance | DB | Purpose | Source file: `.gitea/workflows/ci-cd.yml`
| ----------- | ---------------- | ------------ | ---------------- | ---------------------------- | ---------------------- |
| Development | Local machine | 1 process | Local Postgres | Feature development, testing | 1. Bot job: install dependencies, run lint, build, and test.
| Staging | Coolify | 1 instance | Staging Postgres | Integration | Pre-release validation | 2. Dashboard job: install dependencies in `admin-dashboard`, run lint/build.
| Production | Coolify (scaled) | 2+ instances | Production (HA) | Live community server | 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 # Cross-cutting Concepts
## Logging & Monitoring ## Configuration and Validation
- Structured logging (JSON) to stdout — visible in Coolify logs and via `docker logs` - Central config parsing in `src/config.ts` with typed getters and validation.
- Log levels: DEBUG (dev), INFO (prod), ERROR (alert-worthy) - Required environment variables fail fast at startup.
- Key metrics exposed via Prometheus endpoint: commands/sec, webhook latency, active users - Feature toggles gate optional services (admin API, dailies, OAuth sync).
## Error Handling ## Persistence Strategy
- Command handlers: try/catch → ephemeral error reply to user + logged - PostgreSQL used for both high-volume mileage events and operational configuration.
- Content pollers: exponential backoff on API failures, alert after 3 consecutive failures - Schema initialization runs inside service startup (`init` methods).
- Mileage writes: retry (3x, 50ms backoff) before logging as failed - 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` - Admin API uses bearer token authentication middleware.
- Config schema validated on startup — bot exits on missing required vars - 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 - Command handlers and API handlers return explicit user-safe errors.
- OAuth2 tokens short-lived; refresh flow managed by web app - Mileage persistence applies bounded retries for transient DB failures.
- Admin dashboard routes guarded by Discord OAuth2 role check (`@Producer` or `@Director`) - Dailies polling loop logs and continues on adapter-specific errors.
- All external API calls over HTTPS - Shutdown hooks close HTTP/Discord/DB resources to avoid orphaned connections.
## Conventions ## Integration Concepts
- Slash command names: kebab-case - Discord integration points: slash commands, reactions, stage channels, role management.
- Event handler naming: `on<EventName>` pattern - Dashboard integration points: REST API JSON contracts and OAuth callback/session flow.
- Database table names: snake_case, plural - External content integration: adapter contract + webhook dispatcher for dailies.
- PRs require passing lint + tests before merge
## 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.