Naalya Handbook
Recipes

Recipes

Copy-this-shape checklists for the things you build most — features, pages, tables, panels and surfaces.

Here's the good news about building in this codebase: you almost never invent anything. When a new task lands — "add a Departments screen", "let staff create a term" — the shape you need already exists three folders over. The job is to copy that shape and rename it, not to design a new one.

That's what these recipes are. Each one is a short, copy-this-shape checklist for one kind of thing you build over and over. They tell you which folder to clone, what to rename, and where to wire the new piece in.

Recipes are the how, pattern pages are the why

A recipe is deliberately mechanical — do this, then this. When you hit a step that makes you ask but why is it shaped like that?, that's your cue to jump to the matching pattern page: Data layer, Design system, Panels and surfaces, Permissions. Recipes get you moving; pattern pages stop you cargo-culting.

The recipes

Most of what you'll ever add is one of the first five shapes — each maps to a real folder convention you can see in the source today. The sixth is the odd one out: a single-map edit that makes the AI assistant narrate a new tool.

Real tasks combine several

Here's the part that trips up juniors: a recipe is rarely a whole task. A real ticket — "add Departments" — is almost never just one of the five. It's a stack of them.

Picture that Departments screen end to end. To ship it you'd reach for:

  • a data featuresrc/queries/department/ with the query, options, hook and interfaces — so the list and the detail view have something to read,
  • a page — the route that lays out the header and drops the table in,
  • a data tablesrc/components/data-tables/department/ with its columns, cells and filter,
  • a create surfacecreate-department.surface.tsx, opened by the "New department" button,
  • and often a detail or edit side panel — to view or change one department in place.

That's four or five recipes for one feature. The reason this feels manageable rather than overwhelming is that each piece has a twin already in the tree. You can see the whole department set sitting right next to its neighbours:

What one resource looks like across the tree
src/queries/student/          # the data feature (query/options/hook/interfaces)
src/components/data-tables/student/  # the table (columns/cells/filter/datatable)
src/components/surfaces/create-guardian.surface.tsx  # a create surface
src/components/side-panels/staff-profile.panel.tsx   # a detail panel

Build inside-out

When you're combining recipes, do the data feature first. The table, the surface and the panel all depend on the types and the query key it defines — build them on top once the data is flowing, not before. The a feature end to end walkthrough shows that exact order.

How to use a recipe

Every recipe page follows the same rhythm, so once you've done one the rest feel familiar:

  1. Find the closest twin. Pick the existing folder or file that most resembles what you're adding — same shape of data, same kind of action.
  2. Copy and rename. Duplicate it, rename the folder and the symbols inside, swap the resource name everywhere.
  3. Re-point the data. Change the query, the endpoint and the types to your new resource.
  4. Wire it in. Register the panel or surface, add the column, mount the route — whatever the last mile is for that shape.

Panels and surfaces have one extra beat: they're registered, not imported. Each lives in a _registry folder with a generated *-definitions.gen.ts file, so after you add one you regenerate that map rather than hand-editing an import. The two registry recipes — Add a Side Panel and Add a Surface — walk you through it, and Panels and surfaces explains why the registry exists at all.

Where to go next

On this page