- Backend: mascot-chat module → chatbot, routes /mascot/chat → /chat - Shared schema: pgMascotChatMessagesTable → pgChatbotMessagesTable - Frontend: MascotProvider/useMascot → ChatbotProvider/useChatbot - Gateway schema: update exports to match shared schema - Docs: update all .md references (CLAUDE.md, README, specs, plans) - All API routes, controller names, service classes, types renamed Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
29 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Bete (Discord Moderation Watcher) — A comprehensive microservice-based Discord monitoring and moderation bot. Captures text messages, images, voice audio, and screenshares from Discord servers. Features AI-powered content moderation with auto-delete, voice recording with real-time streaming, music playback, and a React dashboard.
Built with pnpm workspace monorepo with 3 services and 1 shared library:
| Package | Path | Description |
|---|---|---|
discord-moderation-backend |
services/backend |
Express HTTP/WS server, REST API, Redis bridge |
@bete/discord-gateway |
services/discord-gateway |
Discord client, voice recording, message capture, AI moderation |
frontend |
services/frontend |
Next.js 16 (React 19) static dashboard, Tailwind v4, shadcn/ui |
@bete/shared |
packages/shared |
Shared types, errors, logger, utilities |
Database: PostgreSQL (Drizzle ORM) — NOT SQLite.
Inter-service communication: Redis pub/sub.
Architecture
High-Level Flow
Discord
|
v
discord-gateway ---- Redis ---- backend ---- WebSocket ---- frontend
| pub/sub (broadcast) (Next.js static)
| |
| |
<------------------+
(command channel)
-
discord-gateway connects to Discord via
discord.js-selfbot-v13, captures events (messages, voice, attachments), stores in PostgreSQL, and publishes events to Redis channels (e.g.,discord:message:created,discord:voice:pcm). -
backend subscribes to Redis channels, broadcasts events to WebSocket clients, and serves REST API endpoints.
-
frontend connects via WebSocket and HTTP to the backend, provides a dashboard for live monitoring (text, voice, media) and AI moderation oversight.
-
Command flow (reverse): Frontend -> Backend HTTP/WS -> Redis (
backend:command) -> discord-gateway (command handler) - for actions like connect voice, play media, moderate message.
Data Flow
Message Capture:
Discord -> messageCapture.ts -> messageStore.ts (PostgreSQL)
|
+> eventBroadcaster -> Redis -> backend -> WS clients
Voice Recording:
Discord -> voiceController.ts -> recorder.ts -> OGG files on disk
| |
+> eventBroadcaster +> decoder.ts -> PCM -> Redis -> WS clients
AI Moderation:
messageStore -> aiAnalyzer.ts -> LLM API -> moderation result
| |
+> eventBroadcaster +> update message in DB
Service Breakdown
backend (services/backend)
Express 5 + Helmet HTTP server with WebSocket (ws) on port 3001 (default).
REST API endpoints (all public):
GET /api/health— Health check with optional?verbose=trueGET /api/config— App configurationGET /api/messages— List messages (cursor pagination)GET /api/messages/:channelId— Messages by channelGET /api/messages/:channelId/attachments— Attachments by channelGET /api/messages/detail/:id— Single messagePOST /api/messages/reanalyze-batch— Bulk retry AI analysisPOST /api/messages/:id/reanalyze— Retry single messagePOST /api/messages/:id/moderate— Dispatch moderation actionGET /api/review— Flagged/warned messagesGET /api/analysis/search— Full-text search with?q=POST /api/chat— AI chatbot chatGET /api/chat/history— Chat historyPOST /api/chat/clear— Clear chat historyPOST /api/voice/command— Send voice transmit commandsGET /api/status— Voice connection statusPOST /api/connect— Connect to voice channelPOST /api/disconnect— Disconnect from voiceGET /api/guilds— List guildsGET /api/guilds/:guildId/channels— Text channelsGET /api/guilds/:guildId/voice-channels— Voice channelsGET /api/media/status— Media player statusPOST /api/media/queue— Queue media (music/screen)POST /api/media/skip— Skip current trackPOST /api/media/stop— Stop playbackPOST /api/media/volume— Set volumeGET /api/recordings— Voice recordings listGET /api/ui-state— Get persistent UI statePOST /api/ui-state— Save UI state
Modules (feature-based, under src/modules/):
health/— Database connectivity checkmessages/— Message + attachment CRUD, review, reanalyzevoice/— Voice connection, guilds, channelsmedia/— Music/screenshare player controlanalysis/— Full-text search across analyzed messageschatbot/— AI chatbot with server contextrecordings/— Voice recording listingui-state/— Persistent UI state for dashboardconfig/— App config endpoint
WebSocket events (outbound to frontend):
message_created,message_updated,message_deleted,message_analyzedattachment_created,attachment_uploadedvoice_recording_started,voice_recording_stopped,voice_recording_uploadedvoice_active_user,voice_pcm_dataanalysis_queue_statususer_state,ui_state,media_stateheartbeat(every 30s)
WebSocket inbound (from frontend):
- JSON
{ type: "voice_transmit", buffer: "<base64 PCM>" }— forwarded to Redis - JSON
{ type: "voice_command", command: "..." }— forwarded to discord-gateway
discord-gateway (services/discord-gateway)
The core service that connects to Discord using discord.js-selfbot-v13.
Modules:
-
message-capture/— Listens tomessageCreate,messageUpdate,messageDeleteevents. Stores messages in PostgreSQL. Handles edits, deletes, and backlog sync.messageCapture.ts— Event listenersmessageStore.ts— Database operations (upsert, update, delete)messageMetadata.ts— User/channel metadata extractionbroadcaster.ts— Internal event dispatchpagination.ts— Backlog sync for historical messagesanalyticsStore.ts— Per-channel analytics tracking
-
voice-recording/— Voice channel connection, recording, and real-time PCM streaming.voiceController.ts— Connection lifecycle (connect/disconnect per guild+channel)recorder.ts— Manages speaking users, subscribes to audio streamsrecorder/audioStream.ts— Opus packet subscription per userrecorder/decoder.ts— Opus to PCM decoding with rotation/cooldownrecorder/segment.ts— OGG file segment rotation (default 5s)recorder/metadata.ts— User metadata JSON for each segmentrecorder/sessionRecording.ts— Session-scoped recording managementrecorder/uploader.ts— Upload completed segmentsplayer.ts— Discord player (music/screenshare playback)transmitter.ts— Browser-to-Discord audio transmission (Redis -> Opus -> Discord)muxer.ts— Audio muxing logicpacketFilter.ts— Opus packet filteringffmpegProcess.ts— FFmpeg-based processingmediaTypes.ts— Audio/video format definitionsteleUpload.ts— Upload to tele/picser
-
attachment-upload/— Downloads Discord attachments, uploads to external service.attachmentUploader.ts— Download + upload with retryimageResizer.ts— Resize images before uploadteleUpload.ts— Upload to tele/picser API
-
ai-moderation/— AI-powered content moderation pipeline.aiAnalyzer.ts— Analysis worker (batch + individual fallback)aiAnalysisWorker.ts— Piscina worker thread for batch processingllmClient.ts— Generic LLM API clientllmModerationClient.ts— Moderation-specific LLM clientmoderationPrompt.ts— System prompt builder with few-shotautoDeleteManager.ts— Auto-delete flagged messagesconversationContext.ts— Conversation window builderconcurrencyLimiter.ts— Rate limiter for LLM callschannelCultureStore.ts— Channel norms/slang contextcultureLearner.ts— Learn channel culture over timeuserReputationStore.ts— User trust scorestextCacheStore.ts— Deduplicate repeated text analysisstickerCache.ts— Upload and cache sticker imagesstickerPrompt.ts— Sticker analysis prompturlFetcher.ts— Fetch URL content for analysisresponseLogger.ts— Log moderation responses
-
event-broadcaster/— Redis pub/sub publisher for all events.eventBroadcaster.ts—EventBroadcasterclass with typed methodseventTypes.ts— Channel constants and event interfaces
-
command-handler/— Listens onbackend:commandRedis channel for backend requests.commandHandler.ts— Handles voice connect/disconnect, guilds, channels, media, transmit
Infrastructure:
src/shared/config/config.ts— Zod-validated env config (DISCORD_TOKEN, REDIS_URL, AI_LLM_*, etc.)src/shared/database/schema.ts— Full PostgreSQL schema definitionsrc/shared/database/drizzle.ts— Drizzle + pg pool initializationsrc/shared/database/migrate.ts— Migration runner with advisory lockingsrc/shared/database/voiceRecordingRepo.ts— Voice recording queriessrc/shared/discord/clientOptions.ts— Discord client configuration
frontend (services/frontend)
Next.js 16 (React 19) static export dashboard, built with TypeScript + Tailwind v4 + shadcn/ui + base-ui.
Tech stack:
- Next.js 16 (App Router, static export)
- React 19 with React Compiler
- TypeScript strict
- Tailwind v4 + shadcn/ui + base-ui components
- lucide-react icons
Feature structure:
src/app/— App Router pages (login, dashboard with tabs)src/features/— Feature components (dashboard, messages, live, chatbot)src/lib/— Shared utilities (types, API client, WebSocket, hooks)src/components/— Shared UI components (layout, ui)
shared (packages/shared)
Shared library used by both backend and discord-gateway.
Exports:
@bete/shared— Everything below@bete/shared/types— AppConfig, MessageRecord, AttachmentRecord, VoiceSegment, etc.@bete/shared/errors— AppError, ValidationError, NotFoundError, UnauthorizedError, DatabaseError, ConfigError, DiscordError, TimeoutError, etc.@bete/shared/logger— Pino-basedcreateChildLogger(context)@bete/shared/utils— Shared utilities
Database Schema (PostgreSQL)
All tables defined in services/discord-gateway/src/shared/database/schema.ts.
messages
Stores text messages with AI moderation results.
id(text PK),guild_id,channel_id,thread_iduser_id,username,avatar_urlcontent,edited_content,type(text|edited|deleted)created_at,edited_at,deleted_atai_status(pending|processing|clean|warn|flagged|error)ai_moderation_flags,ai_moderation_score,ai_analysis,ai_categoriesai_severity(none|low|medium|high|critical),ai_confidenceai_recommended_action(none|monitor|warn|review|delete|escalate)ai_analyzed_at,ai_error,metadata- Indexes: channel, user, created_at, thread, channel+created, thread+created, ai_status+created, guild+ai_status+created, guild+created+deleted, channel+ai_status+created, thread+ai_status+created
attachments
Discord attachment metadata with upload tracking.
id(text PK),message_id(FK -> messages cascade),guild_id,channel_idfilename,size,type(MIME),discord_url,uploaded_urlupload_status(pending|uploaded|failed),upload_errorcreated_at,uploaded_at- Indexes: channel, message, upload_status, channel+created, thread+created
voice_recordings
Voice segment metadata.
id(text PK),user_id,username,avatar_urlguild_id,channel_id,channel_namefilename,size_bytes,download_urlupload_status(pending|uploaded|failed),upload_errorcreated_at,uploaded_at- Indexes: user_id, channel_id, created_at
ui_state
Persistent dashboard UI state (key-value).
key(text PK),value(text),updated_at
ai_analysis_runs
Tracks AI analysis batch runs.
id(text PK),conversation_key,target_message_ids(JSON)model,request_tokens_estimate,response_rawstatus(pending|processing|completed|failed),errorcreated_at,completed_at- Indexes: conversation_key, status, created_at
user_reputations
User trust scores for AI context.
user_id(text PK),guild_id,trust_score,clean_message_streaktotal_infractions,last_infraction_at,created_at,updated_at- Indexes: guild_id, trust_score
channel_cultures
AI-generated channel norms and slang summaries.
channel_id(text PK),guild_id,culture_summary,last_analyzed_at- Index: guild_id
message_reviews
Manual review tracking for flagged messages.
id(text PK),message_id,guild_id,channel_idreviewer_id,status(pending|approved|rejected|escalated)notes,created_at,reviewed_at- Indexes: message_id, status, created_at, guild+status+created
moderation_actions
Action audit log (delete/mute/warn/kick/ban).
id(text PK),message_id,user_id,guild_idaction_type(delete_message|mute_user|warn_user|kick_user|ban_user)reason,executed_by,status(pending|executed|failed)error,created_at,executed_at- Indexes: message_id, user_id, status, guild+status+created
retention_policies
Data retention rules per guild/channel.
id(text PK),guild_id,channel_idretention_days,apply_to_media,apply_to_voice,enabledcreated_at,updated_at- Indexes: guild_id, enabled
text_analysis_cache
Caches normalized-text moderation results to avoid redundant LLM calls.
text(text PK),flags(JSON array),source(local|primary_ai|vision_llm)analyzed_at,expires_at,hit_count- Indexes: expires_at, source
sticker_cache
Uploaded sticker image URLs for vision analysis.
name(text PK),image_url,mime_type,fetched_at- Index: fetched_at
corrected_moderations
Manual corrections (false positives) for few-shot injection.
id(text PK),message_id,original_flags,corrected_flagscorrection_notes,content_snippet,created_at- Indexes: created_at, message_id
muxer_jobs
Audio post-processing job queue.
id(text PK),data(JSON),status(pending|processing|completed|failed)attempts,maxAttempts,created_at,updated_at,error- Indexes: status, created_at
Redis Communication
discord-gateway publishes (event channels):
| Channel | Event type | When |
|---|---|---|
discord:message:created |
message_created |
New message |
discord:message:updated |
message_updated |
Message edited |
discord:message:deleted |
message_deleted |
Message deleted |
discord:message:analyzed |
message_analyzed |
AI analysis complete |
discord:attachment:created |
attachment_created |
New attachment |
discord:attachment:uploaded |
attachment_uploaded |
Upload complete |
discord:voice:started |
voice_recording_started |
Recording started |
discord:voice:stopped |
voice_recording_stopped |
Recording stopped |
discord:voice:uploaded |
voice_recording_uploaded |
Upload complete |
discord:voice:active_user |
voice_active_user |
Speaker state change |
discord:voice:pcm |
voice_pcm_data |
Live PCM audio chunk |
discord:analysis:queue_status |
analysis_queue_status |
Queue stats |
backend publishes (command channel):
| Channel | Command type | Description |
|---|---|---|
backend:command |
voice:connect |
Connect to voice |
backend:command |
voice:disconnect |
Disconnect voice |
backend:command |
voice:channels |
List voice channels |
backend:command |
voice:transmit:start/stop |
Audio transmit |
backend:command |
guilds:list |
List guilds |
backend:command |
guilds:text-channels |
List text channels |
backend:command |
media:queue/skip/stop/volume |
Media control |
backend:command |
moderation:action |
Execute moderation action |
Envelope format: { id, type, payload, replyChannel }.
Status keys: voice:status, media:status (set by discord-gateway, read by backend).
Development Commands
# Install all dependencies
pnpm install
# Run each service in development mode (separate terminal each)
pnpm run dev:backend # Backend on port 3001
pnpm run dev:discord-gateway # Discord client + all features
pnpm run dev:web # Frontend via next dev (port 3000)
# Build
pnpm run build:backend
pnpm run build:discord-gateway
pnpm run build:web # next build (static export)
# Type checking
pnpm run typecheck # Node services (pnpm -r)
pnpm run typecheck:web # Frontend typecheck (next build)
# Lint (Biome)
pnpm run lint
# Format (Biome)
pnpm run format
# Run tests across all packages
pnpm run test
# Database migrations (Drizzle)
pnpm run db:generate # Generate new migration
pnpm run db:migrate # Apply pending migrations
pnpm run db:studio # Open Drizzle Studio
# Install yt-dlp for media download
pnpm run install:yt-dlp
# Deploy to VPS (build + hot-patch running containers)
./deploy.sh # Build + deploy all services
./deploy.sh --frontend # Frontend (Next.js) only
./deploy.sh --backend # Backend TypeScript only
./deploy.sh --no-build # Skip build, just copy files
Configuration
Configuration via .env (see .env.example). Managed by Zod schemas:
- discord-gateway:
services/discord-gateway/src/shared/config/config.ts - backend:
services/backend/src/shared/config/index.ts
Core (both services)
DISCORD_TOKEN— Discord user token (required)MONITOR_GUILD_ID— Target guild for text monitoringNODE_ENV— development|production|testLOG_LEVEL— Pino log level (default: info)VERBOSE— Enable debug logging (default: false)
Database (PostgreSQL)
DATABASE_URL— Connection string (overrides individual params)POSTGRES_HOST,POSTGRES_PORT(5432),POSTGRES_USER,POSTGRES_PASSWORD,POSTGRES_DBPOSTGRES_POOL_MIN(2),POSTGRES_POOL_MAX(10)AUTO_MIGRATE_ON_STARTUP(default: true)
Redis
REDIS_URL— Connection string (default: redis://localhost:6379)
Voice Recording (discord-gateway)
RECORDINGS_DIR— Audio file output (default: ./recordings)RECORDING_SEGMENT_MS— OGG segment duration (default: 5000)DECODER_ROTATE_MS— Opus decoder rotation (default: 5000)DECODER_COOLDOWN_MS— Decoder error cooldown (default: 30000)AUDIO_STREAM_SILENCE_DURATION_MS— Silence threshold (default: 3000)VOICE_CONNECTION_TIMEOUT_MS— Connection timeout (default: 15000)RECONNECT_TIMEOUT_MS— Reconnect timeout (default: 5000)PACKET_FILTER_MIN_SIZE— Minimum Opus packet size (default: 8)OPUS_FRAME_SIZE(960),AUDIO_SAMPLE_RATE(48000),AUDIO_CHANNELS(2)VOICE_GUILD_ID,VOICE_CHANNEL_ID
Attachments
TELE_UPLOAD_URL— Upload endpoint (default: https://upload.asepharyana.my.id/api/upload)ATTACHMENT_UPLOAD_TIMEOUT_MS(30000),ATTACHMENT_MAX_SIZE_MB(100),ATTACHMENT_RETRY_ATTEMPTS(3)
AI Moderation (discord-gateway)
AI_ANALYSIS_ENABLED— Enable AI analysis (default: false)AI_LLM_API_KEY— LLM API key (required if enabled)AI_LLM_BASE_URL— LLM endpoint (default: https://9router.asepharyana.my.id/v1)AI_LLM_MODEL— Text model (default: text)AI_LLM_VISION_MODEL— Vision model (optional fallback)AI_LLM_MAX_CONCURRENT(5),AI_LLM_TEXT_BATCH_SIZE(20)AI_LLM_MEDIA_ANALYSIS_TIMEOUT_MS(60000),AI_LLM_IMAGE_MAX_DIMENSION(1024)AI_ANALYSIS_DEBOUNCE_MS(500),AI_ANALYSIS_MAX_BATCH_SIZE(200)AI_ANALYSIS_PROCESSING_TIMEOUT_MS(120000)PISCINA_MAX_THREADS— Worker pool size (optional)
Auto-Delete
AUTO_DELETE_FLAGGED_ENABLED(true),AUTO_DELETE_FLAGGED_DRY_RUN(true)AUTO_DELETE_FLAGGED_DELAY_MS(0),AUTO_DELETE_MIN_CONFIDENCE(0.5)AUTO_DELETE_ALLOWED_SEVERITIES,AUTO_DELETE_ALLOWED_CATEGORIESAUTO_DELETE_EXCLUDED_CHANNEL_IDS,AUTO_DELETE_EXCLUDED_USER_IDSAUTO_DELETE_NOTIFY_USER,AUTO_DELETE_LOG_CHANNEL_ID
OpenAI Moderation (optional separate endpoint)
OPENAI_MODERATION_API_KEY,OPENAI_MODERATION_BASE_URL,OPENAI_MODERATION_MODEL
Backend
WEBSERVER_PORT(3001)BACKLOG_SYNC_HOURS(24),BACKLOG_SYNC_BATCH_SIZE(100)
Retention
RETENTION_MESSAGES_DAYS(0=off),RETENTION_ATTACHMENTS_DAYS,RETENTION_VOICE_DAYSRETENTION_CLEANUP_INTERVAL_MS(86400000),RETENTION_DRY_RUN(true)
Testing
Tests use Vitest. Currently minimal test coverage. Test directories should be created per service:
services/backend/tests/
services/discord-gateway/tests/
services/frontend/tests/
Run tests: pnpm run test (runs vitest run in each package).
Code Style
- Formatter: Biome (2-space indent)
- Linter: Biome with strict rules
- Language: TypeScript with strict mode
- Logging: Use
createChildLogger(context)from@bete/shared/logger - Errors: Throw custom
AppErrorsubclasses withcode+statusCode - Database: Use Drizzle ORM or raw parameterized queries (never string interpolation)
- Imports: Use
.jsextensions in source files (ESM convention)
Key Patterns
Event-Driven Architecture
All inter-service communication happens through Redis pub/sub. The discord-gateway publishes events on typed channels, the backend subscribes and broadcasts to WebSocket clients. The backend publishes commands on backend:command with reply channels for request-response patterns.
Message Capture Lifecycle
- Discord event fires (
messageCreate,messageUpdate,messageDelete) - Check guild matches MONITOR_GUILD_ID
- Extract message metadata (user, channel, content, timestamp)
- Upsert into
messagestable in PostgreSQL - Publish event to Redis (
discord:message:*) - If attachments exist, insert into
attachmentstable withstatus='pending' - Start async upload to tele/picser (non-blocking)
- On success: update
uploaded_url,status='uploaded' - On failure: store error,
status='failed'
AI Moderation Pipeline
- Messages with
ai_status='pending'are picked up byaiAnalyzer.ts - Batches messages by conversation (thread/channel proximity)
- Builds context window (recent messages + channel culture + user reputation)
- Calls LLM via
llmModerationClient.tswith moderation prompt - Updates message with
ai_status,ai_moderation_flags,ai_severity,ai_confidence,ai_recommended_action - If
AUTO_DELETE_FLAGGED_ENABLEDand confidence meets threshold, triggers auto-delete - Falls back to individual analysis for messages that could not be batched
- Caches normalized text results in
text_analysis_cacheto avoid repeat calls
Voice Recording Lifecycle
VoiceController.connect(guildId, channelId)via Redis command- Joins Discord voice channel, sets up audio receiver
- On user start speaking: create per-user stream, OGG segment manager, Opus decoder
- Opus packets -> OGG segments on disk + PCM decode for WebSocket broadcast
- PCM data published to Redis (
discord:voice:pcm) -> backend -> WS clients - On silence (3s timeout): close stream, finalize segment
- After segment complete: upload to external storage, update database
VoiceController.disconnect()stops all recording
WebSocket Protocol (frontend)
Outbound (backend -> frontend):
- Binary: PCM audio (24kHz mono s16le), prefixed with 4-byte user hash
- JSON events: all typed in
WSEventMap—message_*,voice_*,attachment_*,user_state,ui_state,media_state
Inbound (frontend -> backend):
- JSON
{ type: "voice_transmit", buffer: "<base64 PCM>" }for mic-to-Discord - JSON
{ type: "voice_command", command: "..." }for voice control
Graceful Shutdown
discord-gateway handles SIGINT/SIGTERM/uncaughtException/unhandledRejection:
- Close database pool
- Disconnect voice controller
- Close event broadcaster (Redis)
- Close command handler (Redis)
- Destroy Discord client
- Exit process
Public API
All backend endpoints are publicly accessible — no authentication required.
Recording Structure
recordings/
+-- <user-id>/
| +-- <user-id>-<session-start>-0.ogg
| +-- <user-id>-<session-start>-0.json
| +-- <user-id>-<session-start>-1.ogg
| +-- ...
Each segment is 5s (configurable via RECORDING_SEGMENT_MS). Metadata JSON includes user info, roles, timestamps, duration.
Vendor Packages
discord.js-selfbot-v13 (vendor/discord.js-selfbot-v13)
Fork of discord.js-selfbot-v13 (git submodule). Provides Discord API access via user account.
discord-video-stream (vendor/discord-video-stream)
Go Live / video streaming support library. Includes:
- H264 encoding (NVENC, VAAPI, software)
- WebRTC wrapper for Discord voice/video connections
- Stream connection management
Dependencies
Shared (@bete/shared):
- pino — Structured logging
- zod — Schema validation
Backend:
- express 5 — HTTP server
- ws — WebSocket server
- helmet — Security headers
- @discordjs/voice — Voice state querying (minimal)
- drizzle-orm + pg — PostgreSQL ORM
- ioredis — Redis client
- pino, pino-http — Logging
- prom-client — Prometheus metrics
- axios — HTTP client
- zod — Config validation
discord-gateway:
- discord.js-selfbot-v13 — Discord client (user account)
- @discordjs/voice — Voice connection
- @discordjs/opus — Native Opus codec
- prism-media — Audio encode/decode
- @snazzah/davey — DA-VEY (Discord Audio Video End-to-end encryption)
- ioredis — Redis client
- drizzle-orm + pg — PostgreSQL ORM
- sharp — Image processing
- openai — OpenAI API client
- piscina — Worker threads for AI analysis
- tiktoken — Token counting
- p-retry, p-limit — Async utilities
- lru-cache — In-memory caching
- libsodium-wrappers — Encryption
- node-crc — CRC checksums
- imghash — Image hashing
- ws — WebSocket (internal)
- zod — Config validation
Frontend:
- react 19, react-dom 19
- @tanstack/react-query — Data fetching
- three, @react-three/fiber, @react-three/drei — 3D
- gsap, framer-motion — Animations
- @radix-ui/* — Accessible UI primitives
- tailwindcss 4, @tailwindcss/postcss — Styling
- lucide-react — Icons
- clsx, tailwind-merge — Class management
- vite 8 — Bundler
Notes
- Bot uses selfbot variant (user account) — check Discord ToS
- Opus decoding requires native
@discordjs/opusoropusscriptunder Node.js - OGG segments include metadata JSON for each segment (user info, timestamps, duration)
- WebSocket broadcasts PCM in real-time; browser can transmit audio back to Discord
- Graceful shutdown ensures clean disconnection and resource cleanup
- All database operations use parameterized queries to prevent SQL injection
- Attachment uploads are non-blocking (async) to avoid blocking message capture
- Message capture continues even if AI analysis or attachment upload fails
Common Tasks
Add a new config variable
- Add to config schema in both
services/backend/src/shared/config/index.tsandservices/discord-gateway/src/shared/config/config.tswith Zod validation - Add to
.env.examplewith description - Use via
config.VARIABLE_NAME
Add a new REST endpoint
- Create route handler in
services/backend/src/modules/<module>/<name>.routes.ts - Register in
services/backend/src/http/app.ts - Use
asyncHandlerwrapper for error handling - Return JSON response
Add a new WebSocket event
- Add to
eventTypes.tsin discord-gateway - Add publish method to
EventBroadcasterin discord-gateway - Add subscription + broadcast mapping in
services/backend/src/ws/redis-bridge.ts - Add event type to
WSEventMapin frontendevents.ts - Add handler to
WsHandlersin frontendsocket.ts
Add a new database table
- Add table definition in
services/discord-gateway/src/shared/database/schema.ts - Generate migration:
pnpm run db:generate - Check migration file in
drizzle/migrations/ - Apply:
pnpm run db:migrate
Add a new Redis command
- Add handler case in
commandHandler.tsswitch statement - Add publish call on backend side (see
voice.service.tsormedia.service.ts) - Update frontend API client if needed
Debug AI moderation
- Set
AI_ANALYSIS_ENABLED=trueandVERBOSE=true - Check
ai_status,ai_errorfields in messages table - Monitor
/api/analysis/search?q=<text>for analysis results - Check
ai_analysis_runstable for batch run status - Adjust
AI_ANALYSIS_*tuning variables
Debug voice recording
- Set
VERBOSE=true - Check
/api/statusfor active connection - Monitor segment files in
recordings/<user-id>/ - Check
voice_recordingstable for upload status
CodeGraph Usage (Required)
- Use CodeGraph first for repo-level questions: architecture, dependencies, references, callers/callees, impact, flow, routes, components.
- If graph is missing or stale, run scan first to refresh
.codegraph/graph.json. - Prefer graph-backed flow:
- scan-codegraph (build/refresh graph)
- query-codegraph (find definitions/references/callers/dependencies)
- analyze-codegraph (architecture, impact, risk, cycles, orphans, hotspots)
- export-codegraph (json/mermaid/dot/markdown/html when needed)
- open-codegraph-ui (interactive visualization when requested)
- Avoid broad grep/find or repeated wide file reads before graph lookup, except for exact literal search or known single-file edits.