Architecture¶
This section provides the technical specifications required for implementing the HNS Ticketing System backend.
Overview¶
The HNS Ticketing System uses a hybrid modular monolith architecture with selective service extraction:
- Core Backend: PHP/Symfony monolith handling most business logic
- Queue Service: standalone
waiting-roomservice (Node 20 + Fastify + Valkey 8), developed in a sibling repo; the backend integrates as the first tenant and gates protected endpoints viaGET /access - Notification delivery: Email via NATS Event Bus → external mailer microservice (Mailgun); push via synchronous Firebase SDK from the request handler. Queue notifications are owned by
waiting-room. See Microservices Strategy → Notification Delivery. - Data Layer: PostgreSQL (system of record — including cart and seat-lock state via
match_seat_inventory.locked_until) + Redis (only the/accessdecision cache) + Grafana Loki (audit logs) + Grafana (dashboards). NATS JetStream is the cross-service event transport.
┌─────────────────────────────────────────────────────────────────────────┐
│ Mobile App / Admin Portal / Quota Portal │
└───────────────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Ticketing Backend (Symfony) │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Bounded Contexts: User/Profile, Match/Stadium, Inventory, Orders, │ │
│ │ Tickets, Quotas, Payments, Loyalty, Blacklist, Support, Petrol │ │
│ └───────────────────────────────────────────────────────────────────┘ │
└────────────┬────────────────────────────────────────────┬───────────────┘
│ │
┌──────▼──────┐ ┌────────▼────────┐
│ waiting-room│ ◄── GET /access ─── │ Notification │
│ (separate │ (1–5s cache) │ Workers (PHP) │
│ deployment) │ │ Email, Push │
│ Node + Fast │ └────────┬────────┘
│ Valkey + PG │ │
└──────┬──────┘ │
│ │
(own DB/Valkey) ┌─────────────────────────┘
│
┌───────────▼───────────────────────────────┐
│ PostgreSQL │ Redis │ Loki │ Grafana │
│ (txn data) │(cache)│(audit)│(dashboards) │
└─────────────────────────────────────────┘
Documentation Index¶
Core Technical Specifications¶
| Document | Description | Use Case |
|---|---|---|
| Architecture Overview | High-level system architecture, component responsibilities, integration patterns | Understanding the big picture |
| Microservices Strategy | Service boundaries, extraction rationale, communication patterns | Understanding deployment decisions |
| Data Model | Complete database schema with all tables, columns, types, constraints, indexes, and relationships | Database design and implementation |
| Audit Logging Infrastructure | Grafana Loki audit log architecture, ingestion, retention, dashboards | Audit log implementation |
| API Specification | OpenAPI 3.0 specification for all REST endpoints | API implementation and integration |
Supporting Documentation¶
| Document | Description |
|---|---|
| Architecture-Features Mapping | How epics/features map to architectural components |
ADR 0001: waiting-room extraction |
Decision record for building the Queue Service as the standalone waiting-room repo |
| Stadium Design Tool Tech | Technical specification for stadium design component |
| Traefik Dashboard | One-pager with clickable links to every local-dev Traefik route |
Quick Reference¶
Technology Stack¶
| Component | Technology | Purpose |
|---|---|---|
| Backend | PHP 8.2+ / Symfony 7.x | Core business logic |
| Queue Service | waiting-room (Node 20 + Fastify 5 + Valkey 8) |
Waiting queue + capacity-mode origin gating |
| Database | PostgreSQL 15+ | System of record |
| Cache (backend) | Redis 7+ | /access decision cache |
| Event bus | NATS JetStream | Cross-service events (mail.*, user.updated, stripe.*, planned domain events) via the hns_ticketing_events stream |
| Payment | Stripe | Card processing |
| Mailgun | Transactional email | |
| Push | Firebase FCM | Mobile notifications |
| Accounting | e-racuni.com | Invoicing/fiscalization |
| Audit Logs | Grafana Loki | Centralized audit log aggregation |
| Audit Dashboards | Grafana | Audit visualization and alerting |
Key Design Decisions¶
- Modular Monolith First: Single deployable with clear module boundaries, extractable later
- PostgreSQL Optimistic Locking:
FOR UPDATE SKIP LOCKEDfor concurrent seat allocation - Postgres-Backed Seat Locks:
match_seat_inventory.locked_untilset tosessionExpiresAtfromwaiting-room'sGET /accessresponse — seat lock and queue session share one clock - Standalone Queue Service:
waiting-room(Node + Valkey) handles 100k+ concurrent WebSocket users; backend gates protected endpoints viaGET /access - Event-Driven Cross-Service Communication: NATS JetStream for everything cross-service (Stripe events,
mail.*,user.updated, planned domain events). Redis is not used as a cross-service transport — only for the/accessdecision cache and the Symfony framework cache/sessions. - Centralized Audit Logging: All audit logs stored in Grafana Loki, keeping PostgreSQL focused on transactional data
API Base URLs¶
| Environment | URL |
|---|---|
| Production | https://api.ulaznice.hns.family/api/v1 |
| Staging | https://api.staging.ulaznice.hns.family/api/v1 |
Authentication¶
All authenticated endpoints require a Bearer token:
Authorization: Bearer <jwt_token>
Tokens are obtained via Drupal SSO integration. See API Specification for details.
For Backend Developers¶
If you're implementing the backend, start with these documents in order:
- Architecture Overview - Understand component responsibilities
- Data Model - Set up database schema
- API Specification - Implement endpoints
- Audit Logging Infrastructure - Configure Loki audit log pipeline
Each endpoint in the API spec references related: - Epic (E1-E15) - Feature files - Business rules
For Frontend Developers¶
The API Specification provides everything needed for frontend integration:
- All REST endpoints with request/response schemas
- Authentication requirements
- Error response formats
- WebSocket protocol for queue (see E5 section)
Key Business Rules Summary¶
| Rule | Value | Reference |
|---|---|---|
| Max tickets per purchase | 4 | E4-F5 |
| Cart reservation timeout | 20 minutes | E4-F4 |
| Queue purchase window | 20 minutes | E5-F4 |
| Self-service transfer cutoff | 48 hours | E9-F5 |
| Loyalty point expiration | 5 years | E6-F1 |
| OIB validation | ISO 7064 MOD 11-10 | E1-F5 |
| Home ticket VAT | 5% | E8-F2 |
| Away ticket VAT | 0% | E8-F2 |
| Service fee | 6% (configurable) | E8-F2 |
Last Updated: May 2026