Status: erledigt Meilenstein: v0.1.0 Labels: phase-1, infra, docs Geschätzt: 6 h Tatsächlich: 1 h 25 min
Ziel
Ein lauffähiges, leeres Projekt mit allen Qualitätsschranken, dem gehärteten Betriebsstand und dem Design-Fundament. Danach ist jeder weitere Meilenstein reine Fachlichkeit.
Aufgaben
Lokalen Branch master auf main umbenennen (Gitea-Default ist main), Remote unverändert lassen
.nvmrc = 24, packageManager: "pnpm@10.34.5" über corepack, engines.node >= 24
Next 16.3.6 (App Router, TypeScript strict) mit output: "standalone", src/-Layout
tsconfig.json: strict, noUncheckedIndexedAccess, verbatimModuleSyntax, forceConsistentCasingInFileNames, Alias @/* → ./src/*
docker-compose.yml gehärtet: postgresohneports:, Netze intern (internal: true) und extern, web auf ${BIND_ADDR:-127.0.0.1}:3000, migrate als One-Shot aus der Bau-Stufe, Healthchecks, ${VAR:?… fehlt in der .env}
docker-compose.dev.yml (nur Postgres, Port 5433) und docker-compose.test.yml (Postgres; der OpenLDAP-Dienst kommt mit #016, wo er tatsächlich benutzt wird)
.env.example mit allen Variablen und Kommentar je Variable
GET /api/gesundheit → SELECT 1 → 200/503
Sicherheitskopfzeilen in next.config.ts, CSP-Nonce in proxy.ts (Next 16: nicht middleware.ts)
scripts/pruefe-doku.mjs und pnpm pruefe:doku: Version hat Changelog-Abschnitt, Issue-Dateien und Übersicht stimmen überein, verlinkte Bilder existieren
scripts/gitea-issues.ts und pnpm issues:sync: spiegelt docs/issues/*.md in den Gitea-Tracker
.gitea/workflows/ci.yml nach ProxLedger-Muster, erweitert um Playwright und shellcheck
Design-Token als CSS-Variablen (Grund #0B0D10, Flächen #14171C/#1B1F26, Linien #262B33, Text #F3F5F7/#98A2B3, Akzent #C6F135, Status #3DDC97/#F5B84A/#F87171), heller Modus optional
Schriften selbst gehostet: @fontsource-variable/space-grotesk, -manrope, -jetbrains-mono
Wortmarke laufzettel (Space Grotesk 700, Laufweite −0.04em, Akzentpunkt) und Bildmarke [ ✓ ] als SVG, Favicon, PWA-Icon, manifest.ts
App-Shell: dunkle Sidebar mit „Scannen"-Knopf direkt unter dem Logo, Pillen-Buttons (40 px, am Handy 44–46 px), Karten mit Radius 16–18 px und 1-px-Linie ohne Schatten
Versionsanzeige unten links aus NEXT_PUBLIC_APP_VERSION und NEXT_PUBLIC_GIT_SHA
README.md, CHANGELOG.md (Keep a Changelog, deutsch), docs/devlog.md, CLAUDE.md mit Konventionen und Namensabbildung, docs/architektur.md, docs/abnahme-mvp.md
Gitea: Labels, Milestones v0.1.0…v0.5.0, Epic-Issues #001–#004 und Meilenstein-Issues #005–#019
Akzeptanzkriterien
docker compose up startet App und Datenbank, Migrationen laufen automatisch
Ein Commit ohne Conventional-Commits-Betreff wird vom Hook abgelehnt
Die App zeigt Wortmarke, Bildmarke und Version unten links im vorgegebenen Farbschema
Beim Bauen aufgefallen
pnpm 12 hat die Freigabe von Build-Skripten umbenannt.onlyBuiltDependencies wird von pnpm config list noch angezeigt, aber nicht mehr angewandt; wirksam ist allowBuilds als
Zuordnung in pnpm-workspace.yaml. Das pnpm-Feld in package.json liest pnpm 12 gar nicht
mehr und warnt darüber.
pnpm 12 prüft die Lieferkette. Pakete, die jünger als 24 Stunden sind, werden abgelehnt. vite@8.3.1 und lucide-react@1.48.0 erschienen am selben Tag und mussten auf 8.3.0 bzw. 1.47.0 zurück. Die Richtlinie bleibt an — sie ist sinnvoll.
eslint 10 bricht mit eslint-config-next.eslint-plugin-react@7.37.5 unterstützt nur bis eslint ^9.7 und hat keinen Nachfolger. Festgestellt, nicht geraten: TypeError: contextOrFilename.getFilename is not a function.
TypeScript 7 geht noch nicht.typescript-eslint@8 erlaubt >=4.8.4 <6.1.0.
shadcn init ist nicht skriptfähig — es fragt nach einem Preset, auch mit --yes, und
bleibt hinter einer Pipe hängen. shadcn add <bauteil> --yes --overwrite < /dev/null
funktioniert dagegen. Die Registry importiert den Helfer als blanken Modulnamen cn, dafür
braucht tsconfig.json den Pfad "cn": ["./src/lib/utils"], und die Bauteile brauchen das
Paket radix-ui.
Port 3000 war von ProxLedger belegt, die Abnahme lief deshalb auf 3100 bzw. 3200.
Die Migrationen laufen im Compose-Stand nachweislich automatisch; eingespielt wird ab #006
etwas, vorher meldet der Dienst korrekt „No pending migrations to apply".
Quelle: docs/issues/005-geruest-prozess-design.md — dort gepflegt, hierher gespiegelt.
**Status:** erledigt
**Meilenstein:** v0.1.0
**Labels:** phase-1, infra, docs
**Geschätzt:** 6 h **Tatsächlich:** 1 h 25 min
## Ziel
Ein lauffähiges, leeres Projekt mit allen Qualitätsschranken, dem gehärteten Betriebsstand und dem Design-Fundament. Danach ist jeder weitere Meilenstein reine Fachlichkeit.
## Aufgaben
- [x] Lokalen Branch `master` auf `main` umbenennen (Gitea-Default ist `main`), Remote unverändert lassen
- [x] `.nvmrc` = `24`, `packageManager: "pnpm@10.34.5"` über corepack, `engines.node >= 24`
- [x] Next 16.3.6 (App Router, TypeScript strict) mit `output: "standalone"`, `src/`-Layout
- [x] `tsconfig.json`: `strict`, `noUncheckedIndexedAccess`, `verbatimModuleSyntax`, `forceConsistentCasingInFileNames`, Alias `@/*` → `./src/*`
- [x] Tailwind 4 (`@import "tailwindcss"` + `@theme`, `@tailwindcss/postcss`), shadcn/ui initialisieren, `lucide-react`
- [x] ESLint flat config nach ProxLedger-Muster (`eslint-config-next/core-web-vitals` + `/typescript` + `eslint-config-prettier/flat`, `globalIgnores` inkl. `src/generated/**`), Prettier (`printWidth: 110`, `singleQuote: false`, `trailingComma: "all"`)
- [x] husky + lint-staged + commitlint (`@commitlint/config-conventional`) als Pre-Commit- und Commit-Msg-Hook
- [x] Vitest 5 (`vitest.config.mts`, `environment: "node"`, `fileParallelism: false`) und `vite@^7` als Peer; Playwright 1.63 (`playwright.config.ts`)
- [x] `Dockerfile` multi-stage (Basis → Abhängigkeiten → Bauen → Laufzeit), `node:24-alpine`, `tini`, Nutzer 1001, non-root
- [x] `docker-compose.yml` gehärtet: `postgres` **ohne** `ports:`, Netze `intern` (`internal: true`) und `extern`, `web` auf `${BIND_ADDR:-127.0.0.1}:3000`, `migrate` als One-Shot aus der Bau-Stufe, Healthchecks, `${VAR:?… fehlt in der .env}`
- [x] `docker-compose.dev.yml` (nur Postgres, Port 5433) und `docker-compose.test.yml` (Postgres; der OpenLDAP-Dienst kommt mit #016, wo er tatsächlich benutzt wird)
- [x] `.env.example` mit allen Variablen und Kommentar je Variable
- [x] `GET /api/gesundheit` → `SELECT 1` → 200/503
- [x] Sicherheitskopfzeilen in `next.config.ts`, CSP-Nonce in `proxy.ts` (Next 16: nicht `middleware.ts`)
- [x] `scripts/pruefe-doku.mjs` und `pnpm pruefe:doku`: Version hat Changelog-Abschnitt, Issue-Dateien und Übersicht stimmen überein, verlinkte Bilder existieren
- [x] `scripts/gitea-issues.ts` und `pnpm issues:sync`: spiegelt `docs/issues/*.md` in den Gitea-Tracker
- [x] `.gitea/workflows/ci.yml` nach ProxLedger-Muster, erweitert um Playwright und `shellcheck`
- [x] Design-Token als CSS-Variablen (Grund `#0B0D10`, Flächen `#14171C`/`#1B1F26`, Linien `#262B33`, Text `#F3F5F7`/`#98A2B3`, Akzent `#C6F135`, Status `#3DDC97`/`#F5B84A`/`#F87171`), heller Modus optional
- [x] Schriften selbst gehostet: `@fontsource-variable/space-grotesk`, `-manrope`, `-jetbrains-mono`
- [x] Wortmarke `laufzettel` (Space Grotesk 700, Laufweite −0.04em, Akzentpunkt) und Bildmarke `[ ✓ ]` als SVG, Favicon, PWA-Icon, `manifest.ts`
- [x] App-Shell: dunkle Sidebar mit „Scannen"-Knopf direkt unter dem Logo, Pillen-Buttons (40 px, am Handy 44–46 px), Karten mit Radius 16–18 px und 1-px-Linie ohne Schatten
- [x] Versionsanzeige unten links aus `NEXT_PUBLIC_APP_VERSION` und `NEXT_PUBLIC_GIT_SHA`
- [x] `README.md`, `CHANGELOG.md` (Keep a Changelog, deutsch), `docs/devlog.md`, `CLAUDE.md` mit Konventionen und Namensabbildung, `docs/architektur.md`, `docs/abnahme-mvp.md`
- [x] Gitea: Labels, Milestones `v0.1.0`…`v0.5.0`, Epic-Issues #001–#004 und Meilenstein-Issues #005–#019
## Akzeptanzkriterien
- [x] `docker compose up` startet App und Datenbank, Migrationen laufen automatisch
- [x] `nc -z localhost 5432` schlägt fehl, `docker compose exec web nc -z postgres 5432` gelingt
- [x] Ein Vitest-Test liest `docker-compose.yml` und schlägt an, wenn unter `postgres` ein `ports:` auftaucht
- [x] `pnpm lint && pnpm typecheck && pnpm test && pnpm pruefe:doku` grün
- [x] Ein Commit ohne Conventional-Commits-Betreff wird vom Hook abgelehnt
- [x] Die App zeigt Wortmarke, Bildmarke und Version unten links im vorgegebenen Farbschema
## Beim Bauen aufgefallen
- **pnpm 12 hat die Freigabe von Build-Skripten umbenannt.** `onlyBuiltDependencies` wird von
`pnpm config list` noch angezeigt, aber nicht mehr angewandt; wirksam ist `allowBuilds` als
Zuordnung in `pnpm-workspace.yaml`. Das `pnpm`-Feld in `package.json` liest pnpm 12 gar nicht
mehr und warnt darüber.
- **pnpm 12 prüft die Lieferkette.** Pakete, die jünger als 24 Stunden sind, werden abgelehnt.
`vite@8.3.1` und `lucide-react@1.48.0` erschienen am selben Tag und mussten auf `8.3.0` bzw.
`1.47.0` zurück. Die Richtlinie bleibt an — sie ist sinnvoll.
- **eslint 10 bricht mit `eslint-config-next`.** `eslint-plugin-react@7.37.5` unterstützt nur bis
`eslint ^9.7` und hat keinen Nachfolger. Festgestellt, nicht geraten:
`TypeError: contextOrFilename.getFilename is not a function`.
- **TypeScript 7 geht noch nicht.** `typescript-eslint@8` erlaubt `>=4.8.4 <6.1.0`.
- **`shadcn init` ist nicht skriptfähig** — es fragt nach einem Preset, auch mit `--yes`, und
bleibt hinter einer Pipe hängen. `shadcn add <bauteil> --yes --overwrite < /dev/null`
funktioniert dagegen. Die Registry importiert den Helfer als blanken Modulnamen `cn`, dafür
braucht `tsconfig.json` den Pfad `"cn": ["./src/lib/utils"]`, und die Bauteile brauchen das
Paket `radix-ui`.
- **Port 3000 war von ProxLedger belegt**, die Abnahme lief deshalb auf 3100 bzw. 3200.
- Die Migrationen laufen im Compose-Stand nachweislich automatisch; eingespielt wird ab #006
etwas, vorher meldet der Dienst korrekt „No pending migrations to apply".
---
Quelle: `docs/issues/005-geruest-prozess-design.md` — dort gepflegt, hierher gespiegelt.
florian.wilde
added this to the v0.1.0 milestone 2026-09-24 20:44:39 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Status: erledigt
Meilenstein: v0.1.0
Labels: phase-1, infra, docs
Geschätzt: 6 h Tatsächlich: 1 h 25 min
Ziel
Ein lauffähiges, leeres Projekt mit allen Qualitätsschranken, dem gehärteten Betriebsstand und dem Design-Fundament. Danach ist jeder weitere Meilenstein reine Fachlichkeit.
Aufgaben
masteraufmainumbenennen (Gitea-Default istmain), Remote unverändert lassen.nvmrc=24,packageManager: "pnpm@10.34.5"über corepack,engines.node >= 24output: "standalone",src/-Layouttsconfig.json:strict,noUncheckedIndexedAccess,verbatimModuleSyntax,forceConsistentCasingInFileNames, Alias@/*→./src/*@import "tailwindcss"+@theme,@tailwindcss/postcss), shadcn/ui initialisieren,lucide-reacteslint-config-next/core-web-vitals+/typescript+eslint-config-prettier/flat,globalIgnoresinkl.src/generated/**), Prettier (printWidth: 110,singleQuote: false,trailingComma: "all")@commitlint/config-conventional) als Pre-Commit- und Commit-Msg-Hookvitest.config.mts,environment: "node",fileParallelism: false) undvite@^7als Peer; Playwright 1.63 (playwright.config.ts)Dockerfilemulti-stage (Basis → Abhängigkeiten → Bauen → Laufzeit),node:24-alpine,tini, Nutzer 1001, non-rootdocker-compose.ymlgehärtet:postgresohneports:, Netzeintern(internal: true) undextern,webauf${BIND_ADDR:-127.0.0.1}:3000,migrateals One-Shot aus der Bau-Stufe, Healthchecks,${VAR:?… fehlt in der .env}docker-compose.dev.yml(nur Postgres, Port 5433) unddocker-compose.test.yml(Postgres; der OpenLDAP-Dienst kommt mit #016, wo er tatsächlich benutzt wird).env.examplemit allen Variablen und Kommentar je VariableGET /api/gesundheit→SELECT 1→ 200/503next.config.ts, CSP-Nonce inproxy.ts(Next 16: nichtmiddleware.ts)scripts/pruefe-doku.mjsundpnpm pruefe:doku: Version hat Changelog-Abschnitt, Issue-Dateien und Übersicht stimmen überein, verlinkte Bilder existierenscripts/gitea-issues.tsundpnpm issues:sync: spiegeltdocs/issues/*.mdin den Gitea-Tracker.gitea/workflows/ci.ymlnach ProxLedger-Muster, erweitert um Playwright undshellcheck#0B0D10, Flächen#14171C/#1B1F26, Linien#262B33, Text#F3F5F7/#98A2B3, Akzent#C6F135, Status#3DDC97/#F5B84A/#F87171), heller Modus optional@fontsource-variable/space-grotesk,-manrope,-jetbrains-monolaufzettel(Space Grotesk 700, Laufweite −0.04em, Akzentpunkt) und Bildmarke[ ✓ ]als SVG, Favicon, PWA-Icon,manifest.tsNEXT_PUBLIC_APP_VERSIONundNEXT_PUBLIC_GIT_SHAREADME.md,CHANGELOG.md(Keep a Changelog, deutsch),docs/devlog.md,CLAUDE.mdmit Konventionen und Namensabbildung,docs/architektur.md,docs/abnahme-mvp.mdv0.1.0…v0.5.0, Epic-Issues #001–#004 und Meilenstein-Issues #005–#019Akzeptanzkriterien
docker compose upstartet App und Datenbank, Migrationen laufen automatischnc -z localhost 5432schlägt fehl,docker compose exec web nc -z postgres 5432gelingtdocker-compose.ymlund schlägt an, wenn unterpostgreseinports:auftauchtpnpm lint && pnpm typecheck && pnpm test && pnpm pruefe:dokugrünBeim Bauen aufgefallen
onlyBuiltDependencieswird vonpnpm config listnoch angezeigt, aber nicht mehr angewandt; wirksam istallowBuildsalsZuordnung in
pnpm-workspace.yaml. Daspnpm-Feld inpackage.jsonliest pnpm 12 gar nichtmehr und warnt darüber.
vite@8.3.1undlucide-react@1.48.0erschienen am selben Tag und mussten auf8.3.0bzw.1.47.0zurück. Die Richtlinie bleibt an — sie ist sinnvoll.eslint-config-next.eslint-plugin-react@7.37.5unterstützt nur biseslint ^9.7und hat keinen Nachfolger. Festgestellt, nicht geraten:TypeError: contextOrFilename.getFilename is not a function.typescript-eslint@8erlaubt>=4.8.4 <6.1.0.shadcn initist nicht skriptfähig — es fragt nach einem Preset, auch mit--yes, undbleibt hinter einer Pipe hängen.
shadcn add <bauteil> --yes --overwrite < /dev/nullfunktioniert dagegen. Die Registry importiert den Helfer als blanken Modulnamen
cn, dafürbraucht
tsconfig.jsonden Pfad"cn": ["./src/lib/utils"], und die Bauteile brauchen dasPaket
radix-ui.etwas, vorher meldet der Dienst korrekt „No pending migrations to apply".
Quelle:
docs/issues/005-geruest-prozess-design.md— dort gepflegt, hierher gespiegelt.