Bỏ qua

🚀 Quick Start Guide

⚡ TL;DR - Start Development

# If this is your first time OR after git pull:
npx nx run-many --target=build --projects=shared,config,database,cache,messaging,observability

# Then start all services:
yarn dev

Done! All 6 services running! ✅


📦 Project Structure

football-booking-backend/
├── apps/                    # Microservices
│   ├── api-gateway/        # Port 3000
│   ├── user-service/       # Port 3001
│   ├── field-service/      # Port 3002 ← Main focus
│   ├── booking-service/    # Port 3003
│   ├── payment-service/    # Port 3004
│   └── notification-service/ # Port 3005
│
├── libs/                    # Shared libraries (MUST BUILD FIRST!)
│   ├── shared/             # Common types, enums, constants
│   ├── config/             # Configuration utilities
│   ├── database/           # Database connection
│   ├── cache/              # Redis cache service
│   ├── messaging/          # Kafka messaging
│   └── observability/      # Tracing & monitoring
│
└── dist/libs/              # Compiled library outputs (auto-generated)

🔑 Key Concepts

1. Libraries Must Be Built First

Why? Apps import from compiled JavaScript in dist/libs/, not from TypeScript source files.

When?

  • ✅ First time setup
  • ✅ After git pull (if libs changed)
  • ✅ After modifying any libs/* code
  • ❌ NOT needed for apps/* changes (auto-reload)

2. Build Commands

# Build all libs (5-10 seconds)
npx nx run-many --target=build --projects=shared,config,database,cache,messaging,observability

# Build single lib (faster for development)
npx nx build shared

# Build everything including apps (slower, rarely needed)
yarn build:all

3. Development Workflow

# ① Build libs (once)
npx nx run-many --target=build --projects=shared,config,database,cache,messaging,observability

# ② Start dev server (watches apps for changes)
yarn dev

# ③ Make changes to apps/* → Auto reloads ✅
# ③ Make changes to libs/* → Need to rebuild that lib ⚠️

🎯 Common Tasks

Start Development

yarn dev

Restart After Error

# Stop: Ctrl+C
# Clear cache
rm -rf dist .nx/cache
# Rebuild libs
npx nx run-many --target=build --projects=shared,config,database,cache,messaging,observability
# Start
yarn dev

Work on Field Service Only

# Terminal 1: Start infrastructure
yarn dev:infra

# Terminal 2: Build libs once
npx nx run-many --target=build --projects=shared,config,database,cache,messaging,observability

# Terminal 3: Start field service
nx serve field-service

Add New Enum to Shared Library

# 1. Create enum file
echo "export enum MyEnum { VALUE1 = 'VALUE1' }" > libs/shared/src/enums/my-enum.enum.ts

# 2. Export from index
echo "export * from './enums/my-enum.enum';" >> libs/shared/src/index.ts

# 3. Rebuild shared library ⚠️ IMPORTANT!
npx nx build shared

# 4. Now you can import it
# import { MyEnum } from '@football-booking/shared';

🧪 Testing Endpoints

Field Service Endpoints

Public (No Auth):

# Get all fields
curl http://localhost:3002/fields

# Search fields
curl http://localhost:3002/fields/search?latitude=10.7626&longitude=106.6823&radiusKm=5

Protected (Need Token):

# 1. Get token
TOKEN=$(curl -s -X POST http://localhost:3001/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"owner@football-booking.com","password":"owner123"}' \
  | jq -r '.access_token')

# 2. Create field
curl -X POST http://localhost:3002/fields \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Test Field",
    "description": "A test field",
    "address": "123 Test St",
    "latitude": 10.7626,
    "longitude": 106.6823,
    "hourlyRate": 200000,
    "capacity": 22,
    "fieldSize": "FOOTBALL_7",
    "surfaceType": "GRASS",
    "amenities": ["PARKING"],
    "operatingHours": {
      "monday": {"open": "06:00", "close": "22:00"}
    }
  }'

🔧 Troubleshooting

Error: "Cannot find module '@football-booking/xxx'"

Cause: Library not built

Fix:

npx nx build shared  # Replace 'shared' with the missing library name

Error: "File not found" (21 errors)

Cause: Stale TypeScript cache

Fix:

rm -rf dist .nx/cache node_modules/.cache
npx nx reset
npx nx run-many --target=build --projects=shared,config,database,cache,messaging,observability
yarn dev

Error: "'Field' cannot be used as a value because it was imported using 'import type'"

Cause: Using import type in runtime decorator

Fix: Use string literal in decorator

// ❌ Wrong
@ManyToOne(() => Field, field => field.images)

// ✅ Correct
@ManyToOne('Field', 'images')

Services Won't Start

# Kill all node processes
pkill -f "node.*service"

# Clear everything
rm -rf dist .nx/cache node_modules/.cache
npx nx reset

# Rebuild libs
npx nx run-many --target=build --projects=shared,config,database,cache,messaging,observability

# Restart
yarn dev

📚 Useful Commands

Development

yarn dev                    # Start all services
yarn dev:infra             # Start Docker infrastructure
yarn dev:infra:down        # Stop Docker infrastructure
yarn dev:stop              # Kill all service processes

Building

yarn build                 # Build current project
yarn build:all             # Build all projects
npx nx build <project>     # Build specific project

Testing & Quality

yarn test                  # Run tests
yarn lint                  # Run linter
yarn lint:fix              # Auto-fix lint errors
yarn format                # Format code with Prettier

Database

yarn typeorm migration:run      # Run migrations
yarn typeorm migration:revert   # Revert last migration
yarn typeorm migration:create   # Create new migration

🎓 Important Notes

1. Always Build Libs After Git Pull

git pull
npx nx run-many --target=build --projects=shared,config,database,cache,messaging,observability
yarn dev

2. Watch Mode Limitations

  • ✅ Apps (apps/*) have watch mode → auto-reload
  • ❌ Libs (libs/*) NO watch mode → manual rebuild needed

3. Import Paths

Always use package aliases:

// ✅ Correct
import { FieldStatus } from '@football-booking/shared';

// ❌ Wrong
import { FieldStatus } from '../../../../libs/shared/src/enums/field-status.enum';

4. Circular Dependencies

Use lazy relations in TypeORM:

// ✅ Correct
@ManyToOne('Field', 'images')
field: Field;

// ❌ Wrong (causes circular dependency)
@ManyToOne(() => Field, field => field.images)
field: Field;

  • Swagger UIs:
  • Field Service: http://localhost:3002/api/docs
  • User Service: http://localhost:3001/api/docs
  • API Gateway: http://localhost:3000/api/docs

  • Infrastructure:

  • Keycloak: http://localhost:8090 (admin/admin)
  • Postgres: localhost:5432 (postgres/postgres)
  • Redis: localhost:6379
  • Kafka: localhost:9092

  • Monitoring:

  • SigNoz: http://localhost:3301

✅ Pre-flight Checklist

Before starting development:

  • [ ] Docker infrastructure running (yarn dev:infra)
  • [ ] All libs built (npx nx run-many --target=build --projects=shared,config,database,cache,messaging,observability)
  • [ ] No port conflicts (ports 3000-3005 free)
  • [ ] Node version: 18+ (node -v)
  • [ ] Yarn installed (yarn -v)

Then:

yarn dev

Happy coding! 🚀