Capstone: Name the Stack
Read a generated booking app, then cut it down to an MVP.
Capstone objectives
- Name every layer from a repository listing
- Write the hosting requirements without guessing a brand of server
- Separate “start here” from “upgrade when you know more”
- Cut the generated app down to a single-page MVP on SQLite
The brief
Workshop Co. booking app — generated over a weekend
- package.json
next,react,next-auth,@prisma/client. Scripts:dev,build,start.- prisma/schema.prisma
provider = "postgresql". Models:User,Class,Booking.Bookinghas a unique pair of user and class.- .env.example
DATABASE_URL,NEXTAUTH_SECRET,NEXTAUTH_URL. Values are empty.- .gitignore
- Lists
.envand.next. - Dockerfile
- Present. The owner has never run Docker. There is no
docker-compose.yml. - What works
npm run devon the owner’s laptop, against Postgres installed by the tool. One test user. No domain.- Goal
- The public can book a class at a real domain, over HTTPS, and the owner can sign in. The studio has a few dozen students, not ten thousand.
Part 1 — name the stack
Write one line for each layer: frontend, backend, database, and what the host has to keep running. Say what the Dockerfile changes and what it does not.
Model answer
- Frontend: React pages served by Next.js.
- Backend: Next.js on Node — the same process serves pages and the booking and login routes.
next-authis the login library. It needsNEXTAUTH_SECRETandNEXTAUTH_URL. - Database: PostgreSQL. Prisma is the library that talks to it. The unique booking constraint is what stops a double booking, if the app actually uses it.
- Host: a machine that can run Node, run the production build, keep
next start(or the Docker image) alive across reboots, and reach a Postgres server. - Dockerfile: it is a recipe for packaging the Node app. It does not provide Postgres, a domain, HTTPS, or the environment variables. Without a compose file, Docker is optional. Installing Node on a VPS is a valid way to run this same app.
Part 2 — what has to exist before the domain works
List the production pieces that are absent from the laptop demo. Keep them in the order you would actually do them.
Model answer
- A VPS (or equivalent) with Node.js, enough memory for the Next.js build, and a firewall that exposes 80 and 443 only.
- PostgreSQL, either on that server or as a separate database, with a user that is not a superuser, and a backup that has been restored once as a test.
- Environment variables set on the server: a real
DATABASE_URL, a long randomNEXTAUTH_SECRET, andNEXTAUTH_URLset to the publichttps://origin. - Prisma migrations applied to that database. Then a production build and a process manager so the app restarts on boot.
- A domain and DNS records (Book 1), then a TLS certificate (Book 2), with the proxy forwarding HTTPS to the app port.
- One real booking and one admin login tested from a phone that is not on the studio Wi-Fi.
Part 3 — what to ask, and what to skip
Write four questions you would send a host before ordering. Then write one upgrade you would not buy yet, and the signal that would change your mind.
Model answer
Ask: Can this plan run a long-lived Node process, or only PHP? Can Postgres run on it or beside it? Who applies security updates and restarts the process? Are backups of the database included, and have you restored one? Where does the server sit — a Canadian data centre is the right default for a studio collecting student names.
Do not buy yet: a large dedicated server, a second app instance, or a cache such as Redis. The studio has a few dozen students. A small VPS that fits Node and Postgres is the starting point. Upgrade when memory or CPU stays high during real class bookings, when the database disk grows, or when a restart causes missed reservations. Learn what the app uses first. The same server can be resized. You do not throw the first one away to find out.
Part 4 — the MVP cut
The studio has a few dozen students. Rewrite the stack as the first version you would actually launch. Name the frontend shape, the database, what you delete from the generated repo, and the signal that means SQLite is finished.
Model answer
- Frontend: a single-page app. One shell for the class list, the reserve button, and the owner view. Deep links fall back to
index.html. - Backend: one Node process with the booking and login routes. No second service.
- Database: SQLite,
studio.dbon persistent disk, same tables Prisma already described. A nightly copy of the file is the backup. Postgres waits. - Delete for now: the unused Dockerfile, any Redis or payment code the model added, and the requirement to run a separate database server.
- SQLite is finished when you need two app processes writing at once, or signups fail with “database is locked.” Then move the same tables to Postgres on the same server and resize. You learned the volume first.