seatr
Event ticketing platform — real-time inventory, intelligent import, multi-tenant SaaS
A full-stack, multi-tenant event ticketing SaaS built as a Turborepo monorepo — 4 frontend apps, 6 shared packages, 21 backend services, ClickHouse OLAP analytics, real-time WebSocket inventory, and an intelligent ticket matching engine. End-to-end TypeScript type safety from database to UI.
Create an event. Import inventory. Sell tickets. Real-time, multi-tenant, five languages.
Mid-size event organizers in Central Europe had no modern ticketing platform. At all.
Existing solutions — Eventbrite, Ticketmaster — are expensive, US-focused, and offer no Hungarian or German localization. Smaller organizers were stuck with Excel spreadsheets, disconnected payment systems, and zero real-time visibility into ticket sales. Multi-venue operators had no unified dashboard. Overselling seats meant angry customers, refund costs, and reputational damage.
Most organizers receive venue seating inventory as CSV or Excel files from venue partners. No existing platform handled this import-and-match workflow. Manual reconciliation consumed 5–10 hours per week — per organizer, per event. The gap was clear: a platform combining real-time inventory, intelligent bulk import, multi-tenant organization support, and a modern booking experience — with proper internationalization for Central Europe.
architecture-first decisions
Every major technology choice was driven by real user needs — not trend-chasing. ClickHouse because organizers need fast analytics. WebSockets because customers need real-time availability. The matching engine because organizers receive inventory as CSV files.
ClickHouse over PostgreSQL
Event ticketing generates massive read-heavy analytical workloads — revenue reports, inventory aggregations, dashboard metrics. ClickHouse's columnar OLAP architecture handles these 10–100x faster than traditional RDBMS. Sub-100ms on queries that would take seconds in PostgreSQL.
Real-time or nothing
For seated events, showing stale availability is worse than no availability. Socket.io-driven live inventory became a core architectural decision — not a feature added later. When a ticket sells, every connected client sees it instantly.
Multi-tenancy from day one
Building organization support as an afterthought would require a painful migration. We implemented it as a foundational architectural layer — every query, every service, every endpoint scoped by organization context from the start.
Monorepo with type safety
With 4 frontend apps, 6 shared packages, and a backend, code sharing through a Turborepo monorepo was essential. A single TypeScript type flows from database schema through the API to the React component. A type change propagates everywhere at compile time.
four apps, one monorepo
The platform consists of four independently deployable frontend applications, a backend API server, and six shared packages — all in a single Turborepo monorepo with end-to-end TypeScript type safety.
Express.js REST API
17 controllers, 21 services, 15+ route modules. JWT authentication with refresh token rotation, Stripe webhook handling, Socket.io WebSocket server for real-time inventory, CSV/Excel parsing with the ticket matching engine, and ClickHouse queries with parameterized syntax.
Layered middleware: authentication → organization context → role verification → Zod input validation → service logic. Helmet security headers, CORS, rate limiting, and Winston logging across every endpoint.
React admin dashboard
The power-user tool that drives adoption. Event, venue, ticket type, and inventory management. CSV/Excel bulk import with preview and schema mapping. Matching rules visual editor. Order tracking, user and organization administration, analytics dashboard with Recharts.
TanStack Table for data grids, react-hook-form with Zod validation, TanStack Query with 5-minute stale times reducing redundant API calls by 80%+. Full CMS: FAQs, pages, banners, settings, legal pages, and translation management.
Customer web app & landing page
Modern event discovery with category, date, and price filters. Real-time ticket availability via Socket.io. Stripe Elements checkout flow with digital QR-code tickets. Social login (Google, Facebook), user accounts, and mobile-responsive Tailwind design.
The landing page is a lightweight CMS-driven marketing site — featured events, feature highlights, and CTAs — optimized for Core Web Vitals. Both deploy independently to Firebase Hosting with aggressive CDN caching.
ticket matching engine
The killer feature. A sophisticated rule-based system for automatically matching imported CSV/Excel inventory to internal ticket types. Supports 12 match operators (equals, contains, regex, range, in, exists — and their negations), nested AND/OR logic groups, priority-based evaluation, and custom expressions.
Organizers upload venue inventory CSVs and tickets are automatically categorized — "Section A, Rows 1–5" → "VIP Front Row." 10,000+ tickets processed and matched in under 30 seconds. A recursive evaluator walks the MatchGroup tree with short-circuit evaluation for performance. No eval() — custom expressions use a safe parser.
WebSocket inventory
Socket.io-driven live ticket availability. Clients subscribe to event rooms and receive instant updates when tickets are reserved, released, or sold. Optimistic reservation sets ticket status to "reserved" with a TTL when checkout starts — if payment fails or times out, the ticket releases automatically.
Room-based subscriptions ensure clients only receive relevant events. Heartbeating, reconnection logic, and polling fallback handle unstable connections. Cloud Run's request-based scaling required careful sticky session configuration to prevent dropped WebSocket connections during instance scale-down.
key integrations & systems
Every integration custom-built. Every system designed for multi-tenant isolation, type safety, and production-grade security.
Stripe end-to-end
PaymentIntent creation on order, Stripe Elements on the frontend, webhook handling for payment confirmation, failure, and cancellation. Automatic order status updates, billing information capture, payment method management, and refund support. Webhook signature verification prevents spoofed payment events.
Subscription-based pricing for organizers with usage tracking. The entire payment flow is testable in Stripe's sandbox — every edge case (declined cards, 3D Secure, webhook retries) was tested before production.
JWT + OAuth2 social login
Three login methods: email/password with bcryptjs hashing, Google OAuth2, and Facebook OAuth2 — with automatic account linking. JWT access tokens (15-minute TTL) paired with 7-day refresh tokens stored in httpOnly, secure, sameSite cookies with rotation on every use.
Super admin impersonation with audit trail (impersonatedBy in JWT payload). Organization context extracted from JWT via multitenancy middleware — every downstream query is automatically scoped. Missing a single org filter would leak data across tenants.
CSV/Excel bulk pipeline
Complete import workflow: file upload via Multer, server-side parsing (Papa Parse for CSV, XLSX for Excel), instant preview of first 10 rows, schema column mapping UI, matching engine execution, batch creation with progress tracking, and detailed error reporting per row.
10MB upload limit prevents oversized attacks. Import batches track total, successful, and failed rows. The column mapping UI lets organizers connect their CSV headers to Seatr fields once — subsequent imports from the same venue use the saved mapping automatically.
5 locales across 4 apps
Full i18n for English, Hungarian, German, Spanish, and French using react-i18next with namespace separation (common, auth, events, checkout, account, admin). Browser language detection with user override. Backend API responses are also localized — error messages, email templates, notification text.
Admin translation management UI lets the team update any string in any locale without developer involvement. Zero hardcoded strings across the entire platform — every user-facing text is a translation key.
administration & analytics
A comprehensive admin dashboard built with React, TanStack Table, and Recharts — powered by ClickHouse aggregation queries that return in under 100ms.
Full event lifecycle
Create events with ticket types, pricing tiers, and sales windows. Manage venues with seating configurations. Import inventory from CSV/Excel with the matching engine. Track sales in real-time.
- Event creation with ticket types
- Venue & seating management
- CSV/Excel inventory import
- Matching rules visual editor
Multi-tenant management
Full multi-tenancy with role-based access — Owner, Admin, Manager, Viewer. Team member invitations with email tokens. Organization switching for operators managing multiple venues. Super admin impersonation for support.
- 4-tier role-based access control
- Team invitations with token auth
- Organization switching
- Super admin impersonation
Admin-managed content
FAQs, CMS pages, banners with scheduling and positioning, site settings (key-value store), legal pages, and translation management — all editable by the business team without developer involvement.
- FAQ & CMS page editor
- Scheduled banner management
- Site settings key-value store
- Translation management UI
Oversales — real-time WebSocket inventory
10,000+ ticket CSV import & matching
ClickHouse dashboard query response
Languages across 4 apps — zero hardcoded strings
ClickHouse is extraordinary for reads. Mutations required a new mental model.
No UPDATE, no DELETE
ClickHouse has no traditional row-level mutations — only ALTER TABLE mutations with FINAL reads. This fundamentally changes how you handle status updates (ticket reserved → sold → cancelled). We designed around ReplacingMergeTree engines and FINAL queries for every read needing current state. The first two weeks were spent rewriting queries that worked in PostgreSQL but silently returned wrong data in ClickHouse.
JOIN column conflicts
SELECT * with JOINs silently prefixes conflicting columns with table aliases — breaking object mapping in application code. Every JOIN query had to use explicit column selection and aliasing. A mandatory code pattern was established: never use SELECT * in JOINs. This pattern is documented in project instructions and enforced through code review.
Multi-tenant data isolation is not a feature. It's a security requirement.
Authorization & isolation
JWT access tokens with refresh rotation in httpOnly cookies. Organization-scoped queries prevent cross-tenant leakage — multitenancy middleware extracts org context from JWT and attaches it to every request. 4-tier role-based access control. Zod schema validation on all API inputs. Parameterized ClickHouse queries prevent SQL injection.
Infrastructure hardening
Helmet security headers (CSP, X-Frame-Options, HSTS). CORS restricted to specific allowed origins per environment. Rate limiting on all endpoints. Stripe webhook signature verification. File upload validation via Multer. bcryptjs password hashing with 10 salt rounds. Super admin impersonation tracked in JWT audit trail.
Intelligent ticket matching
No other mid-market platform offers a rule-based matching engine for bulk inventory import. 12 operators, nested AND/OR groups, regex, custom expressions — automating what organizers did manually for years.
ClickHouse analytics
OLAP instead of RDBMS. Dashboard aggregations — revenue trends, sales funnels, top events — respond in milliseconds even across millions of ticket records. A deliberate trade-off that defines the platform's speed.
End-to-end type safety
A single TypeScript type definition flows from ClickHouse schema through Express service, to API response, through typed API client, to React component. A type change in one place propagates everywhere at compile time.
Full-stack single ownership
One developer designing and implementing every layer: 28 database migrations, 21 services, 4 frontend apps, 6 shared packages, Stripe integration, WebSocket system, OAuth, CMS, and cloud deployment. Zero handoff gaps.
From Excel spreadsheets
to real-time platform.
Seatr transformed event management from fragmented manual processes into a unified, real-time platform. The CSV/Excel import with intelligent matching eliminated hours of manual inventory reconciliation per event. Multi-tenant organization support means a single operator manages all venues and events from one dashboard with proper team access controls.
For customers: modern, mobile-friendly event discovery and booking. Real-time availability, secure Stripe payment, digital QR-code tickets, and social login. Five-language support serves the diverse Central European market. A scalable, cloud-native SaaS architecture that grows from small organizers to large multi-venue operators without architectural changes.
Multi-tenancy is an architecture decision, not a feature. Retrofitting organization support touched every service, controller, and query. What was estimated as 2 weeks became 6 weeks of migration. Building it from day one — even as a simple org_id column — would have saved weeks.
Choose your database for your read patterns. ClickHouse's analytical power is extraordinary for dashboards and reporting, but OLTP-style mutations require workarounds. This trade-off was worth it for a ticketing platform where reads vastly outnumber writes.
Shared types across a monorepo are a superpower. Having @seatr/shared-types as a single source of truth eliminated an entire category of bugs — mismatched API request/response shapes, outdated frontend types, stale contracts between services.
have an idea?
let's make it work.
Send us a message and we'll get back to you quickly.