Skip to content

ftryyln/hotel-booking-ddd-microservices

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

37 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿจ Hotel Booking Microservices Platform

An enterprise-grade distributive system built with Domain-Driven Design (DDD) & Clean Architecture
Engineered for Scability, Resilience, and Technical Excellence using Go (Golang)

Go Architecture Microservices PostgreSQL Docker


๐Ÿ“ Project Mission

Hotel Booking Microservices is a production-ready, backend-only ecosystem designed to handle the complex lifecycles of hotel reservations. This project serves as a showcase of Senior-level Backend Engineering in Go, demonstrating deep proficiency in:

  • Domain-Driven Design (DDD): Managing complex business logic through Aggregates, Value Objects, and Specifications.
  • Microservices Orchestration: 6 independent services communicating via a resilient API Gateway.
  • Clean Architecture (Hexagonal): Strict separation of concerns to ensure maintainability and testability.
  • Event-Driven Patterns: Leveraging domain events for cross-context consistency.

๐Ÿ—๏ธ Technical Highlight: The "Why"

In a monolithic world, a failure in the notification system or a payment lag can paralyze the whole booking flow. This platform solves that through decoupled services. Each service (Auth, Hotel, Booking, Payment, Notification) is ownable, scalable, and resilient.


๐Ÿ“š Documentation Hub

Document Description
๐Ÿ—๏ธ Project Structure Detailed breakdown of folders, layers, and key files.
๐Ÿ“ Architecture Review Design decisions, patterns, and architectural principles.
๐Ÿ—บ๏ธ Entity Analysis Database schema, entities, and business rules.
๐Ÿ”— ER Diagram Visual representation of database relationships.
๐Ÿ“– Glossary Ubiquitous Language definitions.
๐Ÿ”Œ API Swagger OpenAPI 3.0 specification.

๐Ÿ›๏ธ Architecture Overview

The system follows a Microservices Architecture with a Clean Architecture internal structure for each service.

graph TD
    Client["Client (Web/Mobile)"] --> Gateway["API Gateway :8088"]
    
    subgraph "Microservices Mesh"
        Gateway --> Auth["Auth Service :8080"]
        Gateway --> Hotel["Hotel Service :8081"]
        Gateway --> Booking["Booking Service :8082"]
        Gateway --> Payment["Payment Service :8083"]
        
        Booking --> Hotel
        Booking --> Payment
        Booking --> Notification["Notification Service :8085"]
        Payment --> Notification
    end
    
    Auth --> DB[(PostgreSQL)]
    Hotel --> DB
    Booking --> DB
    Payment --> DB
Loading

Bounded contexts & responsibilities

Service Port Responsibilities
API Gateway 8088 JWT verification, rate limiting, reverse proxy, booking+payment aggregation
Auth Service 8080 Register/login, password hashing (bcrypt), JWT issuing, /register /login /me
Hotel Service 8081 CRUD hotels, room types, rooms, public listing with room type summaries
Booking Service 8082 Booking lifecycle (create โ†’ pending โ†’ confirmed โ†’ checked_in โ†’ completed), cancellations, check-ins
Payment Service 8083 PaymentProvider abstraction (mock Xendit), initiation, webhook verification, refunds, booking sync
Notification 8085 Simple dispatcher (zap logger), triggered on booking creation or payment events

๐Ÿ”„ System Flow & User Journey

The following sequence diagram illustrates the core Booking & Payment Workflow, demonstrating how services interact to complete a reservation.

sequenceDiagram
    actor User
    participant Gateway as API Gateway
    participant Auth as Auth Service
    participant Hotel as Hotel Service
    participant Booking as Booking Service
    participant Payment as Payment Service
    participant Notif as Notification Service

    %% Authentication
    User->>Gateway: POST /auth/login
    Gateway->>Auth: Forward Request
    Auth-->>Gateway: Return JWT Token
    Gateway-->>User: Access Token

    %% Browsing
    User->>Gateway: GET /hotels (with Token)
    Gateway->>Hotel: Fetch Inventory
    Hotel-->>Gateway: Hotel List
    Gateway-->>User: Display Hotels

    %% Booking Process
    User->>Gateway: POST /bookings (RoomID, Dates)
    Gateway->>Booking: Create Booking
    Booking->>Hotel: Check Availability
    Booking->>Booking: Calculate Price & Create Record (Pending)
    Booking->>Payment: Initiate Payment
    Payment-->>Booking: Payment URL/ID
    Booking-->>Gateway: Booking Created (Pending)
    Gateway-->>User: Payment Instructions

    %% Payment Webhook (Async)
    Note over Payment, Booking: User pays via Payment Gateway
    Payment->>Payment: Webhook: Status = PAID
    Payment->>Booking: Update Booking Status (Confirmed)
    Booking->>Notif: Emit Event: BookingConfirmed
    Notif-->>User: Send Email Confirmation
Loading

Flow summary

  • User authenticates (JWT), then browses hotels/rooms via the gateway.
  • Booking service validates availability and creates a pending booking; payment service issues an invoice URL.
  • User pays through the provider; webhook validates signature, marks payment paid, and auto-confirms the booking.
  • Booking emits a notification; notification service emails/logs the confirmation to the user.

๐Ÿš€ Tech Stack & Key Features

Core Technology

  • Language: Go 1.23
  • Frameworks: chi router, sqlx/gorm, jwt v5, zap logger
  • Database: PostgreSQL 15 (with uuid-ossp)
  • Containerization: Docker + docker-compose (multi-stage builds)
  • Docs: Swagger generated from handler annotations (docs/swagger/swagger.yaml)

๐ŸŒŸ Advanced DDD Features (New!)

  • Domain Events: Full event sourcing capability (pkg/domain/events.go).
  • Rich Domain Models: Business logic encapsulated in Aggregates (Booking.Confirm(), Booking.GuestCheckIn()).
  • Value Objects: Powerful Money and DateRange types with validation and arithmetic.
  • CQRS Interfaces: Split BookingReader and BookingWriter repositories.
  • Specification Pattern: Complex filtering logic (pkg/domain/specification.go).
  • Domain Services: PricingService for complex calculation logic.
  • Repository Factory: Abstracted repository creation.

Non-functional

  • JWT-based authentication & role checks
  • Rate limiting middleware on gateway
  • Structured logging + context-aware logging helpers
  • Config via environment variables (.env.example)
  • Graceful shutdown using context cancellation & signal handling
  • Payment provider abstraction + mock Xendit signature validation
  • Consistent API error contract (DTO-based)

๐Ÿ“ API Shape (Assemblers, Domain-First, Pagination)

  • Thin Handlers: DTO โ†’ inbound assembler โ†’ usecase (domain) โ†’ outbound assembler โ†’ DTO envelope.
  • Domain-Centric: Usecases return domain models; mapping to DTO only happens at the handler boundary.
  • Pagination: List endpoints accept limit/offset (default limit 50) in hotel, booking, auth, notification.
  • Validation: Booking/Payment/Notification requests are validated in assemblers (ID/date/money/webhook signature).

Mock payment webhook signature generation:

PAYLOAD='{"payment_id":"<uuid>","status":"paid"}'
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$PAYMENT_PROVIDER_KEY" -hex | awk '{print $2}')
curl -X POST http://localhost:8088/api/v1/payments/webhook \
  -H "Content-Type: application/json" \
  -d '{"payment_id":"<uuid>","status":"paid","signature":"'"$SIG"'"}'

๐Ÿ“‹ Complete API Reference (For Testers)

Base URL

http://localhost:8088/api/v1

Authentication Endpoints

1. Register User

POST /auth/register
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "SecurePass123!",
  "role": "customer"  // or "admin"
}

2. Login

POST /auth/login
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "SecurePass123!"
}

Response:
{
  "data": {
    "access_token": "eyJhbGc...",
    "refresh_token": "eyJhbGc..."
  }
}

3. Get User Profile

GET /auth/me/{user_id}
Authorization: Bearer {token}

Admin: List Users (๐Ÿ”’ Admin Only)

GET /auth/users
Authorization: Bearer {admin_token}

Admin: Get User Detail (๐Ÿ”’ Admin Only)

GET /auth/users/{id}
Authorization: Bearer {admin_token}

Hotel Management Endpoints

4. List Hotels (Public)

GET /hotels?limit=10&offset=0

5. Get Hotel by ID (Public)

GET /hotels/{hotel_id}

6. Create Hotel (๐Ÿ”’ Admin Only)

POST /hotels
Authorization: Bearer {admin_token}
Content-Type: application/json

{
  "name": "Grand Hotel",
  "description": "Luxury hotel in city center",
  "address": "123 Main St, Jakarta"
}

7. Update Hotel (๐Ÿ”’ Admin Only)

PUT /hotels/{hotel_id}
Authorization: Bearer {admin_token}
Content-Type: application/json

{
  "name": "Updated Grand Hotel",
  "description": "Updated description",
  "address": "Updated address"
}

8. Delete Hotel (๐Ÿ”’ Admin Only)

DELETE /hotels/{hotel_id}
Authorization: Bearer {admin_token}

Room Type Endpoints

9. List Room Types (Public)

GET /room-types?limit=10&offset=0

10. Create Room Type (๐Ÿ”’ Admin Only)

POST /room-types
Authorization: Bearer {admin_token}
Content-Type: application/json

{
  "hotel_id": "{hotel_id}",
  "name": "Deluxe Suite",
  "capacity": 2,
  "base_price": 1500000,
  "amenities": "WiFi, TV, AC, Minibar"
}

Room Management Endpoints

11. List Rooms (Public)

GET /rooms?limit=10&offset=0

12. Get Room by ID (Public)

GET /rooms/{room_id}

13. Create Room (๐Ÿ”’ Admin Only)

POST /rooms
Authorization: Bearer {admin_token}
Content-Type: application/json

{
  "room_type_id": "{room_type_id}",
  "number": "101",
  "status": "available"  // available, maintenance, occupied
}

14. Update Room (๐Ÿ”’ Admin Only)

PUT /rooms/{room_id}
Authorization: Bearer {admin_token}
Content-Type: application/json

{
  "number": "102",
  "status": "maintenance"
}

15. Delete Room (๐Ÿ”’ Admin Only)

DELETE /rooms/{room_id}
Authorization: Bearer {admin_token}

Booking Endpoints

16. Create Booking ๐Ÿ”’

POST /bookings
Authorization: Bearer {token}
Content-Type: application/json

{
  "room_type_id": "{room_type_id}",
  "check_in": "2025-12-01",
  "check_out": "2025-12-05"
}

17. List Bookings

GET /bookings?limit=10&offset=0
Authorization: Bearer {token}

18. Get Booking by ID

GET /bookings/{booking_id}
Authorization: Bearer {token}

19. Cancel Booking ๐Ÿ”’

POST /bookings/{booking_id}/cancel
Authorization: Bearer {token}

20. Get Booking Status

GET /bookings/{booking_id}/status
Authorization: Bearer {token}

21. Change Booking Status (๐Ÿ”’ Admin Only)

POST /bookings/{booking_id}/status
Authorization: Bearer {admin_token}
Content-Type: application/json

{
  "status": "confirmed"
}

22. Booking Checkpoint (workflow action)

POST /bookings/{booking_id}/checkpoint
Authorization: Bearer {token}
Content-Type: application/json

{
  "action": "check_in" // or other supported actions
}

Payment Endpoints

Admin: Get Payment by ID (๐Ÿ”’ Admin Only)

GET /payments/{payment_id}
Authorization: Bearer {admin_token}

23. Get Payment by Booking ID

GET /payments/by-booking/{booking_id}
Authorization: Bearer {token}

24. Payment Webhook (Provider Callback)

POST /payments/webhook
Content-Type: application/json

{
  "payment_id": "{payment_id}",
  "status": "paid",
  "signature": "{hmac_signature}"
}

25. Refund Payment (๐Ÿ”’ Admin Only)

POST /payments/refund
Authorization: Bearer {admin_token}
Content-Type: application/json

{
  "payment_id": "{payment_id}",
  "reason": "Customer request"
}

Notification Endpoints

26. Send Notification

POST /notifications
Authorization: Bearer {token}
Content-Type: application/json

{
  "type": "booking_confirmed",
  "target": "user@example.com",
  "message": "Your booking has been confirmed"
}

27. List Notifications

GET /notifications?limit=10&offset=0
Authorization: Bearer {token}

28. Get Notification by ID

GET /notifications/{notification_id}
Authorization: Bearer {token}

Gateway Aggregation Endpoint

29. Get Booking Aggregate

GET /gateway/aggregate/bookings/{booking_id}
Authorization: Bearer {token}

Response: Combined data from booking, payment, and hotel services

Legend

  • Requires Authentication = JWT Bearer Token
  • ๐Ÿ”’ Admin Only = Requires role: "admin" in JWT claims

Auto-Checkout Feature

  • Trigger: Automatic CronJob (daily at 10:00 AM)
  • Process: Bookings with checkout_date = today AND status = checked_in are automatically transitioned to completed
  • No API Call Required: Fully automated background process

๐Ÿ“‚ Repository Layout

cmd/<service>/           # each service entry point (auth-service, booking-service, etc.)
internal/
  domain/<bounded>       # entities & repository interfaces
  usecase/<bounded>      # core business logic
  infrastructure/        # http handlers, repositories, provider clients, gateway logic
  usecase/<bounded>/assembler # inbound/outbound mapping DTO <-> domain
pkg/                     # shared libs (config, dto, middleware, logger, etc.)
migrations/001_init.sql  # SQL schema seed
build/<service>/Dockerfile
docs/                    # Swagger + ERD

๐Ÿ› ๏ธ Configuration & Prerequisites

Prerequisites

  • Docker Desktop / Docker Engine 24+
  • Docker Compose V2
  • Go 1.23+ (only needed for local dev/tests)
  • swag CLI (optional): go install github.com/swaggo/swag/cmd/swag@latest

Environment Variables

Copy .env.example to .env:

Variable Default Description
DATABASE_URL postgres://... Shared Postgres DSN
JWT_SECRET super-secret JWT signing secret
PAYMENT_PROVIDER_KEY sandbox-key HMAC key for mock Xendit
RATE_LIMIT_PER_MINUTE 120 Gateway rate limiter

โ–ถ๏ธ Running the Stack

  1. Spin up services

    make run
    # OR
    docker-compose up --build
    • API Gateway: http://localhost:8088/gateway
    • Auth: http://localhost:8080
    • Hotel: http://localhost:8081
    • Booking: http://localhost:8082
    • Payment: http://localhost:8083
    • Notification: http://localhost:8085
    • PostgreSQL: localhost:5432
    • Adminer UI: http://localhost:8089
  2. Shutdown & cleanup

    make down
    # OR
    docker-compose down -v

๐Ÿ—„๏ธ Database & Migrations

  • Schema: migrations/001_init.sql creates tables (users, hotels, room_types, rooms, bookings, payments, refunds, checkins).
  • UUIDs: All keys use UUID (requires CREATE EXTENSION "uuid-ossp").
  • Seeding: Run migrations/002_seed_data.sql manually via Adminer to populate initial data.

๐Ÿ“– Swagger / API Documentation

  1. Generate docs

    make swagger

    Produces docs/swagger/swagger.yaml & docs/swagger/swagger.json.

  2. Serve via swagger-ui (optional)

    docker run --rm -p 8087:8080 \
      -e SWAGGER_JSON=/app/swagger.yaml \
      -v ${PWD}/docs/swagger/swagger.yaml:/app/swagger.yaml \
      swaggerapi/swagger-ui

    Visit http://localhost:8087.

Swagger covers:

  • Auth /register /login /me/{id}
  • Hotel /hotels /room-types /rooms (including full CRUD operations)
    • GET /hotels - List all hotels
    • POST /hotels - Create hotel (admin)
    • GET /hotels/{id} - Get hotel by ID
    • PUT /hotels/{id} - Update hotel (admin)
    • DELETE /hotels/{id} - Delete hotel (admin)
    • GET /rooms - List all rooms
    • POST /rooms - Create room (admin)
    • GET /rooms/{id} - Get room by ID
    • PUT /rooms/{id} - Update room (admin)
    • DELETE /rooms/{id} - Delete room (admin)
  • Booking /bookings, cancellation, checkpoint
    • Auto-checkout via CronJob (daily at 10:00 AM)
  • Payment /payments, /payments/webhook
  • Notification /notifications
  • Gateway /gateway/aggregate/bookings/{id}

Auto-Checkout CronJob

  1. Scheduler: Runs daily at 10:00 AM (configurable via cron expression)
  2. Process:
    • Finds all bookings with checkout_date = today AND status = checked_in
    • Automatically transitions them to completed status
    • Publishes domain events for notification
  3. Configuration: Implemented in booking-service using robfig/cron/v3
  4. Graceful Shutdown: Scheduler stops cleanly when service terminates

๐Ÿงช Testing & Linting

make test     # go test ./... -cover
make lint     # go vet ./...

Covered scenarios:

  • Booking creation: happy path, invalid dates, room type not found.
  • Payment webhook: valid/invalid signature propagation.
  • Refund flows: provider success/fail.
  • Booking repository insert via sqlmock.

๐ŸŒŠ Service Flows

Authentication

  1. POST /auth/register: Email normalized, password hashed (bcrypt), role assigned.
  2. POST /auth/login: Returns access_token + refresh_token.
  3. Protected requests: Gateway checks Authorization: Bearer <token>.

Hotel Inventory

  1. Admin Operations (requires JWT with admin role):
    • Create, update, and delete hotels
    • Create, update, and delete rooms
    • Manage room types
  2. Public Operations (no auth required):
    • List hotels and room types
    • Get hotel details by ID
    • Get room details by ID
  3. Soft Delete: Delete operations use soft delete (data retained with deleted_at timestamp)
  4. Availability: Booking service calls Hotel service for stock validation.

Booking Lifecycle

  1. POST /bookings: Validates dates/availability, calculates price, sets status pending_payment.
  2. PATCH /bookings/{id}/cancel: Allowed only while pending; blocked after confirmed/checked_in/completed.
  3. POST /bookings/{id}/checkin: Transitions to checked_in.

Payment + Refund

  1. POST /payments: Initiates payment via mock provider, returns URL.
  2. POST /payments/webhook: Validates HMAC, updates payment status paid, auto-confirms booking.
  3. POST /payments/refund: Records refund, updates status.

Notifications

  1. Triggered by Booking Confirmed or Payment Paid events.
  2. Logs payload (placeholder for email/SMS).

๐Ÿ“ Complete API Reference (Manual / Postman)

Only used to simulate payment webhook (other endpoints are covered in the tester reference above).

Simulate Webhook (Mark Paid)

Bash

PAYLOAD='{"payment_id":"<payment_uuid>","status":"paid"}'
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$PAYMENT_PROVIDER_KEY" -hex | awk '{print $2}')

curl -X POST http://localhost:8088/api/v1/payments/webhook \
  -H "Content-Type: application/json" \
  -d "{\"payment_id\":\"<payment_uuid>\",\"status\":\"paid\",\"signature\":\"$SIG\"}"

PowerShell

$payload = '{"payment_id":"<payment_uuid>","status":"paid"}'
$key     = $env:PAYMENT_PROVIDER_KEY
$hmac    = [System.Security.Cryptography.HMACSHA256]::new([Text.Encoding]::UTF8.GetBytes($key))
$bytes   = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($payload))
$sig     = -join ($bytes | ForEach-Object { $_.ToString('x2') })

curl -X POST http://localhost:8088/api/v1/payments/webhook `
  -H "Content-Type: application/json" `
  -d "{`"payment_id`":`"<payment_uuid>`",`"status`":`"paid`",`"signature`":`"$sig`"}"

Note: use the same PAYMENT_PROVIDER_KEY as the service (default sandbox-key).

๐Ÿ“‹ Makefile Cheat Sheet

Command Description
make run docker-compose up --build
make down docker-compose down -v
make test go test ./... -cover
make lint go vet ./...
make swagger Generate Swagger docs under docs/swagger/

๐ŸŒ API Gateway Modes

  • Whitelist vs Proxy All: Toggle with GATEWAY_MODE=whitelist|proxy_all (default whitelist).
  • Route Map: Loaded from config/routes.yml.
  • Features:
    • Path rewrite/strip-prefix.
    • Auth forwarding/validation.
    • Circuit breaker & Health checks.
    • Observability (/metrics, /debug/routes).

๐Ÿ”ฎ Next Steps & Customization

  • Payment Provider: Implement real Midtrans/Xendit in domain.Provider.
  • Notifications: Replace logger with SMTP/Twilio in domain.Dispatcher.
  • Caching: Add Redis for hotel search.
  • CI/CD: Setup GitHub Actions for make test.
  • New Contexts: Add Inventory or Pricing microservices.

๐Ÿ‘ค Author

Fitry Yuliani

About

A production-grade hotel booking platform built with Go, demonstrating mastery of Domain-Driven Design (DDD), Clean Architecture, and Event-Driven Microservices. Features polyglot persistence (PostgreSQL), advanced domain modeling (Aggregates, Value Objects, Specs), and high-resilience service orchestration via an API Gateway. Built with Go 1.23.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages