System Overview
The application is built on a multi-layer architecture pattern:Core Components
Entry Point
The server starts fromcmd/server/main.go:21 which:
- Loads configuration from environment variables
- Initializes structured logging
- Establishes database connection
- Wires up all services and dependencies
- Starts the HTTP server with graceful shutdown support
Server Initialization Code Flow
Server Initialization Code Flow
API Layer
The API layer (internal/api/api.go:18) serves as the dependency injection container, holding references to all services:
- Database: PostgreSQL connection via
sqlcgenerated queries - OAuth Service: 42 Intranet authentication provider
- Auth Service: JWT token generation and validation
- Email Service: SMTP-based email notifications
- Calendar Service: Google Calendar integration
- Reservation Service: Core business logic
All services are initialized once during startup and shared across all handlers. This singleton pattern ensures efficient resource usage and consistent state management.
Handler Layer
Handlers (internal/handler/handler.go:14) receive HTTP requests and:
- Parse and validate request data
- Extract authenticated user from context
- Call appropriate service methods
- Format and return JSON responses
Service Layer
The service layer contains all business logic. Key services include: ReservationService (internal/service/reservation.go:26)
- Validates business rules (duration limits, overlapping bookings)
- Manages database transactions
- Coordinates asynchronous operations (email, calendar)
internal/oauth/service.go:17)
- Orchestrates OAuth 2.0 flow with 42 Intranet
- Validates campus affiliation (must be Hive Helsinki)
- Creates or finds users in the database
internal/auth/auth.go:28)
- Issues JWT access tokens with 1-hour expiration
- Verifies token signatures and claims
- Manages user context propagation
Data Layer
The data layer handles all external integrations: Database (internal/database/db.go)
- PostgreSQL via
database/sqlandsqlc - Type-safe query generation
- Transaction support with isolation levels
- Models: User, Room, Reservation
internal/email/email_service.go:21)
- SMTP client with TLS
- HTML template rendering
- Retry logic with exponential backoff (3 attempts)
internal/google/calender.go:27)
- Google Calendar API v3
- Service account authentication
- Automatic retry on transient failures
Request Flow
A typical reservation creation follows this path:- HTTP Request →
POST /api/v1/reservations - Rate Limiting → Middleware checks per-IP limits
- Authentication → Middleware extracts and validates JWT
- Authorization →
RequireAuthmiddleware ensures user is authenticated - Handler → Parses request body, validates fields
- Service → Checks business rules, creates transaction
- Database → Checks for conflicts, inserts reservation
- Async Tasks → Calendar event creation and email confirmation (non-blocking)
- Response → Returns created reservation as JSON
Middleware Stack
Requests pass through middleware in this order:internal/middleware/ratelimit.go:16)
- Per-IP token bucket algorithm
- OAuth endpoints: 5 requests per 12 seconds
- API endpoints: 30 requests per 2 seconds
- Automatic cleanup of stale visitor records
internal/middleware/auth.go:13)
- Extracts Bearer token from
Authorizationheader - Verifies JWT signature and expiration
- Adds user to request context
- Allows request to continue even without valid token (for public endpoints)
internal/middleware/auth.go:52)
- Enforces authentication requirement
- Returns
401 Unauthorizedif user not in context - Used only on protected endpoints
Configuration Management
Configuration is loaded from environment variables (internal/config/config.go:14):
- Server: Port, timeouts (read/write/idle)
- Database: PostgreSQL connection string
- OAuth: 42 API credentials and endpoints
- JWT: Secret key for token signing
- Email: SMTP server credentials
- Google: Service account credentials and calendar ID
Graceful Shutdown
The server implements graceful shutdown (cmd/server/main.go:76):
- Listens for
SIGINTorSIGTERMsignals - Stops accepting new connections
- Waits up to 15 seconds for active requests to complete
- Closes database connections
- Exits cleanly
- No requests are dropped mid-processing
- Database connections are properly released
- Clean deployment with zero downtime
Error Handling
Errors are handled consistently across layers:- Service Layer: Returns domain-specific errors with status codes
- Handler Layer: Translates errors to appropriate HTTP responses
- Logging: All errors are logged with structured context using
slog
Database Schema
The system uses three main tables: usersid: Primary keyemail: Unique, from 42 Intranetname: Display namerole:STUDENTorSTAFF
id: Primary keyname: Room identifier (e.g., “Kalevala”)
id: Primary keyuser_id: Foreign key to usersroom_id: Foreign key to roomsstart_time: Reservation start (timestamp)end_time: Reservation end (timestamp)status:RESERVED(future:CANCELLED,COMPLETED)gcal_event_id: Google Calendar event ID (nullable)
The database uses
sqlc for type-safe query generation. All SQL queries are defined in .sql files and compiled to Go code at build time.