docs: update CLAUDE.md and add git helper scripts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Faultier314
2026-04-06 07:56:33 +02:00
parent 26e8b2cd0c
commit 5b00036951
6 changed files with 195 additions and 82 deletions

View File

@@ -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 <noreply@anthropic.com>"
git push

61
.claude/scripts/git-pr.sh Normal file
View File

@@ -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 <head> <base> "<title>" ["<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

View File

@@ -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)"

View File

@@ -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"

View File

@@ -1,15 +1,7 @@
{ {
"permissions": { "permissions": {
"allow": [ "allow": [
"Bash(curl -s -o /dev/null -w \"%{http_code}\" https://tea.jr-family.de/api/v1/repos/Admin/gartenmanager)", "Bash"
"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)"
] ]
} }
} }

138
CLAUDE.md
View File

@@ -2,97 +2,89 @@
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 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 | - **Code-Bezeichner, Commit-Messages:** Englisch, Imperativ (`Add`, `Fix`, `Refactor`)
|---|---| - **Dokumentation & Kommentare:** Deutsch
| [docs/development-standards.md](docs/development-standards.md) | **Alle Regeln:** Branching, Versionierung, Workflow, Coding, Testing | - **Commit-Format:** `<type>: <short description>` (max. 72 Zeichen)
| [docs/project-structure.md](docs/project-structure.md) | **Alle Module & Funktionen** hier zuerst lesen, bevor Quellcode geöffnet wird | Types: `feat` | `fix` | `refactor` | `test` | `docs` | `chore`
| [CHANGELOG.md](CHANGELOG.md) | Versionshistorie | - Nach jedem Commit sofort pushen
| [VERSION](VERSION) | Aktuelle Versionsnummer | - Keine `console.log`/`print` in Produktionscode, keine auskommentierten Code-Blöcke
| [.claude/session-context.md](.claude/session-context.md) | **Sessionstart hier lesen:** aktiver Branch, Version, offene Arbeit |
## Techstack ## Projektkontext (Schnelleinstieg)
| Schicht | Technologie | **Gartenmanager** Docker-basierte Gartenverwaltung. Multi-User, Multi-Tenant, Rollensystem.
|---|---| **Stack:** Vue 3 + PrimeVue → FastAPI (Python 3.11) → PostgreSQL 15
| Frontend | Vue 3 + Vite + PrimeVue + Pinia + Vue Router | **Phase:** 1 abgeschlossen (Auth, Beete, Pflanzen, Bepflanzung). Phase 2 = Testing & CI/CD.
| Backend | FastAPI (Python 3.11) + Uvicorn | **Version:** `cat VERSION` | **Branch:** `git branch --show-current`
| ORM | SQLAlchemy 2.x async + Alembic | **Sessionstart:** [.claude/session-context.md](.claude/session-context.md) lesen.
| Datenbank | PostgreSQL 15 (asyncpg) | **Modulreferenz:** [docs/project-structure.md](docs/project-structure.md) vor Quellcode-Reads.
| Container | Docker Compose (3 Services: db, backend, frontend/nginx) |
## Build & Entwicklung ## Scripts (immer diese verwenden)
```bash ```bash
# Gesamtes System starten (Produktion) bash .claude/scripts/git-commit.sh "message" # stage all + commit + push
docker compose up -d bash .claude/scripts/git-switch.sh <branch> # branch wechseln
bash .claude/scripts/git-switch.sh <branch> from <base> # neuer branch aus base
# Entwicklungsmodus (mit Hot-Reload) bash .claude/scripts/git-pr.sh create <head> <base> "titel" # PR erstellen
docker compose -f docker-compose.dev.yml up bash .claude/scripts/git-pr.sh merge <nr> squash # PR mergen
bash .claude/scripts/git-pr.sh list # offene PRs
# Nur Backend lokal starten (setzt laufende DB voraus) bash .claude/scripts/bump.sh [patch|minor] "beschreibung" # version + commit + push
cd backend && uvicorn app.main:app --reload --port 8000 bash .claude/scripts/new-feature.sh [feature|fix] <name> # branch aus develop
# 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>
``` ```
## Architektur ## Architektur
### Backend (`backend/app/`)
``` ```
core/ backend/app/
config.py pydantic-settings, liest .env (DATABASE_URL, SECRET_KEY, ...) core/config.py Settings (DATABASE_URL, SECRET_KEY, ...)
security.py JWT-Erzeugung/-Prüfung (Access 30min, Refresh 7 Tage) core/security.py JWT (Access 30min / Refresh 7d), Passwort-Hashing
deps.py FastAPI-Dependencies: get_db, get_current_user, require_role(...) 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/ frontend/src/
base.py SQLAlchemy DeclarativeBase api/client.js Axios + JWT-Interceptor + Auto-Refresh bei 401
session.py async Engine + AsyncSession Factory stores/ Pinia: auth, beds, plants
router/index.js Auth-Guard, /login /beete /beete/:id /pflanzen
models/ SQLAlchemy ORM-Modelle (alle UUID-PKs, async-kompatibel) views/ LoginView, BedsView, BedDetailView, PlantsView
schemas/ Pydantic v2 Schemas (Create/Update/Read je Entität) components/ AppLayout, BedForm, PlantingForm, PlantForm
crud/ CRUD-Funktionen (kein Business-Logik, nur DB-Zugriff)
api/v1/ FastAPI Router je Ressource
seeds/ Initiale Pflanzenbibliothek + Kompatibilitätsdaten
``` ```
### Tenant-Kontext **Tenant-Kontext:** Header `X-Tenant-ID` bei allen Nicht-Auth-Requests.
Alle Nicht-Auth-Endpoints erwarten Header `X-Tenant-ID: <uuid>`. Die Dependency `get_current_tenant` prüft Mitgliedschaft des eingeloggten Users. **Rollen:** `READ_ONLY` < `READ_WRITE` < `TENANT_ADMIN` < `is_superadmin`
### Berechtigungsebenen ## Pflichtregeln
`READ_ONLY``READ_WRITE``TENANT_ADMIN``is_superadmin` (User-Flag, überspringt alle Prüfungen)
### Frontend (`frontend/src/`) 1. **Nie direkt nach `main`** nur PR, nur auf Anweisung
Vue 3 SFC mit PrimeVue-Komponenten, Pinia für State, Axios-Client mit JWT-Interceptor und automatischem Token-Refresh. 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 ## Build
2. **Jede Arbeit in eigenem Branch** unter `develop` (`feature/`, `fix/`, `debug/`)
3. **Nach jeder Änderung:** `bash .claude/scripts/bump.sh` + commit + push ```bash
4. **Vor Merge:** README, CHANGELOG, `docs/project-structure.md` prüfen docker compose -f docker-compose.dev.yml up # Dev (hot-reload)
5. **Branches selbstständig wechseln** passend zur aktuellen Aufgabe 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
```