Case Study

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.

  • Turborepo Monorepo
  • ClickHouse OLAP
  • Real-time WebSocket
  • Stripe Payments
  • Multi-tenant
  • 5-Locale i18n
  • OAuth2

Create an event. Import inventory. Sell tickets. Real-time, multi-tenant, five languages.

Seatr — front page & event discovery
Problem

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.

Approach

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.

01

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.

02

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.

03

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.

04

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.

Notifications — real-time order & inventory alerts Payment methods — Stripe Elements checkout integration
System

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.

01

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.

02

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.

03

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.

Language selector — 5-locale internationalization (EN, HU, DE, ES, FR) User settings — account preferences & profile management
Core Feature

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.

Location settings — venue & seating configuration
Real-time

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.

Event filter — browse events by category, date & price
Platform

key integrations & systems

Every integration custom-built. Every system designed for multi-tenant isolation, type safety, and production-grade security.

Payments

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.

Authentication

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.

Import

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.

Internationalization

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.

Event filter — dropdown selectors for venue, category & date range
Backend

administration & analytics

A comprehensive admin dashboard built with React, TanStack Table, and Recharts — powered by ClickHouse aggregation queries that return in under 100ms.

Events & Venues

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
Organizations

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
Content & CMS

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
Seatr admin — analytics dashboard
Seatr admin — event management Seatr admin — organization management
Seatr admin — venue management Seatr admin — user management
0

Oversales — real-time WebSocket inventory

<30s

10,000+ ticket CSV import & matching

<100ms

ClickHouse dashboard query response

5

Languages across 4 apps — zero hardcoded strings

Challenges

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.

Security

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.

What makes it work

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.

Impact

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.

Learnings
Architecture

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.

Database

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.

Monorepo

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.