docs: update CLAUDE.md and add git helper scripts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
21
.claude/scripts/git-commit.sh
Normal file
21
.claude/scripts/git-commit.sh
Normal 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
61
.claude/scripts/git-pr.sh
Normal 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
|
||||||
36
.claude/scripts/git-switch.sh
Normal file
36
.claude/scripts/git-switch.sh
Normal 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)"
|
||||||
11
.claude/scripts/git-sync.sh
Normal file
11
.claude/scripts/git-sync.sh
Normal 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"
|
||||||
@@ -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
138
CLAUDE.md
@@ -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
|
||||||
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user