docs: registration form fields, section preferences & form redesign

Update SCHEMA.md (v1.8), design-document.md (v1.9), and API.md with
EAV system for dynamic event-specific registration fields, section
preferences, tag picker sync architecture, and field templates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 21:42:36 +02:00
parent 2102a35688
commit fcff3b0344
3 changed files with 385 additions and 22 deletions

View File

@@ -499,4 +499,89 @@ Response: `{ "confirmed": 2, "errors": [{ "match_id": "ulid3", "error": "User al
- `POST /portal/token-auth` — public. Validates a portal token against artists/production_requests tables. Returns `{ context, data, event }` on success. Returns 501 if token tables don't exist yet, 401 if token is invalid.
- `GET /portal/me` — auth:sanctum. Returns the authenticated user's person record for a given event. Query param: `event_id` (required, ULID). Resolves sub-events to parent festival. Returns `PersonResource` with crowdType, shiftAssignments, and volunteerAvailabilities eager-loaded. Returns 404 if no registration found.
## Registration Field Templates (Organisation Settings)
- `GET /organisations/{org}/registration-field-templates` — list active templates (ordered)
- `POST /organisations/{org}/registration-field-templates` — create template
- `PUT /organisations/{org}/registration-field-templates/{template}` — update template
- `DELETE /organisations/{org}/registration-field-templates/{template}` — delete (org-created) or deactivate (system)
> Templates: organisation-level reusable field definitions. System templates
> are seeded on org creation. Org-admins can customize and add their own.
## Registration Form Fields (Event Settings)
- `GET /events/{event}/registration-fields` — list all fields (ordered by sort_order)
- `POST /events/{event}/registration-fields` — create field (manually or from template)
- `POST /events/{event}/registration-fields/from-template` — create field from template
- `PUT /events/{event}/registration-fields/{field}` — update field
- `DELETE /events/{event}/registration-fields/{field}` — delete field definition (answers preserved)
- `POST /events/{event}/registration-fields/reorder` — bulk reorder
- `POST /events/{event}/registration-fields/import-from-event` — copy fields from another event
### From-Template Body
```json
{ "template_id": "ulid" }
```
Creates a COPY of the template as an event field. The copy is independent — changes don't propagate back to the template.
### Import Body
```json
{ "source_event_id": "ulid" }
```
Copies all `registration_form_fields` from the source event. Source must belong to the same organisation. Existing fields on the target event are kept.
### Tag Picker Fields
For `tag_picker` fields: the API response includes `available_tags` array (from `person_tags`, filtered by `tag_category` if set) so the frontend knows which tags to render as options.
## Person Field Values
- `GET /events/{event}/persons/{person}/field-values` — all answers for a person
- `PUT /events/{event}/persons/{person}/field-values` — bulk upsert answers
### Bulk Upsert Body
```json
{
"values": {
"field_slug": "value_or_array",
"shirtmaat": "L",
"dieetwensen": ["Vegetarisch", "Glutenvrij"],
"certificaten": ["01JXYZ...", "01JABC..."]
}
}
```
Replaces all field values for this person in one request. Used by both the registration form and the organiser backend. For `tag_picker` fields: values are arrays of `person_tag_id` ULIDs. If person has a `user_id`, tag sync is triggered automatically.
## Person Section Preferences
- `GET /events/{event}/persons/{person}/section-preferences` — list preferences
- `PUT /events/{event}/persons/{person}/section-preferences` — replace all preferences
### Replace Body
```json
{
"preferences": [
{ "festival_section_id": "01JXYZ...", "priority": 1 },
{ "festival_section_id": "01JABC...", "priority": 2 },
{ "festival_section_id": "01JDEF...", "priority": 3 }
]
}
```
## Person List Filtering (extended)
Additional filter parameters on `GET /events/{event}/persons`:
- `?field[slug]=value` — filter by registration field value (exact match for single-value, `JSON_CONTAINS` for multiselect)
- `?section_preference={section_id}` — filter by section preference (has this section as any priority)
- `?has_preference=true` — only persons who submitted section preferences
_(Extend this contract per module as endpoints are implemented.)_