The Walking Skeleton
The tempting way to build Sprout is layer by layer: design every table, then write every route, then every screen, and join them up at the end. The joining is where it breaks, and by then everything is built on the wrong assumptions. Instead, make one thin feature work through every layer, including production, before you thicken any of them.
The rule
One thin path through every layer, all the way to production, first.
Sprout's skeleton is the first row of the plan: "Asha logs in and sees her plant list", even while the list is empty. It needs one small piece in each place:
- Repository.
client/(Vite and React) andserver/(Express), each withdev,startandtestscripts;.gitignorecoversnode_modulesand.env;.env.exampleis committed. - Database. A first migration creates
usersandplants. - A first user. There is no sign-up screen yet, so a small command-line script,
node scripts/create-user.js asha@example.com, hashes a password and inserts the row. - API.
POST /api/login, therequireUsermiddleware,GET /api/plantsandGET /api/health. - Client. A login page and a dashboard with loading, failed and ready states, plus the Vite proxy for
/api. - Pipeline. CI runs the tests and builds the client on every pull request.
- Production. Nginx, the systemd service and the environment file on the server, and the skeleton goes live.
Every piece is as small as it can be. The dashboard shows plant names and nothing else, and the styling is plain. Detail comes later, in slices.
Why deploy something that barely does anything? Because deployment problems are cheapest to find while there is only one feature. A JWT_SECRET missing from the server, an Nginx block that does not forward /api/, or a migration that never ran on the real database are ten-minute fixes now, and a stressful evening once twenty features depend on them. After the skeleton, every new feature ships along a path that is already known to work.
A two-line smoke test proves the live path end to end:
curl -i https://sprout.example.com/api/health
curl -i -X POST https://sprout.example.com/api/login -H 'Content-Type: application/json' -d '{"email":"asha@example.com","password":"correct-horse"}'Expect 200 for both, and a Set-Cookie header marked HttpOnly and Secure on the second.
The shortcut
When you are unsure what to do next, ask: "Does a request already travel from the screen to the database and back, in production?" If not, work on whatever blocks that path. If it does, add the next feature as a slice.
Locally
npm run devruns in both halves. Atlocalhost:5173, Asha logs in and sees "No plants yet".
Drills
Answer fast — trust the rule.
What is a walking skeleton?
Why deploy the skeleton when it barely does anything?
Sprout has no sign-up screen yet. How does the first user get into the database?
Why does the skeleton's dashboard show only plant names, with plain styling?
Remember
- One thin path through every layer, all the way to production, first.
- Shortcut: "Does a request travel screen to database and back, in production?" If not, unblock that.
- Trap: building layer by layer and joining at the end, when every assumption is already baked in.
