Architecture
This document describes the high-level architecture of Sessiq, including system design, components, data flow, and key architectural decisions.
System Overview
Sessiq is a multi-tenant SaaS platform designed as a modular monolith with clear domain boundaries. It provides booking management for leisure activities, supporting multiple venues, products, resources, and customers.
Architecture Style
Modular Monolith: All modules run in a single process but are organized as distinct domain modules with well-defined interfaces. This provides:
- Clear separation of concerns
- Independent testing capabilities
- Easier future migration to microservices if needed
- Simpler deployment and operations
Tech Stack
| Component | Technology | Version |
|---|---|---|
| API Framework | NestJS (Fastify 5 adapter) | 11.x |
| Frontend | Next.js (App Router) | 15.x |
| UI Library | React | 19.x |
| Database | PostgreSQL + Prisma ORM | 15+ / 5.x |
| Runtime | Node.js | 20+ |
| Package Manager | pnpm (workspaces) | 9.x |
| Payments | Stripe + Paytrail | 14.x |
| Testing | Vitest (unit) + Jest (int/e2e) | 2.x / 30.x |
Backend:
- Framework: NestJS 11 (with Fastify 5 adapter for performance)
- Language: TypeScript (strict mode)
- Database: PostgreSQL 15+ with Prisma ORM
- Caching: Redis (for availability caching)
- Background Jobs: Worker service with queue processing
Frontend:
- Framework: Next.js 15 (App Router)
- UI Library: React 19
- Styling: Tailwind CSS
- State Management: React hooks and context
Infrastructure:
- Containerization: Docker
- Orchestration: Docker Compose (local), Kubernetes (production)
- Observability: Prometheus metrics, structured logging
External Services:
- Payments: Stripe, Paytrail
- Notifications: Brevo (email), Twilio (SMS)
- Storage: PostgreSQL (data), S3 (files, future)
System Architecture
High-Level Components
┌─────────────────────────────────────────────────────────────┐
│ Client Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Web App │ │ Mobile App │ │ Admin UI │ │
│ │ (Next.js) │ │ (Future) │ │ (Next.js) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ API Gateway (BFF) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ NestJS API Server (Fastify) │ │
│ │ • Authentication & Authorization │ │
│ │ • Request Routing │ │
│ │ • Input Validation │ │
│ │ • Response Transformation │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Domain Modules │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Catalog │ │ Scheduling │ │ Booking │ │
│ │ Module │ │ Engine │ │ Orchestrator │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Pricing │ │ Payments │ │ Notifications│ │
│ │ Engine │ │ Module │ │ Module │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Data Layer │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ PostgreSQL with Row-Level Security (RLS) │ │
│ │ • Multi-tenant data isolation │ │
│ │ • ACID transactions │ │
│ │ • Audit trails │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Background Services │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Worker │ │ Outbox │ │ SSE Stream │ │
│ │ Service │ │ Processor │ │ (Admin) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
Core Modules
1. Catalog Module
Purpose: Manage products, variants, resources, and add-ons.
Key Components:
- Product CRUD operations
- Variant management
- Resource allocation
- Add-on configuration
- Site management
Responsibilities:
- Product definition and metadata
- Resource capacity configuration
- Add-on inventory tracking
- Catalog versioning
2. Scheduling & Availability Engine
Purpose: Generate available time slots from schedule templates, overrides, and resource availability.
Key Components:
- Schedule template processor
- Slot generation engine
- Availability calculator
- Capacity checker
- Label matcher
Responsibilities:
- Recurring pattern processing
- Timezone handling
- Blackout window management
- Capacity pool management
- Slot label application
Data Flow:
Schedule Templates → Effective Hours → Slot Generation →
Capacity Check → Label Matching → Available Slots
3. Booking Orchestrator
Purpose: Manage the booking lifecycle from hold to confirmation using a Saga pattern for distributed transactions.
Key Components:
- Saga orchestrator: Coordinates multi-step workflows
- State machine: Tracks booking status transitions
- Compensation handlers: Automatic rollback on failures
- Policy evaluator: Validates business rules
- Capacity locker: Ensures resource availability
- Hold management: TTL-based automatic expiration
Booking Lifecycle:
Hold → Pricing → Payment → Confirm → Notify → Complete
│ │ │ │ │ │
└───────┴────────┴─────────┴────────┴─────────┘
Saga Steps with Compensation
Booking Statuses:
hold: Temporary reservation (15-minute TTL by default)tentative: Hold extended for payment processingpart_paid: Partial payment received (voucher + external)paid: Fully paid and confirmedcanceled: Customer cancelledno_show: Customer did not arrivecompleted: Activity finished
Saga Pattern:
- Each step is transactional with checkpointing
- Automatic compensation for rollback on failures
- Retry mechanisms with exponential backoff
- Idempotency guarantees via correlation IDs
- State tracking:
not_started → running → completed/failed - Compensation states:
none → pending → in_progress → completed
Multi-Slot Bookings:
Bookings can span multiple time slots with atomic capacity management:
- BookingSlot junction table links slots to bookings
- Capacity consumed tracked per slot
- Atomic locking across all slots during hold creation
- Cascading release on cancellation
Hold Expiration:
- Automatic TTL-based expiration (default: 15 minutes)
- Worker service processes expired holds
- Capacity automatically released
- Prevents slot hogging
4. Pricing Engine
Purpose: Calculate booking prices with rules, modifiers, promotions, and tax.
Key Components:
- Price resolver service
- Ruleset evaluator
- Promotion validator
- Tax calculator
- Pricing hash generator
Pricing Flow:
Base Price → Tier Pricing → Temporal Modifiers →
Promotions → Vouchers → Tax → Final Price
Price Rules:
- Base prices
- Party size tiers
- Temporal modifiers (peak/off-peak)
- Participant type pricing
- Label modifiers
5. Payments Module
Purpose: Process payments through multiple providers with webhook handling and comprehensive payment lifecycle management.
Key Components:
- Payment adapters: Provider-specific implementations
- Stripe adapter: Credit/debit cards with Authorize & Capture
- Paytrail adapter: Finnish payment gateway for local methods
- Payment orchestrator: Coordinates payment workflow
- Refund engine: Automatic and manual refund processing
- Webhook processors: Secure webhook verification and handling
- Payment ledger: Transaction history and auditing
- Fee assessment service: No-show and cancellation fees
Payment Flow:
Authorization → Capture → Confirmation → Webhook →
Ledger Update → Notification
Supported Methods:
- Stripe: Credit/Debit cards with 3D Secure
- Paytrail: Finnish local payment methods (online banking, mobile)
- Payment on Arrival (PoA): Pay at venue
- Vouchers: Gift cards and prepaid credits
- Mixed Tender: Voucher + external payment method
Payment Security:
- Webhook signature verification (HMAC)
- Replay attack prevention with idempotency keys
- PCI DSS compliant (tokenization)
- Audit trail for all transactions
Refund Processing:
- Automatic refund calculation based on cancellation policy
- Fee deduction for late cancellations
- Partial refund support
- Multi-step refund workflow
- Async processing with compensation
No-Show Fee Management:
- Automatic fee assessment on no-show status
- Configurable fee amounts and policies
- Payment capture for fees
- Grace period handling
6. Notifications Module
Purpose: Send email and SMS notifications with templating, reliable delivery tracking, and the Outbox Pattern for at-least-once delivery guarantees.
Key Components:
- Notification service: Event-driven notification creation
- Template engine: Dynamic content personalization
- Outbox pattern: Transactional event store
- Outbox worker: Background processing with retry logic
- Provider adapters: Multi-channel delivery
- Brevo: Transactional email delivery
- Twilio: SMS delivery (future)
- Delivery tracking: Status monitoring and DLQ handling
- Alert evaluator: Threshold-based alerting for failures
Notification Flow:
Event → Template Selection → Personalization →
Outbox Write (Same TX) → Worker Picks Up →
Provider Adapter → Delivery → Mark Sent
↓ (on failure)
Retry with Backoff → DLQ after max attempts
Notification Types:
- Booking confirmations
- Payment receipts
- Cancellation notices
- Pre-arrival reminders
- No-show alerts
- Payment on Arrival (PoA) reminders
Outbox Pattern Details:
- Transactional writes: Notifications written to outbox in same transaction as booking
- At-least-once delivery: Guaranteed delivery even if app crashes
- Worker-based processing: Background workers poll outbox table
- Exponential backoff: Configurable retry intervals (1s, 2s, 4s, 8s, etc.)
- Dead Letter Queue (DLQ): Failed messages after max retries
- Idempotent consumers: Providers handle duplicate delivery
- Monitoring: Alert when DLQ threshold exceeded
DLQ Alert System:
- Monitors outbox message failures
- Threshold-based alerting (configurable: 5, 10, 20+ messages)
- Admin dashboard for DLQ inspection
- Manual retry capability
- Root cause analysis support
7. Saga Orchestration Module
Purpose: Coordinate distributed transactions across multiple services with automatic compensation on failures using the Saga pattern.
Key Components:
- Saga orchestrator: Central coordinator for multi-step workflows
- State machine: Tracks saga execution state and progress
- Retry worker: Background service for automatic retry with exponential backoff
- Compensation handlers: Rollback logic for each saga step
- Checkpoint manager: State persistence for failure recovery
- Correlation tracking: End-to-end tracing with correlation IDs
Saga States:
not_started: Saga initialized but not yet executingrunning: Saga currently executing stepscompleted: All steps completed successfullyfailed: Saga failed and compensation completedcompensating: Rolling back completed stepstimeout: Saga exceeded maximum execution timecancelled: Saga manually cancelled
Compensation States:
none: No compensation neededpending: Compensation queuedin_progress: Actively compensatingcompleted: All compensations successfulpartial: Some compensations failedfailed: Compensation failed completely
Saga Execution Flow:
Initialize Saga → Execute Step 1 → Checkpoint
↓
Execute Step 2 → Checkpoint
↓
Execute Step 3 → Checkpoint
↓ (Success)
Mark Complete
(On Failure at Step 3)
↓
Trigger Compensation
↓
Compensate Step 2 → Compensate Step 1
↓
Mark Failed with Compensation
Key Features:
- Checkpointing: Each step success persisted before next step
- Automatic retry: Failed steps retried with exponential backoff (1s, 2s, 4s, 8s, 16s...)
- Idempotency: Steps can be safely retried without side effects
- Correlation IDs: Track saga execution across logs and services
- Timeout handling: Maximum execution time prevents infinite loops
- Manual intervention: Admin can retry or cancel sagas
- Monitoring: Real-time saga state visibility
Common Saga Patterns:
Booking Confirmation Saga:
1. Lock capacity
2. Calculate final price
3. Process payment
4. Confirm booking
5. Send notifications
On failure: Release capacity → Refund payment → Cancel booking
Cancellation Saga:
1. Validate cancellation policy
2. Release capacity
3. Process refund
4. Update booking status
5. Send cancellation notice
On failure: Re-lock capacity → Cancel refund → Restore booking
Implementation Details:
- Saga state stored in
Bookingtable (saga_state,saga_correlation_id) - Worker service polls for pending sagas and retries
- Compensation handlers mirror forward step logic
- All saga operations logged with correlation ID
- Failed sagas after max retries moved to DLQ for manual review
8. Promotions & Vouchers Module
Purpose: Manage discount codes, promotional campaigns, and gift card/voucher systems with sophisticated stacking rules.
Key Components:
- Promotion service: Validation and application logic
- Voucher service: Gift card balance and redemption
- Stacking engine: Multi-promotion conflict resolution
- Promotion validator: Eligibility checking (date, usage, minimums)
- Voucher ledger: Balance tracking and transaction history
Promotion Types:
- Percentage discounts: 10%, 25%, 50% off
- Fixed amount: €10 off, €25 off
- Free items: Complimentary add-ons
- BOGO: Buy-one-get-one promotions
- Seasonal campaigns: Holiday specials, peak/off-peak
Voucher Features:
- Pre-loaded balance: Gift cards with initial amount
- Partial redemption: Use portion of balance
- Expiration dates: Time-limited validity
- Stock tracking: Limited quantity vouchers
- Usage limits: Single-use or multi-use
- Transfer restrictions: Non-transferable vouchers
Promotion Stacking:
Booking Price: €100
├─ Promotion 1 (20% off): -€20 → €80
├─ Promotion 2 (€10 off): -€10 → €70
└─ Voucher (€30 balance): -€30 → €40 (final price)
Stacking Rules:
- Maximum 2 percentage promotions
- Fixed amount promotions stack additively
- Vouchers applied last
- Final price cannot be negative
Validation Rules:
- Minimum spend requirements
- Product/variant eligibility
- Date range (valid from/to)
- Usage per customer limits
- Total usage limits across all customers
- Blackout dates exclusions
- Site/location restrictions
Conflict Resolution:
When multiple promotions conflict:
- Check mutual exclusivity rules
- Apply highest-priority promotion first
- Validate stacking permissions
- Calculate cumulative discount
- Ensure minimum price thresholds
Voucher Redemption Flow:
Apply Voucher Code → Validate Stock → Check Balance →
Check Expiration → Lock Balance (Tentative) →
Payment Complete → Deduct Balance → Mark Used
↓ (On Failure)
Release Locked Balance → Voucher Available Again
9. Admin Module
Purpose: Provide comprehensive administrative interfaces and operations for managing bookings, resources, and platform configuration.
Key Components:
- Admin controllers: CRUD operations for all admin entities
- Calendar management: Real-time calendar with SSE streaming
- Resource maintenance: Scheduled downtime and capacity adjustments
- Reporting endpoints: Analytics and business intelligence
- Audit logging: Comprehensive action tracking
- No-show management: Fee processing and customer tracking
- Booking move API: Precheck and commit booking rescheduling
Calendar Management (SSE):
Server-Sent Events (SSE) streaming for real-time calendar updates:
Client connects → SSE stream opens →
Real-time events pushed to client:
- New bookings created
- Booking status changes
- Cancellations
- Resource availability updates
- Maintenance windows
Calendar Features:
- Multi-site view: View bookings across multiple locations
- Drag-and-drop rescheduling: Visual booking moves with validation
- Real-time sync: All admins see updates instantly via SSE
- Capacity visualization: Color-coded capacity indicators
- Time slot management: Block/unblock slots for maintenance
- Filtering: By site, product, status, date range
No-Show Management:
Automated no-show detection and fee processing:
Booking Start Time + Grace Period → Auto-detect no-show →
Assess Fee → Process Payment → Update Status → Notify Customer
No-Show Features:
- Grace period: Configurable time after start (default: 15 minutes)
- Manual marking: Admin can mark no-show before auto-detection
- Fee assessment: Percentage or fixed fee from booking price
- Payment capture: Automatic charge for no-show fees
- Customer notifications: Email/SMS alerts
- Dispute handling: Admin override and refund capability
- Tracking dashboard: No-show rates and fee collection stats
Booking Move API:
Two-phase commit for safe booking rescheduling:
Phase 1 - Precheck:
POST /api/v1/admin/bookings/{id}/move/precheck
Validates:
- New slot availability
- Capacity constraints
- Policy compliance
- Price difference calculation
Returns: Move plan with price adjustment
Phase 2 - Commit:
POST /api/v1/admin/bookings/{id}/move/commit
Executes:
- Release old slot capacity
- Lock new slot capacity
- Update booking details
- Process payment adjustment (if needed)
- Send notifications
All operations atomic via Saga pattern
Resource Maintenance:
- Scheduled downtime: Plan resource unavailability
- Capacity adjustments: Temporary capacity changes
- Recurring maintenance: Weekly/monthly patterns
- Impact analysis: Preview affected bookings
- Automatic notifications: Alert customers of changes
Admin Dashboard:
- Real-time metrics: Active bookings, revenue, capacity utilization
- Quick actions: Common operations accessible from dashboard
- Alert notifications: DLQ failures, payment issues, high no-show rates
- Activity feed: Recent booking changes and admin actions
Reporting & Analytics:
- Revenue reports by site/product/time period
- Booking trends and forecasting
- No-show rate tracking
- Promotion effectiveness analysis
- Capacity utilization metrics
- Customer behavior insights
Data Flow
Booking Creation Flow
1. Customer selects product/variant
↓
2. Query availability (Scheduling Engine)
↓
3. Select slot and add-ons
↓
4. Calculate price (Pricing Engine)
↓
5. Apply promotions/vouchers
↓
6. Create hold (Booking Orchestrator)
↓
7. Process payment (Payments Module)
↓
8. Confirm booking (Orchestrator)
↓
9. Send notifications (Notifications Module)
↓
10. Update capacity (Scheduling Engine)
Availability Query Flow
1. Request availability
↓
2. Get effective schedules (Scheduling Engine)
↓
3. Generate slots for date range
↓
4. Check capacity (Capacity Checker)
↓
5. Apply blackouts/maintenance
↓
6. Match slot labels
↓
7. Return available slots
Payment Processing Flow
1. Payment request
↓
2. Validate payment method
↓
3. Authorize payment (Payment Adapter)
↓
4. Create payment intent
↓
5. Process payment
↓
6. Webhook received
↓
7. Update booking status
↓
8. Send confirmation
Multi-Tenancy Architecture
Tenant Resolution
The system automatically resolves tenant context from the request domain, enabling white-label deployments:
Resolution Methods (in priority order):
- JWT Token - Tenant ID extracted from authenticated user
- Subdomain -
acme.booking.com→ tenantacme - Custom Domain -
booking.acme.com→ mapped tenant - Header Fallback -
x-tenant-idheader (development/API clients)
Resolution Flow:
Request → TenantResolverMiddleware → TenantGuard → RLS Context
(subdomain/domain) (validates) (enforces)
Local Development:
For local testing, use *.localhost subdomains:
# Access demo tenant
http://demo.localhost:3000
# API calls
curl http://demo.localhost:3001/api/v1/availability
See the Tenant Resolution Guide for detailed configuration.
Tenant Isolation
Row-Level Security (RLS):
- Database-level tenant filtering
- Automatic query filtering
- Prevents data leakage
- No application-level filtering needed
Implementation:
-- Example RLS policy
CREATE POLICY tenant_isolation ON booking
FOR ALL
USING (tenant_id = current_setting('app.current_tenant_id')::text);
Tenant Context:
- Set per-request via middleware
- Available throughout request lifecycle
- Enforced at database level
- Cannot be bypassed
Tenant Data Model
Tenant (root)
├── Sites (venues)
│ ├── Products (activities)
│ │ ├── Variants
│ │ └── Resources
│ └── Schedules
├── Bookings
├── Payments
└── Configuration
Key Design Decisions
1. Modular Monolith
Decision: Use modular monolith instead of microservices.
Rationale:
- Phase 1 doesn't require microservices complexity
- Easier development and deployment
- Can split later if needed
- Clear module boundaries prepare for migration
2. Saga Pattern for Bookings
Decision: Use Saga pattern for distributed booking transactions.
Rationale:
- Multiple steps (hold, pricing, payment, confirm)
- Need compensation on failures
- Long-running transaction
- Better than 2PC for this use case
3. Row-Level Security
Decision: Enforce tenant isolation at database level.
Rationale:
- Security by default
- Prevents data leakage
- Simplifies application code
- Performance at database level
4. Outbox Pattern
Decision: Use outbox pattern for notifications.
Rationale:
- Guarantees delivery
- Prevents lost notifications
- Allows retry mechanism
- Eventually consistent
5. Pricing Hash
Decision: Use pricing hash for price consistency.
Rationale:
- Prevents price changes mid-flow
- Ensures price consistency
- Audit trail
- Customer fairness
Scalability Considerations
Horizontal Scaling
API Server:
- Stateless design
- Can scale horizontally
- Load balancer distribution
- Shared database connection pool
Worker Service:
- Process queues independently
- Horizontal scaling supported
- Job distribution via queues
Database Scaling
Read Replicas:
- Availability queries can use replicas
- Reduces load on primary
- Eventual consistency acceptable
Partitioning:
- Potential tenant-based partitioning
- Not implemented in Phase 1
- Can be added for large tenants
Caching Strategy
Availability Caching:
- Cache slot generation results
- TTL-based invalidation
- Redis for shared cache
- Cache warming for popular queries
Security Architecture
Authentication
JWT Tokens:
- Stateless authentication
- Tenant ID in claims
- Role-based claims
- Token expiration
Authorization
RBAC (Role-Based Access Control):
- Roles: Admin, Operator, Viewer
- Permissions: Resource-level
- Policy-based evaluation
- Audit logging
Data Protection
Encryption:
- TLS in transit
- Encryption at rest (database)
- Secure credential storage
- PII handling
Audit Trail
Comprehensive Logging:
- All mutations logged
- Immutable audit records
- User attribution
- Compliance ready
Observability
Logging
Structured Logging:
- JSON format
- Correlation IDs
- Log levels
- Context enrichment
Metrics
Prometheus Metrics:
- Request counts
- Response times
- Error rates
- Business metrics
Tracing
Distributed Tracing (Future):
- Request correlation
- Performance analysis
- Dependency mapping
Error Handling
Error Types
Validation Errors:
- Input validation
- Business rule violations
- Returned to client
System Errors:
- Infrastructure failures
- Retryable errors
- Circuit breakers
Compensation:
- Saga compensation
- Rollback operations
- Idempotent handlers
Resilience Patterns
Retries:
- Exponential backoff
- Max retry limits
- Idempotent operations
Circuit Breakers:
- Failure threshold
- Automatic recovery
- Fallback handlers
Degradation:
- Graceful degradation
- Feature flags
- Fallback modes
Development Workflow
Module Structure
Each module follows consistent structure:
module-name/
├── module-name.controller.ts # REST endpoints
├── module-name.service.ts # Business logic
├── module-name.module.ts # NestJS module
├── dto/ # Data Transfer Objects
└── __tests__/ # Tests
Shared Packages
@booking/db: Database schema and DAL
@booking/contracts: Shared TypeScript types
@aetech/scheduling-engine: Scheduling logic
@repo/observability: Logging and metrics
Future Architecture Evolution
Potential Migrations
Microservices (if needed):
- Extract modules to services
- Maintain clear boundaries
- API gateway for routing
- Service mesh for communication
Event-Driven (future):
- Event sourcing for bookings
- CQRS pattern
- Event bus for decoupling
Caching Layer:
- More aggressive caching
- Cache invalidation strategies
- CDN for static assets
Performance Targets
API Response Times:
- 95th percentile < 200ms
- Availability queries < 100ms
- Booking creation < 500ms
Throughput:
- Support 1000+ concurrent users
- Handle peak booking periods
- Scale horizontally
Database:
- Query optimization
- Index strategy
- Connection pooling
Next Steps
- Learn about Database Schema for data model details
- Review Setup Guide for development environment
- Check Testing Guide for testing strategies
- Explore API Reference for API details