docs: remove voice/recording/media references from AGENTS/ARCHITECTURE/README

This commit is contained in:
asepharyana committed 2026-09-23 21:25:03 +07:00
1 parent 2c69c51fba
commit a13884d80f
9 files changed
+39 -142

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# GMW — Agent Guide # GMW — Agent Guide
GMW (Guild Moderation Watcher) is a Discord bot + web dashboard for AI-powered moderation. A monorepo with three services: a selfbot gateway that captures messages/voice and runs LLM moderation, an Express/oRPC backend that serves the dashboard API, and a Next.js 16 SSR frontend. They communicate via Redis pub/sub (gateway→backend) and WebSocket (backend→browser). GMW (Guild Moderation Watcher) is a Discord bot + web dashboard for AI-powered moderation. A monorepo with three services: a selfbot gateway that captures Discord events and runs LLM moderation, an Express/oRPC backend that serves the dashboard API, and a Next.js 16 SSR frontend. They communicate via Redis pub/sub (gateway→backend) and WebSocket (backend→browser).
## Quick reference ## Quick reference
-3
View File
@@ -59,8 +59,6 @@ src/
| messages | Store & query Discord messages | `messages`, `ai_moderations`, `ai_moderation_flags` | | messages | Store & query Discord messages | `messages`, `ai_moderations`, `ai_moderation_flags` |
| moderation | Moderation actions & metrics | `ai_moderations`, `moderation_actions` | | moderation | Moderation actions & metrics | `ai_moderations`, `moderation_actions` |
| media | Media file management | `media_attachments` | | media | Media file management | `media_attachments` |
| voice | Live speakers + recordings | `voice_recordings` |
| recordings | Recordings API | `voice_recordings` |
| dashboard | Stats aggregation | Various (read-only) | | dashboard | Stats aggregation | Various (read-only) |
| knowledge | Semantic search | Qdrant vector DB | | knowledge | Semantic search | Qdrant vector DB |
| chatbot | AI chatbot with tools | `chatbot_history` | | chatbot | AI chatbot with tools | `chatbot_history` |
@@ -91,7 +89,6 @@ The frontend fetches via `src/lib/api/server.ts` (SSR, server-side) and
``` ```
discord:message:{created,updated,deleted,analyzed} discord:message:{created,updated,deleted,analyzed}
discord:attachment:{created,uploaded} discord:attachment:{created,uploaded}
discord:voice:{started,stopped,uploaded,active_user,pcm,analyzed}
discord:analysis:queue_status discord:analysis:queue_status
discord:reaction:{added,removed} discord:reaction:{added,removed}
discord:thread:{created,deleted,updated} discord:thread:{created,deleted,updated}
-12
View File
@@ -35,16 +35,6 @@ services/backend/
│ │ │ └── routes/ │ │ │ └── routes/
│ │ │ └── index.ts │ │ │ └── index.ts
│ │ │ │ │ │
│ │ ├── media/
│ │ │ ├── media.service.ts
│ │ │ └── routes/
│ │ │ └── index.ts
│ │ │
│ │ ├── voice/
│ │ │ ├── voice.service.ts
│ │ │ └── routes/
│ │ │ └── index.ts
│ │ │
│ │ └── health/ │ │ └── health/
│ │ ├── health.schema.ts │ │ ├── health.schema.ts
│ │ ├── health.repository.ts │ │ ├── health.repository.ts
@@ -148,8 +138,6 @@ export const messageQuerySchema = z.object({
|--------|---------|--------| |--------|---------|--------|
| **messages** | Text message storage & retrieval | GET /api/messages, GET /api/messages/:channelId | | **messages** | Text message storage & retrieval | GET /api/messages, GET /api/messages/:channelId |
| **analytics** | Moderation statistics & trends | GET /api/analytics/overview, /daily-trend, /hourly-stats | | **analytics** | Moderation statistics & trends | GET /api/analytics/overview, /daily-trend, /hourly-stats |
| **media** | Media file management | GET /api/media/list, POST /api/media/upload |
| **voice** | Voice recording management | GET /api/voice/recordings, POST /api/voice/connect |
| **health** | Service health checks | GET /api/health | | **health** | Service health checks | GET /api/health |
## Data Flow ## Data Flow
+1 -25
View File
@@ -36,9 +36,6 @@ src/
├── modules/ ├── modules/
│ ├── ai-moderation/ # LLM moderation pipeline (largest module) │ ├── ai-moderation/ # LLM moderation pipeline (largest module)
│ ├── message-capture/ # Discord event listeners + DB store │ ├── message-capture/ # Discord event listeners + DB store
│ ├── voice-recording/ # Voice connect + Opus→OGG recording
│ │ └── recorder/ # decoder, segment, session, uploader, oggCrc
│ ├── voice-pcm-ws/ # Real-time PCM → backend WebSocket
│ ├── attachment-upload/ # Download + sharp resize + upload │ ├── attachment-upload/ # Download + sharp resize + upload
│ ├── event-broadcaster/ # Redis pub/sub publisher │ ├── event-broadcaster/ # Redis pub/sub publisher
│ ├── command-handler/ # Backend→gateway Redis commands │ ├── command-handler/ # Backend→gateway Redis commands
@@ -76,24 +73,6 @@ textBatchProcessor.ts mediaBatchProcessor.ts llmClient.ts
- Piscina: text pool (4 threads) + media pool (2 threads) - Piscina: text pool (4 threads) + media pool (2 threads)
- **Each worker thread has its own pg Pool** (min 0, grows to `POSTGRES_POOL_MAX`) - **Each worker thread has its own pg Pool** (min 0, grows to `POSTGRES_POOL_MAX`)
## Voice recording pipeline
```
receiver.speaking "start" → speakingHandler(userId)
→ collectUserMetadata → receiver.subscribe → PacketFilter → oggPacketStream
→ SegmentManager.open → OggLogicalBitstream → .ogg file
→ data: rotateIfNeeded + decoder.write
→ end: finalizeSegment → upload + transcribe
```
Key files:
- `voiceController.ts` — connect/disconnect/list
- `recorder.ts` — orchestration
- `recorder/segment.ts` — segment rotation
- `recorder/sessionRecording.ts` — session management
- `recorder/uploader.ts` — upload to storage
- `voiceTranscriber.ts` — Whisper transcription (if enabled)
## Module: message-capture ## Module: message-capture
- `messageCapture.ts` — Discord event listeners (messageCreate/Update/Delete) - `messageCapture.ts` — Discord event listeners (messageCreate/Update/Delete)
@@ -107,7 +86,7 @@ Key files:
See `src/shared/redis-channels.ts` for canonical names. Examples: See `src/shared/redis-channels.ts` for canonical names. Examples:
``` ```
discord:message:created, discord:voice:active_user, discord:attachment:uploaded discord:message:created, discord:moderation:action, discord:attachment:uploaded
``` ```
## Config (env vars) ## Config (env vars)
@@ -120,7 +99,6 @@ All validated via Zod in `shared/config/index.ts`. Critical:
- `REDIS_URL` — pub/sub to backend - `REDIS_URL` — pub/sub to backend
- `AI_ANALYSIS_ENABLED` — master toggle for AI moderation - `AI_ANALYSIS_ENABLED` — master toggle for AI moderation
- `AI_LLM_BASE_URL` / `AI_LLM_API_KEY` — LLM router - `AI_LLM_BASE_URL` / `AI_LLM_API_KEY` — LLM router
- `AI_VOICE_TRANSCRIPTION_ENABLED` — toggle Whisper transcription
- `PISCINA_MAX_THREADS` / `PISCINA_MEDIA_MAX_THREADS` — worker pool sizing - `PISCINA_MAX_THREADS` / `PISCINA_MEDIA_MAX_THREADS` — worker pool sizing
## Concurrency model ## Concurrency model
@@ -143,8 +121,6 @@ All validated via Zod in `shared/config/index.ts`. Critical:
- **Piscina pool isolation**: worker threads are NOT the main thread. Cannot - **Piscina pool isolation**: worker threads are NOT the main thread. Cannot
share state via module-level variables. Use DB or Redis for cross-thread state. share state via module-level variables. Use DB or Redis for cross-thread state.
- **AfterSilence race**: `@discordjs/voice` AfterSilence can fail to emit "end"
on disconnect. Always have a watchdog/timeout.
- **Cache eviction**: LRU caches (user metadata, term glossary) evict at max size. - **Cache eviction**: LRU caches (user metadata, term glossary) evict at max size.
Don't assume cache hit after eviction. Don't assume cache hit after eviction.
- **Circuit breaker**: per-conversation CB opens after repeated failures. - **Circuit breaker**: per-conversation CB opens after repeated failures.
+5 -9
View File
@@ -1,7 +1,7 @@
# Discord Gateway — Architecture # Discord Gateway — Architecture
Pure event-driven microservice (no HTTP server). Captures Discord Pure event-driven microservice (no HTTP server). Captures Discord
messages/voice/attachments/reactions/threads/presence, runs LLM-based AI messages/attachments/reactions/threads/presence, runs LLM-based AI
moderation, and publishes everything to Redis pub/sub for the backend to moderation, and publishes everything to Redis pub/sub for the backend to
consume. The backend serves the HTTP/WS API to the frontend. consume. The backend serves the HTTP/WS API to the frontend.
@@ -24,9 +24,9 @@ services/discord-gateway/
│ │ ├── config/ # Zod-validated env (index.ts = schema+loader) │ │ ├── config/ # Zod-validated env (index.ts = schema+loader)
│ │ ├── database/ # Drizzle ORM + pg Pool + migrations │ │ ├── database/ # Drizzle ORM + pg Pool + migrations
│ │ │ ├── init.ts drizzle.ts pool.ts migrate.ts migrateCli.ts │ │ │ ├── init.ts drizzle.ts pool.ts migrate.ts migrateCli.ts
│ │ │ └── schema/ # messages, cache, voice, analytics, meta │ │ │ └── schema/ # messages, cache, meta, analytics
│ │ ├── logger/ # pino wrapper + createChildLogger() │ │ ├── logger/ # pino wrapper + createChildLogger()
│ │ ├── errors/ # AppError / ConfigError / AudioError ... │ │ ├── errors/ # AppError / ConfigError ...
│ │ ├── utils/ # retry, pagination │ │ ├── utils/ # retry, pagination
│ │ ├── discord/clientOptions.ts # discord.js-selfbot-v13 client options │ │ ├── discord/clientOptions.ts # discord.js-selfbot-v13 client options
│ │ ├── uploader.ts # Shared attachment upload helper │ │ ├── uploader.ts # Shared attachment upload helper
@@ -35,9 +35,6 @@ services/discord-gateway/
│ └── modules/ │ └── modules/
│ ├── message-capture/ # Discord event listeners + DB store │ ├── message-capture/ # Discord event listeners + DB store
│ ├── ai-moderation/ # LLM moderation pipeline (see below) │ ├── ai-moderation/ # LLM moderation pipeline (see below)
│ ├── voice-recording/ # Voice connect + Opus→OGG recording
│ │ └── recorder/ # decoder, segment, session, uploader, oggCrc
│ ├── voice-pcm-ws/ # Real-time PCM → backend WebSocket (bypasses Redis)
│ ├── attachment-upload/ # Download + (sharp) resize + upload │ ├── attachment-upload/ # Download + (sharp) resize + upload
│ ├── event-broadcaster/ # RedisEventPublisher + EventBroadcaster │ ├── event-broadcaster/ # RedisEventPublisher + EventBroadcaster
│ ├── command-handler/ # Redis-subscribed backend→gateway commands │ ├── command-handler/ # Redis-subscribed backend→gateway commands
@@ -102,7 +99,6 @@ grows on demand up to `POSTGRES_POOL_MAX`.
`discord:message:{created,updated,deleted,analyzed}`, `discord:message:{created,updated,deleted,analyzed}`,
`discord:attachment:{created,uploaded}`, `discord:attachment:{created,uploaded}`,
`discord:voice:{started,stopped,uploaded,active_user,pcm,analyzed}`,
`discord:analysis:queue_status`, `discord:analysis:queue_status`,
`discord:reaction:{added,removed}`, `discord:reaction:{added,removed}`,
`discord:thread:{created,deleted,updated}`, `discord:thread:{created,deleted,updated}`,
@@ -124,8 +120,8 @@ See `src/shared/redis-channels.ts` for the canonical names.
`SIGINT`/`SIGTERM` (and uncaught transient stream errors: EPIPE / ECONNRESET / `SIGINT`/`SIGTERM` (and uncaught transient stream errors: EPIPE / ECONNRESET /
ERR_STREAM_DESTROYED / ERR_STREAM_WRITE_AFTER_END are treated as non-fatal): ERR_STREAM_DESTROYED / ERR_STREAM_WRITE_AFTER_END are treated as non-fatal):
stop metrics → stop muxer → disconnect voice → close PCM WS → close Redis → stop metrics → close event broadcaster (Redis) → close command handler →
close command handler → close DB → destroy client → exit. close DB → destroy client → exit.
## Observability ## Observability
+1 -8
View File
@@ -18,8 +18,6 @@ services/discord-gateway/
│ └── modules/ │ └── modules/
│ ├── message-capture/ # Discord listeners + DB store + metadata │ ├── message-capture/ # Discord listeners + DB store + metadata
│ ├── ai-moderation/ # LLM moderation pipeline (largest module) │ ├── ai-moderation/ # LLM moderation pipeline (largest module)
│ ├── voice-recording/ # Voice connect + Opus→OGG recording (+ recorder/)
│ ├── voice-pcm-ws/ # Real-time PCM → backend WebSocket
│ ├── attachment-upload/ # Download + sharp resize + upload │ ├── attachment-upload/ # Download + sharp resize + upload
│ ├── event-broadcaster/ # RedisEventPublisher + EventBroadcaster │ ├── event-broadcaster/ # RedisEventPublisher + EventBroadcaster
│ ├── command-handler/ # Backend→gateway Redis commands │ ├── command-handler/ # Backend→gateway Redis commands
@@ -51,11 +49,6 @@ semantic Qdrant → LLM), `textBatchProcessor.ts` / `mediaBatchProcessor.ts`
`embeddingClient.ts` + `qdrantClient.ts` (semantic cache), plus `embeddingClient.ts` + `qdrantClient.ts` (semantic cache), plus
`channelCultureStore.ts` / `userProfileStore.ts`. `channelCultureStore.ts` / `userProfileStore.ts`.
### voice-recording
`voiceController.ts` (connect/disconnect/list) + `recorder.ts` (orchestration)
+ `recorder/` (decoder, segment, session, uploader, oggCrc). Publishes
`discord:voice:*` events. Real-time audio also streamed via `voice-pcm-ws`.
### attachment-upload ### attachment-upload
`attachmentUploader.ts` (download → upload to storage) + `imageResizer.ts` `attachmentUploader.ts` (download → upload to storage) + `imageResizer.ts`
(sharp resize). Emits `discord:attachment:*`. (sharp resize). Emits `discord:attachment:*`.
@@ -72,7 +65,7 @@ per scrape; live pipeline gauges registered in `bootstrap.ts`.
- **config** — Zod schema in `shared/config/index.ts` (single source of truth). - **config** — Zod schema in `shared/config/index.ts` (single source of truth).
- **database** — Drizzle ORM over `pg`; pool `min:0` (`shared/config`). - **database** — Drizzle ORM over `pg`; pool `min:0` (`shared/config`).
- **logger** — `pino` wrapper, `createChildLogger()` for context loggers. - **logger** — `pino` wrapper, `createChildLogger()` for context loggers.
- **errors** — `AppError` hierarchy (`ConfigError`, `AudioError`, …). - **errors** — `AppError` hierarchy (`ConfigError`, …).
## Notes ## Notes
- No HTTP server (other than the metrics endpoint). Pure event-driven. - No HTTP server (other than the metrics endpoint). Pure event-driven.
+29 -73
View File
@@ -19,7 +19,6 @@ services/discord-gateway/
│ │ │ ├── schema.ts # Drizzle ORM schema │ │ │ ├── schema.ts # Drizzle ORM schema
│ │ │ ├── drizzle.ts # PostgreSQL connection │ │ │ ├── drizzle.ts # PostgreSQL connection
│ │ │ ├── migrate.ts # Migration runner │ │ │ ├── migrate.ts # Migration runner
│ │ │ └── voiceRecordingRepo.ts
│ │ ├── errors/ │ │ ├── errors/
│ │ │ └── errors.ts # Custom error classes │ │ │ └── errors.ts # Custom error classes
│ │ ├── logger/ │ │ ├── logger/
@@ -43,17 +42,6 @@ services/discord-gateway/
│ │ │ ├── indonesianTextNormalizer.ts # Service: Text normalization │ │ │ ├── indonesianTextNormalizer.ts # Service: Text normalization
│ │ │ ├── moderationPrompt.ts # Service: Prompt generation │ │ │ ├── moderationPrompt.ts # Service: Prompt generation
│ │ │ └── index.ts # Module exports │ │ │ └── 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 │ │ ├── attachment-upload/ # Controller-Service-Repository
│ │ │ ├── attachmentUploader.ts # Service: Upload orchestration │ │ │ ├── attachmentUploader.ts # Service: Upload orchestration
│ │ │ ├── imageResizer.ts # Service: Image resizing │ │ │ ├── imageResizer.ts # Service: Image resizing
@@ -85,11 +73,6 @@ Each feature module follows **Controller-Service-Repository** pattern:
- **Service** (`aiAnalysisWorker.ts`): Worker pool management - **Service** (`aiAnalysisWorker.ts`): Worker pool management
- **Service** (`indonesianTextNormalizer.ts`): Text preprocessing - **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**: **Attachment Upload Module**:
- **Service** (`attachmentUploader.ts`): Upload orchestration - **Service** (`attachmentUploader.ts`): Upload orchestration
- **Service** (`imageResizer.ts`): Image processing - **Service** (`imageResizer.ts`): Image processing
@@ -107,9 +90,6 @@ Discord Events → Discord Gateway Service → Redis Pub/Sub → Backend Service
- discord:message:analyzed - discord:message:analyzed
- discord:attachment:created - discord:attachment:created
- discord:attachment:uploaded - discord:attachment:uploaded
- discord:voice:started
- discord:voice:stopped
- discord:voice:uploaded
- discord:analysis:queue_status - discord:analysis:queue_status
``` ```
@@ -146,20 +126,6 @@ Centralized, reusable components:
5. `eventBroadcaster.messageAnalyzed()` publishes results 5. `eventBroadcaster.messageAnalyzed()` publishes results
6. Backend service receives and updates UI 6. Backend service receives and updates UI
### Voice Recording
1. `voiceController.connect()` joins voice channel
2. `recorder.ts` subscribes to user audio streams
3. For each speaking user:
- `audioStream.ts` subscribes to Opus packets
- `decoder.ts` decodes Opus to PCM
- `segment.ts` rotates OGG files (5s default)
- `metadata.ts` collects user info
4. On silence (3s):
- `sessionRecording.ts` finalizes segment
- `uploader.ts` uploads to storage
- `eventBroadcaster.voiceRecordingUploaded()` publishes
5. Backend service indexes recording
### Attachment Upload ### Attachment Upload
1. `messageCapture.ts` detects attachments 1. `messageCapture.ts` detects attachments
2. `attachmentUploader.ts` downloads from Discord 2. `attachmentUploader.ts` downloads from Discord
@@ -194,21 +160,16 @@ Centralized, reusable components:
On SIGINT/SIGTERM/uncaughtException/unhandledRejection: On SIGINT/SIGTERM/uncaughtException/unhandledRejection:
1. Close PostgreSQL connection 1. Close PostgreSQL connection
2. Disconnect from voice channels 2. Close Redis connection
3. Close Redis connection 3. Destroy Discord client
4. Destroy Discord client 4. Exit process (code 0 for clean, 1 for error)
5. Exit process (code 0 for clean, 1 for error)
## Dependencies ## Dependencies
**Core Discord**: **Core Discord**:
- `discord.js-selfbot-v13` — Discord client (selfbot variant) - `discord.js-selfbot-v13` — Discord client (selfbot variant)
- `@discordjs/voice` — Voice connection management
- `@discordjs/opus` — Native Opus codec
**Audio Processing**: **Media Processing**:
- `prism-media` — Opus encoding/decoding
- `opusscript` — Opus fallback for Node v26+
- `sharp` — Image resizing - `sharp` — Image resizing
**Data & Config**: **Data & Config**:
@@ -269,7 +230,6 @@ On SIGINT/SIGTERM/uncaughtException/unhandledRejection:
### Modules (28 files) ### Modules (28 files)
- `src/modules/message-capture/` (5 files) - `src/modules/message-capture/` (5 files)
- `src/modules/ai-moderation/` (6 files) - `src/modules/ai-moderation/` (6 files)
- `src/modules/voice-recording/` (9 files)
- `src/modules/attachment-upload/` (3 files) - `src/modules/attachment-upload/` (3 files)
- `src/modules/event-broadcaster/` (3 files) - `src/modules/event-broadcaster/` (3 files)
@@ -289,7 +249,6 @@ On SIGINT/SIGTERM/uncaughtException/unhandledRejection:
✅ Shared infrastructure migrated ✅ Shared infrastructure migrated
✅ Message capture module migrated ✅ Message capture module migrated
✅ AI moderation module migrated ✅ AI moderation module migrated
✅ Voice recording module migrated
✅ Attachment upload module migrated ✅ Attachment upload module migrated
✅ Event broadcaster module created (Redis pub/sub) ✅ Event broadcaster module created (Redis pub/sub)
✅ Bootstrap and entry point created ✅ Bootstrap and entry point created
@@ -304,36 +263,33 @@ On SIGINT/SIGTERM/uncaughtException/unhandledRejection:
``` ```
┌─────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────┐
│ Discord Gateway Service │ │ Discord Gateway Service │
├─────────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────────────┤
│ │ │ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────┐ │ │ ┌────────────────────────────┐ ┌────────────────────────────┐ │
│ │ Message Capture │ │ AI Moderation │ │ Voice Record │ │ │ │ Message Capture │ │ AI Moderation │ │
│ │ (Controller) │ │ (Controller) │ │ (Controller) │ │ │ │ (Controller) │ │ (Controller) │ │
│ └────────┬─────────┘ └────────┬─────────┘ └──────┬───────┘ │ │ └──────────────┬─────────────┘ └──────────────┬─────────────┘ │
│ │ │ │ │ │ │ │ │
│ ├─────────────────────┼───────────────────┤ │ │ ├───────────────────────────────┤ │
│ │ │ │ │ │ │ │ │
│ ▼ ▼ ▼ │ │ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │ │ ┌───────────────────────────────────────────────────────────┐ │
│ │ Event Broadcaster (Redis Pub/Sub) │ │ │ │ Event Broadcaster (Redis Pub/Sub) │ │
│ │ - discord:message:created │ │ │ │ - discord:message:created │ │
│ │ - discord:message:updated │ │ │ │ - discord:message:updated │ │
│ │ - discord:message:deleted │ │ │ │ - discord:message:deleted │ │
│ │ - discord:message:analyzed │ │ │ │ - discord:message:analyzed │ │
│ │ - discord:attachment:created │ │ │ │ - discord:attachment:created │ │
│ │ - discord:attachment:uploaded │ │ │ │ - discord:attachment:uploaded │ │
│ │ - discord:voice:started │ │ │ │ - discord:analysis:queue_status │ │
│ │ - discord:voice:stopped │ │ │ └───────────────────────────────────────────────────────────┘ │
│ │ - discord:voice:uploaded │ │ │ │ │
│ │ - discord:analysis:queue_status │ │ └────────────────────────────────┼────────────────────────────────┘
│ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │ Redis Pub/Sub
└───────────┼────────────────────────────────────────────────────┘ │
│ ▼
│ Redis Pub/Sub
│
▼
┌─────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────┐
│ Backend Service │ │ Backend Service │
│ (Subscribes to events, serves HTTP API, manages WebSocket) │ │ (Subscribes to events, serves HTTP API, manages WebSocket) │
+1 -9
View File
@@ -14,12 +14,7 @@ Key points:
- **API client** at `src/lib/api/client.ts` — browser-side fetch for live ops, - **API client** at `src/lib/api/client.ts` — browser-side fetch for live ops,
same-origin through the reverse proxy. same-origin through the reverse proxy.
- **WebSocket** at `src/lib/ws/` — auto-reconnecting client with typed event - **WebSocket** at `src/lib/ws/` — auto-reconnecting client with typed event
subscriptions. Realtime state (voice, media, messages) stays client-side. subscriptions. Realtime state (moderation, messages) stays client-side.
- **Shared realtime state is server-authoritative**: the backend aggregates the
gateway's `voice_active_user` deltas into a live speaker snapshot
(`GET /api/voice/status` → `activeSpeakers`, plus WS `voice_state` sent on
connect). Every browser converges on the same voice state; `useSpeakers`
seeds from the server snapshot instead of accumulating per-tab.
- **No authentication**: all endpoints are public - **No authentication**: all endpoints are public
## Data flow (match these — do not invent endpoints) ## Data flow (match these — do not invent endpoints)
@@ -47,12 +42,9 @@ Discord → discord-gateway → Redis pub/sub → backend (Express :4001) ←→
each row is `{ id, user_id, user_message, bot_response, context, created_at }`. each row is `{ id, user_id, user_message, bot_response, context, created_at }`.
Map rows to display messages in `chatbot-context.tsx`. Map rows to display messages in `chatbot-context.tsx`.
- `message_deleted` WS payload → `{ id, deleted_at }` (an object, not a string). - `message_deleted` WS payload → `{ id, deleted_at }` (an object, not a string).
- `voice_recording_uploaded` WS payload has **no** `duration_bytes` (REST rows do).
- Dashboard endpoints: `/api/dashboard/stats|users|channels` (+ `/:id` details). - Dashboard endpoints: `/api/dashboard/stats|users|channels` (+ `/:id` details).
- Channel/guild names live inside `message.metadata` JSON (`channel.channelName`), - Channel/guild names live inside `message.metadata` JSON (`channel.channelName`),
not top-level. not top-level.
- `GET /api/voice/status` now includes `activeSpeakers` (authoritative shared
snapshot from `src/modules/voice/live-speaker.ts` on the backend).
<!-- BEGIN:nextjs-agent-rules --> <!-- BEGIN:nextjs-agent-rules -->
+1 -2
View File
@@ -20,10 +20,9 @@ src/
│ ├── page.tsx # Redirect ke /dashboard │ ├── page.tsx # Redirect ke /dashboard
│ └── dashboard/ # Dashboard layout + tabs │ └── dashboard/ # Dashboard layout + tabs
│ ├── layout.tsx # Sidebar, header, WS provider, chatbot │ ├── layout.tsx # Sidebar, header, WS provider, chatbot
│ └── page.tsx # Tab routing (messages/live/dashboard) │ └── page.tsx # Tab routing (messages/dashboard)
├── features/ ├── features/
│ ├── messages/ # Message feed, search, review, detail modal │ ├── messages/ # Message feed, search, review, detail modal
│ ├── live/ # Voice connection, music player, recordings
│ ├── dashboard/ # Stats, users, channels overview │ ├── dashboard/ # Stats, users, channels overview
│ └── chatbot/ # AI chatbot │ └── chatbot/ # AI chatbot
├── lib/ ├── lib/