Lesson 10 of 12 · Build the app

Connect the app to the database

Swap the in-memory fake data for real reads and writes through Prisma, then prove it: add a client, see it in Prisma Studio, restart, and it is still there.

40 min You end with: A client tracker that saves every add, edit and delete to Postgres, tested three ways, committed.

This is the lesson where it becomes a real app. Until now, refreshing the page wiped everything. After this, the app reads clients from the database when the page loads and writes every change back. The screen does not change. The data underneath it does.

Everything running (Lesson 6, “Stopping and coming back”): Docker database, dev server, Prisma Studio, Claude Code in manual mode.

Step 1: Ask for the swap, in plan mode

Shift + Tab into plan mode. Paste:

Replace the in-memory fake data on the client tracker screen with real data from the database through Prisma.

- When the page loads, read all clients from the database, sorted by name.
- Adding a client creates a row. Editing updates it. Deleting removes it.
- After each of those, the list on screen updates to match the database.
- Keep the same screen, form, validation and status pills. Do not redesign anything.
- Use Next.js server actions (or route handlers if you think that is clearly better; tell me why) for the writes, so the database is never touched from the browser directly.
- Validate on the server too: name is required and status must be one of the four allowed values. Return a readable error to the form if validation fails.
- Remove the fake data and any code that only existed for it.

Tell me the plan first, in plain English, including how a click on Save travels from the screen to the database and back.

Read the plan. What you are checking:

  • Reads happen when the page loads, writes happen through the server, and the browser never talks to the database itself. If the plan says something like “the client component calls Prisma,” say no: “The browser must not touch the database. Do the writes on the server.”
  • It keeps the screen and only changes where data comes from.
  • It validates on the server, not only in the form.

Approve the plan with manually approve edits. This is the biggest change in the course. It may touch several files and ask you to approve each.

Step 2: Read the explanation of the round trip

When it is done, before you test anything:

Walk me through what happens, step by step, when I click Save on a new client. Which file handles each step? Where could it fail, and what would I see?

Read it. This is the map of your app. You are not expected to remember it, but the day something breaks in production, “walk me through what happens when I click X” is the first thing a CTO would ask, and now you know to ask it too.

Step 3: Test it three ways

Testing is not “it looks fine.” It is trying to prove it is broken and failing to.

Test 1: the round trip. In the browser, add a client named “Test Round Trip.” Switch to the Prisma Studio tab and refresh it. The row is there. Edit it in the app; change the status to Active. Refresh Studio. The status changed. Delete it in the app. Refresh Studio. Gone.

Test 2: it survives a restart. Add two clients in the app. Go to Terminal 1, press Ctrl + C to stop the dev server, then npm run dev again. Refresh the browser. The two clients are still there. Before this lesson they would have vanished.

Test 3: the other direction. In Prisma Studio, add a client by hand with the name “From Studio.” Refresh the app. It appears in the list, sorted into place. The app and the database are the same thing now.

And one deliberately nasty one:

Test 4: bad input. Try to save a client with a blank name. The form should refuse. Now ask Claude Code:

Prove the server-side validation works even if the browser is bypassed: send a request to create a client with an empty name directly to the server action or route, without using the form, and show me the error it returns.

It will find a way to call the server directly (a small script or a curl command) and show you a rejection. That is the difference between a form that looks validated and a server that is.

Step 4: Fix what you found

One thing per prompt, same as always. Common ones at this stage:

After saving, the list does not update until I refresh. Make it update immediately.
Deleting shows the confirmation but the row does not disappear. Fix it and tell me what was wrong.
The status pill for the client I added from Studio shows as blank. Handle the case where a client comes back with a status the screen does not expect.

Step 5: Ask the two questions a CTO would ask

What happens if two people use this at the same time and edit the same client? Explain what the app does today, in plain English, and whether that is a problem for a small business tool.
Is there anything on this screen or in these server actions that would let one user see or change data they should not? We have no login yet; explain what that means for who can see this data once it is on the internet.

You are not expected to fix these today. You are expected to know the answers before Lesson 12, when this goes online. Write down what it says. The second answer, in particular, is the reason the deploy lesson keeps the app private until you are ready.

Step 6: Commit

Show me which files would be committed and confirm .env is not among them. Then commit with the message "Persist clients in Postgres via Prisma" and push.

Check your work

  • All four tests pass: round trip, restart, other direction, bad input rejected by the server.
  • The screen looks the same as it did in Lesson 7.
  • No fake data remains (ask: “Is there any leftover fake data or in-memory code?”).
  • You have written down the answers to the two CTO questions.
  • Committed and pushed, .env still absent from Git.

If something went wrong

The page shows a database error on load. Docker is not running the database, or the dev server started before it did. docker compose up -d, then restart the dev server.

Everything works but Prisma Studio does not show the new rows. Studio does not refresh on its own. Click its refresh button or reload the tab.

“Too many connections” or the dev server slows down after a while. The shared Prisma client from Lesson 9 is not being used everywhere. Ask: “Make sure every database access goes through the single shared Prisma client instance, and explain why that matters in development.”

Saving works once, then errors on the second save. Usually a stale form state. “After a successful save, reset the form and re-read the list from the server. Explain what was wrong.”

Three rounds and it is still broken. Commit nothing. Ask Claude Code to “throw away every change since the last commit and take me back to it.” This deletes everything you did since that commit, which is what you want here. That takes you back to the working Lesson 9 state. Then either try Step 1 again with a fresh /clear, or, honestly, this is the lesson people most often ask a person about, and there is a button for that at the bottom of this page.

Next

The app works. Lesson 11 is the checklist you run before anything goes on the internet: secrets, a security read-through, a couple of automated tests, and a production build.

Did this lesson not go to plan?

A CTO can help you starting today.

Screenshot the error, note which step you were on, and request a call. Every member starts with a call: bring what you built and where it stopped, and that is where we work out whether we can help and what to do first. No card. No sales deck.

Request a call with your CTO

Bring it to a CTO.

The error, the screenshot, or the thing you are afraid to touch. Every member starts with a call, and that is where we work out whether we can help and what to do first.

Request a call with your CTO

Every member starts with a call. No card.