How to plan a web app before coding: eight artifacts
The eight decisions that are cheap now and expensive later: scope, routes, data, access, API, tokens, tests, and traceability — plus when planning is done.
Plan the decisions that are expensive to reverse
Planning a web app is not a phase, and it is not a document. It is the small set of decisions that get dramatically more expensive after implementation starts — and the useful discipline is telling those apart from the ones that do not.
Changing a button's colour after launch costs minutes. Changing what a Project belongs to costs a migration, a rewrite of every query that assumed the old shape, and an audit of every permission check built on top of it. Both are "changes"; only one deserves a decision before the first commit.
The eight artifacts below are the ones that pay. Each is cheap to produce now, and each becomes a rewrite if it is wrong. What they are not is a specification of the whole product — most detail is better discovered while building, and planning it early is waste dressed as diligence.
Why this pays off more now, not less
The common argument against planning is that AI agents make code cheap, so you may as well generate and iterate. The opposite follows. When implementation is the cheap part, the bottleneck moves to knowing what should exist — and an agent given a weak brief produces plausible code implementing the wrong rules, quickly and in volume.
The practical difference is reviewability. Generated code that traces to a stated requirement can be checked against it. Generated code that traces to nothing can only be read and hoped over, which does not scale past a few hundred lines. Speed raises the cost of unclear direction rather than lowering it.
That is the argument for artifacts over prose: a route tree, an ER diagram, and a permission matrix are things an agent can be pointed at and a reviewer can check against.
1. Scope as stories with acceptance criteria
Write what the first version does as user stories — actor, capability, reason — and give each one acceptance criteria: the observable conditions that make it true. The criteria are what turns a story from an intention into something testable.
The reason to write them before code is that they expose dependencies you would otherwise discover mid-implementation. One story:
As a workspace admin, I want to invite a teammate so they can access the workspace.
- The admin enters an email and selects a role.
- Invalid addresses are rejected before an invitation is created.
- The invited user has no access until they authenticate.
- Non-admins cannot send invitations.
Four lines, and they already imply an Invitation entity, a role on the membership rather than the user, an endpoint, an access rule, and four test cases. That is the point: a story with criteria is a probe into the other seven artifacts.
Record what is explicitly out of scope too. Scope creep rarely arrives as a new feature request; it arrives as an unstated assumption about an existing one.
2. The route tree
The URL structure is the app's skeleton, and it is load-bearing for things that are awkward to move later: which routes are public, which share a layout, where authentication applies, and what navigation implies about hierarchy.
Sketch the whole tree before building any of it — the public pages, the authenticated shell, the feature routes, the settings and administration areas. Then add the states that get forgotten because they are nobody's happy path: empty, loading, not-found, and access-denied. Those four are where most of the second-sprint UI work comes from, and they are free to notice now.
Sketching the route tree and the architecture checklist go deeper on the App Router specifics; navigation architecture covers what the tree implies for how people move. The Structure Painter turns the tree into a downloadable skeleton, which is the cheapest possible test of whether it holds together.
3. The data model, before the schema
Entities and their relationships first; tables, columns, and indexes second. The distinction matters because the hard questions are about meaning rather than storage. Can a user belong to several workspaces? Can a project have more than one owner? What happens to a workspace's projects when it is deleted?
For each entity, decide the plain-language purpose, the required fields, the uniqueness constraints, the relationships, the lifecycle states, and whether anything needs auditing. Then draw it — an ER diagram that renders on GitHub is reviewable in a pull request, which is the property that gets it actually reviewed. The ER Designer produces the same thing visually.
The failure mode worth naming: designing screens first and letting the schema emerge from form fields. That survives a prototype and collapses the first time you need reporting, collaboration, or permissions, because forms encode one user's view of the data rather than its actual shape.
4. Roles, permissions, and access rules
Authentication is who someone is; authorisation is what they may do. Decide the second one now, because it reaches into the data model (ownership fields), the API (which endpoints exist), the UI (hidden versus disabled versus blocked), and the tests (every rule needs both an allowed and a denied case).
"Admin only" is not an access rule. A rule names the actor, the resource, the action, the condition, and the failure behaviour:
Actor workspace admin · Resource project · Action archive Condition the project belongs to the actor's workspace On failure 403, with a non-destructive message — no data in the response
The last line matters more than it looks. A denied request that leaks the resource's existence, or returns a 401 where it meant 403, is a security decision made by accident. Deciding it once, in a table, is how it stays consistent across thirty endpoints. Access rules per route are worth expressing as a matrix for exactly this reason — the gaps are visible in a grid and invisible in prose.
5. The API surface each screen needs
Work from the screens outward. For each one, ask what it loads, what it changes, what can fail, and what shape the UI actually wants back. Endpoints designed from the backend's convenience produce clients that fetch four times and reassemble the result.
Per endpoint: method and path, one-sentence purpose, whether authentication is required, which permission governs it, the request shape, the response shape, the validation failures, and the acceptance criterion it serves.
And decide where each rule is enforced. Anything touching money, ownership, data integrity, or access belongs on the server without exception. The client may guide, disable, and pre-validate — but a rule that exists only in the UI is a rule that does not exist.
6. Design system decisions, not a brand
You do not need a finished visual identity before the first commit. You need enough named decisions that components stop being invented one at a time: colour tokens by role rather than by hue, a spacing scale, a type scale, button hierarchy, form and validation patterns, and the four states again — empty, loading, error, success.
This matters more when an agent is generating components, because generation without constraints produces a different button every time. A semantic colour palette and spacing, shadows, and borders cover the token vocabulary; the Theme Generator emits it as a theme you can hand to the build.
Accessibility belongs in this artifact rather than in a later audit — focus treatment, contrast minimums, label conventions, keyboard paths. Retrofitting those is a rewrite of every component; deciding them is a paragraph.
7. The tests that prove each requirement
Plan tests against acceptance criteria, before implementation. The reason is diagnostic as much as practical: a requirement you cannot describe a test for is a requirement that is not yet clear enough to build. Planning tests before code is the fastest way to find the vague ones, and accessibility and test planning covers the cases that are hardest to add later.
Cover the levels deliberately — unit for isolated rules, integration for queries and endpoints, end-to-end for the few flows that genuinely must not break, and a permission test per access rule in both directions.
Then write the definition of done, which is the artifact that stops quality becoming a cleanup task. Something like: the criteria pass, the access rule is enforced and tested, the error and empty states exist, and the implementation matches the spec.
8. Traceability from requirement to implementation
Traceability answers one question: where is this requirement implemented, and how do we know it works? Without it, rules quietly evaporate between planning and review — not through disagreement, but because nobody was holding the list.
Link each requirement to its screen, route, endpoints, entities, access rules, tests, and the change that implemented it. A traceability matrix does this in a grid, and the grid's value is its holes: unimplemented requirements and untested rules are visible at a glance, which is not true of any amount of prose.
This is also what makes review possible when generation is fast. A change that traces to a requirement can be checked; one that traces to nothing is either scope that arrived unannounced or work nobody asked for. Both are worth catching.
How much planning is enough
Planning is done when the riskiest decisions are settled well enough that building does not require inventing requirements. Not when the document feels complete — documents always feel incomplete, which is why "enough" has to be defined by something else.
Two practical tests. Could a developer — or an agent — start the first task without guessing at the data model, the roles, or the expected behaviour? And is there still an open question about ownership, relationships, or permissions? The first says stop; the second says continue, because those three are the gaps that become rework.
Stop when more detail stops changing implementation decisions. That threshold arrives much earlier than most planning templates assume, and much later than "let's just start" implies. Everything past it is better discovered while building, where it is cheap.
Then keep the plan alive. It is a living specification, not a gate you pass through once: when reality diverges, update it deliberately, so the change is a decision rather than a drift. If the plan and the code disagree, that disagreement is the useful signal — someone has to say which one is wrong.
The Nodlume workspace holds all eight artifacts in one document — routes, data model, access matrix, endpoints, theme, tests, and traceability — and generates the scaffolding from them, which is the version of this where the plan and the code cannot drift apart quietly.
Frequently asked questions
How long should planning a web app take?
Long enough to remove the uncertainty that would otherwise become rework, which for a small project is hours rather than days. Measure it by readiness, not by calendar time: if the first task still requires someone to invent the data model or guess a permission rule, planning is not finished, however long it has taken.
What is the difference between a spec and a wireframe?
A wireframe shows what a screen contains — layout, fields, actions, navigation. A spec states how it behaves: rules, data, permissions, failure cases, and the criteria that make it correct. They fail in opposite directions. A wireframe alone leaves business logic to interpretation; a spec alone misses UI states and the data a screen actually needs.
Do I still need to plan if an AI agent writes the code?
More, not less. An agent will produce confident, working code from an underspecified brief — it just implements assumptions instead of requirements, and does it faster than anyone can review. The plan is what gives you a standard to check the output against, which is the only thing that makes fast generation safe.
What should I plan first if I only have a weekend?
Scope, then the data model, then access rules. Those three are the expensive-to-reverse decisions; routes and API shape follow from them quickly, and visual polish can be discovered entirely while building. Three to five stories with acceptance criteria and an ER diagram is a genuinely sufficient weekend plan.
How do I stop the plan from going stale during development?
Keep it where the work happens and update it in the same change that contradicts it — a spec in a separate tool decays the moment the first shortcut is taken. Traceability is what makes staleness visible: if a requirement points at code that no longer matches, one of the two is wrong, and someone has to decide which.
Provable planning
Continue this learning path
Data models, acceptance criteria, accessibility, traceability, and the artifacts that show how a feature will actually be delivered.
Design your application
Connect requirements to routes, components, entities, endpoints, roles, and tests in one reviewable plan.
Open projects