versione prima dle menu della clincia

This commit is contained in:
2026-04-20 15:07:07 +02:00
parent 051b9c2102
commit c73efb7680
21 changed files with 256 additions and 0 deletions

1
backend/app/__init__.py Normal file
View File

@@ -0,0 +1 @@
# Backend package for the Clinica Veterinaria Formiginese project.

View File

@@ -0,0 +1 @@
# API routers package.

29
backend/app/api/health.py Normal file
View File

@@ -0,0 +1,29 @@
from fastapi import APIRouter, Depends
from sqlalchemy import text
from sqlalchemy.orm import Session
from app.config import settings
from app.db.session import get_db
router = APIRouter(prefix="/api", tags=["health"])
@router.get("/health")
def healthcheck() -> dict[str, str]:
return {
"status": "ok",
"environment": settings.app_env,
"app_name": settings.app_name,
}
@router.get("/db-health")
def database_healthcheck(db: Session = Depends(get_db)) -> dict[str, str | int]:
result = db.execute(text("SELECT 1")).scalar_one()
return {
"status": "ok",
"database": "connected",
"result": result,
"sqlite_file": settings.sqlite_file_path or "not-applicable",
}

31
backend/app/config.py Normal file
View File

@@ -0,0 +1,31 @@
from pathlib import Path
import os
from dotenv import load_dotenv
BASE_DIR = Path(__file__).resolve().parent.parent
PROJECT_ROOT = BASE_DIR.parent
ENV_FILE = PROJECT_ROOT / ".env"
load_dotenv(ENV_FILE)
class Settings:
def __init__(self) -> None:
self.app_name = os.getenv("APP_NAME", "Clinica Veterinaria Formiginese API")
self.app_env = os.getenv("APP_ENV", "development")
self.app_host = os.getenv("APP_HOST", "127.0.0.1")
self.app_port = int(os.getenv("APP_PORT", "8000"))
default_sqlite_path = (PROJECT_ROOT / "data" / "clinica.db").resolve()
self.database_url = os.getenv("DATABASE_URL", f"sqlite:///{default_sqlite_path.as_posix()}")
@property
def sqlite_file_path(self) -> str | None:
sqlite_prefix = "sqlite:///"
if self.database_url.startswith(sqlite_prefix):
return self.database_url.removeprefix(sqlite_prefix)
return None
settings = Settings()

View File

@@ -0,0 +1 @@
# Database package.

5
backend/app/db/base.py Normal file
View File

@@ -0,0 +1,5 @@
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass

24
backend/app/db/init_db.py Normal file
View File

@@ -0,0 +1,24 @@
import hashlib
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.db.base import Base
from app.db.session import SessionLocal, engine
from app.models import TestUser
def init_db() -> None:
Base.metadata.create_all(bind=engine)
seed_test_data()
def seed_test_data() -> None:
with SessionLocal() as db:
existing_user = db.scalar(select(TestUser).where(TestUser.username == "admin_test"))
if existing_user:
return
password_hash = hashlib.sha256("change_me_123".encode("utf-8")).hexdigest()
db.add(TestUser(username="admin_test", password_hash=password_hash))
db.commit()

25
backend/app/db/session.py Normal file
View File

@@ -0,0 +1,25 @@
from collections.abc import Generator
from pathlib import Path
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from app.config import settings
if settings.sqlite_file_path:
Path(settings.sqlite_file_path).parent.mkdir(parents=True, exist_ok=True)
engine = create_engine(
settings.database_url,
connect_args={"check_same_thread": False} if settings.database_url.startswith("sqlite") else {},
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db() -> Generator[Session, None, None]:
db = SessionLocal()
try:
yield db
finally:
db.close()

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

@@ -0,0 +1,11 @@
from fastapi import FastAPI
from app.api.health import router as health_router
from app.config import settings
from app.db.init_db import init_db
init_db()
app = FastAPI(title=settings.app_name)
app.include_router(health_router)

View File

@@ -0,0 +1,3 @@
from app.models.test_user import TestUser
__all__ = ["TestUser"]

View File

@@ -0,0 +1,12 @@
from sqlalchemy import String
from sqlalchemy.orm import Mapped, mapped_column
from app.db.base import Base
class TestUser(Base):
__tablename__ = "test_users"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True)
password_hash: Mapped[str] = mapped_column(String(128), nullable=False)

View File

@@ -0,0 +1 @@
# Data access layer package.

View File

@@ -0,0 +1 @@
# Pydantic schemas package.

View File

@@ -0,0 +1 @@
# Business services package.