Skip to main content

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

FieldTypeNotes
idUUIDAPI-generated.
app_idintMandatory.
domain_idint | nullOptional per-domain scoping.
semantic_idstringUnique per app. Lowercase + hyphens.
labelstringDefault-locale name.
label_i18n, description_i18nrecord<locale, string> | nullLocale overrides.
view_pathsstring[]Ordered. Non-empty.
required_field_idsstring[]UUIDs of fields in this form.
submit_control_id, entry_control_idstring | nullUUIDs of controls.
visibility_rulesarrayDSL: { when: {control, op, value?}, show: [semantic_ids] }.
field_defaultsrecord<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:

  1. view_paths non-empty.
  2. submit_control_id / entry_control_id reference controls in the same app.
  3. entry_control_id is NOT itself a field of this form.
  4. Every required_field_id is a field of this form.
  5. visibility_rules.when.control exists in the app; show[] references fields of this form.
  6. field_defaults keys 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 assemblePlan post-processor validates form_values, applies visibility rules/defaults, inlines prerequisites, and emits the trusted AssembledPlan consumed 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.