Live events and ticketing · Case study
Paint Nite: Rebuilding a national events platform beside the legacy system
Event platform rebuild case study: a NestJS and Next.js replacement for Paint Nite's booking, checkout and operations, shipped in slices beside the old system.

- Client
- Paint Nite runs ticketed live events and experiences across the US and Canada.
- Team
- 5 committing engineers alongside a client-side technical lead
- Timeline
- Database architecture from November 2025; platform development March to June 2026
- Services
- Enterprise software, Web development, Cloud and DevOps, AI and data
- 8
- Backend services and 3 frontend apps
- 330+
- Features across 49 modules
- 754
- Automated test files run on every pull request
- 474
- Data models across 3 databases
In short
Paint Nite needed a modern booking, checkout and operations platform but could not stop selling tickets while one was built. Five engineers delivered eight NestJS services behind one GraphQL gateway, three Next.js apps, a six-stage checkout with idempotent Stripe payments and zero-downtime search reindexing. Sync services keep the new platform aligned with the legacy one, so the migration ships in slices rather than a single switchover.
Where they started.
- A platform with more than a decade of change had become slow for customers and slow for the team building on it
- The entire purchase flow lived in one function of roughly 1,200 lines, with no Stripe idempotency keys and a live double-charge risk
- Adding a filterable field to event search required a manual reindex that took production search offline with no rollback
- The business could not pause ticket sales while a replacement was built
The approach.
- Eight independent NestJS services behind a single GraphQL gateway, communicating only through a RabbitMQ message queue
- Checkout rebuilt as a six-stage pipeline: quote, tax, tender, persist, emit, effects, with an atomic order transaction and explicit compensation
- Versioned OpenSearch indexes behind aliases, dual-write during rebuilds and resumable reindex jobs, so schema changes ship with no downtime
- Dedicated sync services keep the new platform and the legacy one aligned, so features migrate in slices
- A painting recommendation engine tuned over four measured iterations with an offline replay harness
- Separate Stripe accounts, keys and webhook secrets for the US and Canada, with a Canadian tax path and per-state nexus rules
What shipped.
- Public booking site with a country, state and city page hierarchy and seven types of structured data
- Three-step checkout with idempotent payments, promo codes, membership join and zero-total orders
- Internal operations console with 12 feature areas and 7 role-specific dashboards
- Host management, payouts with PDF statements, venue management with Google Places enrichment
- Private-event sales workflow with lead inbox, conversations and invoicing
- Social media planning with AI-generated post suggestions and an approval flow
- Shared design system with 12 UI primitives and centralised tokens
- 26 architecture decision records and 42 feature documents
How the engagement ran.
Context
Paint Nite sells tickets to live painting events across the United States and Canada. The platform behind that business had grown for more than ten years and carried the marks of it: a 474-table database with backup and temporary tables, a purchase flow crammed into one very long function, and a search reindex process that could take production search offline halfway through with no way back. The team described the checkout code as a disastrous mess, and they were right to. The business needed a modern platform, but revenue depended on the old one every day.
The platform being replaced was not small. It had grown since 2014 into roughly 36 repositories and close to 29,600 commits, covering booking, a nine-processor checkout, tax handling in three countries, search, payouts and Kubernetes infrastructure. Any rebuild had to keep that system earning revenue every day while the new one took over slice by slice.
The engagement started with a database architecture phase in November 2025 and moved into active platform development from March to June 2026. Five engineers committed across two repositories and worked directly with a client-side technical lead.
What we built
- A public site with homepage, event discovery, city landing pages, event detail, virtual and on-demand events, passes and membership, owner microsites and recruitment funnels
- A rebuilt three-step checkout (review, pay, done) with promo validation, membership join, referral cards and a zero-total path
- An order pipeline in six replaceable stages: deterministic decimal pricing, tax behind a swappable provider, multi-method tender, atomic persistence, publishing to the message bus, and queued effects
- An operations console with 12 feature areas: event draft generation, calendar management, host management and payouts, venue management, painting catalogue, private-event sales, social planning and owner administration
- A painting recommendation engine with tag-based selection, signal tables, a venue no-repeat rule and lottery sampling
- A GraphQL gateway with 88 queries and 80 mutations across 27 resolvers, request throttling and structured logging with trace propagation
- Search, notification, event, venue, user, media, AI and legacy-sync services
Architecture and stack
| Layer | Technology | Why |
|---|---|---|
| Frontend | Next.js, React 19 with the React Compiler, TypeScript, Turborepo, Tailwind, Zustand, Apollo Client | Three apps share one component library and one GraphQL client setup |
| Gateway | NestJS, Apollo Server GraphQL | Authentication, rate limiting and logging happen once, at one entry point |
| Services | Eight NestJS microservices, RabbitMQ, Zod, Pino | Services own their tables and talk only through the queue, so cross-domain shortcuts are impossible by construction |
| Data | MySQL across three databases, Prisma with per-domain clients, OpenSearch, Redis/Valkey | Core, operations and accounting data stay separate; search never touches transactional tables |
| Infrastructure | AWS object storage, managed OpenSearch and message broker, DynamoDB, Lambda, EventBridge | Managed services keep the operations burden low for a five-person team |
| Integrations | Stripe (US and Canada), Auth0, Twilio, Mandrill, Iterable, Google Places, Anthropic, fal.ai, TalkJS, Google Tag Manager | Payments, identity, messaging and AI features without building commodity pieces |
Checkout originally lived inside the events service. It was pulled into its own service so that a bad deploy in event management could never take payments offline, and payment credentials now exist in exactly one place. Tax sits behind an interface so the real provider can be swapped without touching pricing, and payment is a multi-method abstraction from the start, so gift cards and passes become new processors rather than new branches.
How we worked
Everything in the process is visible in the repositories rather than described in a slide. Tests run on every pull request through Bitbucket Pipelines in both repositories: 158 backend test files, 589 frontend test files and 7 end-to-end browser specs, with a written policy of 80 percent coverage on new code and 95 percent on checkout and authentication. Main and develop are protected, all code enters through reviewed pull requests, and automated review runs alongside the human one.
Decisions are written down. The team produced 26 architecture decision records, each listing the alternatives considered and the trade-offs accepted, 42 plain-English feature documents and 8 design plans. A defined security audit runs before any pull request touching authentication, payments, user input or a new integration. Every schema change ships as a reviewed migration and production takes a snapshot before each one.
Scale and complexity
| Measure | Figure |
|---|---|
| Backend services / frontend apps | 8 / 3 |
| Modules / features | 49 / 330+ |
| GraphQL operations | 168 (88 queries, 80 mutations) |
| Internal service handlers | 188 |
| Data models / databases / migrations | 474 / 3 / 53 |
| Automated test files | 754 |
| Architecture decision records | 26 |
What this means for your project
If you run a revenue-critical platform that has outgrown its codebase, the pattern here is the one to copy: put a single gateway in front, split the riskiest flow into its own service, and keep the old system alive with sync services while features move across one at a time. The cost of that discipline is a few extra weeks of architecture. The payoff is that no release day is a bet on the whole business.
Innovation Insight delivers rebuilds like this with a dedicated team on a monthly contract, with discovery first so the scope and estimate are written down before the first sprint.
What changed.
- Search schema changes that previously required production downtime now ship with none
- Checkout runs with idempotent payments, atomic order persistence and queued, retryable side effects
- The replay harness caught the recommendation algorithm selecting the same artwork 187 times out of 187 before it reached production
- 168 GraphQL operations and 188 internal service handlers delivered, with 53 tracked migrations
Questions about this project.
Can you rebuild our platform without taking it offline?
Yes. This project ran the new platform beside the legacy one with dedicated sync services, so features moved over in slices. The same approach applies to most replatforming work: keep the old system serving traffic and migrate module by module.
How do you keep payments safe during a checkout rewrite?
Every charge carries an idempotency key, database writes run in a transaction, and the card charge sits outside it with explicit rollback. Side effects such as emails and CRM sync go onto a queue with retries and a dead-letter queue.
What does a build like this cost?
Multi-service platforms of this size run from $150k upward and are usually delivered by a dedicated team over four to eight months. A one to two week discovery gives you a fixed estimate for your scope.