Documentatie-pipeline (CI-workflows)

Dit document legt uit welke GitHub Actions-workflows de documentatie bewaken en publiceren, en hoe ze samenwerken over de levenscyclus van een wijziging. Voor de werkwijze per PR (waar hoort welke doc), zie Documentatie bijdragen.

Twee soorten documentatie, twee bestemmingen

Tapster kent twee soorten docs, met elk een eigen pijplijn (zie ook Documentatie bijdragen):

  • Interne docs in docs/ (deze map): voor het team, gepubliceerd als GitHub Pages-site.
  • Eindgebruiker-docs in apps/**/userdocs/: voor klanten, gepubliceerd in de Freescout knowledge base.

De vier workflows hieronder verdelen zich over deze twee soorten en over drie momenten in de levenscyclus: bij een pull request (controle), bij een release (generatie) en na merge naar main (publicatie).

Overzicht

Workflow Bestand Trigger Soort docs Wat het doet Schrijft naar buiten
Docs check docs-check.yml Pull request Interne docs/ Waarschuwt als productiecode wijzigt zonder docs/-update Nee (PR-comment)
Userdocs check userdocs-check.yml Pull request userdocs/ Valideert frontmatter (hard) + waarschuwt bij ontbrekende userdocs (soft) Nee (PR-comment)
Release Docs (AI) release-docs.yml Release-please PR met label release:minor/release:major Interne docs/releases/ Genereert met Claude een test-checklist en klant-release-notes Ja (commit naar release-branch)
Userdocs sync naar Freescout KB freescout-sync.yml Push naar main (of handmatig) userdocs/ Pusht userdocs naar de Freescout KB Ja (Freescout-API + frontmatter-back-commit)

Fase 1: controle bij de pull request

Twee workflows draaien op elke PR als zachte vangrails. Ze blokkeren niets behalve één harde validatie, en plaatsen een comment dat zichzelf opruimt zodra het probleem is opgelost.

Docs check

docs-check.yml vergelijkt de gewijzigde bestanden tussen base en head. Raakt de PR productiecode (apps/api/src/, apps/frontend/src/app/ of libs/) zonder ook maar iets onder docs/ aan te passen, dan plaatst de workflow een waarschuwingscomment dat een doc-update of ADR suggereert. Het comment is geen blocker.

Onderdrukken kan op twee manieren:

  • Vink Geen docs nodig aan in de PR-body, of
  • Plak het label docs: not-needed op de PR.

Een marker-comment (<!-- docs-check:warning -->) zorgt dat de workflow zijn eigen comment terugvindt: bij een volgende push wordt het geüpdatet, en zodra de waarschuwing niet meer nodig is, verwijdert de workflow het comment weer.

Userdocs check

userdocs-check.yml doet twee dingen op elke PR:

  1. Hard (validate-job): draait npm run userdocs:validate en controleert dat álle bestaande userdocs/ valide frontmatter hebben (zod-validator). Dit faalt de PR bij een fout, want een kapotte frontmatter breekt later de Freescout-sync.
  2. Soft (check-job): raakt de PR feature-code (apps/frontend/src/app/features/ of apps/api/src/modules/) zonder een userdocs/-update, dan plaatst de workflow een waarschuwingscomment dat naar /generate-userdocs verwijst. Dezelfde onderdruk-opties als bij Docs check gelden hier.

Beide PR-checks slaan release-please-branches over (release-please--*), zodat automatische release-PR’s geen ruis veroorzaken.

Wanneer draaien deze checks (en waarom niet meteen)?

Beide checks zijn pull_request-getriggerd en hebben dus een PR nodig. Een kale git push van een branch opent zelf geen PR; dat doet de “Pull Request”-workflow (pr-auto-open.yml) automatisch. Twee dingen om te weten:

  • Branch-prefix: de auto-opener accepteert alleen branchnamen met prefix feat/, fix/, hotfix/, chore/, task/ of docs/. Een afwijkende naam wordt geweigerd en er komt geen PR (en dus geen checks).
  • Draft plus GITHUB_TOKEN: de auto-opener maakt de PR als draft aan met de standaard GITHUB_TOKEN. GitHub start bewust geen pull_request-workflows voor events die door GITHUB_TOKEN zijn veroorzaakt. Daarom draaien docs-check en userdocs-check nog niet op het moment dat de draft-PR verschijnt.

De checks vuren zodra er een PR-event langskomt dat niet van GITHUB_TOKEN komt. In dit project gebeurt dat bewust door de PR handmatig op “Ready for review” te zetten. Een vervolg-commit pushen werkt ook (dat is een synchronize-event). Dit geldt voor elke auto-geopende PR, niet alleen voor docs-branches. Dit is een bewuste keuze: de auto-opener gebruikt expres geen PAT, zodat een PR pas door CI loopt als de auteur ‘m klaar acht voor review.

Fase 2: generatie bij de release

release-docs.yml (“Release Docs (AI)”) draait op de PR die release-please opent, maar alleen als die PR het label release:minor of release:major draagt. Patch-releases slaan deze stap dus over.

De flow:

  1. scripts/generate-release-docs.sh verzamelt input voor de AI: het nieuwe versienummer, de lijst merged PR’s sinds de vorige release, afgeknipte diffs per PR en de conventional-commit changelog.
  2. De anthropics/claude-code-action laat Claude twee bestanden genereren:
    • release-docs/test-checklist.md: een interne test-checklist voor het ontwikkelteam.
    • docs/releases/v<versie>.md: klantvriendelijke release-notes met Jekyll-frontmatter.
  3. De test-checklist wordt in de PR-body geplakt (tussen release-docs:begin/end-markers), de release-notes worden naar de release-branch gecommit, en scripts/generate-docs-index.cjs werkt de index van docs/releases/ bij.

Twee bewuste ontwerpkeuzes zitten hierin verwerkt:

  • Loop guard: omdat de docs-commit met de RELEASE_PLEASE PAT wordt gepusht (nodig om downstream required checks te triggeren), vuurt die push de workflow opnieuw af. De AI is niet-deterministisch, dus de output verschilt vrijwel altijd en een diff-guard alleen houdt de loop niet tegen. De loop guard slaat daarom alle vervolgstappen over zodra HEAD onze eigen docs(releases): voeg klant-release-notes-commit is.
  • PAT in plaats van GITHUB_TOKEN: een push met de default GITHUB_TOKEN fired geen pull_request: synchronize, waardoor required checks niet opnieuw rapporteren op de nieuwe HEAD. De PAT-push doet dat wel.

Fase 3: publicatie na merge

freescout-sync.yml (“Userdocs sync naar Freescout KB”) draait bij elke push naar main waarbij iets onder apps/**/userdocs/** (of de sync-tool zelf) wijzigt, plus handmatig via workflow_dispatch.

De workflow draait npm run freescout:sync, dat de userdocs via de Freescout-API publiceert (FREESCOUT_BASE_URL / FREESCOUT_API_KEY). Daarna commit het bijgewerkte frontmatter (bijvoorbeeld de toegekende KB-article-ID’s) met [skip ci] terug naar de repo, zodat een volgende run weet welke artikelen al bestaan.

Handmatige workflow_dispatch-opties:

  • full_scan: scan alle userdocs in plaats van alleen de HEAD~1..HEAD-diff.
  • dry_run: print de geplande acties, doet geen API-calls en geen frontmatter-back-commit.
  • confirm_deletes: override de max_deletes_per_run safety-rail (vangrail tegen massale verwijderingen).

De volledige flow in één beeld

Pull request
 ├─ Docs check ............ productiecode zonder docs/?      → PR-comment
 └─ Userdocs check ........ frontmatter valide? (hard)       → faalt PR bij fout
                            feature-code zonder userdocs/?   → PR-comment

Release-please PR (label release:minor/major)
 └─ Release Docs (AI) ..... genereer test-checklist          → PR-body
                            genereer klant-release-notes     → docs/releases/

Push naar main (userdocs gewijzigd)
 └─ Freescout sync ........ publiceer userdocs               → Freescout KB
                            schrijf KB-ID's terug            → frontmatter-commit

Veelgemaakte verwarring

  • Docs check vs Userdocs check: beide draaien op PR’s en plaatsen een waarschuwingscomment, maar ze bewaken verschillende mappen. Docs check kijkt naar de interne docs/-map; Userdocs check kijkt naar userdocs/ én valideert daarvan de frontmatter hard.
  • Userdocs check vs Freescout sync: “check” is de pre-merge poortwachter binnen de repo; “sync” is de post-merge publicatie naar de externe Freescout KB. De check schrijft niets naar buiten, de sync wel.
  • Release Docs vs de andere drie: dit is de enige doc-workflow die inhoud genereert (met AI) in plaats van bestaande docs te controleren of te kopiëren, en de enige die op een release-PR hangt.

Zie ook