Functions — how this works
In the app: /functions
How it works
A function is a saved, named Expr tree — field-read | literal | allow-listed-fn-call (concat/upper/lower/round/if) | binop (add/sub/mul/div/eq/neq/gte/lte/gt/lt/and/or) — over a FIXED allow-list of Lead fields, validated (validateUserFunctionSpec()) before it's ever saved. "Create from a template" is the only authoring path — no free-form expression editor. Every saved function renders as its own computed column, evaluated LIVE against each visible lead by the pure evaluateExpr() — never eval/Function, never arbitrary code. An unsafe or malformed spec (an unknown field/function/operator) is refused with reasons and no row is written.
Data source
src/lib/functions/userFunctions.ts (Expr, evaluateExpr, validateUserFunctionSpec, the Prisma repo).
Troubleshooting
A computed column shows "—"? The expression evaluated to null for that row — usually a referenced field (e.g. website) is empty on that lead. "Create function" doesn't appear in the list? Its key is already in use by an existing saved function — check the error banner.
Who can see this: admin