Schritt 1: Fundament der Lebensmittel-Lagerverwaltung (Pantry)

Backend (FastAPI + PostgreSQL): Chargen mit MHD, FEFO-Auslagern,
Einheiten-Umrechnung (Stueck/g/ml + Packungen), Open-Food-Facts-Lookup
mit lokalem Fallback, JWT-Auth mit Rollen (Admin/Nutzer), erster Admin
beim Setup, Einkaufsliste, Ablaufwarnung, Lagerorte, pytest fuer FEFO.

Web-UI (React/Vite): Login, Dashboard, Ein-/Auslagern, Produkte,
Lagerorte, Benutzerverwaltung, Einkaufsliste - rollenabhaengig.

Deploy: docker-compose + install.sh (Docker-Autoinstall, Secrets),
README und Roadmap fuer Schritt 2 (iOS) und Schritt 3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-22 09:14:14 +02:00
commit 639126468f
57 changed files with 3460 additions and 0 deletions

61
backend/app/main.py Normal file
View File

@@ -0,0 +1,61 @@
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from .config import get_settings
from .database import Base, SessionLocal, engine
from .routers import (
auth,
groups,
locations,
products,
settings as settings_router,
stock,
users,
views,
)
from .seed import ensure_first_admin
settings = get_settings()
@asynccontextmanager
async def lifespan(app: FastAPI):
# Tabellen anlegen (MVP: create_all statt Alembic-Migrationen).
Base.metadata.create_all(bind=engine)
db = SessionLocal()
try:
ensure_first_admin(db)
finally:
db.close()
yield
app = FastAPI(title="Pantry Lebensmittel-Lagerverwaltung", version="1.0.0", lifespan=lifespan)
origins = ["*"] if settings.cors_origins.strip() == "*" else [
o.strip() for o in settings.cors_origins.split(",") if o.strip()
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/health", tags=["meta"])
def health() -> dict:
return {"status": "ok"}
app.include_router(auth.router)
app.include_router(users.router)
app.include_router(products.router)
app.include_router(stock.router)
app.include_router(locations.router)
app.include_router(groups.router)
app.include_router(views.router)
app.include_router(settings_router.router)