queries
Installation
SKILL.md
Queries
Reads live in app/<mod>/queries/ — never services/ (those are for behavior with side effects). Types are defined inside the query file; the frontend consumes them via import type, so there is no duplication and no separate types/ file.
Two flavors — pick one, then open its reference
The two shapes never coexist in one task. Choose by what you're building:
- List query — a paginated CRUD table (search / filter / sort), returning
ModelPaginatorContract<Model>for a resourceindex. → references/list-queries.md. - Read model — an aggregate screen (dashboard, report): one query per business concept, composed by the controller with
Promise.all([...]). → references/read-models.md.
Rules (both flavors)
- Location:
app/<mod>/queries/<verb>_<subject>.ts— e.g.,list_users.ts,get_revenue_metrics.ts. - Shape: default-export a class with
async handle(input).Inputis a plaintypeorinterface. NoHttpContext. - Split by business concept — not by widget (fragmentation) and not per screen (couples the query to a UI).
- Frontend consumes types via
import typefrom the query file. Type-only imports are stripped at build, so the frontend never bundles server code. - Never return raw Lucid instances to Inertia — lists run through a Transformer variant ([[crud]]); read models return a plain object shape.