Hapus seluruh fitur embedding/Qdrant (tidak dipakai lagi): - gateway: drop embeddingClient.ts, qdrantClient.ts, archiveEmbedder.ts dan tes qdrantEnsure.test.ts; moderationOrchestrator kembali ke exact-hash cache -> LLM (tanpa phase-2 semantic lookup); textCacheStore kehilangan findSimilarTextModeration / parseQdrantVerdict / isSemanticBandAccepted / upsertBareKeyToQdrant; cache-prune hanya menyapu Postgres. - backend: drop embed.ts + qdrant.ts, endpoint messages.semanticSearch dan schema/type terkait; kolom embedding dilepas dari schema text_analysis_cache. - frontend: hapus toggle EXACT/SEMANTIC, hook useSemanticSearch, API client + tipe SemanticSearchResult. - config: buang AI_LLM_EMBEDDING_* dan QDRANT_* (env + .env.example). - docs: ARCHITECTURE.md / AGENTS.md / README.md / diagram arsitektur disesuaikan (LLM caller - vision, cache = exact-hash saja). Verifikasi: tsc 0 (backend, gateway, frontend); bun test 135 pass + 37 pass, 0 fail; biome 0 error.
4.3 KiB
4.3 KiB
Backend Service — Agent Guide
Read
../../AGENTS.mdfirst. This file adds backend-specific conventions.
Backend service: Express HTTP server + WebSocket, serves the GMW dashboard API.
Quick reference
pnpm typecheck # tsc --noEmit
pnpm lint # biome check --diagnostic-level=error .
pnpm build # tsc
pnpm test # vitest run
pnpm format # biome format --write .
Architecture (Modular MVC)
src/
├── shared/ # Infrastructure (no business logic)
│ ├── config/index.ts # Zod-validated env
│ ├── database/ # Drizzle ORM + pg Pool
│ ├── errors/index.ts # AppError hierarchy
│ ├── logger/index.ts # pino + createChildLogger()
│ ├── middlewares/index.ts # errorHandler, asyncHandler, rateLimit
│ └── utils/ # Pagination, messageMapper
├── modules/ # Feature modules
│ └── <module>/
│ ├── <module>.schema.ts # Zod validation schemas
│ ├── <module>.repository.ts # DB operations only
│ ├── <module>.service.ts # Business logic
│ ├── <module>.controller.ts # HTTP handlers
│ └── routes/index.ts # Express router
├── http/ # app.ts (factory) + server.ts (startup)
├── ws/ # WebSocket server + Redis bridge
└── index.ts # Entry point
Dependency rules
- Controller → Service → Repository → Database
- No cross-module repo imports (each module owns its data)
- No HTTP in Service layer (no req/res)
- No DB in Controller layer
- Any layer → Config, Logger, Errors
API: oRPC + Express
- oRPC (
src/orpc/router.ts+src/orpc/ws.ts): type-safe procedures for frontend - Express routes (
src/modules/*/routes/): REST endpoints under/api/ - WebSocket (
src/ws/): Redis bridge → broadcast to connected browsers - Never invent endpoints. Match what the frontend calls (
src/lib/api/).
Key modules
| Module | Purpose | DB tables |
|---|---|---|
| messages | Store & query Discord messages | messages, ai_moderations, ai_moderation_flags |
| moderation | Moderation actions & metrics | ai_moderations, moderation_actions |
| media | Media file management | media_attachments |
| dashboard | Stats aggregation | Various (read-only) |
| knowledge | Channel cultures & glossary browser | channel_cultures, term_glossary_cache |
| chatbot | AI chatbot with tools | chatbot_history |
| health | Health checks + metrics | Various |
| analysis | Text analysis cache | text_analysis_cache |
| ui-state | Persist UI preferences | ui_state |
Config (env vars)
All validated via Zod in shared/config/index.ts. Key vars:
WEBSERVER_PORT(default 4001)DATABASE_URLor individualDATABASE_HOST/PORT/NAME/USER/PASSWORDREDIS_URL— for pub/sub with gatewayMONITOR_GUILD_ID— primary Discord guildADMIN_PASSWORD— admin endpoints
Data contract with frontend
The frontend fetches via src/lib/api/server.ts (SSR, server-side) and
src/lib/api/client.ts (browser, same-origin through proxy).
Do not change response shapes without updating both sides. Check
services/frontend/src/lib/types/ for frontend type definitions.
Redis channels (inbound from gateway)
discord:message:{created,updated,deleted,analyzed}
discord:attachment:{created,uploaded}
discord:analysis:queue_status
discord:reaction:{added,removed}
discord:thread:{created,deleted,updated}
discord:channel_topic:updated
discord:presence:updated
discord:guild_member:{added,removed}
Canonical names: src/shared/redis-channels.ts.
Testing
- Vitest for unit tests
- Mock database and external services
- Test files:
src/modules/<module>/*.test.tsortests/*.test.ts - Run:
pnpm test
Common pitfalls
- oRPC vs REST: check both routers when adding an endpoint
- Redis channel mismatch: gateway publishes → backend subscribes. Channel
names must match exactly (see
redis-channels.tsin BOTH services) - DB pool: backend uses one pool (main thread). Gateway has per-piscina-thread pools.