Update moderation guidelines to prevent false positives on song lyrics, poems, memes, and literary quotes, ensuring political or revolutionary content is not flagged as conflict instigation unless accompanied by explicit incitement.
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
-
Docker & CI/CD
- Dockerfile for Discord Gateway
- Docker Compose for multi-service setup
- GitHub Actions for build/deploy
-
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)src/shared/errors/errors.tssrc/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.