Skip to content

Commit feb1510

Browse files
vitorbariclaude
andcommitted
feat: ordered arrays for step fields, actions, and gates
Implements ADR 021: `fields`, `actions`, `gates` on the runtime step and the definition step are ordered `[]{name, ...}` arrays on the wire instead of name-keyed dicts, preserving authorial display order through every layer (OpenAPI, ogen types, Go domain, validator, mappers, embed loader, JSONB storage). `transitions` stays a dict. The default Liquid template will iterate the arrays and build a name-indexed map locally for keyed lookups; that template change rides with the frontend PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c097a5f commit feb1510

35 files changed

Lines changed: 1206 additions & 1115 deletions

api/generated/oas_json_gen.go

Lines changed: 175 additions & 371 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/generated/oas_schemas_gen.go

Lines changed: 70 additions & 196 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/generated/oas_validators_gen.go

Lines changed: 59 additions & 73 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/openapi/components/flows/field.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
type: object
2-
required: [type, text_key]
2+
required: [name, type, text_key]
33
description: |
44
A data input capability. Describes what the user must provide.
55
Does not contain display text — only a `text_key` resolved client-side.
66
properties:
7+
name:
8+
type: string
9+
description: |
10+
Field name, matching a property in the flow's user schema. Carries
11+
the submitted value back to the engine.
12+
example: email
713
type:
814
type: string
915
enum: [text, email, password, tel, number, url, date, hidden]

api/openapi/components/flows/flow-definition-step.yaml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,31 @@ properties:
3232
example: [email, password]
3333

3434
actions:
35-
type: object
35+
type: array
3636
description: |
37-
Actions the user can take. Keyed by action name.
38-
The action name is what the frontend sends back in the submit request.
39-
If omitted, the engine provides a default `submit` action.
40-
additionalProperties:
37+
Ordered list of actions the user can take. The action name is what the
38+
frontend sends back in the submit request. If omitted, the engine
39+
provides a default `submit` action.
40+
items:
4141
$ref: step-action.yaml
42-
default: {}
42+
default: []
4343
example:
44-
submit:
44+
- name: submit
4545
primary: true
46-
forgot_password: {}
46+
- name: forgot_password
4747

4848
gates:
49-
type: object
49+
type: array
5050
description: |
51-
Security gates that must be satisfied before submission. Keyed by gate
52-
name. Each gate selects a kind (e.g. "captcha") and provider-specific
51+
Ordered list of security gates that must be satisfied before submission.
52+
Each gate selects a kind (e.g. "captcha") and provider-specific
5353
configuration. The engine may also inject gates dynamically based on
5454
policy.
55-
additionalProperties:
55+
items:
5656
$ref: gate.yaml
57-
default: {}
57+
default: []
5858
example:
59-
bot_check:
59+
- name: bot_check
6060
kind: captcha
6161
provider: altcha
6262

@@ -95,7 +95,7 @@ properties:
9595
description: |
9696
Maps action/outcome names to their transition descriptor.
9797
98-
Keys match action names from the `actions` dict. Additional keys
98+
Keys match action names from the `actions` array. Additional keys
9999
come from implicit outcomes based on schema annotations
100100
(e.g. `user_not_found` from `x-unique` fields) and engine
101101
events (e.g. `sso`, `callback`).

api/openapi/components/flows/flow-step.yaml

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
11
type: object
22
required: [name, fields, actions, gates]
33
description: |
4-
A step contains unordered capability dictionaries: what to collect (fields),
4+
A step contains ordered capability arrays: what to collect (fields),
55
what the user can do (actions), and what security gates must be satisfied (gates).
6-
Layout and element ordering are controlled by the LiquidJS template in `branding.liquid_template`.
6+
The LiquidJS template in `branding.liquid_template` iterates these arrays in order
7+
and builds name-keyed indexes locally for lookup.
78
example:
89
name: login
910
texts:
1011
title_key: login.title
1112
description_key: login.description
1213
fields:
13-
email:
14+
- name: email
1415
type: email
1516
text_key: login.field.email
1617
required: true
17-
password:
18+
- name: password
1819
type: password
1920
text_key: login.field.password
2021
required: true
2122
actions:
22-
submit:
23+
- name: submit
2324
text_key: login.action.submit
2425
primary: true
25-
register:
26+
- name: register
2627
text_key: login.action.register
27-
recover:
28+
- name: recover
2829
text_key: login.action.recover
2930
gates:
30-
captcha:
31+
- name: captcha
3132
kind: captcha
3233
provider: altcha
3334
config:
@@ -65,32 +66,32 @@ properties:
6566
format: uri
6667
description: URL to navigate to (e.g., SSO provider redirect).
6768
fields:
68-
type: object
69+
type: array
6970
description: |
70-
Unordered dictionary of input fields to collect. Keyed by field name.
71-
The LiquidJS template controls which fields appear and in what order.
72-
Field metadata (type, validation) is resolved by the engine from the
73-
flow's user schema.
74-
additionalProperties:
71+
Ordered list of input fields to collect. Field metadata (type, validation)
72+
is resolved by the engine from the flow's user schema. The LiquidJS
73+
template iterates this array; for keyed lookup it builds a name-indexed
74+
map locally.
75+
items:
7576
$ref: field.yaml
76-
default: {}
77+
default: []
7778
actions:
78-
type: object
79+
type: array
7980
description: |
80-
Unordered dictionary of available user actions. Keyed by action name.
81-
The LiquidJS template controls positioning and presentation.
82-
additionalProperties:
81+
Ordered list of available user actions. The LiquidJS template iterates
82+
this array and builds a name-indexed map locally for keyed lookup.
83+
items:
8384
$ref: step-action.yaml
84-
default: {}
85+
default: []
8586
gates:
86-
type: object
87+
type: array
8788
description: |
8889
Security gates that must be satisfied before the step can be submitted.
8990
The engine injects gates dynamically based on policy, even if they
9091
are not declared in the flow definition.
91-
additionalProperties:
92+
items:
9293
$ref: gate.yaml
93-
default: {}
94+
default: []
9495
sso_providers:
9596
type: array
9697
description: Available SSO identity providers for this step.

api/openapi/components/flows/gate.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
type: object
2-
required: [kind, provider]
2+
required: [name, kind, provider]
33
description: |
44
A security challenge that must be satisfied before this step's submission
55
is accepted. The engine may also inject gates at runtime based on policy
66
or risk evaluation.
77
properties:
8+
name:
9+
type: string
10+
description: Gate identifier within the step.
11+
example: bot_check
812
kind:
913
type: string
1014
enum: [captcha]

api/openapi/components/flows/step-action.yaml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
type: object
2+
required: [name]
23
description: |
3-
Configuration for a user-invokable action on a step. Keyed by action name
4-
in the parent dictionary. The action name is sent back in the submit
5-
request as `action`.
4+
Configuration for a user-invokable action on a step. The `name` is sent
5+
back in the submit request as `action`.
66
properties:
7+
name:
8+
type: string
9+
description: Action identifier. Sent back in the submit request as `action`.
10+
example: submit
711
primary:
812
type: boolean
913
default: false

0 commit comments

Comments
 (0)