Files
gartenmanager/docs/project-structure.md
Faultier314 834a3bf4d5 feat: Phase 1 complete – full working application
Backend (FastAPI):
- REST API: auth, plants, beds, plantings
- CRUD layer with CRUDBase
- Pydantic v2 schemas for all entities
- Alembic migration: complete schema + all enums
- Seed data: 28 global plants + 15 compatibilities

Frontend (Vue 3 + PrimeVue):
- Axios client with JWT interceptor + auto-refresh
- Pinia stores: auth, beds, plants
- Views: Login, Beds, BedDetail, PlantLibrary
- Components: AppLayout, BedForm, PlantingForm, PlantForm

Docker:
- docker-compose.yml (production)
- docker-compose.dev.yml (development with hot-reload)
- Nginx config with SPA fallback + API proxy
- Multi-stage frontend Dockerfile
- .env.example, .gitignore

Version: 1.0.0-alpha
2026-04-06 07:45:00 +02:00

148 lines
7.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Projektstruktur & Modulreferenz
> **Token-Sparmaßnahme:** Dieses Dokument ist die erste Anlaufstelle.
> Vor dem Öffnen von Quellcode hier nachschlagen.
> Bei jeder Änderung an Funktionen, Modulen oder der Verzeichnisstruktur sofort aktualisieren.
---
## Verzeichnisstruktur
```
gartenmanager/
├── .claude/ # Claude-Tooling (kein Projektcode)
│ ├── scripts/bump.sh # Version bumpen + commit + push
│ ├── scripts/new-feature.sh # Feature-Branch erstellen
│ └── session-context.md # Sessionstart-Kontext
├── .gitea/PULL_REQUEST_TEMPLATE.md
├── backend/ # FastAPI Python Backend
│ ├── app/
│ │ ├── main.py # FastAPI App, CORS, Router-Include, /health
│ │ ├── core/
│ │ │ ├── config.py # pydantic-settings (DATABASE_URL, SECRET_KEY, ...)
│ │ │ ├── security.py # JWT erstellen/prüfen, Passwort-Hashing
│ │ │ └── deps.py # FastAPI-Dependencies: get_current_user, get_tenant_context, require_min_role()
│ │ ├── db/
│ │ │ ├── base.py # DeclarativeBase + alle Model-Imports für Alembic
│ │ │ └── session.py # async Engine, AsyncSessionLocal, get_session()
│ │ ├── models/ # SQLAlchemy ORM (alle UUID-PKs, async)
│ │ │ ├── user.py # User, UserTenant (+ TenantRole Enum)
│ │ │ ├── tenant.py # Tenant
│ │ │ ├── plant.py # PlantFamily, Plant, PlantCompatibility
│ │ │ ├── bed.py # Bed (+ LocationType, SoilType Enums)
│ │ │ └── planting.py # BedPlanting
│ │ ├── schemas/ # Pydantic v2 (Create/Update/Read)
│ │ │ ├── auth.py # LoginRequest, RefreshRequest, TokenResponse, AccessTokenResponse
│ │ │ ├── user.py # UserCreate, UserUpdate, UserRead
│ │ │ ├── tenant.py # TenantCreate, TenantUpdate, TenantRead
│ │ │ ├── plant.py # PlantCreate/Update/Read, PlantFamilyRead, PlantCompatibilityRead
│ │ │ ├── bed.py # BedCreate/Update/Read/DetailRead, PlantingInBed
│ │ │ └── planting.py # PlantingCreate/Update/Read
│ │ ├── crud/ # DB-Zugriff, keine Business-Logik
│ │ │ ├── base.py # CRUDBase[Model, Create, Update]: get, get_multi, create, update, remove
│ │ │ ├── user.py # get_by_email, authenticate, get_tenants
│ │ │ ├── plant.py # get_multi_for_tenant (global+tenant), create_for_tenant
│ │ │ ├── bed.py # get_multi_for_tenant, get_with_plantings, create_for_tenant
│ │ │ └── planting.py # get_multi_for_bed, create_for_bed
│ │ ├── api/v1/
│ │ │ ├── router.py # Alle Sub-Router unter /api/v1
│ │ │ ├── auth.py # POST /login, POST /refresh, GET /me
│ │ │ ├── plants.py # GET/POST/PUT/DELETE /plants, GET /plant-families
│ │ │ ├── beds.py # GET/POST/PUT/DELETE /beds
│ │ │ └── plantings.py # GET/POST /beds/{id}/plantings, PUT/DELETE /plantings/{id}
│ │ └── seeds/
│ │ └── initial_data.py # 28 globale Pflanzen + 15 Kompatibilitäten (idempotent)
│ ├── alembic/
│ │ ├── env.py # Async Alembic-Config, liest DATABASE_URL aus Settings
│ │ └── versions/001_initial.py # Vollständiges initiales Schema (alle Tabellen + Enums)
│ ├── requirements.txt
│ └── Dockerfile # python:3.11-slim, uvicorn
├── frontend/ # Vue 3 SPA
│ ├── src/
│ │ ├── main.js # App-Bootstrap: PrimeVue, Pinia, Router
│ │ ├── App.vue # Root: AppLayout (eingeloggt) / router-view (Login)
│ │ ├── api/
│ │ │ ├── client.js # Axios-Instanz, JWT-Interceptor, Auto-Refresh bei 401
│ │ │ └── index.js # authApi, plantsApi, bedsApi, plantingsApi
│ │ ├── stores/
│ │ │ ├── auth.js # user, tenants, activeTenantId, login(), logout(), setActiveTenant()
│ │ │ ├── beds.js # beds, currentBed, fetchBeds/Bed, createBed/Planting, deleteBed/Planting
│ │ │ └── plants.js # plants, families, fetchPlants/Families, create/update/deletePlant
│ │ ├── router/index.js # /login, /beete, /beete/:id, /pflanzen auth guard
│ │ ├── views/
│ │ │ ├── LoginView.vue # Email+Passwort Formular
│ │ │ ├── BedsView.vue # DataTable aller Beete, Create/Edit-Dialog
│ │ │ ├── BedDetailView.vue # Beet-Infos + Bepflanzungs-Tabelle + Add-Dialog
│ │ │ └── PlantsView.vue # Pflanzenbibliothek DataTable, Filter, eigene Pflanze anlegen
│ │ └── components/
│ │ ├── AppLayout.vue # Navbar (Logo, Nav-Links, Tenant-Selector, Logout)
│ │ ├── BedForm.vue # Formular für Beet anlegen/bearbeiten
│ │ ├── PlantingForm.vue # Formular für Bepflanzung hinzufügen
│ │ └── PlantForm.vue # Formular für eigene Pflanze anlegen
│ ├── nginx.conf # SPA fallback + API-Proxy → backend:8000
│ ├── Dockerfile # Multi-stage: node:20 build → nginx:alpine
│ └── package.json
├── docker-compose.yml # Produktion: db + backend + frontend
├── docker-compose.dev.yml # Entwicklung: db + backend (reload) + Frontend lokal via npm run dev
├── .env.example # Vorlage für .env
├── .gitignore
├── CHANGELOG.md
├── CLAUDE.md
├── README.md
└── VERSION
```
---
## Berechtigungslogik
```
is_superadmin=True → alles erlaubt, Tenant-Prüfung wird übersprungen
TENANT_ADMIN → alles im eigenen Tenant (inkl. Beet löschen)
READ_WRITE → lesen + schreiben, kein Beet löschen
READ_ONLY → nur GET-Endpoints
```
`require_min_role(TenantRole.READ_WRITE)` in `deps.py` gibt `(user, tenant_id, role)` zurück.
---
## Datenbankschema (Kurzform)
```
users → id, email, hashed_password, is_superadmin
tenants → id, name, slug
user_tenants → user_id, tenant_id, role
plant_families → id, name, latin_name
plants → id, tenant_id(nullable=global), family_id, nutrient_demand, water_demand, rest_years, ...
plant_compat. → plant_id_a, plant_id_b, rating, reason
beds → id, tenant_id, width_m, length_m, location, soil_type
bed_plantings → id, bed_id, plant_id, area_m2, count, planted_date, removed_date
```
---
## API-Routen Übersicht
```
POST /api/v1/auth/login
POST /api/v1/auth/refresh
GET /api/v1/auth/me
GET /api/v1/plant-families
GET /api/v1/plants
GET /api/v1/plants/{id}
POST /api/v1/plants (READ_WRITE+)
PUT /api/v1/plants/{id} (READ_WRITE+, global nur Superadmin)
DELETE /api/v1/plants/{id} (READ_WRITE+, global nur Superadmin)
GET /api/v1/beds
GET /api/v1/beds/{id} (mit Bepflanzungen)
POST /api/v1/beds (READ_WRITE+)
PUT /api/v1/beds/{id} (READ_WRITE+)
DELETE /api/v1/beds/{id} (TENANT_ADMIN+)
GET /api/v1/beds/{id}/plantings
POST /api/v1/beds/{id}/plantings (READ_WRITE+)
PUT /api/v1/plantings/{id} (READ_WRITE+)
DELETE /api/v1/plantings/{id} (READ_WRITE+)
GET /health
```