chore: initial project setup with backend, frontend, and infrastructure
Some checks failed
CI / backend (push) Failing after 31s
CI / frontend (push) Successful in 40s
CI / docker (push) Has been skipped

Add complete NexaPantry application structure including:
- Docker Compose configuration with PostgreSQL, Redis, FastAPI backend, worker, frontend and Caddy
- Environment configuration template with database, auth, and service settings
- GitHub Actions CI workflow for backend/frontend linting, testing, auditing and Docker builds
- AGPL-3.0 license and comprehensive README with setup, development, and security documentation
- Backend
This commit is contained in:
2026-06-04 10:26:38 +02:00
commit 3792ca55e7
74 changed files with 13417 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
from datetime import date
from typing import Protocol
import httpx
from sqlalchemy.orm import Session
from app.models.entities import Home, Product
def expiry_status(product: Product, home: Home) -> str:
if not product.expires_at:
return "ok"
today = date.today()
if product.expires_at <= today:
return "expired"
if (product.expires_at - today).days <= home.expiry_warning_days:
return "soon"
return "ok"
class ProductLookup(Protocol):
async def by_barcode(self, barcode: str) -> dict | None:
...
class OpenFoodFactsLookup(ProductLookup):
async def by_barcode(self, barcode: str) -> dict | None:
url = f"https://world.openfoodfacts.org/api/v2/product/{barcode}.json"
async with httpx.AsyncClient(timeout=8) as client:
response = await client.get(url)
if response.status_code != 200:
return None
data = response.json()
product = data.get("product")
if not product:
return None
return {
"name": product.get("product_name") or product.get("generic_name") or "",
"brand": product.get("brands"),
"category": (product.get("categories_tags") or ["Other"])[0].replace("en:", ""),
"image_url": product.get("image_front_small_url") or product.get("image_url"),
"barcode": barcode,
}
def low_stock_products(db: Session, home_id: str) -> list[Product]:
return [
product
for product in db.query(Product).filter(Product.home_id == home_id).all()
if product.quantity <= product.min_quantity
]