Files
flipventory_v2/app/main.py
Martin Hohenberg 4e0d0d3962 feat: initial FastAPI stub with auth, user management, and inventory CRUD
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>
2026-06-16 10:40:53 +02:00

83 lines
2.7 KiB
Python
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.
"""
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}