diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..9a01de9f --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,15 @@ +## Ziel +Kurze Beschreibung des Ziels/Problems und was dieser PR löst. + +## Änderungen +- + +## Prüfliste (Definition of Done) +- [ ] CI grün (Backend/Docs) +- [ ] Doku-Front‑Matter vorhanden und valide (`modul`, `status`, `summary`, optional `last_reviewed`, `review_cycle`, `yt_epic/yt_issues`) +- [ ] Links geprüft (CI Link‑Checker läuft grün) +- [ ] Falls relevant: YouTrack‑Key im PR‑Titel/Commit enthalten (z. B. MP-7) +- [ ] Bei Architekturänderung: ADR aktualisiert und verlinkt + +## Screenshots/Notizen (optional) +- diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml new file mode 100644 index 00000000..0a8d3387 --- /dev/null +++ b/.github/workflows/ci-docs.yml @@ -0,0 +1,89 @@ +name: CI Docs +on: + pull_request: + paths: + - 'docs/**' + - '.junie/**' + - '.github/workflows/ci-docs.yml' + - '.markdownlint.yaml' + - '.vale.ini' + push: + branches: [ main ] + paths: + - 'docs/**' + - '.junie/**' + - '.github/workflows/ci-docs.yml' + - '.markdownlint.yaml' + - '.vale.ini' + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node (markdownlint) + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Install markdownlint + run: npm i -g markdownlint-cli + - name: Markdownlint + run: markdownlint 'docs/**/*.md' + + - name: Setup Vale + run: | + curl -fsSL https://install.goreleaser.com/github.com/errata-ai/vale.sh | sh + sudo mv bin/vale /usr/local/bin/vale + - name: Vale + run: vale docs/ + + - name: Link Checker + uses: lycheeverse/lychee-action@v1 + with: + args: --verbose --no-progress 'docs/**/*.md' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Front-Matter Schema Validate + run: | + pip install pyyaml jsonschema + python .junie/scripts/validate-frontmatter.py + + - name: Docs Drift Check + run: bash .junie/scripts/check-docs-drift.sh + + - name: Render PlantUML + run: bash .junie/scripts/render-plantuml.sh + + - name: Upload diagrams artifact + uses: actions/upload-artifact@v4 + with: + name: diagrams + path: build/diagrams + + - name: Validate YouTrack issues exist (optional) + if: ${{ env.YT_URL != '' && env.YT_TOKEN != '' }} + run: | + set -euo pipefail + KEYS=$(grep -Rho "[A-Z]\+-[0-9]\+" docs | sort -u || true) + if [ -z "$KEYS" ]; then + echo "No YouTrack keys found in docs." + exit 0 + fi + echo "Prüfe Keys:" $KEYS + fail=0 + for k in $KEYS; do + code=$(curl -s -o /dev/null -w "%{http_code}" \ + -H "Authorization: Bearer $YT_TOKEN" \ + -H "Accept: application/json" \ + "$YT_URL/api/issues/$k?fields=idReadable") + if [ "$code" != "200" ]; then + echo "[YT] Issue nicht gefunden: $k (HTTP $code)"; fail=1; + fi + done + exit $fail + env: + YT_URL: ${{ secrets.YT_URL }} + YT_TOKEN: ${{ secrets.YT_TOKEN }} diff --git a/.github/workflows/youtrack-sync.yml b/.github/workflows/youtrack-sync.yml new file mode 100644 index 00000000..74855540 --- /dev/null +++ b/.github/workflows/youtrack-sync.yml @@ -0,0 +1,29 @@ +name: YouTrack Sync (on merge) +on: + push: + branches: [ main ] + +jobs: + notify: + runs-on: ubuntu-latest + steps: + - name: Comment to YouTrack Issue(s) + run: | + set -euo pipefail + KEYS=$(git log -1 --pretty=%B | grep -o '[A-Z]\+-[0-9]\+' | sort -u || true) + if [ -z "$KEYS" ]; then + echo "No issue keys in last commit message. Skipping." + exit 0 + fi + for ISSUE in $KEYS; do + MSG=$(printf 'PR/Commit gemergt: %s\nRepo: %s\nCommit: %s' "${{ github.event.head_commit.url }}" "${{ github.repository }}" "${{ github.sha }}") + curl -sS -X POST \ + -H "Authorization: Bearer $YT_TOKEN" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" \ + "$YT_URL/api/issues/$ISSUE/comments" \ + -d "{\"text\": \"$MSG\"}" + done + env: + YT_URL: ${{ secrets.YT_URL }} + YT_TOKEN: ${{ secrets.YT_TOKEN }} diff --git a/.junie/scripts/check-docs-drift.sh b/.junie/scripts/check-docs-drift.sh new file mode 100644 index 00000000..0d9e7d2c --- /dev/null +++ b/.junie/scripts/check-docs-drift.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +err=0 + +has() { grep -q "$2" "$1" || { echo "[DRIFT] '$2' fehlt in $1"; err=1; }; } +miss() { grep -q "$2" "$1" && { echo "[DRIFT] Veralteter Begriff '$2' in $1"; err=1; }; } + +# Quelle der Wahrheit: Spring Cloud Gateway +has docs/overview/system-overview.md "Spring Cloud Gateway" +has docs/architecture/adr/0007-api-gateway-pattern-de.md "Spring Cloud Gateway" +miss docs/architecture/adr/0007-api-gateway-pattern-de.md "Ktor" + +# C4: Container muss Technology korrekt führen +has docs/architecture/c4/02-container-de.puml "Spring Cloud Gateway" +miss docs/architecture/c4/02-container-de.puml "Ktor" + +# Verbiete versehentlich verbliebene englische ADR/C4 ohne -de +if ls docs/architecture/adr/*.md 2>/dev/null | grep -E -v '-de\.md$' >/dev/null; then + echo "[DRIFT] Englische ADR-Dateien ohne -de gefunden in docs/architecture/adr/" + ls docs/architecture/adr/*.md | grep -E -v '-de\.md$' || true + err=1 +fi +if ls docs/architecture/c4/*.puml 2>/dev/null | grep -E -v '-de\.puml$' >/dev/null; then + echo "[DRIFT] Englische C4-Dateien ohne -de gefunden in docs/architecture/c4/" + ls docs/architecture/c4/*.puml | grep -E -v '-de\.puml$' || true + err=1 +fi + +exit $err diff --git a/.junie/scripts/render-plantuml.sh b/.junie/scripts/render-plantuml.sh new file mode 100644 index 00000000..0f12d6aa --- /dev/null +++ b/.junie/scripts/render-plantuml.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +mkdir -p build/diagrams +shopt -s nullglob +for f in docs/architecture/c4/*.puml; do + docker run --rm -v "$PWD":/data plantuml/plantuml -tsvg "/data/$f" -o "/data/build/diagrams" + echo "Rendered build/diagrams/$(basename "${f%.puml}").svg" +done diff --git a/.junie/scripts/validate-frontmatter.py b/.junie/scripts/validate-frontmatter.py new file mode 100644 index 00000000..a736dba5 --- /dev/null +++ b/.junie/scripts/validate-frontmatter.py @@ -0,0 +1,33 @@ +import os, re, yaml, json +from glob import glob + +try: + import jsonschema +except ImportError: + # GitHub Actions step will install this before running; provide friendlier message if missing + raise SystemExit("[FM] jsonschema package not installed. Please run: pip install jsonschema pyyaml") + +SCHEMA_PATH = 'docs/.frontmatter.schema.json' +FM_REGEX = re.compile(r'^---\n(.*?)\n---', re.S) + +with open(SCHEMA_PATH, encoding='utf-8') as f: + schema = json.load(f) + +errors = 0 +for path in glob('docs/**/*.md', recursive=True): + # Skip generated or non-content files if any (none by default) + with open(path, 'r', encoding='utf-8') as fh: + content = fh.read() + m = FM_REGEX.search(content) + if not m: + print(f"[FM] fehlt: {path}") + errors = 1 + continue + try: + fm = yaml.safe_load(m.group(1)) or {} + jsonschema.validate(fm, schema) + except Exception as e: + print(f"[FM] invalid in {path}: {e}") + errors = 1 + +exit(errors) diff --git a/.junie/vale/MoCode/ForbiddenTerms.yml b/.junie/vale/MoCode/ForbiddenTerms.yml new file mode 100644 index 00000000..759863ae --- /dev/null +++ b/.junie/vale/MoCode/ForbiddenTerms.yml @@ -0,0 +1,8 @@ +extends: existence +message: "Veralteter Begriff: '%s'" +level: error +ignorecase: true +scope: text +nonword: true +tokens: + - Ktor diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 00000000..1215c074 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,3 @@ +default: true +MD013: false # Zeilenlänge entspannt +MD033: false # Inline-HTML erlaubt diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 00000000..80c02d6b --- /dev/null +++ b/.vale.ini @@ -0,0 +1,5 @@ +StylesPath = .junie/vale +MinAlertLevel = warning + +[*.md] +BasedOnStyles = Vale, MoCode diff --git a/docs/.frontmatter.schema.json b/docs/.frontmatter.schema.json new file mode 100644 index 00000000..2d2edaec --- /dev/null +++ b/docs/.frontmatter.schema.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": ["status", "summary"], + "properties": { + "modul": {"type": "string"}, + "status": {"type": "string", "enum": ["active", "draft", "deprecated"]}, + "summary": {"type": "string"}, + "last_reviewed": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"}, + "review_cycle": {"type": "string", "pattern": "^\\d+d$"}, + "yt_epic": {"type": "string", "pattern": "^[A-Z]+-\\d+$"}, + "yt_issues": {"type": "array", "items": {"type": "string", "pattern": "^[A-Z]+-\\d+$"}}, + "tags": {"type": "array", "items": {"type": "string"}} + }, + "additionalProperties": true +} diff --git a/docs/api/README.md b/docs/api/README.md index db431745..b488d119 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -1,4 +1,15 @@ -# Meldestelle REST API Documentation +--- +modul: api-overview +status: active +last_reviewed: 2025-10-22 +review_cycle: 180d +summary: Überblick und Einstieg in die REST‑APIs der Meldestelle. +yt_epic: MP-1 +yt_issues: [MP-7] +tags: [api, overview] +--- + +# Meldestelle – REST‑API Dokumentation ## Überblick diff --git a/docs/api/members-api.md b/docs/api/members-api.md index 9c3595f7..fd35688f 100644 --- a/docs/api/members-api.md +++ b/docs/api/members-api.md @@ -1,4 +1,15 @@ -# Members API Documentation +--- +modul: members-api +status: active +last_reviewed: 2025-10-22 +review_cycle: 180d +summary: Dokumentation der Members‑API (Endpunkte, Parameter, Beispiele). +yt_epic: MP-1 +yt_issues: [] +tags: [api, members] +--- + +# Members‑API – Dokumentation ## Überblick diff --git a/docs/how-to/branchschutz-und-pr-workflow.md b/docs/how-to/branchschutz-und-pr-workflow.md new file mode 100644 index 00000000..37558912 --- /dev/null +++ b/docs/how-to/branchschutz-und-pr-workflow.md @@ -0,0 +1,49 @@ +--- +modul: workflow-pr-branchschutz +status: active +last_reviewed: 2025-10-22 +review_cycle: 180d +summary: Empfehlungen für Branchschutz, PR-Ablauf und Naming-Konventionen. +yt_epic: MP-1 +yt_issues: [] +--- + +# Branchschutz & Pull-Request Workflow + +Diese Anleitung beschreibt einen einfachen, robusten Flow für `main` mit kurzen Feature-Branches und klaren Qualitätschecks. + +## 1) Branch-Naming +- Feature: `feature/` +- Bugfix: `fix/` +- Docs: `docs/` + +Optional: Issue-Key voranstellen, z. B. `feature/MP-7-doku-konsolidieren`. + +## 2) Pull Request (PR) +- PR-Titel nach Conventional Commits (kurz): `docs(api): Front‑Matter vereinheitlicht (MP-7)` +- Beschreibung kurz mit Bulletpoints; DoD-Checkliste abhaken (Template vorhanden) +- CI muss grün sein (Backend + Docs) + +## 3) Branchschutz (GitHub Einstellungen → Branches → main) +- Require a pull request before merging +- Require status checks to pass before merging + - aktivieren: `CI Docs`, `CI` (Backend falls vorhanden) +- Require linear history +- Require approvals: mindestens 1 (bei Solo-Projekt optional, aber empfohlen) +- Allow squash merging only +- Disallow force pushes, Disallow deletions + +## 4) Commits & YouTrack +- Commit-Message enthält Issue-Key (z. B. `MP-7`) → erleichtert Nachverfolgung +- In Doku-Front‑Matter `yt_epic`/`yt_issues` pflegen +- Optional: GitHub Secrets `YT_URL`, `YT_TOKEN` setzen → CI validiert verlinkte Issues, und `youtrack-sync.yml` kommentiert beim Merge automatisch ins Issue + +## 5) Definition of Done (Auszug) +- Doku aktuell (README/ADR/C4/API) +- Front‑Matter valide (`modul`, `status`, `summary`, optional `last_reviewed`, `review_cycle`, `yt_*`) +- Links funktionieren (CI link-check grün) +- Tests grün + +## 6) Lokale Tipps +- Vor dem Push: `markdownlint`, `vale` lokal laufen lassen (optional via pre-commit hooks) +- kleine, häufige PRs statt großer Monster-PRs