Sets up the complete application skeleton for Flipventory v2, an inventory management tool for small/medium resellers using chaotic stockpiling. Architecture ------------ - app/config.py pydantic-settings; reads .env; holds admin_email guard - app/database.py SQLAlchemy 2.x engine, SessionLocal, Base, get_db dep - app/models/user.py User (email, bcrypt hash, is_admin bool, is_active) - app/models/item.py StorageBin + Item with FOUND/LISTED/SOLD/ARCHIVED enum - app/schemas/ Pydantic request/response shapes (separate from models) - app/auth/security.py bcrypt password hashing + HS256 JWT creation/validation - app/routers/auth.py POST /auth/register, POST /auth/login, GET /auth/me - app/routers/users.py Admin-only CRUD for user accounts - app/routers/items.py /bins and /items CRUD with role-based access control Key design decisions -------------------- - martin@hohenberg.jp is ALWAYS admin: enforced on every login, cannot be demoted, cannot be deactivated. Prevents accidental lockout. - All other registered e-mails are customers (is_admin=False). - Customers can manage their own bins and items; admins see everything. - Item hard-delete is admin-only; customers archive instead (audit safety). - SQLite default for zero-infra local dev; any SQLAlchemy URL works in prod. - Tables are created on startup via create_tables(); swap for Alembic later. Addresses v1 Gitea issues -------------------------- - Issue #1 (storage bins): StorageBin model + /bins CRUD endpoints - Issue #2 (item CRUD): Item model + /items CRUD endpoints - Issue #3 (audit logging): created_by_id / updated_by_id on every item row Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
"""
|
||
Flipventory v2 – FastAPI application entry point.
|
||
|
||
What is this?
|
||
--------------
|
||
Inventory management system for small-to-medium resellers who use a
|
||
"chaotic stockpiling" approach: buy first, sort later. Items are added
|
||
quickly, placed in physical storage bins, and gradually processed through
|
||
a FOUND → LISTED → SOLD lifecycle.
|
||
|
||
Architecture overview
|
||
----------------------
|
||
app/
|
||
config.py – settings (secret key, DB URL, admin e-mail)
|
||
database.py – SQLAlchemy engine + session factory
|
||
models/ – ORM table definitions (user, item, storage_bin)
|
||
schemas/ – Pydantic request/response shapes
|
||
auth/ – JWT creation & FastAPI dependencies
|
||
routers/
|
||
auth.py – /auth/register, /auth/login, /auth/me
|
||
users.py – /users CRUD (admin only)
|
||
items.py – /bins and /items CRUD
|
||
|
||
Running locally
|
||
----------------
|
||
uvicorn app.main:app --reload
|
||
|
||
Then open http://127.0.0.1:8000/docs for the interactive Swagger UI.
|
||
"""
|
||
from contextlib import asynccontextmanager
|
||
|
||
from fastapi import FastAPI
|
||
|
||
from app.database import create_tables
|
||
from app.routers import auth, items, users
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Lifespan: run startup/shutdown logic without deprecated @app.on_event hooks
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@asynccontextmanager
|
||
async def lifespan(app: FastAPI):
|
||
# Startup: create DB tables if they don't exist yet.
|
||
# In a production deployment with Alembic migrations this call would be
|
||
# replaced by running `alembic upgrade head` in the CI/CD pipeline.
|
||
create_tables()
|
||
yield
|
||
# (Nothing to clean up on shutdown for now.)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Application instance
|
||
# ---------------------------------------------------------------------------
|
||
|
||
app = FastAPI(
|
||
title="Flipventory v2",
|
||
description=(
|
||
"Inventory management for small/medium resellers. "
|
||
"Tame the chaos: add items fast, sort later, track every flip."
|
||
),
|
||
version="0.1.0",
|
||
lifespan=lifespan,
|
||
)
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Routers
|
||
# ---------------------------------------------------------------------------
|
||
|
||
app.include_router(auth.router)
|
||
app.include_router(users.router)
|
||
app.include_router(items.router)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Health check
|
||
# ---------------------------------------------------------------------------
|
||
|
||
@app.get("/health", tags=["meta"])
|
||
def health() -> dict:
|
||
"""Simple liveness probe. Returns 200 if the server is up."""
|
||
return {"status": "ok", "version": app.version}
|