Getting Started
A guided path from “I know Java, new to Spring” to a production-grade backend and fullstack application — built around one real domain: TicketFlow, an event ticketing marketplace that sells seats for theatre runs, arena concerts and club gigs, on Java 21 and Spring Boot 3.5.
Twenty-six steps. There’s no deadline on any of it — take a step in an evening or over two weeks. The order matters, the pace doesn’t.
Who this is for
Section titled “Who this is for”- Comfortable with Java — generics, collections, streams, records, the concurrency primitives
- New to Spring, or you’ve only followed a tutorial
- Can navigate a terminal and use git; Docker installed
Not assumed: JPA, Spring Security, Redis, message queues, React.
If you are new to Java itself, this will move too fast — learn the language first. Already shipped Spring in production? Skim steps 0–6 as a checklist and start at step 7.
What you are building, concretely
Section titled “What you are building, concretely”TicketFlow is one application where organizers publish events against a venue, and customers buy seats for a given date. Three events run through the whole roadmap. They were picked because they disagree with each other on exactly the points that are hard to build:
- the baseline
Hamlet at the Lyric Theatre
380 seats · assigned seating · multiple showtimes
A seat map, per-showtime inventory, the N+1 trap on every seat render, and two browsers racing for the same seat.
- the constraint
Riverside Arena
20 000 cap · GA + reserved · on-sale spikes
High-concurrency inventory, horizontal scaling, a hold timer that expires seats across instances, and a queue page at on-sale.
- the exception
The Foundry
Standing room only · no seat map · small capacity
No seats to assign, GA inventory only, no map to render — a strategy built around seat maps has nothing to say here.
| The event | The setup | What it forces you to handle |
|---|---|---|
| Hamlet at the Lyric Theatre | 380 numbered seats — stalls, circle, balcony, each its own price. One venue, twelve nights. | A seat map hierarchy, availability computed per showtime rather than per event, and a catalog query that must not issue one query per date |
| A touring band at Riverside Arena | 5,000 seats, one night, on sale at 09:00 on a Friday | Bulk seat generation, holds under real contention, caching and stampede protection, rate limiting, a second application instance |
| A club gig at The Foundry | 400 standing places, no numbered seats at all | Capacity as a count on a ticket type rather than a set of seat rows — the case that breaks a model built only around Seat |
Seed all three from step 6 onward and keep them. The arena is where the concurrency and scale steps get their teeth; the theatre is where seat maps and read performance do; the club gig is the one that catches a model which assumed every ticket has a seat.
Other things sold this way, if you want to point your own version at one: sports fixtures, cinema screenings, conferences with limited workshop places, museum timed entry, comedy clubs, festival day passes, ferry crossings, guided tours. All of them sell a fixed inventory against a moment in time, and all of them oversell if you get the locking wrong.
Why an event ticketing marketplace
Section titled “Why an event ticketing marketplace”Most backend tutorials pick a domain with no hard problems in it, then add caching, locking, and queues on top as demos. You learn the syntax and none of the judgement.
Ticketing was chosen because the hard parts are unavoidable:
| Reality of the domain | Forces you to learn |
|---|---|
| Two people can’t buy the same seat | Pessimistic vs optimistic locking, deadlock ordering, distributed locks |
| Payment gateways are slow and unreliable | Idempotency, the outbox pattern, webhooks, saga compensation |
| On-sales are genuine traffic spikes | Caching, stampede protection, rate limiting, horizontal scaling |
| Seat maps need real client state | An SPA that earns its complexity |
You can’t fake concurrency correctness. Either your test proves 100 concurrent buyers get exactly 10 seats, or it doesn’t.
Every one of these is somebody’s production system today, and every one of them is a system people pay to have built.
What you’ll learn
Section titled “What you’ll learn”| Area | Technology |
|---|---|
| Language / runtime | Java 21 LTS, virtual threads |
| Framework | Spring Boot 3.5 (Jakarta EE 10) |
| Persistence | Spring Data JPA, PostgreSQL 16, Testcontainers |
| API | REST, RFC 9457 Problem Details, OpenAPI, versioning |
| Security | Session + CSRF → hand-rolled JWT → Spring Authorization Server (OAuth2 + PKCE) |
| Async & messaging | RabbitMQ 3, the outbox pattern, idempotent consumers, sagas |
| Caching & scale | Redis 7, a CQRS read path, stampede protection, two-instance horizontal scaling |
| Resilience | Circuit breakers, retries with jitter, distributed rate limiting, graceful shutdown |
| Observability | Structured logs, correlation IDs across async boundaries, p95/p99 metrics |
| Architecture | Layered → hexagonal refactor → modular monolith → one extracted service |
| Admin frontend | Thymeleaf + HTMX, Tailwind 4 + daisyUI 5, a hand-built design system |
| Customer frontend | React 19 + TypeScript + Vite, Tailwind 4 + shadcn/ui, a live seat map |
| Java quality | Spotless, Error Prone + NullAway, ArchUnit, SpotBugs + FindSecBugs, OWASP dependency-check |
| Frontend quality | Biome, minimal ESLint for react-hooks, TypeScript strict |
| AI workflow | An AGENTS.md harness (v1→v5), a LEARN/BUILD mode contract, a portable code-reviewer prompt |
Optional advanced track: Kafka, Elasticsearch, event sourcing scoped to one aggregate, and a Kubernetes decision document.
How this material is structured
Section titled “How this material is structured”Three parts. Read them in this order the first time, then jump back as needed.
| Part | What it is | When you read it |
|---|---|---|
| Setup | The AI harness — AGENTS.md, the make verify loop, the LEARN/BUILD mode contract — and a portable code-reviewer prompt. This is step 0. |
Once, before step 1. Configure it, then leave it. |
| Roadmap | The 26 sequenced steps in five sections, plus an overview of locked decisions, the domain model, and the always-on quality guardrails. | Skim the overview first. Work the steps in order. |
| Reference | Per-step rubrics (acceptance criteria + anti-patterns), the AGENTS.md template, and a list of deliberate omissions. |
One rubric section per step. The rest, as questions come up. |
The roadmap sections:
| Section | Steps | Focus |
|---|---|---|
| Foundations | 0–4 | Tooling, harness, Spring fundamentals, persistence, API contract, security |
| Domain Depth | 5–8 | Admin UI, design system, seat maps, read performance, the concurrency problem |
| Integration and Scale | 9–14 | Hexagonal refactor, messaging, caching, horizontal scaling, observability, resilience |
| Fullstack | 15–18 | React storefront, seat map, checkout, frontend production readiness |
| Advanced | 19–24 | OAuth2, service extraction, and the optional Kafka / Elasticsearch / event-sourcing track |
- Foundations0–4
- 0Dev environment, quality gate, agent harness
- 1Project skeleton and the Spring mental model
- 2Persistence and schema migration
- 3API contract: DTOs, validation, error model
- 4Security I: session auth, CSRF, RBAC
- Domain Depth5–8
- 5Admin back-office (Thymeleaf + HTMX)
- 5bDesign system foundation
- 6Venues, seat maps, and bulk operations
- 7Read performance: N+1, projections, indexing
- 8Concurrency: seat holds and the overselling problem
- Integration and Scale9–14
- 9Hexagonal refactor and the payment adapter
- 10Async, webhooks, idempotency, the outbox pattern
- 11Caching and the CQRS read model
- 12Horizontal scaling: load balancing and distributed state
- 13Observability
- 14Resilience and rate limiting
- Fullstack15–18
- 15React storefront foundation and token auth
- 16Interactive seat map and hold timer
- 17Checkout, payment, and the confirmation flow
- 18Frontend production readiness
- Advanced19–24
- 19Security II: OAuth2 and Spring Authorization Server
- 20Service extraction and production deployment
- 21Kafka: the event stream
- 22Elasticsearch: real search
- 23Event sourcing (scoped to Ticket only)
- 24Kubernetes: conceptual only
LEARN the agent tutors, you decideBUILD the agent may generate
There is deliberately no implementation code in any of these documents. Handing you working code gives you the feeling of understanding, and you remember almost none of it later. The roadmap tells you what to build and how to prove it works; the building is yours.
The two paths
Section titled “The two paths”API development — steps 0–14. Tooling → foundations → domain depth → concurrency → integration → scale → resilience. Ends with a production-grade API.
Fullstack — steps 5, 5b, then 15–18. A Thymeleaf + HTMX admin back-office and its design system first; a React + TypeScript customer storefront later.
Two frontends is intentional. Internal CRUD back-offices are faster to build and maintain server-rendered — a permanent choice, not a temporary step. The customer storefront needs client state (seat map, hold countdown, live availability) and earns the SPA. You learn session + CSRF auth on one and token auth on the other, and why they differ.
After both: steps 19–20 (OAuth2, service extraction, deployment), then the optional advanced track.
How to read a roadmap step
Section titled “How to read a roadmap step”Every step has the same parts. Once you know them you can skim to whichever one you need.
| Part | What it’s for |
|---|---|
| Story | The user story driving the step. This is the goal — if you can’t demo it, you haven’t finished. |
| Mode | LEARN or BUILD — whether an AI agent may write the implementation. See the mode contract. |
| Why now | What this step depends on, and why it isn’t earlier or later. The ordering encodes dependencies you can’t see yet. |
| Concepts | What you’re actually learning. This is the real point of the step; the code is just the vehicle. |
| Libraries | What to add, and sometimes why that choice over the obvious alternative. |
| Expected outcome | What you should have when the step is done — the pieces to build, and where useful a high-level project structure. The how is yours to work out. |
| Verification | How you prove it’s done — see below. |
Some steps also carry a Harness impact note: what to add to AGENTS.md afterwards.
Proving a step is done
Section titled “Proving a step is done”The common failure of self-directed learning is that everything feels like it works. Five verification layers exist to prevent that:
| Layer | What it is |
|---|---|
| L1 — Gating test | The acceptance test, ACC-NN. Unambiguous pass/fail. Write it, watch it fail, then make it pass. |
| L2 — Manual checks | What a test can’t catch — timing something, reading an EXPLAIN plan, killing a container mid-request. |
| L3 — AI code review | The reviewer prompt, run by you at the end of every step. |
| L4 — Anti-patterns | AP-NN-x: “you did it wrong if…”. This is where most of the real learning is — the mistakes that don’t show up on their own. |
| L5 — Automated guardrails | CI, ArchUnit, coverage, contract diffs. Continuous rather than per-step; listed in the Roadmap Overview. |
The step’s Verification block vs. the Rubrics page
Section titled “The step’s Verification block vs. the Rubrics page”These are two views of the same thing. Be clear which is which:
- The Verification block ends every step. It’s the checklist you work through to close
that step: the
ACC-NNtest to write, the L2 checks to run by hand, theAP-NN-xIDs to self-check against, and a one-line Done when. This is the thing you do. - The Rubrics page holds the full text of the
ACC-NNcriteria and theAP-NN-xanti-patterns that each step only names by ID. It lives in one place so the AI reviewer can be handed exactly one step’s section without seeing the others. This is a lookup — you read one section per step while working that step’s Verification block. You don’t “complete” it.
The per-step loop
Section titled “The per-step loop”- Check the step’s Mode.
LEARN→ your agent tutors only.BUILD→ it may generate. - Read the step: story, why now, concepts.
- For concurrency, money, or state-transition steps — write the acceptance test first, watch it fail. (Steps 8, 10, 11, 12, 17 especially.)
- Write the implementation until the test passes.
- Run the L2 manual checks.
- Self-check against the step’s
AP-NN-*list in the rubrics. - Submit to the reviewer with that step’s rubric section only.
- Fix findings, resubmit until
PASS. - Next step.
Expect to fail review the first time at steps 8, 10, and 12. That’s the design, not a setback.
How to use the rubrics
Section titled “How to use the rubrics”Each step has a rubric in Reference → Rubrics — the objective pass/fail bar for that step, in two parts:
ACC-NN— one gating acceptance test. Objective, no judgement call. You write it, watch it fail, then make it pass.AP-NN-x— named anti-patterns: mistakes that pass the tests but are still wrong (a@Transactionalself-invocation that silently runs in no transaction; a@Scheduledjob that double-executes the moment you run two instances).
Use it three times per step: read ACC-NN before you build and write that test first;
self-check against every AP-NN-x once it passes; then paste only that step’s section
into the reviewer. Never paste the whole file — it leaks later steps.
Start here
Section titled “Start here”- Read this page to the end. The step format only makes sense once.
- Skim the Roadmap Overview — the locked decisions and the domain model. Don’t memorise it; know it’s there.
- Set up the agent harness. This is step 0. Setting up tooling before any domain code feels like procrastination; it’s what makes every later step fast.
- Set up the reviewer. Configure once, run at the end of every step. Works in a plain chat window — no repo access needed.
- Start step 1. A ping endpoint and a config file. Small on purpose.
If you’re still tuning AGENTS.md after a couple of sessions, you’re procrastinating. Ship a
minimal version and move on — it’s designed to grow.
Reference material — not a tracked step.