A comprehensive club management system built with React, TypeScript, and Node.js.
- Docker and Docker Compose
- Node.js 20+ (for local development)
- npm or yarn
Production-oriented Compose stack (database, backend, frontend with same-origin API proxy):
cp .env.example .env
# Edit .env — set POSTGRES_PASSWORD, JWT secrets, CORS_ORIGIN, etc.
docker compose --env-file .env up -d --build
docker compose ps
./scripts/docker-smoke.sh # health checks on http://127.0.0.1:3001Access (local):
- App (SPA + API + WebSocket): http://127.0.0.1:3001 — API at
/api, Socket.IO at/socket.io/ - Database: internal only (not published on the host)
Server deployment with HTTPS: see docs/DEPLOY.md.
The Docker database is PostgreSQL. Use backend/docs/SUPABASE_POSTGRES_MIGRATION.md when importing the legacy MySQL/MariaDB dump into Supabase.
Option A: Run Everything Locally
-
Database Setup (PostgreSQL or Supabase)
- Set
DATABASE_URLinbackend/.env - For Supabase migration, follow
backend/docs/SUPABASE_POSTGRES_MIGRATION.md
- Set
-
Backend Setup
cd backend npm install # Create .env file (see Environment Variables section) npm run dev
Backend will run on
http://localhost:5000 -
Frontend Setup
# From project root npm install npm run devFrontend will run on
http://localhost:3000with hot-reload enabled.
Option B: Hybrid (Docker stack + local frontend dev server)
Run the full stack with Compose, or run npm run dev locally with VITE_API_URL pointing at your API (see Environment Variables).
├── backend/ # Node.js + Express + TypeScript API
│ ├── src/
│ │ ├── config/ # Database configuration
│ │ ├── routes/ # API routes
│ │ ├── controllers/ # Request handlers
│ │ ├── models/ # Data models
│ │ └── types/ # TypeScript types
│ └── .sql/ # SQL schema and migration helpers
├── src/ # React frontend
│ ├── components/ # React components
│ └── config/ # API configuration
└── public/ # Static assets
The Docker setup includes three services:
- Database: PostgreSQL 16 for local development
- Backend: Node.js API server (TypeScript + Express)
- Frontend: React application served with nginx
- Frontend:
127.0.0.1:3001→ container port 80 (Nginx serves SPA and proxies/api/and/socket.io/to the backend) - Backend: internal port 5000 only (not published on the host)
- Database: internal port 5432 only (not published on the host)
The database is stored in a Docker volume (postgres_data), so data persists between container restarts. The legacy dump at backend/.sql/icas_cmu_hub.sql is MySQL/MariaDB syntax and should be migrated with pgloader before loading into Supabase/Postgres.
To reset the database and re-run the SQL file:
docker-compose down
docker volume rm icas-cmu-hub_postgres_data
docker-compose up -dTo access the database directly:
docker exec -it icas-database psql -U icas_user -d icas_cmu_hub
psql "postgresql://icas_user:icas_password@127.0.0.1:5433/icas_cmu_hub?sslmode=disable"# View all service logs
docker-compose logs -f
# View specific service logs
docker-compose logs -f database
docker-compose logs -f backend
docker-compose logs -f frontend
# Restart a specific service
docker-compose restart backend
# Rebuild and restart services
docker-compose up -d --build
# Stop all services
docker-compose down
# Stop and remove volumes (will delete database data)
docker-compose down -vCopy .env.example to .env at the project root. Compose loads it via env_file. Do not set VITE_API_URL for production Docker (same-origin /api via Nginx).
Key variables: POSTGRES_PASSWORD, DATABASE_URL, JWT_SECRET, JWT_REFRESH_SECRET, CORS_ORIGIN, CHAT_ENCRYPTION_KEY, SMTP settings.
Backend - Create backend/.env:
PORT=5000
NODE_ENV=development
DATABASE_URL=postgresql://icas_user:icas_password@localhost:5433/icas_cmu_hub?sslmode=disable
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_EXPIRES_IN=7dFrontend - Create .env in project root (optional):
VITE_API_URL=http://localhost:5000/apiNote: For Docker backend, use http://localhost:5002/api instead.
With Docker:
curl http://127.0.0.1:3001/health
curl http://127.0.0.1:3001/api/health
docker exec -it icas-database psql -U icas_user -d icas_cmu_hub -c "\\dt"Local Development:
cd backend
npm run dev
# Check http://localhost:5000/api/healthOr test directly:
cd backend
npx tsx src/scripts/test-connection.tsPOST /api/auth/login- User loginPOST /api/auth/verify- Verify JWT tokenGET /api/auth/me- Get current user (protected)
GET /api/health- Health check and database connection status
cd backend
npm run dev # Development with hot-reload
npm run build # Build for production
npm start # Run production build
npm run type-check # TypeScript type checkingnpm run dev # Development server
npm run build # Production build- Three services:
database,backend,frontend(Nginx proxies API and Socket.IO) - Volumes:
postgres_data,backend_uploads - Only the frontend is published on
127.0.0.1:3001
- Database connection uses PostgreSQL via
DATABASE_URL - Update
backend/.envwhen using Supabase or another Postgres instance - Frontend uses axios for API calls (configured in
src/config/api.ts) - Backend uses TypeScript with Express and PostgreSQL via
pg(e.g. Supabase). See backend/docs/SUPABASE_POSTGRES_MIGRATION.md for moving from MySQL/MariaDB.
Port conflicts:
If port 3001 is in use, change the frontend mapping in docker-compose.yml (e.g. 127.0.0.1:3002:80).
Database reset:
docker compose down -v
docker compose --env-file .env up -d --buildFrontend can't reach API:
With Docker, use http://127.0.0.1:3001 (same origin). Do not set VITE_API_URL unless using a split dev setup.