# Routes `config/routes.toml` is the product's route table: which path reaches which function or container, and which paths require an end user's session. A route's posture is read off where it is declared, never off an attribute: - a `[[route]]` entry is **public**; - a `[[authenticate.route]]` entry, inside the `[authenticate]` block, **requires a session**. `aircloud routes` prints the resolved table and which routes require a session. ```sh aircloud routes ``` ## Public routes ```toml [[route]] prefix = "/api/health" function = "health" org_path = "/" ``` `prefix` is an absolute path with no trailing slash. A route names exactly one target: `function` or `container` (`flow` and `module` are reserved and refused). `strip_prefix = true` removes the prefix before the request reaches its target. A public route never carries `roles`. A public route has no end user, so a route to a function declares the node its invocations act at, `org_path`: `aircloud check` refuses one without it (`route.org_path_required`). `"/"` acts at the root, over every customer, and counts only because it is written; the generators write it, so edit it to act lower. A route to a container runs no function and declares none (`route.org_path_not_invocation`). See [The acting node and elevation](acting-node.md). ## Public site pages need no route The site is the fallback: every path that no route claims is answered by the site, so a page anyone may open needs no entry in `config/routes.toml`. `/about` is served by the site's `/about` page with nothing declared. A `[[route]]` entry therefore never carries `site`: `aircloud check` refuses it with `schema.unknown_key`, and the message says why. Declare a site route only for pages that require a session, as an `[[authenticate.route]]` with `site = true` (below). ## Routes that require a session ```toml [authenticate] sign_in = "/sign-in" [[authenticate.route]] prefix = "/api/session" function = "session" [[authenticate.route]] site = true prefix = "/account" roles = ["staff"] ``` Without a session, a site page redirects to `sign_in` (by default `/_air/session/login`), and any other request is refused with `session_required`. `roles` narrows a route to the end users holding at least one of the listed roles; a session holding none of them is refused with `session_role_required`. Without `roles`, any session passes. The roles themselves are declared once in `[authenticate]`: see [Members, roles and registration](members.md). The roles are those of the end user's selected membership. `at = ""` evaluates them at that node: the route passes only when one of its roles is effective there or at a node below it, through the membership's home or a grant. A product that declares workspaces must scope with `at` every route admitting a role of its workspace admin profile (`authenticate.route_at_required`, see [Workspaces](workspaces.md)). ## Nested site routes A `site = true` route of `[authenticate]` protects **every path under its prefix**, so one entry protects a whole area of the site. Its page is `src/pages//index.jsx`, named in `src/routes.js` with the path `/*`, and its sub-routes are `` inside that page. With the `/account` route above, `/account/orders/42` requires a session too: it is a sub-route of the `/account` page, never a separate entry. `aircloud check` validates the table against the product, and `aircloud routes` shows it as the platform resolves it. --- Rendered from aircloud 0.1.12 at commit d84a0ce6dae53629277f656d96d81549df36807e.