feat: Implement Tour Schedule Engine with queue management and announcement features
- Added TourScheduleEngine class for managing user queues in a guild. - Implemented methods for joining, leaving, listing, and clearing queues. - Added functionality to promote users to speaker in a stage channel and send announcements. - Created integration tests for the TourScheduleEngine to verify FIFO behavior and announcement dispatch. test: Add unit tests for ping and sign-up commands - Created tests for ping command to ensure it replies with "Pong!". - Implemented tests for sign-up command to verify queue joining, listing, and permission checks. test: Add integration tests for mileage engine flow - Developed tests to validate mileage awarding, event persistence, and role upgrades based on mileage thresholds. chore: Update TypeScript configuration for ESLint - Added tsconfig.eslint.json for ESLint integration. - Modified tsconfig.json to exclude test files from the main compilation.
This commit is contained in:
@@ -1,65 +1,77 @@
|
||||
# Discord Bot for Open Mic Odyssey
|
||||
|
||||
A custom Discord bot and web integration layer designed to bridge the [openmicodyssey.com](https://openmicodyssey.com) experience with our community server. This application gamifies community engagement, automates content syndication, and provides a suite of event management tools centered around the themes of stand-up comedy, indie filmmaking, and a cross-country road trip.
|
||||
A modular Discord bot + admin platform that syncs community engagement between Discord and [openmicodyssey.com](https://openmicodyssey.com).
|
||||
The system includes onboarding roles, stage queue management, mileage progression, content syndication, an admin API, and a React admin dashboard.
|
||||
|
||||
## Core Features
|
||||
|
||||
### The Call Sheet (User & Role Management)
|
||||
### The Call Sheet (Onboarding + Roles)
|
||||
|
||||
- **The Experience:** New members are greeted with a customized onboarding menu to declare their interests (e.g., `@ComedyFan`, `@Filmmaker`). Active users progress through community ranks, leveling up from **"Extra"** to **"Roadie"** and eventually **"Executive Producer"**.
|
||||
- **Technical Implementation:** Utilizes Discord's Reaction Role payloads and interaction webhooks for automated Role-Based Access Control (RBAC). Implements dynamic permission bitfield assignment and role hierarchy state management based on user activity telemetry.
|
||||
- Reaction-role onboarding message with emoji-to-role bindings
|
||||
- Role hierarchy safety checks before assignment/removal
|
||||
- Optional onboarding completion role and welcome-channel message
|
||||
|
||||
### The Tour Schedule (Event Management)
|
||||
### The Tour Schedule (Stage Queue)
|
||||
|
||||
- **The Experience:** Organizes virtual **"Tour Stops"** (screenings) and digital open mics. Users can utilize the `/sign-up` command to enter the stage queue, while attendees receive temporary **"VIP Backstage"** passes for live Q&As.
|
||||
- **Technical Implementation:** Wraps the Discord Scheduled Events API. Implements a FIFO (First-In-First-Out) queue data structure for managing Voice/Stage channel speaker states. Handles automated role assignment/revocation for temporary event permissions.
|
||||
- `/sign-up` subcommands: `join`, `leave`, `list`, `next`, `clear`
|
||||
- FIFO queue per guild
|
||||
- Optional stage-speaker promotion and queue announcement dispatch
|
||||
|
||||
### The Dailies (Content Webhooks & Syndication)
|
||||
### The Dailies (Content Syndication)
|
||||
|
||||
- **The Experience:** Automatically delivers fresh behind-the-scenes content directly from the crew's socials to dedicated server channels:
|
||||
- `#polaroids-from-the-van`: Instagram drops.
|
||||
- `#outtakes`: TikTok crowd work and detours.
|
||||
- `#screenings`: YouTube trailers and vlogs.
|
||||
- Adapter-based polling pipeline
|
||||
- YouTube RSS adapter implemented
|
||||
- Discord webhook dispatch with duplicate suppression
|
||||
|
||||
- **Technical Implementation:** Event-driven architecture utilizing incoming Discord Webhooks. Integrates external API polling (YouTube Data API, TikTok/IG endpoints) to fetch, parse, and format multimedia payloads into rich Discord Embeds.
|
||||
### Mileage Engine
|
||||
|
||||
### Mileage & The Hidden Map (Gamified Progression)
|
||||
- PostgreSQL-backed mileage event/user persistence
|
||||
- Configurable event scoring
|
||||
- Role-tier upgrades on threshold milestones
|
||||
- Retry behavior for transient write failures
|
||||
|
||||
- **The Experience:** Every interaction earns users **"Mileage"**. Accumulating miles unlocks secure passwords and GPS coordinates for the hidden `/map` route on the main website, granting access to deleted scenes and exclusive scripts.
|
||||
- **Technical Implementation:** Requires Discord OAuth2 integration with the main web application. Message and event telemetry are captured, scored, and stored in a database (e.g., PostgreSQL/MongoDB), continuously syncing the user's Discord state with their authenticated web session.
|
||||
### Admin API + Dashboard
|
||||
|
||||
### The Control Room (Admin Web Interface)
|
||||
- Express Admin API for config, queue, stats, OAuth bridge, configuration DB
|
||||
- React/Vite dashboard for OAuth login + analytics views
|
||||
|
||||
- **The Experience:** A dedicated dashboard for the **"Producers"** and **"Directors"** to manage the server, schedule content drops, and view engagement without touching Discord commands.
|
||||
- **Technical Implementation:** A standalone web portal (intended for `admin.openmicodyssey.com`). Exposes secure RESTful/GraphQL endpoints for bot configuration, CRON job scheduling for content drops, and data visualization for external link click-through rates.
|
||||
### OAuth2 Bridge
|
||||
|
||||
- Discord OAuth2 code exchange to user profile
|
||||
- Ephemeral session issuance
|
||||
- Optional sync callback to openmicodyssey.com backend
|
||||
|
||||
### Configuration Database
|
||||
|
||||
- `bot_settings`, `content_schedules`, `engagement_stats` tables
|
||||
- Admin CRUD endpoints for settings/schedules
|
||||
- Engagement snapshot persistence from runtime events
|
||||
|
||||
## Implemented Modules
|
||||
|
||||
- `src/bot.ts`: gateway client lifecycle, command dispatch, service wiring
|
||||
- `src/call-sheet.ts`: reaction role onboarding and role hierarchy guards
|
||||
- `src/tour-schedule.ts`: FIFO queue, stage speaker promotion, announcements
|
||||
- `src/mileage.ts`: mileage persistence, scoring, role-upgrade triggers
|
||||
- `src/dailies/*`: adapter/poller/webhook syndication pipeline
|
||||
- `src/admin-api.ts`: operational and configuration endpoints
|
||||
- `src/oauth-bridge.ts`: Discord code exchange + openmic session sync
|
||||
- `src/configuration-database.ts`: bot settings, schedules, engagement snapshots
|
||||
- `admin-dashboard/src/*`: admin SPA, OAuth callback flow, analytics views
|
||||
|
||||
## Architecture Documentation (arc42)
|
||||
|
||||
This project uses the [arc42](https://arc42.org) architecture documentation template.
|
||||
All chapters are in `docs/`:
|
||||
|
||||
| # | Chapter | File |
|
||||
| --- | ------------------------ | ---------------------------------------------------------------------------- |
|
||||
| 1 | Introduction & Goals | [`docs/01_introduction_and_goals.md`](docs/01_introduction_and_goals.md) |
|
||||
| 2 | Architecture Constraints | [`docs/02_architecture_constraints.md`](docs/02_architecture_constraints.md) |
|
||||
| 3 | Context & Scope | [`docs/03_context_and_scope.md`](docs/03_context_and_scope.md) |
|
||||
| 4 | Solution Strategy | [`docs/04_solution_strategy.md`](docs/04_solution_strategy.md) |
|
||||
| 5 | Building Block View | [`docs/05_building_block_view.md`](docs/05_building_block_view.md) |
|
||||
| 6 | Runtime View | [`docs/06_runtime_view.md`](docs/06_runtime_view.md) |
|
||||
| 7 | Deployment View | [`docs/07_deployment_view.md`](docs/07_deployment_view.md) |
|
||||
| 8 | Cross-cutting Concepts | [`docs/08_concepts.md`](docs/08_concepts.md) |
|
||||
| 9 | Architecture Decisions | [`docs/09_architecture_decisions.md`](docs/09_architecture_decisions.md) |
|
||||
| 10 | Quality Requirements | [`docs/10_quality_requirements.md`](docs/10_quality_requirements.md) |
|
||||
| 11 | Risks & Technical Debt | [`docs/11_technical_risks.md`](docs/11_technical_risks.md) |
|
||||
| 12 | Glossary | [`docs/12_glossary.md`](docs/12_glossary.md) |
|
||||
This project uses the arc42 template. Chapters are in `docs/`.
|
||||
|
||||
## Architecture & Tech Stack
|
||||
|
||||
| Layer | Choice |
|
||||
| --------------- | -------------------- |
|
||||
| Runtime | Node.js (Discord.js) |
|
||||
| Runtime | Node.js + TypeScript |
|
||||
| Discord SDK | discord.js |
|
||||
| Database | PostgreSQL |
|
||||
| Admin Dashboard | React |
|
||||
| Admin API | Express |
|
||||
| Admin Dashboard | React + Vite |
|
||||
| Auth | Discord OAuth2 |
|
||||
| Hosting | Coolify + Nixpacks |
|
||||
|
||||
@@ -67,52 +79,139 @@ All chapters are in `docs/`:
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js v16+ (or Python 3.9+)
|
||||
- A Discord Developer Application with Bot Token
|
||||
- Access to `openmicodyssey.com` backend for OAuth syncing
|
||||
- Node.js 22+
|
||||
- npm 10+
|
||||
- Discord Developer Application (bot token + OAuth2 app)
|
||||
- PostgreSQL instance
|
||||
|
||||
### Installation
|
||||
|
||||
1. Clone the repository:
|
||||
1. Clone repository:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-org/open-mic-odyssey-bot.git
|
||||
cd open-mic-odyssey-bot
|
||||
|
||||
git clone https://git.allucanget.biz/allucanget/omo-bot.git
|
||||
cd omo-bot
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
2. Install root dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
|
||||
```
|
||||
|
||||
3. Configure environment variables. Duplicate `.env.example` to `.env` and add your specific keys:
|
||||
3. Configure bootstrap environment variables (`.env` from `.env.example`):
|
||||
|
||||
```env
|
||||
DISCORD_TOKEN=your_bot_token
|
||||
CLIENT_ID=your_client_id
|
||||
GUILD_ID=your_server_id
|
||||
DB_CONNECTION_STRING=your_db_uri
|
||||
YOUTUBE_API_KEY=your_yt_key
|
||||
|
||||
DATABASE_URL=postgres://...
|
||||
CONFIG_DB_ENABLED=true
|
||||
DISCORD_GUILD_ID=... # optional seed scope
|
||||
```
|
||||
|
||||
4. Deploy Slash Commands:
|
||||
4. Register slash commands:
|
||||
|
||||
```bash
|
||||
npm run deploy-commands
|
||||
|
||||
npm run register:commands
|
||||
```
|
||||
|
||||
5. Start the bot:
|
||||
5. Run bot in development:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
6. Build and run production bundle:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm start
|
||||
|
||||
```
|
||||
|
||||
### Admin Dashboard
|
||||
|
||||
```bash
|
||||
cd admin-dashboard
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Dashboard environment template: `admin-dashboard/.env.example`.
|
||||
|
||||
### Validation Commands
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
npm run build
|
||||
npm run test
|
||||
```
|
||||
|
||||
### Database Setup Commands
|
||||
|
||||
`DATABASE_URL` is required for each command.
|
||||
|
||||
```bash
|
||||
npm run db:migrate
|
||||
npm run db:seed
|
||||
npm run db:setup
|
||||
```
|
||||
|
||||
- `db:migrate`: applies schema migrations tracked in `schema_migrations`
|
||||
- `db:seed`: inserts initial config values from environment into `bot_settings` when missing
|
||||
- `db:setup`: runs migrate then seed
|
||||
|
||||
### Runtime Config Source
|
||||
|
||||
Runtime reads configuration keys from `bot_settings` table first, then falls back to environment values.
|
||||
|
||||
- Global scope: `guild_id = __global__`
|
||||
- Guild override scope: `guild_id = DISCORD_GUILD_ID`
|
||||
- Key names match previous env variable names (examples: `DISCORD_TOKEN`, `DISCORD_CLIENT_ID`, `ADMIN_API_TOKEN`)
|
||||
|
||||
Recommended flow:
|
||||
|
||||
1. Set bootstrap env (`DATABASE_URL`, optional `DISCORD_GUILD_ID`).
|
||||
2. Run `npm run db:migrate`.
|
||||
3. Run `npm run db:seed` once while legacy env vars are still present.
|
||||
4. Remove legacy runtime vars from `.env` after confirming `bot_settings` contains required keys.
|
||||
|
||||
Dashboard quality check:
|
||||
|
||||
```bash
|
||||
cd admin-dashboard
|
||||
npm run lint
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Admin API Endpoints
|
||||
|
||||
- `GET /health`
|
||||
- `GET /admin/config`
|
||||
- `GET /admin/stats?guildId=...`
|
||||
- `GET /admin/schedule?guildId=...`
|
||||
- `POST /admin/schedule/clear`
|
||||
- `POST /admin/oauth/discord/exchange`
|
||||
- `GET /admin/oauth/session/:sessionId`
|
||||
- `GET /admin/db/settings?guildId=...`
|
||||
- `PUT /admin/db/settings`
|
||||
- `GET /admin/db/schedules?guildId=...`
|
||||
- `PUT /admin/db/schedules`
|
||||
- `DELETE /admin/db/schedules/:guildId/:scheduleKey`
|
||||
- `GET /admin/db/engagement/latest?guildId=...`
|
||||
|
||||
## CI/CD (Gitea Actions)
|
||||
|
||||
Pipeline file: `.gitea/workflows/ci-cd.yml`
|
||||
|
||||
Flow:
|
||||
|
||||
- bot checks: `npm ci -> npm run lint -> npm run build -> npm run test`
|
||||
- dashboard checks: `admin-dashboard/npm ci -> npm run lint -> npm run build`
|
||||
- deploy: on push to `main`, trigger Coolify deploy webhook
|
||||
|
||||
Required Gitea secrets:
|
||||
|
||||
- `COOLIFY_DEPLOY_HOOK_URL` (required)
|
||||
- `COOLIFY_DEPLOY_TOKEN` (optional bearer token)
|
||||
|
||||
## Contributing
|
||||
|
||||
For internal development only. Please refer to [CONTRIBUTING.md](CONTRIBUTING.md) for styling guidelines and PR review processes for "The Control Room" dashboard updates.
|
||||
Internal development only. See `CONTRIBUTING.md`.
|
||||
|
||||
Reference in New Issue
Block a user