diff --git a/.claude/scripts/git-commit.sh b/.claude/scripts/git-commit.sh new file mode 100644 index 0000000..2c93f4e --- /dev/null +++ b/.claude/scripts/git-commit.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# git-commit.sh – Stage all, commit, push +# Verwendung: bash .claude/scripts/git-commit.sh "commit message" [minor|patch(default)] +set -euo pipefail + +MESSAGE="${1:-}" +BUMP="${2:-patch}" + +if [[ -z "$MESSAGE" ]]; then + echo "Verwendung: bash .claude/scripts/git-commit.sh \"message\" [patch|minor]" + exit 1 +fi + +ROOT="$(git rev-parse --show-toplevel)" +cd "$ROOT" + +git add -A +git commit -m "$MESSAGE + +Co-Authored-By: Claude Sonnet 4.6 " +git push diff --git a/.claude/scripts/git-pr.sh b/.claude/scripts/git-pr.sh new file mode 100644 index 0000000..d1cb1ea --- /dev/null +++ b/.claude/scripts/git-pr.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# git-pr.sh – Pull-Request via Gitea API erstellen und optional mergen +# +# Verwendung: +# bash .claude/scripts/git-pr.sh create "" ["<body>"] +# bash .claude/scripts/git-pr.sh merge <pr_number> [squash|merge|rebase] +# bash .claude/scripts/git-pr.sh list [open|closed] + +set -euo pipefail + +REPO="Admin/gartenmanager" +API="https://tea.jr-family.de/api/v1" + +get_token() { + git credential fill <<'EOF' | grep "^password=" | cut -d= -f2- +protocol=https +host=tea.jr-family.de +EOF +} + +CMD="${1:-}" + +case "$CMD" in + create) + HEAD="${2:?'head branch fehlt'}" + BASE="${3:?'base branch fehlt'}" + TITLE="${4:?'titel fehlt'}" + BODY="${5:-}" + TOKEN=$(get_token) + RESULT=$(curl -s -X POST "$API/repos/$REPO/pulls" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"head\":\"$HEAD\",\"base\":\"$BASE\",\"title\":\"$TITLE\",\"body\":\"$BODY\"}") + PR_NUM=$(echo "$RESULT" | python3 -c "import sys,json; r=json.load(sys.stdin); print(r.get('number','ERR: '+str(r.get('message',''))))") + echo "PR #$PR_NUM erstellt: $TITLE ($HEAD → $BASE)" + ;; + + merge) + PR_NUM="${2:?'PR-Nummer fehlt'}" + STYLE="${3:-squash}" + TOKEN=$(get_token) + curl -s -X POST "$API/repos/$REPO/pulls/$PR_NUM/merge" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"Do\":\"$STYLE\"}" + echo "PR #$PR_NUM gemergt ($STYLE)" + ;; + + list) + STATE="${2:-open}" + TOKEN=$(get_token) + curl -s "$API/repos/$REPO/pulls?state=$STATE&limit=20" \ + -H "Authorization: Bearer $TOKEN" | \ + python3 -c "import sys,json; [print(f\"#{r['number']} [{r['state']}] {r['title']} ({r['head']['label']} → {r['base']['label']})\") for r in json.load(sys.stdin)]" + ;; + + *) + echo "Verwendung: bash .claude/scripts/git-pr.sh [create|merge|list] ..." + exit 1 + ;; +esac diff --git a/.claude/scripts/git-switch.sh b/.claude/scripts/git-switch.sh new file mode 100644 index 0000000..453cc7b --- /dev/null +++ b/.claude/scripts/git-switch.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# git-switch.sh – Branch wechseln oder erstellen, remote aktualisieren +# +# Verwendung: +# bash .claude/scripts/git-switch.sh <branch> – wechseln (pull wenn vorhanden) +# bash .claude/scripts/git-switch.sh <branch> create – neu aus aktuellem Branch +# bash .claude/scripts/git-switch.sh <branch> from <base> – neu aus <base> + +set -euo pipefail + +BRANCH="${1:?'Branch-Name fehlt'}" +MODE="${2:-switch}" +BASE="${3:-}" + +ROOT="$(git rev-parse --show-toplevel)" +cd "$ROOT" + +case "$MODE" in + switch) + git fetch origin "$BRANCH" 2>/dev/null || true + git checkout "$BRANCH" 2>/dev/null || git checkout -b "$BRANCH" + git pull origin "$BRANCH" 2>/dev/null || true + ;; + create) + git checkout -b "$BRANCH" + git push -u origin "$BRANCH" + ;; + from) + BASE="${3:?'Basis-Branch fehlt'}" + git fetch origin "$BASE" + git checkout -b "$BRANCH" "origin/$BASE" + git push -u origin "$BRANCH" + ;; +esac + +echo "Aktiver Branch: $(git branch --show-current)" diff --git a/.claude/scripts/git-sync.sh b/.claude/scripts/git-sync.sh new file mode 100644 index 0000000..62813d7 --- /dev/null +++ b/.claude/scripts/git-sync.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# git-sync.sh – aktuellen Branch mit Remote synchronisieren (pull + push) +set -euo pipefail + +ROOT="$(git rev-parse --show-toplevel)" +cd "$ROOT" + +BRANCH=$(git branch --show-current) +git pull origin "$BRANCH" +git push origin "$BRANCH" +echo "Synchronisiert: $BRANCH" diff --git a/.claude/settings.local.json b/.claude/settings.local.json index f00869b..aecadcb 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -1,15 +1,7 @@ { "permissions": { "allow": [ - "Bash(curl -s -o /dev/null -w \"%{http_code}\" https://tea.jr-family.de/api/v1/repos/Admin/gartenmanager)", - "Bash(git -C c:/Projekte/Home/gartenmanager config --get credential.helper)", - "Bash(git credential:*)", - "Bash(python3 -m json.tool)", - "Bash(git -C c:/Projekte/Home/gartenmanager credential fill)", - "Bash(python3 -c \"import sys,json; r=json.load\\(sys.stdin\\); print\\('allow_squash_merge:', r.get\\('allow_squash_merge'\\), '| default_merge_style:', r.get\\('default_merge_style'\\)\\)\")", - "Bash(bash .claude/scripts/bump.sh patch \"Add autonomous branch-switching rule to workflow docs\")", - "Bash(bash .claude/scripts/bump.sh patch \"Update project plan: finalize phases, techstack and architecture decisions\")", - "Bash(git -C c:/Projekte/Home/gartenmanager credential approve)" + "Bash" ] } } diff --git a/CLAUDE.md b/CLAUDE.md index 5f78993..ac53a17 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,97 +2,89 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -## Projekt +## Verhaltensregeln -**Gartenmanager** – Docker-basierte Web-Platform zur Verwaltung von Gartenaktivitäten. Multi-User, Multi-Tenant. +- Kein erklärender Text bei Routineaufgaben (Commits, Pushes, Branch-Wechsel) +- Bei Fehlern: erst 2x selbst versuchen, dann fragen +- Branches selbstständig wechseln wie benötigt -## Dokumente – wo was steht +## Sprache & Konventionen -| Dokument | Inhalt | -|---|---| -| [docs/development-standards.md](docs/development-standards.md) | **Alle Regeln:** Branching, Versionierung, Workflow, Coding, Testing | -| [docs/project-structure.md](docs/project-structure.md) | **Alle Module & Funktionen** – hier zuerst lesen, bevor Quellcode geöffnet wird | -| [CHANGELOG.md](CHANGELOG.md) | Versionshistorie | -| [VERSION](VERSION) | Aktuelle Versionsnummer | -| [.claude/session-context.md](.claude/session-context.md) | **Sessionstart hier lesen:** aktiver Branch, Version, offene Arbeit | +- **Code-Bezeichner, Commit-Messages:** Englisch, Imperativ (`Add`, `Fix`, `Refactor`) +- **Dokumentation & Kommentare:** Deutsch +- **Commit-Format:** `<type>: <short description>` (max. 72 Zeichen) + Types: `feat` | `fix` | `refactor` | `test` | `docs` | `chore` +- Nach jedem Commit sofort pushen +- Keine `console.log`/`print` in Produktionscode, keine auskommentierten Code-Blöcke -## Techstack +## Projektkontext (Schnelleinstieg) -| Schicht | Technologie | -|---|---| -| Frontend | Vue 3 + Vite + PrimeVue + Pinia + Vue Router | -| Backend | FastAPI (Python 3.11) + Uvicorn | -| ORM | SQLAlchemy 2.x async + Alembic | -| Datenbank | PostgreSQL 15 (asyncpg) | -| Container | Docker Compose (3 Services: db, backend, frontend/nginx) | +**Gartenmanager** – Docker-basierte Gartenverwaltung. Multi-User, Multi-Tenant, Rollensystem. +**Stack:** Vue 3 + PrimeVue → FastAPI (Python 3.11) → PostgreSQL 15 +**Phase:** 1 abgeschlossen (Auth, Beete, Pflanzen, Bepflanzung). Phase 2 = Testing & CI/CD. +**Version:** `cat VERSION` | **Branch:** `git branch --show-current` +**Sessionstart:** [.claude/session-context.md](.claude/session-context.md) lesen. +**Modulreferenz:** [docs/project-structure.md](docs/project-structure.md) – vor Quellcode-Reads. -## Build & Entwicklung +## Scripts (immer diese verwenden) ```bash -# Gesamtes System starten (Produktion) -docker compose up -d - -# Entwicklungsmodus (mit Hot-Reload) -docker compose -f docker-compose.dev.yml up - -# Nur Backend lokal starten (setzt laufende DB voraus) -cd backend && uvicorn app.main:app --reload --port 8000 - -# Nur Frontend lokal starten -cd frontend && npm run dev - -# Datenbankmigrationen ausführen -docker compose exec backend alembic upgrade head - -# Neue Migration erstellen -docker compose exec backend alembic revision --autogenerate -m "beschreibung" - -# Seed-Daten einspielen -docker compose exec backend python -m app.seeds.initial_data - -# Version bumpen + commit + push -bash .claude/scripts/bump.sh patch "Beschreibung" - -# Neuen Feature-Branch erstellen -bash .claude/scripts/new-feature.sh feature <name> +bash .claude/scripts/git-commit.sh "message" # stage all + commit + push +bash .claude/scripts/git-switch.sh <branch> # branch wechseln +bash .claude/scripts/git-switch.sh <branch> from <base> # neuer branch aus base +bash .claude/scripts/git-pr.sh create <head> <base> "titel" # PR erstellen +bash .claude/scripts/git-pr.sh merge <nr> squash # PR mergen +bash .claude/scripts/git-pr.sh list # offene PRs +bash .claude/scripts/bump.sh [patch|minor] "beschreibung" # version + commit + push +bash .claude/scripts/new-feature.sh [feature|fix] <name> # branch aus develop ``` ## Architektur -### Backend (`backend/app/`) - ``` -core/ - config.py – pydantic-settings, liest .env (DATABASE_URL, SECRET_KEY, ...) - security.py – JWT-Erzeugung/-Prüfung (Access 30min, Refresh 7 Tage) - deps.py – FastAPI-Dependencies: get_db, get_current_user, require_role(...) +backend/app/ + core/config.py – Settings (DATABASE_URL, SECRET_KEY, ...) + core/security.py – JWT (Access 30min / Refresh 7d), Passwort-Hashing + core/deps.py – get_current_user, get_tenant_context, require_min_role() + db/session.py – async Engine + get_session() + models/ – SQLAlchemy ORM (UUID-PKs): User, Tenant, Plant, Bed, BedPlanting + schemas/ – Pydantic v2 Create/Update/Read je Entität + crud/ – CRUDBase + spezialisierte Klassen, nur DB-Zugriff + api/v1/ – Router: auth, plants, beds, plantings + seeds/initial_data.py – 28 Pflanzen + 15 Kompatibilitäten (idempotent) -db/ - base.py – SQLAlchemy DeclarativeBase - session.py – async Engine + AsyncSession Factory - -models/ – SQLAlchemy ORM-Modelle (alle UUID-PKs, async-kompatibel) -schemas/ – Pydantic v2 Schemas (Create/Update/Read je Entität) -crud/ – CRUD-Funktionen (kein Business-Logik, nur DB-Zugriff) -api/v1/ – FastAPI Router je Ressource -seeds/ – Initiale Pflanzenbibliothek + Kompatibilitätsdaten +frontend/src/ + api/client.js – Axios + JWT-Interceptor + Auto-Refresh bei 401 + stores/ – Pinia: auth, beds, plants + router/index.js – Auth-Guard, /login /beete /beete/:id /pflanzen + views/ – LoginView, BedsView, BedDetailView, PlantsView + components/ – AppLayout, BedForm, PlantingForm, PlantForm ``` -### Tenant-Kontext -Alle Nicht-Auth-Endpoints erwarten Header `X-Tenant-ID: <uuid>`. Die Dependency `get_current_tenant` prüft Mitgliedschaft des eingeloggten Users. +**Tenant-Kontext:** Header `X-Tenant-ID` bei allen Nicht-Auth-Requests. +**Rollen:** `READ_ONLY` < `READ_WRITE` < `TENANT_ADMIN` < `is_superadmin` -### Berechtigungsebenen -`READ_ONLY` → `READ_WRITE` → `TENANT_ADMIN` → `is_superadmin` (User-Flag, überspringt alle Prüfungen) +## Pflichtregeln -### Frontend (`frontend/src/`) -Vue 3 SFC mit PrimeVue-Komponenten, Pinia für State, Axios-Client mit JWT-Interceptor und automatischem Token-Refresh. +1. **Nie direkt nach `main`** – nur PR, nur auf Anweisung +2. **Arbeit in `feature/`, `fix/` oder `chore/`** unter `develop` +3. **Nach jeder Änderung:** `bump.sh` ausführen (MINOR bei Features, PATCH bei Fixes) +4. **MAJOR-Version** niemals selbstständig erhöhen +5. **Vor Merge/PR:** CHANGELOG, README, `docs/project-structure.md` prüfen +6. **In `develop` mergen erst** wenn alle Tests grün sind -## Pflichtregeln (immer befolgen) +## Testing -Vollständige Regeln in [docs/development-standards.md](docs/development-standards.md). Kurzfassung: +- Integrationstests testen gegen echte DB (keine DB-Mocks) +- Backend: pytest in `backend/tests/` | Frontend: Vitest neben Quelldateien oder `__tests__/` +- Run: `docker compose exec backend pytest` / `cd frontend && npm run test` -1. **Nie direkt nach `main`** – nur per Pull-Request, nur auf explizite Anweisung -2. **Jede Arbeit in eigenem Branch** unter `develop` (`feature/`, `fix/`, `debug/`) -3. **Nach jeder Änderung:** `bash .claude/scripts/bump.sh` + commit + push -4. **Vor Merge:** README, CHANGELOG, `docs/project-structure.md` prüfen -5. **Branches selbstständig wechseln** – passend zur aktuellen Aufgabe +## Build + +```bash +docker compose -f docker-compose.dev.yml up # Dev (hot-reload) +docker compose up -d # Prod +docker compose exec backend alembic upgrade head +docker compose exec backend python -m app.seeds.initial_data +cd frontend && npm run dev +```