Files
gartenmanager/backend/app/crud/plant.py
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

55 lines
1.9 KiB
Python

from uuid import UUID
from sqlalchemy import or_, select
from sqlalchemy.orm import selectinload
from sqlalchemy.ext.asyncio import AsyncSession
from app.crud.base import CRUDBase
from app.models.plant import Plant, PlantCompatibility, PlantFamily
from app.schemas.plant import PlantCreate, PlantUpdate
class CRUDPlant(CRUDBase[Plant, PlantCreate, PlantUpdate]):
async def get(self, db: AsyncSession, *, id: UUID) -> Plant | None:
result = await db.execute(
select(Plant)
.options(selectinload(Plant.family))
.where(Plant.id == id)
)
return result.scalar_one_or_none()
async def get_multi_for_tenant(
self, db: AsyncSession, *, tenant_id: UUID, skip: int = 0, limit: int = 200
) -> list[Plant]:
result = await db.execute(
select(Plant)
.options(selectinload(Plant.family))
.where(
Plant.is_active == True, # noqa: E712
or_(Plant.tenant_id == None, Plant.tenant_id == tenant_id), # noqa: E711
)
.order_by(Plant.name)
.offset(skip)
.limit(limit)
)
return list(result.scalars().all())
async def create_for_tenant(
self, db: AsyncSession, *, obj_in: PlantCreate, tenant_id: UUID
) -> Plant:
return await self.create(db, obj_in=obj_in, tenant_id=tenant_id)
class CRUDPlantFamily(CRUDBase[PlantFamily, PlantFamily, PlantFamily]):
async def get_all(self, db: AsyncSession) -> list[PlantFamily]:
result = await db.execute(select(PlantFamily).order_by(PlantFamily.name))
return list(result.scalars().all())
async def get_by_name(self, db: AsyncSession, *, name: str) -> PlantFamily | None:
result = await db.execute(select(PlantFamily).where(PlantFamily.name == name))
return result.scalar_one_or_none()
crud_plant = CRUDPlant(Plant)
crud_plant_family = CRUDPlantFamily(PlantFamily)