Forms
Forms are the structural primitive Appilot uses to author multi-field workflows. This page is a brief technical slice for integrators. The admin authoring guide is Managing Forms.
Schema
| Field | Type | Notes |
|---|---|---|
id | UUID | API-generated. |
app_id | int | Mandatory. |
domain_id | int | null | Optional per-domain scoping. |
semantic_id | string | Unique per app. Lowercase + hyphens. |
label | string | Default-locale name. |
label_i18n, description_i18n | record<locale, string> | null | Locale overrides. |
view_paths | string[] | Ordered. Non-empty. |
required_field_ids | string[] | UUIDs of fields in this form. |
submit_control_id, entry_control_id | string | null | UUIDs of controls. |
visibility_rules | array | DSL: { when: {control, op, value?}, show: [semantic_ids] }. |
field_defaults | record<semantic_id, value> | null | 'none' | 'lorem' | 'sample_url' | 'sample_email' | { literal: string }. |
Controls gain two columns:
form_id: UUID | null. The form this control belongs to.form_order: int | null. Position inside the form's fill order. Both set together or both NULL (DB CHECK).
REST API
All endpoints require a JWT and are org-scoped via requireSameOrg.
List forms
curl -H "Authorization: Bearer $TOKEN" \
"https://api.appilot.example/domain/forms?app_id=42&resolveFields=true"
resolveFields=true populates each form's fields[] projection (joining controls.form_id).
Get a single form
curl -H "Authorization: Bearer $TOKEN" \
"https://api.appilot.example/domain/forms/$FORM_ID"
Always returns the form with fields[] resolved.
Create
curl -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
"https://api.appilot.example/domain/forms" \
-d '{
"app_id": 42,
"semantic_id": "online-service-form",
"label": "Online service form",
"view_paths": ["app/online-services/form/general", "app/online-services/form/params"],
"required_field_ids": [],
"submit_control_id": null,
"entry_control_id": null
}'
Update / Delete
PUT /domain/forms/:id and DELETE /domain/forms/:id. Delete returns 409 with dependents when KB entries reference the form (active in PR-2 once tokens land).
Validation
The backend validator (formsValidator.ts) enforces:
view_pathsnon-empty.submit_control_id/entry_control_idreference controls in the same app.entry_control_idis NOT itself a field of this form.- Every
required_field_idis a field of this form. visibility_rules.when.controlexists in the app;show[]references fields of this form.field_defaultskeys are semantic_ids of fields in this form.
Failures return HTTP 400 with a violations: [{ code, message, field }] array.
Agent integration
- Step 0 loads forms via
FormsRepository.getByAppId({ resolveFields: true }). - The model references forms through Narrative Step markers such as
[Complete the form]({{form:online-service-form}}). - The
assemblePlanpost-processor validatesform_values, applies visibility rules/defaults, inlines prerequisites, and emits the trustedAssembledPlanconsumed by the guided Action Plan UI.
Authors reference forms / controls / tools from KB markdown via {{form:semantic_id}} / {{control:semantic_id}} / {{tool:semantic_id}}. KnowledgeContentCrud extracts the tokens at write time into knowledge_content.refs_index (migration 017) so cascade-prevention queries do not have to re-parse markdown.