NestJS 11 backend API and WebSocket server.
- Framework: NestJS 11 with TypeScript
- Database: PostgreSQL 16+ with Drizzle ORM
- Authentication: JWT tokens in httpOnly cookies + Google OAuth
- Real-time: Socket.IO WebSockets
- Security: Helmet, CORS, rate limiting, input validation
See docs/ARCHITECTURE.md for the full system diagram, module breakdown, and data flows.
apps/back/
├── src/
│ ├── main.ts # Application entry point
│ ├── app.module.ts # Root module with Joi env validation
│ ├── internal.module.ts # Metrics-only app on INTERNAL_PORT
│ ├── database/ # Drizzle ORM configuration
│ │ ├── schema/ # Database schema definitions
│ │ ├── seed/ # Seed scripts and admin promotion
│ │ └── database.module.ts # Database module
│ ├── modules/ # Feature modules
│ │ ├── auth/ # Authentication (JWT, Google OAuth, anonymous)
│ │ ├── users/ # User management
│ │ ├── workspaces/ # Workspace CRUD
│ │ ├── retrospectives/ # Retrospective sessions
│ │ ├── boards/ # Board and column management
│ │ ├── cards/ # Retro cards
│ │ ├── voting/ # Voting system
│ │ ├── reactions/ # Card reactions (emoji)
│ │ ├── action-items/ # Action items
│ │ ├── templates/ # Custom retro templates
│ │ ├── insights/ # Retro insights and analytics
│ │ ├── admin/ # System administration panel
│ │ ├── growth/ # Growth analytics (signups, retention, churn)
│ │ ├── audit/ # Audit logging
│ │ ├── event-tracking/ # User event tracking and analytics
│ │ ├── metrics/ # Prometheus metrics (internal observability)
│ │ ├── health/ # Health check endpoint
│ │ └── email/ # Email service (Mailgun)
│ ├── gateways/ # WebSocket gateway
│ │ ├── retro.gateway.ts # Main gateway
│ │ ├── handlers/ # Event handlers (Card, Vote, Reaction, Timer, Column, Session, ActionItem)
│ │ └── guards/ # WebSocket JWT guard
│ └── common/ # Shared utilities
│ ├── guards/ # Access guards (Workspace, Retro, Roles)
│ ├── dto/ # DTOs (Pagination)
│ └── utils/ # Utility functions
├── drizzle/ # Database migrations
└── test/ # E2E tests
# Development
yarn start:dev # Start in watch mode
yarn build # Build for production
yarn start:prod # Start production build
# Database
yarn db:generate # Generate new migration from schema changes
yarn db:migrate # Run pending migrations
yarn db:push # Push schema directly (dev only — skips migrations)
yarn db:studio # Open Drizzle Studio (visual database browser)
yarn db:seed # Seed the database with sample data
yarn db:promote-admin # Promote a user to system admin
# Testing
yarn test # Run unit tests
yarn test:watch # Run tests in watch mode
yarn test:cov # Generate coverage report
yarn test:debug # Run tests with Node inspector (port 9229)
yarn test:e2e # Run E2E tests (requires PostgreSQL)All environment variables are configured in the root .env file. See the root README.md and .env.example for the complete list.
This project uses Drizzle ORM with forward-only SQL migrations in drizzle/.
- Modify schema files in
src/database/schema/ - Generate migration:
yarn db:generate - Review generated SQL in
drizzle/ - Apply migration:
yarn db:migrate
For rapid iteration during development, use yarn db:push to sync schema without creating migration files. Never use this in production.
Drizzle ORM does not provide a built-in rollback command. Rollbacks must be performed manually:
-
Backup first:
pg_dump $DATABASE_URL > backup_$(date +%Y%m%d_%H%M%S).sql -
Identify the migration in
drizzle/meta/_journal.json -
Write and execute inverse SQL in a transaction:
BEGIN; -- Your inverse SQL here (e.g. DROP TABLE, DROP COLUMN) DELETE FROM drizzle.__drizzle_migrations WHERE name = '<migration_name>'; COMMIT;
-
Remove the entry from
drizzle/meta/_journal.json -
Verify application health and data integrity
Always test rollbacks on a staging environment first. Never leave code and schema out of sync in production.
See docs/TESTING.md for the full testing guide including patterns, mocking strategies, and CI integration.
See docs/WEBSOCKET.md for the full protocol reference.
A multi-stage Dockerfile is included. Build from the repo root:
docker build -f apps/back/Dockerfile -t retroloop-backend .MIT