Files
GMW/services/discord-gateway/ARCHITECTURE.md
T
MythEclipseandClaude Opus 4.8 c48a0c5e3b refactor: split monolith into 3 microservices (frontend, backend, discord-gateway)
- Extract services into services/{frontend,backend,discord-gateway}
- Create packages/shared/ for shared logger, errors, utils, types
- Setup Modular MVC pattern in backend (controller→service→repository)
- Setup event-driven architecture in discord-gateway with Redis pub/sub
- Move Docker files to infra/docker/ with per-service Dockerfiles
- Update docker-compose.yml to use Traefik-only routing (no port exposes)
- Update GitHub Actions deploy workflow for multi-service matrix build
- Fix all import paths and resolve type errors across all services
- All 3 services pass tsc --noEmit clean

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 21:44:29 +07:00

7.4 KiB

services/discord-gateway/ ├── src/ │ ├── app/ │ │ ├── bootstrap.ts # Discord Gateway initialization (no HTTP server) │ │ └── shutdown.ts # Graceful shutdown handler │ ├── shared/ │ │ ├── config/ │ │ │ └── config.ts # Environment configuration (Zod validated) │ │ ├── database/ │ │ │ ├── schema.ts # Drizzle ORM schema │ │ │ ├── drizzle.ts # Database connection │ │ │ ├── migrate.ts # Migration runner │ │ │ └── voiceRecordingRepo.ts │ │ ├── errors/ │ │ │ └── errors.ts # Custom error classes │ │ ├── logger/ │ │ │ ├── logger.ts # Winston logger wrapper │ │ │ └── serialization.ts # Log value serialization │ │ ├── utils/ │ │ │ └── retry.ts # Retry with backoff utility │ │ └── discord/ │ │ └── clientOptions.ts # Discord.js client configuration │ ├── modules/ │ │ ├── message-capture/ # Modular MVC: Message capture & storage │ │ │ ├── messageCapture.ts # Controller: Discord event listeners │ │ │ ├── messageStore.ts # Repository: Database operations │ │ │ ├── messageMetadata.ts # Service: Message metadata extraction │ │ │ ├── types.ts # Domain types │ │ │ └── index.ts # Module exports │ │ ├── ai-moderation/ # Modular MVC: AI analysis & moderation │ │ │ ├── aiAnalyzer.ts # Controller: Analysis orchestration │ │ │ ├── llmModerationClient.ts # Service: LLM API client │ │ │ ├── aiAnalysisWorker.ts # Service: Worker pool management │ │ │ ├── indonesianTextNormalizer.ts # Service: Text normalization │ │ │ ├── moderationPrompt.ts # Service: Prompt generation │ │ │ └── index.ts # Module exports │ │ ├── voice-recording/ # Modular MVC: Voice recording & streaming │ │ │ ├── voiceController.ts # Controller: Voice connection management │ │ │ ├── recorder.ts # Service: Recording orchestration │ │ │ ├── recorder/ │ │ │ │ ├── audioStream.ts # Service: Audio stream subscription │ │ │ │ ├── decoder.ts # Service: Opus decoding │ │ │ │ ├── segment.ts # Service: OGG segment rotation │ │ │ │ ├── metadata.ts # Service: Segment metadata │ │ │ │ ├── sessionRecording.ts # Service: Session management │ │ │ │ └── uploader.ts # Service: Segment upload │ │ │ └── index.ts # Module exports │ │ ├── attachment-upload/ # Modular MVC: Attachment handling │ │ │ ├── attachmentUploader.ts # Service: Upload orchestration │ │ │ ├── imageResizer.ts # Service: Image resizing │ │ │ └── index.ts # Module exports │ │ └── event-broadcaster/ # Event-driven: Redis pub/sub │ │ ├── eventBroadcaster.ts # Service: Event publishing │ │ ├── eventTypes.ts # Domain: Event type definitions │ │ └── index.ts # Module exports │ ├── mock-crc.ts # CRC polyfill for discord.js │ └── index.ts # Service entry point ├── package.json # Service dependencies └── tsconfig.json # TypeScript configuration

Architecture Patterns

Modular MVC Structure

Each module follows Controller-Service-Repository pattern:

  • Controller: Discord event listeners (messageCapture, aiAnalyzer, voiceController)
  • Service: Business logic (messageStore, llmModerationClient, recorder)
  • Repository: Data access (messageStore, voiceRecordingRepo)

Event-Driven Design

  • Redis Pub/Sub: All events published to Redis channels
  • Event Channels:
    • discord:message:created — New message captured
    • discord:message:updated — Message edited
    • discord:message:deleted — Message deleted
    • discord:message:analyzed — AI analysis complete
    • discord:attachment:created — Attachment detected
    • discord:attachment:uploaded — Attachment uploaded to storage
    • discord:voice:started — Voice recording started
    • discord:voice:stopped — Voice recording stopped
    • discord:voice:uploaded — Voice segment uploaded
    • discord:analysis:queue_status — Analysis queue status update

Shared Infrastructure

  • Config: Zod-validated environment variables
  • Logger: Winston logger with context support
  • Database: Drizzle ORM with PostgreSQL
  • Errors: Custom error classes with codes and status codes
  • Utils: Retry logic with exponential backoff

No HTTP Server

  • Discord Gateway service is event-driven only
  • No Express, WebSocket, or HTTP routes
  • All communication via Redis pub/sub
  • Backend service consumes events and serves HTTP API

Initialization Flow

  1. Load environment config (Zod validation)
  2. Initialize database connection
  3. Run pending migrations
  4. Create Discord client with optimized cache settings
  5. Initialize Redis event broadcaster
  6. Register Discord event listeners (messageCapture, aiAnalyzer)
  7. Login to Discord
  8. Listen for graceful shutdown signals (SIGINT, SIGTERM)

Graceful Shutdown

On shutdown signal:

  1. Close database connection
  2. Disconnect from voice channels
  3. Close Redis connection
  4. Destroy Discord client
  5. Exit process

Dependencies

Core Discord:

  • discord.js-selfbot-v13
  • @discordjs/voice
  • @discordjs/opus

Audio Processing:

  • prism-media (Opus encoding/decoding)
  • opusscript (Opus fallback)
  • sharp (Image resizing)

Data & Config:

  • drizzle-orm (ORM)
  • pg (PostgreSQL driver)
  • zod (Config validation)
  • ioredis (Redis client)

Logging & Utilities:

  • winston (Structured logging)
  • p-retry (Retry logic)
  • p-limit (Concurrency limiting)
  • piscina (Worker pool)

Event Flow Example

Message Capture Flow

  1. Discord emits messageCreate event
  2. messageCapture.ts listener receives event
  3. Extract metadata (user, channel, content, timestamp)
  4. messageStore.ts inserts into database
  5. eventBroadcaster.messageCreated() publishes to Redis
  6. Backend service subscribes to discord:message:created channel
  7. Backend processes and stores in its own database

Voice Recording Flow

  1. voiceController.connect() joins voice channel
  2. recorder.ts subscribes to user audio streams
  3. For each speaking user:
    • Create audio stream subscription
    • Decode Opus packets to PCM
    • Rotate OGG segments (5s default)
    • Collect user metadata
  4. On silence (3s):
    • Finalize segment
    • Create metadata JSON
    • Upload segment to storage
    • Publish discord:voice:uploaded event
  5. Backend service receives event and indexes recording

No Breaking Changes

  • Original src/ remains untouched for now
  • 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