Bumps the production group with 8 updates in the /services/discord-gateway directory: | Package | From | To | | --- | --- | --- | | [ioredis](https://github.com/redis/ioredis) | `5.11.1` | `6.0.0` | | [openai](https://github.com/openai/openai-node) | `6.49.0` | `7.5.0` | | [opusscript](https://github.com/abalabahaha/opusscript) | `0.0.8` | `0.1.1` | | [pg](https://github.com/brianc/node-postgres/tree/HEAD/packages/pg) | `8.22.0` | `8.23.0` | | [pino](https://github.com/pinojs/pino) | `9.14.0` | `10.3.1` | | [piscina](https://github.com/piscinajs/piscina) | `5.3.0` | `5.3.1` | | [sharp](https://github.com/lovell/sharp) | `0.34.5` | `0.35.3` | | [ws](https://github.com/websockets/ws) | `8.21.1` | `8.21.3` | Updates `ioredis` from 5.11.1 to 6.0.0 - [Release notes](https://github.com/redis/ioredis/releases) - [Changelog](https://github.com/redis/ioredis/blob/main/CHANGELOG.md) - [Commits](https://github.com/redis/ioredis/compare/v5.11.1...v6.0.0) Updates `openai` from 6.49.0 to 7.5.0 - [Release notes](https://github.com/openai/openai-node/releases) - [Changelog](https://github.com/openai/openai-node/blob/main/CHANGELOG.md) - [Commits](https://github.com/openai/openai-node/compare/v6.49.0...v7.5.0) Updates `opusscript` from 0.0.8 to 0.1.1 - [Release notes](https://github.com/abalabahaha/opusscript/releases) - [Commits](https://github.com/abalabahaha/opusscript/compare/0.0.8...0.1.1) Updates `pg` from 8.22.0 to 8.23.0 - [Changelog](https://github.com/brianc/node-postgres/blob/master/CHANGELOG.md) - [Commits](https://github.com/brianc/node-postgres/commits/pg@8.23.0/packages/pg) Updates `pino` from 9.14.0 to 10.3.1 - [Release notes](https://github.com/pinojs/pino/releases) - [Commits](https://github.com/pinojs/pino/compare/v9.14.0...v10.3.1) Updates `piscina` from 5.3.0 to 5.3.1 - [Release notes](https://github.com/piscinajs/piscina/releases) - [Changelog](https://github.com/piscinajs/piscina/blob/v5.3.1/CHANGELOG.md) - [Commits](https://github.com/piscinajs/piscina/compare/v5.3.0...v5.3.1) Updates `sharp` from 0.34.5 to 0.35.3 - [Release notes](https://github.com/lovell/sharp/releases) - [Commits](https://github.com/lovell/sharp/compare/v0.34.5...v0.35.3) Updates `ws` from 8.21.1 to 8.21.3 - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.21.1...8.21.3) --- updated-dependencies: - dependency-name: ioredis dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: production - dependency-name: openai dependency-version: 7.5.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: production - dependency-name: opusscript dependency-version: 0.1.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: pg dependency-version: 8.23.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: pino dependency-version: 10.3.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: production - dependency-name: piscina dependency-version: 5.3.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: sharp dependency-version: 0.35.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: ws dependency-version: 8.21.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production ... Signed-off-by: dependabot[bot] <support@github.com>
Discord Gateway Service - Extraction Complete
Overview
Successfully extracted Discord Gateway service with Modular MVC + Event-Driven Architecture using Redis pub/sub for inter-service communication.
Directory Structure
services/discord-gateway/
├── src/
│ ├── app/
│ │ ├── bootstrap.ts # Service initialization (Discord client, DB, Redis)
│ │ └── shutdown.ts # Graceful shutdown handler
│ ├── shared/ # Shared infrastructure layer
│ │ ├── config/
│ │ │ └── config.ts # Zod-validated environment config
│ │ ├── database/
│ │ │ ├── schema.ts # Drizzle ORM schema
│ │ │ ├── drizzle.ts # PostgreSQL connection
│ │ │ ├── migrate.ts # Migration runner
│ │ │ └── voiceRecordingRepo.ts
│ │ ├── errors/
│ │ │ └── errors.ts # Custom error classes
│ │ ├── logger/
│ │ │ ├── logger.ts # Winston logger wrapper
│ │ │ └── serialization.ts # Log serialization
│ │ ├── utils/
│ │ │ └── retry.ts # Retry with exponential backoff
│ │ └── discord/
│ │ └── clientOptions.ts # Discord.js client config
│ ├── modules/ # Feature modules (Modular MVC)
│ │ ├── message-capture/ # Controller-Service-Repository
│ │ │ ├── messageCapture.ts # Controller: Discord event listeners
│ │ │ ├── messageStore.ts # Repository: DB operations
│ │ │ ├── messageMetadata.ts # Service: Metadata extraction
│ │ │ ├── types.ts # Domain types
│ │ │ └── index.ts # Module exports
│ │ ├── ai-moderation/ # Controller-Service-Repository
│ │ │ ├── aiAnalyzer.ts # Controller: Analysis orchestration
│ │ │ ├── llmModerationClient.ts # Service: LLM API client
│ │ │ ├── aiAnalysisWorker.ts # Service: Worker pool
│ │ │ ├── indonesianTextNormalizer.ts # Service: Text normalization
│ │ │ ├── moderationPrompt.ts # Service: Prompt generation
│ │ │ └── index.ts # Module exports
│ │ ├── voice-recording/ # Controller-Service-Repository
│ │ │ ├── voiceController.ts # Controller: Voice connection mgmt
│ │ │ ├── recorder.ts # Service: Recording orchestration
│ │ │ ├── recorder/ # Sub-services
│ │ │ │ ├── audioStream.ts # Audio stream subscription
│ │ │ │ ├── decoder.ts # Opus decoding
│ │ │ │ ├── segment.ts # OGG segment rotation
│ │ │ │ ├── metadata.ts # Segment metadata
│ │ │ │ ├── sessionRecording.ts # Session management
│ │ │ │ └── uploader.ts # Segment upload
│ │ │ └── index.ts # Module exports
│ │ ├── attachment-upload/ # Controller-Service-Repository
│ │ │ ├── attachmentUploader.ts # Service: Upload orchestration
│ │ │ ├── imageResizer.ts # Service: Image resizing
│ │ │ └── index.ts # Module exports
│ │ └── event-broadcaster/ # Event-driven layer
│ │ ├── eventBroadcaster.ts # Service: Redis pub/sub publisher
│ │ ├── eventTypes.ts # Domain: Event type definitions
│ │ └── index.ts # Module exports
│ ├── mock-crc.ts # CRC polyfill for discord.js
│ └── index.ts # Service entry point
├── ARCHITECTURE.md # Detailed architecture documentation
├── package.json # Service dependencies
└── tsconfig.json # TypeScript configuration (inherited)
Architecture Patterns
1. Modular MVC Structure
Each feature module follows Controller-Service-Repository pattern:
Message Capture Module:
- Controller (
messageCapture.ts): Listens to Discord events (messageCreate, messageUpdate, messageDelete) - Service (
messageMetadata.ts): Extracts and normalizes message metadata - Repository (
messageStore.ts): Database CRUD operations
AI Moderation Module:
- Controller (
aiAnalyzer.ts): Orchestrates analysis workflow - Service (
llmModerationClient.ts): LLM API integration - Service (
aiAnalysisWorker.ts): Worker pool management - Service (
indonesianTextNormalizer.ts): Text preprocessing
Voice Recording Module:
- Controller (
voiceController.ts): Voice channel connection management - Service (
recorder.ts): Recording orchestration - Sub-services (
recorder/*): Audio stream, decoding, segmentation, upload
Attachment Upload Module:
- Service (
attachmentUploader.ts): Upload orchestration - Service (
imageResizer.ts): Image processing
2. Event-Driven Architecture
Redis Pub/Sub replaces WebSocket broadcaster:
Discord Events → Discord Gateway Service → Redis Pub/Sub → Backend Service
↓
Event Channels:
- discord:message:created
- discord:message:updated
- discord:message:deleted
- discord:message:analyzed
- discord:attachment:created
- discord:attachment:uploaded
- discord:voice:started
- discord:voice:stopped
- discord:voice:uploaded
- discord:analysis:queue_status
3. Shared Infrastructure Layer
Centralized, reusable components:
- Config: Zod-validated environment variables
- Logger: Winston logger with context support
- Database: Drizzle ORM with PostgreSQL
- Errors: Custom error classes with codes and HTTP status codes
- Utils: Retry logic with exponential backoff
- Discord: Client configuration and options
4. No HTTP Server
- Event-driven only: No Express, WebSocket, or HTTP routes
- Redis pub/sub: All inter-service communication via Redis
- Backend service: Consumes events and serves HTTP API
- Frontend: Continues to use Backend HTTP API
Key Features
Message Capture
- Discord emits
messageCreate,messageUpdate,messageDeleteevents messageCapture.tslistener receives and validates event- Extract metadata: user, channel, content, timestamp, attachments
messageStore.tsinserts into PostgreSQLeventBroadcaster.messageCreated()publishes to Redis- Backend service subscribes and processes
AI Moderation
aiAnalyzer.tsqueues messages for analysisllmModerationClient.tscalls LLM API with contextindonesianTextNormalizer.tspreprocesses text- Results stored in database
eventBroadcaster.messageAnalyzed()publishes results- Backend service receives and updates UI
Voice Recording
voiceController.connect()joins voice channelrecorder.tssubscribes to user audio streams- For each speaking user:
audioStream.tssubscribes to Opus packetsdecoder.tsdecodes Opus to PCMsegment.tsrotates OGG files (5s default)metadata.tscollects user info
- On silence (3s):
sessionRecording.tsfinalizes segmentuploader.tsuploads to storageeventBroadcaster.voiceRecordingUploaded()publishes
- Backend service indexes recording
Attachment Upload
messageCapture.tsdetects attachmentsattachmentUploader.tsdownloads from DiscordimageResizer.tsresizes images if needed- Upload to external storage with retry logic
eventBroadcaster.attachmentUploaded()publishes- Backend service stores metadata
Initialization Flow
1. Load environment config (Zod validation)
↓
2. Initialize PostgreSQL connection
↓
3. Run pending database migrations
↓
4. Create Discord client with optimized cache
↓
5. Initialize Redis event broadcaster
↓
6. Register Discord event listeners
- messageCapture (message events)
- aiAnalyzer (analysis worker)
↓
7. Login to Discord
↓
8. Listen for graceful shutdown signals
Graceful Shutdown
On SIGINT/SIGTERM/uncaughtException/unhandledRejection:
- Close PostgreSQL connection
- Disconnect from voice channels
- Close Redis connection
- Destroy Discord client
- Exit process (code 0 for clean, 1 for error)
Dependencies
Core Discord:
discord.js-selfbot-v13— Discord client (selfbot variant)@discordjs/voice— Voice connection management@discordjs/opus— Native Opus codec
Audio Processing:
prism-media— Opus encoding/decodingopusscript— Opus fallback for Node v26+sharp— Image resizing
Data & Config:
drizzle-orm— Type-safe ORMpg— PostgreSQL driverzod— Config validationioredis— Redis client
Logging & Utilities:
winston— Structured loggingp-retry— Retry with backoffp-limit— Concurrency limitingpiscina— Worker pool
No Breaking Changes
- Original
src/remains untouched - Discord Gateway is a new service in
services/discord-gateway/ - Can run alongside existing monolith during transition
- Backend service will consume Redis events
- Frontend continues to use Backend HTTP API
Next Steps
-
Create Backend service (
services/backend/)- HTTP API endpoints
- Redis event subscribers
- Database models
- WebSocket broadcaster
-
Update Frontend (
frontend/)- Connect to Backend HTTP API
- Subscribe to WebSocket events
-
Nix & CI/CD
- flake.nix package for Discord Gateway
- systemd services (gmw-backend, gmw-discord-gateway)
- GitHub Actions for build/deploy (nix copy → systemctl restart)
-
Documentation
- API documentation
- Event schema documentation
- Deployment guide
Files Created
Total: 43 files
Shared Infrastructure (9 files)
src/shared/config/config.tssrc/shared/database/(5 files)@bete/shared/errors(shared package)src/shared/logger/logger.tssrc/shared/logger/serialization.tssrc/shared/utils/retry.tssrc/shared/discord/clientOptions.ts
Modules (28 files)
src/modules/message-capture/(5 files)src/modules/ai-moderation/(6 files)src/modules/voice-recording/(9 files)src/modules/attachment-upload/(3 files)src/modules/event-broadcaster/(3 files)
App & Entry (4 files)
src/app/bootstrap.tssrc/app/shutdown.tssrc/index.tssrc/mock-crc.ts
Configuration (2 files)
package.jsonARCHITECTURE.md
Verification Checklist
✅ Directory structure created ✅ Shared infrastructure migrated ✅ Message capture module migrated ✅ AI moderation module migrated ✅ Voice recording module migrated ✅ Attachment upload module migrated ✅ Event broadcaster module created (Redis pub/sub) ✅ Bootstrap and entry point created ✅ Package.json with dependencies ✅ No HTTP server code (Express, WebSocket removed) ✅ Event-driven architecture implemented ✅ Graceful shutdown handler ✅ Module index files for clean exports ✅ Architecture documentation
Event Flow Diagram
┌─────────────────────────────────────────────────────────────────┐
│ Discord Gateway Service │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────┐ │
│ │ Message Capture │ │ AI Moderation │ │ Voice Record │ │
│ │ (Controller) │ │ (Controller) │ │ (Controller) │ │
│ └────────┬─────────┘ └────────┬─────────┘ └──────┬───────┘ │
│ │ │ │ │
│ ├─────────────────────┼───────────────────┤ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Event Broadcaster (Redis Pub/Sub) │ │
│ │ - discord:message:created │ │
│ │ - discord:message:updated │ │
│ │ - discord:message:deleted │ │
│ │ - discord:message:analyzed │ │
│ │ - discord:attachment:created │ │
│ │ - discord:attachment:uploaded │ │
│ │ - discord:voice:started │ │
│ │ - discord:voice:stopped │ │
│ │ - discord:voice:uploaded │ │
│ │ - discord:analysis:queue_status │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
└───────────┼────────────────────────────────────────────────────┘
│
│ Redis Pub/Sub
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Backend Service │
│ (Subscribes to events, serves HTTP API, manages WebSocket) │
└─────────────────────────────────────────────────────────────────┘
│
│ HTTP API
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Frontend Application │
│ (React SPA, real-time updates via WebSocket) │
└─────────────────────────────────────────────────────────────────┘
Summary
The Discord Gateway service has been successfully extracted with:
- Modular MVC architecture for clean separation of concerns
- Event-driven design using Redis pub/sub for inter-service communication
- Shared infrastructure layer for reusable components
- No HTTP server — pure event-driven service
- Graceful shutdown handling
- Type-safe configuration with Zod validation
- Structured logging with Winston
- PostgreSQL integration with Drizzle ORM
The service is ready for integration with the Backend service, which will consume Redis events and serve the HTTP API to the Frontend.