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

16
.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
# Python local environments
backend/.venv/
__pycache__/
*.py[cod]
# Local environment files
.env
backend/.env
# Local SQLite databases
data/*.db
data/*.db-*
# Logs and temporary files
*.log
*.tmp

5
backend/.env.example Normal file
View File

@@ -0,0 +1,5 @@
APP_NAME=Clinica Veterinaria Formiginese API
APP_ENV=development
APP_HOST=127.0.0.1
APP_PORT=8000
DATABASE_URL=sqlite:///C:/devel/clinica_veterinaria_formiginese/data/clinica.db

View File

@@ -0,0 +1,22 @@
@echo off
setlocal
set "BACKEND_DIR=C:\devel\clinica_veterinaria_formiginese\backend"
set "VENV_ACTIVATE=%BACKEND_DIR%\.venv\Scripts\activate.bat"
if not exist "%VENV_ACTIVATE%" (
echo ERRORE: virtual environment non trovato.
echo Crea prima il venv con:
echo py -3.13 -m venv .venv
exit /b 1
)
cd /d "%BACKEND_DIR%"
call "%VENV_ACTIVATE%"
echo.
echo Ambiente backend attivo in %BACKEND_DIR%
echo Per uscire usa: deactivate
echo.
cmd /k

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.

6
backend/requirements.txt Normal file
View File

@@ -0,0 +1,6 @@
fastapi
uvicorn[standard]
sqlalchemy
pydantic
python-dotenv
aiosqlite

17
backend/run_backend.bat Normal file
View File

@@ -0,0 +1,17 @@
@echo off
setlocal
set "BACKEND_DIR=C:\devel\clinica_veterinaria_formiginese\backend"
set "PYTHON_EXE=%BACKEND_DIR%\.venv\Scripts\python.exe"
if not exist "%PYTHON_EXE%" (
echo ERRORE: python del virtual environment non trovato.
echo Crea prima il venv con:
echo py -3.13 -m venv .venv
echo Poi installa le dipendenze con:
echo pip install -r requirements.txt
exit /b 1
)
cd /d "%BACKEND_DIR%"
"%PYTHON_EXE%" -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

21
istruzioni.txt Normal file
View File

@@ -0,0 +1,21 @@
Ho aggiunto due file nel repository locale:
publish_demo.bat
coming-soon/index.html
Come funziona:
publish_demo.bat true pubblica la demo completa
publish_demo.bat false mostra la pagina coming soon
lo script aggiorna il blocco del dominio nel C:\caddy\Caddyfile e ricarica Caddy
Prima di usarlo, fai una volta sola il normale flusso repo -> deploy, così la cartella coming-soon arriva anche in:
C:\deploy\clinica_veterinaria_formiginese
Quindi:
fai git add ., git commit, git push nel repo locale
lancia deploy_to_local_server.bat
poi puoi usare:
publish_demo.bat false
oppure
publish_demo.bat true

23
menu_sito.txt Normal file
View File

@@ -0,0 +1,23 @@
- servizi
- visite clincihe e medicina preventiva
- ecografia
- radiologia
- laboratorio
- ematologia
- biochimica
- urine
- citologia
- coagulazione
- ednoscopia
- laparoscopia
- viite specialistiche
- oncologia
- dermatologia
- oculistica
- nutrizione
- ortopedia
- team medico