Eindgebruiker-documentatie (userdocs)

Userdocs zijn de Nederlandstalige uitleg die een klant te zien krijgt voor een Tapster-feature: niet voor het ontwikkelteam, maar voor de gebruiker, beheerder of admin die in de app zit. Ze wonen naast de feature-code in de repo, ze worden in dezelfde PR gereviewd als de code, en na merge naar main verschijnen ze automatisch als KB-artikel in Freescout onder mailbox 1.

Deze pagina legt het mentale model uit. Voor de stappen om er één toe te voegen, zie Voeg eindgebruiker-documentatie toe. Voor de CI-workflows die userdocs bewaken en publiceren, zie Documentatie-pipeline.

Wat een userdoc is en wat niet

Een userdoc is een markdown-bestand met frontmatter, in een userdocs/-map naast de feature-code:

apps/frontend/src/app/features/<scope>/<feature>/
  └── userdocs/
      ├── index.md            (verplicht als de feature user-facing is)
      ├── how-to-<verb>.md    (optioneel, voor afgebakende deeltaken)
      └── assets/             (optioneel, screenshots)

Voor backend-modules in apps/api/src/modules/<module>/ werkt het op dezelfde manier, mits het gedrag iets is dat een eindgebruiker (vaak een beheerder of admin) ziet of merkt.

Wat een userdoc niet is:

  • Geen developer-uitleg (“hoe is het geïmplementeerd”): dat hoort in docs/ of in code-commentaar.
  • Geen API-documentatie: die genereert de backend zelf via OpenAPI.
  • Geen release-notes: die komen uit docs/releases/, gegenereerd per minor of major release.

Het verschil tussen userdocs en docs/ staat ook in CONTRIBUTING-DOCS.

Eén audience per feature-folder

De top-level folder onder features/ bepaalt voor wie de userdoc is. Dat zorgt dat de juiste categorie-prefix in Freescout vanzelf klopt.

Folder audience Category-prefix
apps/frontend/src/app/features/user/... gebruiker Gebruiker > ...
apps/frontend/src/app/features/backoffice/... beheerder Beheerder > ...
apps/frontend/src/app/features/admin/... admin Admin > ...
apps/frontend/src/app/features/global/... passend bij wie het ziet matchend
apps/api/src/modules/... passend bij wie het raakt matchend

De levenscyclus

  schrijven         valideren           publiceren           bijwerken
  ─────────         ─────────           ──────────           ─────────
 /generate-     ─►  userdocs-check  ─►  freescout-sync  ─►   slash-command
 userdocs           (pull request)      (push naar main)     opnieuw, content
 + review                                                    hash detecteert
                                                             wijziging
  1. Schrijven. De slash-command /generate-userdocs <pad> leest routes, page-templates, components en i18n; past de Tapster-stijlregels toe (Nederlands, geen em-dashes, korte zinnen, tweede persoon); en schrijft een index.md met geldige frontmatter. Je reviewt de tekst zelf voor commit, want de AI mag niets verzinnen maar misinterpreteren kan altijd.
  2. Valideren. De CI-check userdocs-check.yml draait npm run userdocs:validate op elke PR. Een kapotte frontmatter (volgens het Zod-schema in tools/freescout-sync/src/frontmatter.ts) faalt hard. Daarnaast plaatst dezelfde workflow een zachte waarschuwing als feature-code wijzigt zonder bijbehorende userdocs-mutatie.
  3. Publiceren. Bij elke push naar main waarbij iets onder apps/**/userdocs/** wijzigt, draait freescout-sync.yml. Die rendert markdown naar HTML, regelt het categorie-pad in Freescout idempotent aan (categorieën worden aangemaakt als ze nog niet bestaan), maakt of updatet het artikel via de Freescout-API, en commit de toegekende freescout_article_id/freescout_category_id/content_hash terug naar de repo.
  4. Bijwerken. Wijzigt de tekst, dan verandert de content_hash en detecteert sync dat. Wijzigt er niets, dan skipt sync via die hash. Zet status: draft om een artikel weer in te trekken (DELETE op de Freescout-API); het bronbestand blijft staan voor traceability.

Het volledige CI-mechanisme (loop guards, draft-PR’s, safety-rails staat in detail uitgelegd in Documentatie-pipeline.

Waarom naast de code

Drie redenen om userdocs niet in een aparte repo of in Freescout-zelf te beheren:

  • Eén review, één merge. Wie het UI-gedrag verandert, raakt vrijwel altijd ook de uitleg. Door beide in dezelfde PR te zetten merk je verstoringen meteen (label hernoemd, knop verplaatst, flow gewijzigd).
  • Versiebeheer en blame. Een userdoc is gewoon markdown in git. Geschiedenis, branches en revert werken zoals bij code, en niet zoals in een ad-hoc WYSIWYG-editor in een KB.
  • AI-genereerbaar maar mensgereviewd. De slash-command kan een goede eerste versie schrijven omdat de bronnen (routes, templates, i18n) letterlijk naast het document liggen. Een mens reviewt voor commit. Een losse repo of CMS zou dat vertragen.

Het frontmatter-contract

Elke userdoc begint met YAML-frontmatter. Drie soorten velden:

Veld Wie zet ‘m Mag muteren?
title, slug, category, audience, visibility, status, last_reviewed jij, bij creatie of update ja, behalve slug (zie hieronder)
freescout_article_id, freescout_category_id de sync-workflow, na eerste publicatie nee, hand-aanpassen breekt idempotentie
content_hash de sync-workflow, na elke succesvolle sync nee, automatisch beheerd

slug is de stabiele ID over de levensduur van het document: aanpassen geeft een nieuw artikel in Freescout en laat het oude wezen-bestaan. status: draft is de standaard voor nieuw werk; published als de tekst geschikt is voor live KB. Setting status terug op draft na publicatie trekt het artikel in.

Het volledige schema en welke velden waarom verplicht zijn, staat in tools/freescout-sync/src/frontmatter.ts.

Wat je als developer doet

Concreet, op een normale feature-PR:

  1. Maak of update de feature-code.
  2. Roep /generate-userdocs apps/frontend/src/app/features/<scope>/<feature> (of het backend-equivalent) aan in Claude Code.
  3. Lees de gegenereerde tekst. Klopt elke UI-label met wat in de templates staat? Klopt de audience met de feature-folder? Zet status op published zodra de tekst geschikt is voor live KB.
  4. Draai lokaal npm run userdocs:validate. Verwacht ✓ N userdoc(s) valide.
  5. Commit beide (feature + userdocs) in dezelfde PR en push.
  6. Na merge naar main publiceert freescout-sync.yml het artikel automatisch binnen seconden.

De stap-voor-stap-versie met commando’s en branche-conventies staat in Voeg eindgebruiker-documentatie toe.

Wanneer hoort er een userdoc bij een PR?

Korte vuistregel: als een eindgebruiker iets nieuws of anders ziet, ja. Voor het volledige beslisschema (refactor, styling-tweak, bug-fix, admin- feature in apps/api/) zie de tabel in de how-to.

De CI-check is een waarschuwing, geen blocker. Onderdrukken met label docs: not-needed of de checkbox in de PR-body als er bewust geen userdoc nodig is.

Veelgemaakte verwarring

  • Userdocs valideren vs userdocs sync. npm run userdocs:validate controleert frontmatter lokaal of in CI; npm run freescout:sync publiceert naar Freescout. De PR-check valideert alleen; de post-merge workflow publiceert.
  • status: draft vs niet committen. draft betekent “wel in git, nog niet geschikt voor klanten”. Sync slaat draft-docs over voor publicatie en trekt eerder gepubliceerde docs in als hun status terug naar draft springt. Wil je een artikel echt nooit publiceren, commit dan niet.
  • /generate-userdocs vs hand-schrijven. Beide mag. De slash-command geeft een consistente eerste versie omdat hij routes/templates/i18n leest; hand-aanpassen na review is altijd toegestaan. Wijzig wel slug, freescout_article_id of content_hash niet hand-matig (zie frontmatter-contract).

Zie ook