115 lines
4.3 KiB
Markdown
115 lines
4.3 KiB
Markdown
# Backend Service — Agent Guide
|
|
|
|
> **Read `../../AGENTS.md` first.** This file adds backend-specific conventions.
|
|
|
|
Backend service: Express HTTP server + WebSocket, serves the GMW dashboard API.
|
|
|
|
## Quick reference
|
|
|
|
```bash
|
|
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 | Semantic search | Qdrant vector DB |
|
|
| 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_URL` or individual `DATABASE_HOST/PORT/NAME/USER/PASSWORD`
|
|
- `REDIS_URL` — for pub/sub with gateway
|
|
- `MONITOR_GUILD_ID` — primary Discord guild
|
|
- `ADMIN_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.ts` or `tests/*.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.ts` in BOTH services)
|
|
- **DB pool**: backend uses one pool (main thread). Gateway has per-piscina-thread pools.
|