Bỏ qua

System Design - Football Field Booking System

Version: 1.0 Last Updated: 2026-01-13 Owner: Tech Lead Architecture: Microservices (NX monorepo + NestJS) + Kafka + Redis + PostgreSQL + MongoDB + Keycloak + Signoz


1) High-Level Architecture

1.1 Components

  • API Gateway (3000): single entry point, auth enforcement, routing, rate limiting, request validation, observability propagation.
  • user-service (3001): user data, profiles, optional player profile/rating.
  • field-service (3002): field catalog, amenities, pricing, availability metadata.
  • booking-service (3003): booking lifecycle, conflict prevention, booking state machine.
  • payment-service (3004): payment intents, webhooks, idempotency, refunds.
  • notification-service (3005): email/ZNS (Phase 2), consumes Kafka events and records logs to MongoDB.

1.2 Infrastructure

  • PostgreSQL: per-service OLTP databases (user/field/booking/payment) + Keycloak DB.
  • Redis: caching + distributed locks (booking conflict) + rate limiting counters (optional).
  • Kafka: async event bus for decoupling services.
  • Keycloak: authentication + RBAC claims.
  • Signoz (OpenTelemetry): tracing/metrics/logs correlation.

1.3 Diagram

flowchart LR
  Client[Web/Mobile Client] -->|HTTPS| GW[API Gateway :3000]

  subgraph Services
    U[user-service :3001]
    F[field-service :3002]
    B[booking-service :3003]
    P[payment-service :3004]
    N[notification-service :3005]
  end

  subgraph Infra
    KC[Keycloak]
    R[Redis]
    K[Kafka]
    PGU[(Postgres User)]
    PGF[(Postgres Field)]
    PGB[(Postgres Booking)]
    PGP[(Postgres Payment)]
    MG[(MongoDB Logs)]
    SZ[Signoz OTEL]
  end

  GW --> U
  GW --> F
  GW --> B
  GW --> P
  GW --> N

  GW --> KC
  U --> PGU
  F --> PGF
  B --> PGB
  P --> PGP
  N --> MG

  U <--> R
  F <--> R
  B <--> R
  P <--> R

  U <--> K
  F <--> K
  B <--> K
  P <--> K
  N <--> K

  GW --> SZ
  U --> SZ
  F --> SZ
  B --> SZ
  P --> SZ
  N --> SZ

2) Service Responsibilities & Boundaries

2.1 API Gateway

  • Token verification (Keycloak OIDC)
  • Role enforcement (coarse-grained)
  • Request shaping: consistent response format, requestId/trace propagation
  • Rate limiting
  • Routing to services

2.2 user-service

  • User profile CRUD
  • Role mapping (as stored/derived from Keycloak)
  • Zalo user mapping (zalo_user_id) for ZNS integration
  • (Phase 2) Player profile + ratings + ranking

2.3 field-service

  • Field CRUD + owner-specific restrictions
  • Search and filters (geo radius, sport type, amenities)
  • Field status workflow (PENDING_APPROVAL → ACTIVE)

2.4 booking-service

  • Booking creation and lifecycle:
  • PENDING → CONFIRMED → COMPLETED
  • PENDING/CONFIRMED → CANCELLED
  • Conflict detection:
  • distributed lock (Redis) + DB checks
  • Publishes booking events to Kafka

2.5 payment-service

  • Payment intent creation and tracking
  • Webhook ingestion (Stripe/VNPay)
  • Idempotency and reconciliation
  • Publishes payment events to Kafka

2.6 notification-service

  • Consumes Kafka events and sends notifications
  • Logs delivery attempts in MongoDB
  • Retry policies for transient provider failures

3) Data Flow Diagrams

3.1 Booking Flow (Create Booking)

sequenceDiagram
  autonumber
  participant C as Client
  participant GW as API Gateway
  participant B as booking-service
  participant R as Redis
  participant DB as Booking DB
  participant K as Kafka

  C->>GW: POST /v1/bookings (token)
  GW->>B: Forward request + claims + trace
  B->>R: Acquire lock lock:booking:{fieldId}:{start}:{end}
  alt lock acquired
    B->>DB: Check overlap + create booking (transaction)
    DB-->>B: bookingId, status=PENDING
    B->>K: Publish BOOKING_CREATED (optional)
    B->>R: Release lock
    B-->>GW: 201 booking created (expiresAt)
    GW-->>C: 201
  else lock not acquired
    B-->>GW: 409 CONFLICT (another booking in progress)
    GW-->>C: 409
  end

3.2 Payment Flow (Confirm Payment)

sequenceDiagram
  autonumber
  participant C as Client
  participant GW as API Gateway
  participant P as payment-service
  participant DB as Payment DB
  participant K as Kafka
  participant N as notification-service
  participant M as MongoDB Logs
  participant Provider as Payment Provider

  C->>GW: POST /v1/payments/create
  GW->>P: create payment intent
  P->>DB: upsert payment (idempotency)
  P->>Provider: create checkout session
  Provider-->>P: checkoutUrl + provider ids
  P->>DB: update payment=PENDING
  P-->>C: checkoutUrl

  Provider->>P: POST /v1/webhooks/provider (signed)
  P->>P: verify signature + idempotency
  P->>DB: update payment=SUCCESS
  P->>K: publish PAYMENT_SUCCESS (bookingId)
  K->>N: consume PAYMENT_SUCCESS
  N->>M: log notification attempt
  N-->>Provider: send email/ZNS

3.3 Notification Flow (Event-driven)

flowchart TD
  Event[Kafka Event] --> N[notification-service]
  N -->|Send| Email[Email Provider]
  N -->|Send| ZNS[Zalo ZNS Provider]
  N -->|Write| MG[(MongoDB notification_logs)]
  N -->|Retry| Queue[Background Jobs/BullMQ (optional)]

4) Critical Design Decisions & Justifications

4.1 Database-per-service

Why

  • Clear ownership boundaries and independent scaling.
  • Avoids tight coupling through shared schema changes.

Trade-offs

  • Cross-entity constraints cannot be enforced with native DB foreign keys across DBs.
  • Requires careful consistency strategy (events, validation calls, eventual consistency).

4.2 Kafka for Async Communication

Why

  • Decouple payment and notification from booking hot path.
  • Enable future services (analytics, fraud detection) with minimal coupling.

Trade-offs

  • Requires operational maturity (topics, partitioning, lag monitoring).
  • Exactly-once delivery is hard; must design for at-least-once and idempotency.

4.3 Redis for Locks & Cache

Why

  • Booking conflict is a concurrency hotspot; Redis locks reduce race conditions.
  • Cache reduces read load for popular fields and searches.

Trade-offs

  • Redis outages degrade performance; must have fallback and resilience.
  • Locks must be implemented carefully (value-based unlock, TTL).

4.4 Keycloak for Authn/Authz

Why

  • Standard OIDC, centralized identity management, easy integration for web/mobile.

Trade-offs

  • Additional infra and operational overhead.
  • Token claim mapping and gateway enforcement must be consistent.

5) Design Patterns Used

Used for booking + payment + notifications where no single DB transaction spans services.

  • Booking created (PENDING) → payment created → webhook confirms payment → booking confirmed (event) → notify user.

Implementation options

  • Choreography (Kafka events) for MVP.
  • Orchestration (dedicated saga orchestrator) for complex flows (Phase 2).

Prevent missing events when DB commit succeeds but Kafka publish fails.

  • Write event to booking_outbox/payment_outbox in same DB transaction.
  • Background publisher reads outbox and publishes to Kafka.

5.3 Circuit Breaker + Retry + Timeout

Required for:

  • Payment providers
  • Email/ZNS providers
  • Cross-service calls

5.4 CQRS (Optional, Phase 2)

For high-scale search and reporting:

  • Command side: OLTP Postgres
  • Query side: denormalized read models (Redis/Elastic/Postgres read replica)

6) Scalability Considerations

  • Hot paths:
  • Field search
  • Availability queries
  • Booking creation
  • Payment webhooks
  • Techniques:
  • Cache field details and search results (short TTL)
  • Precompute availability windows (optional)
  • Partition Kafka topics by bookingId/fieldId
  • Use indexes for time-range queries in bookings
  • Limit synchronous fan-out; prefer events

7) Failure Modes & Mitigations

Failure Impact Mitigation
Redis down slower booking conflict checks fallback to DB checks + reduced throughput, alerts
Kafka down events not delivered outbox + retry publisher, degrade notifications
Payment provider down cannot pay show failure + retry, allow PENDING booking expiry
Notification provider down no notifications queue retries + fallback channel
Keycloak down auth failures short-term token caching, degrade to 503 for protected endpoints

8) Deployment Topology (Production)

flowchart LR
  Ingress[Ingress/Load Balancer] --> GW[api-gateway]
  GW --> U[user-service]
  GW --> F[field-service]
  GW --> B[booking-service]
  GW --> P[payment-service]
  GW --> N[notification-service]
  U --> PGU[(Postgres User)]
  F --> PGF[(Postgres Field)]
  B --> PGB[(Postgres Booking)]
  P --> PGP[(Postgres Payment)]
  N --> MG[(MongoDB)]
  GW --> KC[Keycloak]
  subgraph Shared
    R[Redis]
    K[Kafka]
    SZ[Signoz]
  end
  U --> R
  F --> R
  B --> R
  P --> R
  U --> K
  F --> K
  B --> K
  P --> K
  N --> K
  GW --> SZ
  U --> SZ
  F --> SZ
  B --> SZ
  P --> SZ
  N --> SZ

Document Version: 1.0 Last Updated: 2026-01-13 Owner: Tech Lead