Getting Started
A guided path from “I know PHP, new to Laravel” to a production-grade multi-tenant SaaS — built around one real domain: Bookline, an appointment-booking platform that barbershops, dental clinics and yoga studios use to sell their own time, on PHP 8.5 and Laravel 13.
Twenty-four 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 PHP 8 — classes, interfaces, traits, enums, closures, Composer
- Comfortable with SQL, a terminal, and git; Docker installed
- New to Laravel, or you’ve only followed a tutorial
Not assumed: Eloquent, migrations, the service container, middleware, queues, Blade, Livewire, Inertia, Stripe.
If you are new to PHP itself, this will move too fast — learn the language first. Already shipping Laravel in production? Skim steps 0–4 as a checklist and start at step 5.
What you are building, concretely
Section titled “What you are building, concretely”Bookline is one Laravel application serving many independent businesses. Each one signs up, gets its own address, configures what it sells and when, and takes bookings from its own customers — who never see any other business on the platform.
Three of them are used as the running examples all the way through the roadmap. They were picked because they disagree with each other on exactly the points that are hard to build:
- the baseline
Northside Barbershop
3 barbers · 30-min cuts · walk-ins
Per-staff schedules, a fast slot grid, and availability that must survive concurrent mobile requests.
- the constraint
Bright Smile Dental
4 dentists · 45-min appointments · deposits
Cleanup buffers after each service, deposit and refund logic, a cancellation window, and day-before reminders.
- the exception
Loft Yoga
2 instructors · group classes · weekly timetable
Capacity greater than one, recurring weekly rules, and DST — a Sunday 09:00 class must stay at 09:00 through the clock change.
| The business | What it sells | What it forces you to handle |
|---|---|---|
| Northside Barbershop — 3 barbers | 30-minute cuts, back to back, walk-ins between them | Per-staff schedules, a slot grid, availability that must be fast because customers book on a phone in the street |
| Bright Smile Dental — 4 dentists, 2 hygienists | 45-minute appointments, 15 minutes of cleanup after each, deposits to reduce no-shows | Buffers after a service, deposits and refunds, a cancellation window, reminders the day before |
| Loft Yoga — 2 instructors | Group classes with 12 places, a weekly timetable, some seasonal | Capacity greater than one, recurring weekly rules, and DST — a Sunday 09:00 class stays at 09:00 through the clock change |
Same code, same database, three businesses whose rules do not match. That is the whole
exercise: one system, configured per tenant, and never a line of if ($tenant->name === …).
Other businesses in this shape, if you want to point your own version at one: driving schools, tattoo studios, physiotherapists, veterinary clinics, photography studios, private tutors, car service centres, nail bars, massage therapists, coworking meeting rooms. All of them sell time in slots, all of them lose money to no-shows, and all of them are somebody’s paying customer today.
Why a booking SaaS
Section titled “Why a booking SaaS”Most Laravel tutorials build a blog or a todo list, then bolt on a queue and a cache as demos. You learn the syntax and none of the judgement. A booking platform sold to many businesses at once was chosen because the hard parts are unavoidable:
| Reality of the domain | Forces you to learn |
|---|---|
| Every business is a separate tenant sharing one database | Tenant resolution, global scopes, tenant context in queues, cache and storage, and a test that proves no data crosses the line |
| Two customers can book the same 10:00 slot | Transactions, row locking, Postgres exclusion constraints, and why a SELECT then INSERT is a bug |
| The business is in one timezone, the customer in another, and clocks shift twice a year | Storing instants in UTC, rendering in tenant time, and the DST hours that happen twice or not at all |
| The business pays you monthly; their customers pay the business | Subscriptions and dunning, webhook idempotency, per-tenant payment credentials, refunds |
| Reminders go out when nobody is on the site | Queues, scheduled jobs, retries, failed-job handling, idempotent workers |
You can’t fake a tenancy leak. Either your test proves tenant A’s query never returns tenant B’s row, or it doesn’t.
Every business that sells time runs on software shaped like this, and most of them are paying for it today. Building it once teaches you the shape.
What you’ll learn
Section titled “What you’ll learn”| Area | Technology |
|---|---|
| Language / runtime | PHP 8.5, Composer, strict types |
| Framework | Laravel 13 — container, providers, middleware, events, policies |
| Persistence | Eloquent, migrations, PostgreSQL 17, factories and seeders |
| Multi-tenancy | Subdomain resolution, global scopes, tenant-aware cache / storage / queues, then stancl/tenancy for database-per-tenant |
| API | Form requests, API resources, RFC 9457 problem details, versioning, Sanctum tokens |
| Auth | Session auth, roles and policies, per-tenant membership, signed URLs |
| Money | Laravel Cashier (Stripe) subscriptions, plan limits, dunning; encrypted per-tenant credentials; then Stripe Connect |
| Async | Queues, Horizon, scheduled jobs, idempotent consumers, failed-job policy |
| Realtime | Laravel Reverb — a slot disappearing while the customer is looking at it |
| Caching & scale | Redis 8, cache keys under tenancy, N+1 elimination, index design for availability queries |
| Observability | Structured logs, request and job correlation, slow-query and queue-depth signals |
| Admin frontend | Blade + Livewire 4 + Tailwind 4 — a tenant back-office |
| Customer frontend | Inertia 2 + React 19 + TypeScript — the public booking page |
| Quality | Pest 4, Larastan, Laravel Pint, Rector, database-backed tests |
| AI workflow | An AGENTS.md harness (v1→v4), a LEARN/BUILD mode contract, a portable code-reviewer prompt |
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 24 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, the Laravel mental model, Eloquent, the request contract, auth |
| Multi-Tenancy | 5–8 | Tenant resolution, scoping and the leak test, tenant context outside the request, the Livewire back-office |
| Booking and Availability | 9–13 | The availability engine, time correctness, the booking state machine, double-booking, read performance |
| Money and Async | 14–18 | Subscriptions, webhooks, per-tenant payment credentials, deposits and refunds, queues |
| Scale and Migration | 19–23 | The public booking page, the public API, Connect migration, database-per-tenant migration, deploy |
- Foundations0–4
- 0Dev environment, quality gate, agent harness
- 1Project skeleton and the Laravel mental model
- 2Eloquent, migrations, and the schema
- 3The request contract: validation, resources, error model
- 4Auth I: session auth, roles, policies
- Multi-Tenancy5–8
- 5The tenant, and resolving it from the request
- 6Scoping every query, and the leak test
- 7Tenant context outside the request
- 8The tenant back-office (Livewire)
- Booking9–13
- 9Working hours, staff schedules, and the availability engine
- 10Time correctness: timezones, DST, recurrence
- 11The booking flow and its state machine
- 12Double-booking: locking vs an exclusion constraint
- 13Read performance: N+1, eager loading, indexing
- Money and Async14–18
- 14Subscriptions: plans, trials, and plan limits
- 15Webhooks: idempotency, retries, dunning
- 16Per-tenant payment credentials
- 17Deposits, refunds, and the no-show policy
- 18Queues, Horizon, and work that must not be lost
- Scale and Migration19–23
- 19The public booking page (Inertia + React + Reverb)
- 20The public API and token authentication
- 21Payments migration: BYO keys → Stripe Connect
- 22Tenancy migration: shared database → database per tenant
- 23Observability and production deployment
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”Backend and tenancy — steps 0–18. Tooling → Laravel fundamentals → tenancy → availability and booking → money → async. Ends with a working multi-tenant SaaS that takes bookings and payments, driven from the Livewire back-office.
Public-facing and scale — steps 19–23. The Inertia booking page, the public API, and the two migrations: BYO payment keys → Stripe Connect, and shared database → database per tenant.
Two frontends is intentional. A tenant back-office is CRUD-heavy and internal; server-rendered Livewire is faster to build and cheaper to maintain, and that is a permanent choice, not a temporary step. The public booking page needs real client state — slot selection, a hold countdown, live availability — and earns the SPA. You learn session auth on one and token auth on the other, and why they differ.
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 — reading an EXPLAIN plan, watching two browsers fight over one slot, changing your machine’s clock to a DST boundary. |
| 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, Larastan, Pint, the tenancy leak sweep, coverage. 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 tenancy, concurrency, time, and money steps — write the acceptance test first, watch it fail. (Steps 6, 7, 10, 12, 15, 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 6, 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 queued job that runs without a tenant and writes rows to whichever tenant was last active; a cache key that serves Northside’s schedule to a Bright Smile patient).
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 health 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.