feat: update documentation for architecture, runtime scenarios, and deployment strategies
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user