None yet
{{ /for }}` | | `{% include "card" with x=y %}` | `{{ partial "card" x=y }}` (file: `components/card.x.html`) | | `{% set x = v %}` | `{{ set x = v }}` | | `{% extends "base" %}` / block | `{{ layout "base" }}` at top; layout file prints content with `{{ slot }}` | Conditions support `== != < > <= >= and or not` and dotted paths: `{{ if user.role == "admin" }}`. Template `==` coerces numeric strings to numbers (`{{ if old.company_id == c.id }}` works when `old` came from form values). Modifiers (pipe-separated, args after `:`): `default`, `upper`, `lower`, `capitalize`, `truncate:80`, `length`/`count`/`size`, `reverse`, `strip`, `nl2br`, `raw`, `escape`, `json`, `slug`, `first`, `last`, `date:"%Y-%m-%d"`, `sort:"key"`, `where:"key",value`, `plural:"item","items"`, `join:", "`. Example: `{{ title | default:"Untitled" | truncate:80 }}`. An unknown modifier is an error that names the valid ones. Every page automatically has: `csrf_field`, `csrf_token`, `user`, `logged_in`, `path`, `method`, plus URL params. ## 6. Schema — `_schema/schema.lua` is the only migration artifact Declare desired state; the framework diffs against the live database and converges (in dev: on every request; in prod: via `effortless migrate`). **There are no migration files. To change the schema, edit this file.** ```lua local t = require "effortless.types" return { users = { id = t.pk, email = t.text { required = true, unique = true }, password_hash = t.secret, -- text + required + hidden + protected }, todos = { id = t.pk, user_id = t.ref "users", -- FK to users.id (or ref "users.id") title = t.text { required = true, min = 3, max = 120 }, status = t.enum { "new", "active", "done", default = "new" }, -- text + one_of in one call amount = t.real { min = 0 }, contact = t.text { email = true, unique = true }, completed = t.boolean { default = false }, created_at = t.now, -- datetime, defaults to now() day = t.text { computed = "date(created_at)" }, -- read-only SQL expression indexes = { "user_id", "created_at" }, }, -- Multi-tenant / CRM: owner_id is required in the DB but never posted in forms. -- validate() skips it; you set it in EQL from $auth.id (section 7). visits = { id = t.pk, visitor_id = t.visitor, -- text + required + hidden + protected; owner principal is visitor path = t.text, }, contacts = { id = t.pk, owner_id = t.ref "users" { required = true }, company_id = t.ref "companies", -- optional FK; empty