Designing application structure: routes, navigation, and guards
A route tree where a page's path is simply where it sits, navigation drawn as the paths people actually travel, and guards that protect a page however someone arrives at it.
Four questions, one canvas
The structure of an application is really four questions, and they usually get answered in four different places. What pages exist? What do they share? How does a user get between them? Who is allowed where?
Answered separately, they drift. The route tree lives in a folder structure, the navigation lives in whatever component happens to render the links, and the access rules live in a config file nobody reads until something leaks. Each is a partial view of one thing, and none of them can see the others.
Nodlume's Structure tab keeps all four on one board and gives you four views of it — Routes, Components, State, and Nav. Each view asks a different question of the same application, and switching between them never duplicates anything, because there is only ever one board underneath.
The path is the position
A route's path is where it sits in the tree: its parents' segments, then its own. Nest a route under /trips and it becomes /trips/whatever-you-called-it. There is no separate path field to keep in sync with the tree, because the tree is the path.
Names become segments the way you would expect. Type "User Settings" and the route becomes user-settings — spaces fold to hyphens, and anything that would not survive in a URL is dropped. The name you see on the canvas and the folder you get in the export are always the same thing.
Every board starts with one root, fixed at /. That is your home page, so it is a label rather than an editable field — there is no way to accidentally rename your app out of having a front door.
Dynamic segments use App Router bracket syntax, so /trips/[tripId] and /docs/[...slug] mean what you already think they mean.
Drawing instead of arranging
The canvas is modal, closer to Blender than to a diagramming tool: you pick up a tool and stroke with it.
Paint places routes. Erase is its opposite number — a brush that deletes what it sweeps over. Select is a rectangle drag from empty canvas, and clicking a card still just selects it.
The part that surprises people: you never drag nodes into position. Layout is automatic and always tidy — parents sit centered over the sections they own, and a branch with more in it makes room for itself. You spend your attention on what the tree is rather than on where the boxes sit, and a board stays readable as it grows.
Two more brushes appear where they mean something. Layout marks a route as a section with shared chrome — a nav, a sidebar — wrapping itself and everything nested under it. Name walks you through the tree one route at a time, in the order you would read a site map: a section, then the pages inside it. Enter commits and moves on; Esc closes. A left rail lists every route with its full path beside it, which is how you tell two routes both called edit apart.
Components and state hang off routes
Components and stores are not cards on the board. You paint them onto the routes that use them, with a circular brush you drag across the tree.
That is a modeling choice rather than a UI shortcut. A component is not a peer of a page; it is something a page renders. Attaching them to routes means a component used by nine pages is one name in nine places instead of a web of boxes and arrows you have to read around.
The brush has a target, and that is where the real distinction lives: attach to a route and the component belongs to that page; attach to a layout and it belongs to the whole section, and so to every route inside it. It is the difference between a component imported into page.tsx and one rendered in layout.tsx. For a store it is the same split — a hook called in a page versus a provider mounted in the layout above it.
Navigation is the paths people travel
The Nav view shows the same route tree and asks one thing of it: where can each route go next? Drag across routes to draw links.
What is worth noticing is what doesn't need drawing. Parent-child nesting already implies its own navigation — the tree carries that for free. Nav is for the paths the nesting does not imply: cross-links between branches, a trail page that links into the trip planner, the shortcuts real users actually take.
Those links are not decoration. They arrive in the generated pages as real <Link> elements pointing at the right URLs, labeled with the target page's name.
Guards live on the page, not the path
The Nav view has a third tool: Guard pages. Load it with a role, then click a page to toggle the guard or drag across several.
It is a separate tool from the link brush on purpose. Guarding a page and drawing a path to it are two different claims about two different things — "who may be here" versus "you can get there from here" — and folding them into one gesture means you cannot make one without accidentally making the other.
The rule underneath is the one that matters: a guard protects the page, not the route you took to reach it. "This page requires Admin" holds however someone arrives, including by typing the URL into the address bar. A guard attached to a link would only cover the one path you happened to draw, and every other way in would be open — a board that looked audited and wasn't.
The vocabulary is small. signedIn admits any authenticated user. role:Admin admits only that role, and putting several role guards on one page admits any of them. Roles come from the Domain tab, and capitalization does not have to match.
Guards become the security matrix
Guards do not just sit on the canvas. The Security tab turns them into an access matrix.
The reading is the plain one: a page guarded role:Admin is a page only an Admin may reach, so every other role is denied it. A page with no guards implies nothing at all — an unguarded page is not a decision to lock anybody out. Remove a guard on the canvas and the restriction disappears from the matrix immediately.
You also set a baseline: allow everything and record the denials, or deny everything and record the grants. Because the default is a real default rather than a pre-filled grid, a route you add next week inherits it automatically — there is nothing to backfill.
Guards that are not about roles — signedIn, or a plan gate — do not show up as role restrictions. They are real rules, they are just not rules about roles, and reporting them as "no role may enter" would be wrong in the one place being wrong matters most.
Walking the app as a persona
There is one more way to check a structure, and it is the one I would reach for before exporting. The persona walkthrough takes a role from your Domain tab and explores the app the way a first-time visitor would: by making choices, rather than reading a route list top to bottom.
Starting at your home page, it reacts to each route it lands on and offers a few plausible next steps. A step that matches a page you already have walks into it. A step with no match creates the page it describes and then walks into that too — so the exploration keeps going into what it just added, not only what was there when it started.
The guard interaction is the good part. When the persona reaches a page their role cannot enter, the walkthrough records the denial and stops exploring down that branch — no wandering past a door that role cannot open. What you get is a readable account of what one role can actually reach, which is a very different artifact from a grid of checkboxes.
It is otherwise careful with what is already on your board: it adds pages and components, never edits or removes them, and renames only when you explicitly accept a suggestion. Each visit costs one credit, and a run is capped so a growing app still finishes.
Generating a first draft
If you would rather not start from a single root, the structure generator designs the whole tab in one pass: the route tree, which routes are layout sections, the components and stores each route needs — with the same name reused across pages showing the same thing — and the cross-branch links the nesting does not already imply. It costs three credits, the top tier, because one request produces an entire application shape.
It lands as an ordinary board. Paint over it, erase what is wrong, rename it with the naming walk.
What lands in the export
Structure is what the rest of the workspace builds on. It feeds SEO, Accessibility, Security, Traceability, Scaffolding, and the project report.
In the exported skeleton, each route becomes its own directory with a page.tsx that carries the route's description as a comment, imports its attached components, and renders its drawn nav links. Layout routes become layout.tsx wrapping their section.
A guarded page gets a real guard call before it renders, plus a lib/guards.ts module to implement it in. Worth being clear about this one: that module is a stub. It documents the guard vocabulary and where enforcement belongs, but until you wire it to your project's auth system, guarded pages render for everyone. The guard is real code sitting in the right place rather than a comment that disappears on the first save — and it says so, rather than looking finished.
Two rules govern the rest. A route nothing reaches from the root generates nothing, and an unnamed route generates nothing — a route you have not named is not yet a fact about the project. Route groups take their name from the routes inside them, because (group-1) in a file tree tells you nothing.
Where to start
Open a project's Structure tab, paint a handful of routes, and name them with the naming walk. Switch to Nav, draw the cross-links the tree does not already imply, and guard the pages that need it. Check Security to see the matrix those guards produced, then run a persona walkthrough to see what one role can actually reach.
The Structure tab reference covers each view in detail, and the Security tab reference covers the matrix. For the layer underneath, generating custom themes covers the visual system these routes get rendered with.
Design your application
Map pages, components, routes, and stores on the Nodlume canvas, then export the project skeleton when you are ready.
Open projects