- Add VitePress pages for AVAILABILITY_PICKER and SECTION_PRIORITY
and a TAG_PICKER configuration note. Wire them into the organisator
sidebar under a new Formulieren section alongside the existing
"Wat is een formulier" page.
- BACKLOG.md: nuance FORM-05 — the stub-shaped behaviour for public
event_registration submissions is already shipping via the existing
TriggerPersonIdentityMatchOnFormSubmit listener (writes 'pending').
The real work (PersonIdentityService::detectMatchesByValues + an
extra branch in resolveStatus) is what remains. Added a done entry
for S3a PR 2 to the Opgeloste items list.
- API.md: add VALIDATION_FAILED to the public-form error code table
and document the SECTION_PRIORITY shape error messages (Dutch copy
served under errors."values.{slug}").
- COPY_CATALOGUE.md: new S3a PR 2 section capturing the seeder
help_text, the IdentityMatchBanner copy (clearly marking the
backend message as authoritative), all empty/error state copy for
the three new components, and the SECTION_PRIORITY shape error
strings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
207 lines
7.8 KiB
Markdown
207 lines
7.8 KiB
Markdown
# Crewli — In-app copy catalogue
|
|
|
|
> Single source of truth for user-facing Dutch copy. Seeded from
|
|
> `/dev-docs/ARCH-FORM-BUILDER.md` §30.
|
|
|
|
## Purpose
|
|
|
|
Centralises terminology and warnings so every screen, tooltip, and
|
|
error message stays consistent. Without this, "Dienst" / "Shift" /
|
|
"Taak" drift across pages and confuse organisers; "Privacy-gevoelig"
|
|
and "Bevat persoonsgegevens" appear side-by-side for the same flag.
|
|
|
|
This catalogue is the canonical reference for both backend validation
|
|
messages (Form Requests) and frontend rendering (Vue components).
|
|
Whenever you write Dutch copy that a user will read, look here first.
|
|
|
|
## Growth strategy
|
|
|
|
Living document. Each session that adds user-facing UI:
|
|
|
|
1. **Check first.** Search for the concept (in Dutch and English) before
|
|
coining a new term. If it's here, use the existing wording verbatim.
|
|
2. **Propose new terms in PR.** Add to the relevant section. Brief
|
|
rationale in the commit message.
|
|
3. **Reviewer (Bert) signs off** on terminology before merge. Once a
|
|
term is in the catalogue, it's binding for future sessions.
|
|
|
|
The catalogue stays in `/dev-docs/` (developer-facing) rather than
|
|
`/docs/` (end-user-facing). End-user docs are written *using* this
|
|
catalogue, not *about* it.
|
|
|
|
## Update workflow
|
|
|
|
- Adding a tooltip → update §30.2 here.
|
|
- Adding a warning → update §30.3 here.
|
|
- Renaming a concept → update §30.1 here AND grep for all current
|
|
Dutch occurrences (frontend, validation messages, end-user docs)
|
|
and update them in the same PR.
|
|
- Wholesale restructure → discuss in design-document.md first; then
|
|
rewrite this catalogue in one commit.
|
|
|
|
## Naming conventions
|
|
|
|
| Concept | Canonical Dutch term | Never use |
|
|
| -------------------- | ---------------------------- | ---------------------------------- |
|
|
| `form_schema` | Formulier | Schema, template |
|
|
| `form_field` | Veld | Vraag, item |
|
|
| `form_template` | Formulier-sjabloon | Template (alleen in dev-docs) |
|
|
| `form_field_library` | Veldenbibliotheek | Library, bibliotheek alleen |
|
|
| `form_submission` | Inzending | Submission, antwoord |
|
|
| `is_filterable` | Filterbaar | Queryable, zoekbaar |
|
|
| `is_pii` | Bevat persoonsgegevens | Privacy-gevoelig |
|
|
| `freeze_on_submit` | Bevriezen na inzending | Vergrendelen |
|
|
| `consent_version` | Toestemmingsversie | Consent-versie |
|
|
|
|
## Tooltip catalogue (selection)
|
|
|
|
```
|
|
is_filterable:
|
|
"Filterbaar — dit veld wordt extra geïndexeerd voor snelle filtering
|
|
in overzichten. Alleen aanvinken voor velden die je daadwerkelijk als
|
|
filter gebruikt (bijvoorbeeld: shirtmaat wel, motivatie niet)."
|
|
|
|
is_pii:
|
|
"Bevat persoonsgegevens — bij retentie-verwerking worden deze waardes
|
|
geanonimiseerd volgens je privacy-instellingen. Vink aan voor velden
|
|
zoals telefoon, e-mail, noodcontact, medische info."
|
|
|
|
is_unique:
|
|
"Uniek per formulier — waardes van dit veld moeten uniek zijn over alle
|
|
inzendingen heen. Geschikt voor bijvoorbeeld BSN of werknemersnummer.
|
|
Dubbele waardes worden afgewezen."
|
|
|
|
freeze_on_submit:
|
|
"Bevriezen na eerste inzending — zodra iemand het formulier indient
|
|
kunnen de velden niet meer gewijzigd worden. Gebruik dit voor
|
|
contracten, signatures, of formulieren waar de structuur vast moet
|
|
staan voor audit-doeleinden."
|
|
|
|
snapshot_mode:
|
|
never: "Geen snapshot — wijzigingen worden alleen in het activity log
|
|
bijgehouden."
|
|
on_submit: "Snapshot bij inzending — bij elke indiening wordt het
|
|
complete formulier gesnapshot voor audit-doeleinden."
|
|
always: "Altijd snapshot — elke wijziging (ook drafts) wordt
|
|
gesnapshot. Gebruikt meer opslag maar biedt het volledige
|
|
audit-spoor."
|
|
|
|
retention_days:
|
|
"Bewaartermijn — na deze periode (vanaf inzendingsdatum) worden
|
|
PII-velden automatisch geanonimiseerd. Typische waardes: 1095 dagen
|
|
(3 jaar) voor vrijwilligers, 2555 dagen (7 jaar) voor contracten,
|
|
null voor onbeperkt bewaren."
|
|
```
|
|
|
|
## Warning catalogue (selection)
|
|
|
|
```
|
|
binding_change_with_submissions:
|
|
"Je staat op het punt de koppeling van dit veld te wijzigen terwijl er
|
|
al {count} ingediende inzendingen zijn. De historische waardes blijven
|
|
bestaan, maar zijn niet meer de bron-van-waarheid. Dit kan niet
|
|
ongedaan worden gemaakt."
|
|
|
|
delete_schema_with_submissions:
|
|
"Dit formulier heeft {count} inzendingen. Als je het verwijdert, blijven
|
|
de inzendingen bewaard als archief maar zijn niet meer nieuw in te
|
|
dienen. Type de naam van het formulier om te bevestigen:"
|
|
|
|
field_type_change:
|
|
"Je wijzigt het veldtype van {old} naar {new}. Bestaande waardes worden
|
|
mogelijk niet correct omgezet — sommige kunnen onleesbaar worden.
|
|
Aanbevolen: maak een nieuw veld aan in plaats van dit veld te
|
|
wijzigen."
|
|
|
|
public_token_rotation:
|
|
"Je roteert de publieke link voor dit formulier. Bestaande gebruikers
|
|
kunnen nog 7 dagen inzenden met de oude link; daarna krijgen ze een
|
|
410 Gone foutmelding."
|
|
```
|
|
|
|
## S3a PR 2 — Public form field types & identity-match
|
|
|
|
### Seeder help_text (showcase demo fields)
|
|
|
|
```
|
|
beschikbaarheid.help_text:
|
|
"Vink alle dagdelen aan waarop je kunt werken."
|
|
|
|
sectie_voorkeur.help_text:
|
|
"Sleep je voorkeuren in volgorde. Nummer 1 is je eerste keuze."
|
|
```
|
|
|
|
### IdentityMatchBanner — single source of truth is the backend
|
|
|
|
Copy is served by PublicFormSubmissionResource::formatIdentityMatch()
|
|
in `identity_match.message`. The frontend fallbacks in
|
|
`IdentityMatchBanner.vue` duplicate these exactly and must stay in sync
|
|
whenever the backend copy changes.
|
|
|
|
```
|
|
identity_match.pending.title: "We controleren je gegevens"
|
|
identity_match.pending.body:
|
|
"We kijken of je al bekend bent bij de organisator. Je gegevens
|
|
worden automatisch gekoppeld zodra zij dit bevestigen."
|
|
(backend message:
|
|
"We controleren of je al bekend bent bij de organisator. Je gegevens
|
|
worden gekoppeld zodra zij dit bevestigen.")
|
|
|
|
identity_match.matched.title: "Gegevens gekoppeld"
|
|
identity_match.matched.body:
|
|
"Je bent automatisch gekoppeld aan je bestaande account bij de
|
|
organisator."
|
|
(backend message:
|
|
"Je account is gekoppeld aan een bekende deelnemer.")
|
|
|
|
identity_match.none.title: "Aanmelding ontvangen"
|
|
identity_match.none.body:
|
|
"De organisator neemt contact met je op zodra je aanmelding is
|
|
verwerkt."
|
|
(backend message:
|
|
"Geen bestaand account gevonden — je wordt als nieuwe deelnemer
|
|
geregistreerd.")
|
|
```
|
|
|
|
### Empty-state copy (public form field components)
|
|
|
|
```
|
|
FieldTagPicker.empty:
|
|
"Er zijn nog geen tags beschikbaar voor dit formulier."
|
|
|
|
FieldAvailabilityPicker.empty:
|
|
"Er zijn nog geen tijdsloten beschikbaar."
|
|
|
|
FieldAvailabilityPicker.error:
|
|
"Kon beschikbaarheidsopties niet laden." [button: "Opnieuw proberen"]
|
|
|
|
FieldSectionPriority.empty:
|
|
"Er zijn nog geen secties gepubliceerd voor registratie."
|
|
|
|
FieldSectionPriority.error:
|
|
"Kon secties niet laden." [button: "Opnieuw proberen"]
|
|
|
|
FieldSectionPriority.cap_hint:
|
|
"Maximaal {max_priorities} voorkeuren"
|
|
|
|
FieldSectionPriority.first_rank_hint:
|
|
"Tik of sleep een sectie hieronder om je eerste voorkeur te kiezen."
|
|
```
|
|
|
|
### SECTION_PRIORITY — FormValueService shape errors
|
|
|
|
Returned under `errors."values.{slug}"` in the standard
|
|
`VALIDATION_FAILED` envelope.
|
|
|
|
```
|
|
"Ongeldig formaat voor sectievoorkeuren."
|
|
"Je kunt maximaal 5 voorkeuren opgeven."
|
|
"Ongeldig voorkeur-element op positie {n}."
|
|
"section_id ontbreekt op positie {n}."
|
|
"priority ontbreekt of is ongeldig op positie {n}."
|
|
"priority moet tussen 1 en 5 liggen (positie {n})."
|
|
"Dezelfde sectie mag slechts één keer worden opgegeven."
|
|
"Elke prioriteit mag slechts één keer worden toegekend."
|
|
"Eén of meer secties horen niet bij dit evenement."
|
|
```
|