This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
FreedomTalk is a Discord clone built as a monorepo using npm workspaces. The project uses a microservices-style architecture with a shared package for types, schemas, and utilities.
Core Tech Stack:
- Backend: Fastify 5.x + Socket.io 4.x + PostgreSQL + Redis
- Frontend: Next.js 16.x (App Router) + React 19.x + Tailwind CSS 4.x + Zustand
- Database: PostgreSQL (using Knex for query building)
- Testing: Vitest
- Infrastructure: Docker Compose (PostgreSQL, Redis, RabbitMQ)
npm run dev # Start all packages in development mode
npm run build # Build all packages
npm run start # Start all packages (production)
npm run lint # Lint all packages
npm run lint:fix # Lint and auto-fix all packages
npm run format # Format with Prettier
npm run type-check # TypeScript type checking
npm run clean # Clean build artifacts
# Docker infrastructure
npm run docker:up # Start Docker services (PostgreSQL, Redis, RabbitMQ)
npm run docker:down # Stop Docker services
npm run docker:logs # View Docker logs# Development
npm run dev --workspace=@freedomtalk/api # Start API with tsx watch
# Database migrations
npm run migrate:make --workspace=@freedomtalk/api # Create new migration
npm run migrate:latest --workspace=@freedomtalk/api # Run pending migrations
npm run migrate:rollback --workspace=@freedomtalk/api # Rollback last migration
npm run migrate:status --workspace=@freedomtalk/api # Check migration status
# Database seeds
npm run seed:make --workspace=@freedomtalk/api # Create new seed
npm run seed:run --workspace=@freedomtalk/api # Run seeds
# Testing
npm run test --workspace=@freedomtalk/api # Run tests once
npm run test:watch --workspace=@freedomtalk/api # Watch mode
npm run test:coverage --workspace=@freedomtalk/api # Coverage report
npm run test:ui --workspace=@freedomtalk/api # UI test runnernpm run dev --workspace=@freedomtalk/web # Start Next.js with Turbopack
npm run build --workspace=@freedomtalk/web # Build for production
npm run start --workspace=@freedomtalk/web # Start production serverfreedomtalk/
├── packages/
│ ├── api/ # Backend API (Fastify + Socket.io)
│ ├── web/ # Frontend (Next.js App Router)
│ ├── shared/ # Shared types, schemas, constants, utilities
│ ├── desktop/ # Placeholder (Electron)
│ ├── mobile/ # Placeholder (React Native)
│ └── scripts/ # Deployment scripts
Layered Architecture:
-
Routes (
src/routes/) - HTTP endpoints organized by domainauth/- Authentication endpointsusers/- User managementmessages/- Message CRUDreactions.routes.ts- Message reactionsattachments.routes.ts- File attachmentswebsocket/- WebSocket HTTP endpoints- Routes use Fastify's plugin system with prefixes:
/api/v1/*
-
Services (
src/services/) - Business logic layerauth/- Authentication, JWT, 2FAmessage/- Message operations and storageattachment/- File upload/download via MinIO/S3embed/- Open Graph metadata extractionreaction/- Reaction operationswebsocket/- Real-time communication:websocket.server.ts- Singleton Socket.io server wrapperhandlers/- Event handlers (connection, message, reaction, presence, room)managers/- State management (connection, room, presence, typing, status, subscription)message.broadcaster.ts- Broadcasting logicmessage.router.ts- Message routing
-
Middleware (
src/middleware/) - Request processingauth.middleware.ts- JWT and session authenticationcsrf.middleware.ts- CSRF protectionerror.middleware.ts- Centralized error handlingvalidation.middleware.ts- Zod schema validation
-
Config (
src/config/) - Infrastructure setupdatabase.ts- PostgreSQL pool + Knex instanceredis.ts- Redis clientwebsocket.ts- WebSocket configuration
Database:
- PostgreSQL with Knex for query building and migrations
- Migrations in
packages/api/migrations/(created withnpm run migrate:make) - Seeding with
npm run seed:run - Snowflake IDs for primary keys (20-character strings)
WebSocket:
- Socket.io with Redis adapter for horizontal scaling
- Singleton
wsServerinstance inservices/websocket/websocket.server.ts - Event handlers registered via
registerHandlers() - Room-based subscriptions for channels
- Presence, typing indicators, status management
Next.js App Router structure:
app/- App Router pages and layoutscomponents/- Reusable UI componentsstores/- Zustand state storeshooks/- Custom React hookslib/- Utilities and API clients
State Management:
- Zustand for global state
- Socket.io-client for real-time updates
Exports from @freedomtalk/shared:
types/- TypeScript interfaces (User, Message, Channel, Server)schemas/- Zod validation schemas (auth, messages, reactions)constants/- Validation constants (password length, message limits)utils/- Shared utilities
Key Schema Usage:
- Input validation in API routes via
validation.middleware.ts - Type inference:
z.infer<typeof schemaName>generates TypeScript types
docker-compose up -d # Start: PostgreSQL (5432), Redis (6379), RabbitMQ (5672, 15672)Service Details:
- PostgreSQL:
timescale/timescaledb:latest-pg16(supports time-series data) - Redis:
redis:7-alpinewith AOF persistence - RabbitMQ:
rabbitmq:3-management-alpinewith admin UI at http://localhost:15672
Environment Variables:
- API:
packages/api/.env(copy from.env.example) - Web:
packages/web/.env.local(copy from.env.example) - Key vars:
DATABASE_URL,REDIS_URL,JWT_SECRET,COOKIE_SECRET
API Testing (Vitest):
- Test files:
src/**/__tests__/*.test.ts - Run:
npm run test --workspace=@freedomtalk/api - Coverage:
npm run test:coverage --workspace=@freedomtalk/api - UI runner:
npm run test:ui --workspace=@freedomtalk/api
Test Setup:
packages/api/src/test-setup.ts- Test configuration and helpers- Use
supertestfor HTTP endpoint testing - Use in-memory database for integration tests (configure via env)
- Snowflake IDs for all entities (20-character strings)
- Format:
[timestamp][worker][sequence] - Enables sorting by creation time and distributed generation
- JWT tokens stored in httpOnly cookies
- Socket.io authenticated via middleware using JWT
- Refresh token flow for long-lived sessions
- Optional 2FA (TOTP) via
speakeasy
- Client emits event (e.g.,
MESSAGE_CREATE) auth.middleware.tsauthenticates socket- Handler processes event (e.g.,
handleMessageCreate) - Service performs business logic
- Changes broadcast via Redis adapter to all server instances
- Clients receive updates in subscribed rooms
- Centralized in
middleware/error.middleware.ts - Errors follow
ApiResponse<T>format from shared schemas - HTTP status codes mapped appropriately
npm run migrate:make --workspace=@freedomtalk/api create_users_table
# Edit generated migration in migrations/
npm run migrate:latest --workspace=@freedomtalk/apiimport { FastifyInstance } from 'fastify';
export default async function routes(app: FastifyInstance) {
// Get endpoint
app.get('/:id', { onRequest: [authenticate] }, async (req, reply) => {
// Handler logic
});
// Post endpoint with validation
app.post('/', {
onRequest: [authenticate],
schema: {
body: createMessageSchema
}
}, async (req, reply) => {
// Handler logic
});
}- Database Pool: Connection pool closes on
closePool()- call during shutdown - WebSocket Singleton: Always use
wsServer.getIO()after initialization - Rate Limiting: In-memory store (not distributed) - update for multi-instance deployment
- CORS: Configure
CORS_ORIGINenv var for frontend access - TypeScript Build: Run
npm run type-checkbefore committing - Knex: Use
dbinstance for queries, notpooldirectly
- Swagger UI available at
http://localhost:3001/docswhen API is running - OpenAPI spec auto-generated from route schemas
- Bearer auth and cookie auth configured