-- name: CreatePerson :one INSERT INTO core.persons (user_id, display_name, primary_email, primary_email_verified) VALUES ($1, $2, $3, $4) RETURNING *; -- name: EnsureSystemPerson :exec -- Idempotently insert the reserved system person that owns the System tenant -- (keyed on the unique user_id). Read back with GetPersonByUserID. INSERT INTO core.persons (user_id, display_name, primary_email) VALUES ($1, $2, $3) ON CONFLICT (user_id) DO NOTHING; -- name: GetPersonByUserID :one SELECT * FROM core.persons WHERE user_id = $1; -- name: GetPersonByID :one SELECT * FROM core.persons WHERE person_id = $1; -- name: UpdatePerson :one UPDATE core.persons SET display_name = $1, primary_email = $2, primary_email_verified = $3 WHERE person_id = $4 RETURNING *; -- name: ListPersons :many SELECT * FROM core.persons ORDER BY display_name; -- name: LookupPersons :many -- Resolves a lookup term to one or more active persons for the operator -- landing-surface lookup affordance. Exact email match wins (deterministic -- — operators using email expect precision); otherwise falls through to -- case-insensitive substring match against display_name. Status='active' -- filters out removed accounts. LIMIT 20 caps the disambiguation list -- without paging. SELECT person_id, display_name, primary_email, status FROM core.persons WHERE status = 'active' AND (primary_email = $1 OR display_name ILIKE '%' || $1 || '%') ORDER BY CASE WHEN primary_email = $1 THEN 0 ELSE 1 END, display_name LIMIT 20; -- name: CountActivePersons :one -- Operator overview tile: how many people the deployment currently serves. -- Mirrors LookupPersons' status='active' filter so the headline number and -- the lookup affordance above it are counting the same population. SELECT COUNT(*) FROM core.persons WHERE status = 'active'; -- name: CountPersonsJoinedLast30Days :one -- The People tile's caption: velocity rather than a restatement of the -- census. Same status filter as CountActivePersons so both numbers -- describe the same population. SELECT COUNT(*) FROM core.persons WHERE status = 'active' AND created_at > now() - interval '30 days'; -- name: ListPersonsPage :many -- People directory operator surface (operator-list-scale UX-4 / -- operator-people-directory D6): the paged, searched query feeding -- GET /operator/persons. Ordered newest-joined first so "who joined this -- week?" is answered by page one. -- -- sqlc.narg(q): NULL matches every row; set, a case-insensitive substring -- match against display_name or primary_email (operator-list-scale: -- "carries a scoped server-side search" -- "people: display name and -- email"). -- sqlc.narg(exclude_person_id): the reserved system person (maintainer -- decision 2026-08-23: infrastructure, never "joined", excluded from the -- directory and its totals; it stays visible as the System tenant's owner -- in the organizations context). NULL excludes nothing. -- count(*) OVER() carries the true total for the filtered set alongside -- the page's rows (design D2), so the stated total never reflects only -- the page. SELECT person_id, user_id, display_name, primary_email, primary_email_verified, status, created_at, count(*) OVER() AS total_count FROM core.persons WHERE (sqlc.narg(exclude_person_id)::uuid IS NULL OR person_id <> sqlc.narg(exclude_person_id)::uuid) AND (sqlc.narg(q)::text IS NULL OR display_name ILIKE '%' || sqlc.narg(q)::text || '%' OR primary_email ILIKE '%' || sqlc.narg(q)::text || '%') ORDER BY created_at DESC LIMIT sqlc.arg(page_limit)::int OFFSET sqlc.arg(page_offset)::int;