From c73efb7680c18c74d834d7821d4baf4b41378f6b Mon Sep 17 00:00:00 2001 From: allebonvi Date: Mon, 20 Apr 2026 15:07:07 +0200 Subject: [PATCH] versione prima dle menu della clincia --- .gitignore | 16 ++++++++++++++ backend/.env.example | 5 +++++ backend/activate_backend_env.bat | 22 ++++++++++++++++++++ backend/app/__init__.py | 1 + backend/app/api/__init__.py | 1 + backend/app/api/health.py | 29 ++++++++++++++++++++++++++ backend/app/config.py | 31 ++++++++++++++++++++++++++++ backend/app/db/__init__.py | 1 + backend/app/db/base.py | 5 +++++ backend/app/db/init_db.py | 24 +++++++++++++++++++++ backend/app/db/session.py | 25 ++++++++++++++++++++++ backend/app/main.py | 11 ++++++++++ backend/app/models/__init__.py | 3 +++ backend/app/models/test_user.py | 12 +++++++++++ backend/app/repositories/__init__.py | 1 + backend/app/schemas/__init__.py | 1 + backend/app/services/__init__.py | 1 + backend/requirements.txt | 6 ++++++ backend/run_backend.bat | 17 +++++++++++++++ istruzioni.txt | 21 +++++++++++++++++++ menu_sito.txt | 23 +++++++++++++++++++++ 21 files changed, 256 insertions(+) create mode 100644 .gitignore create mode 100644 backend/.env.example create mode 100644 backend/activate_backend_env.bat create mode 100644 backend/app/__init__.py create mode 100644 backend/app/api/__init__.py create mode 100644 backend/app/api/health.py create mode 100644 backend/app/config.py create mode 100644 backend/app/db/__init__.py create mode 100644 backend/app/db/base.py create mode 100644 backend/app/db/init_db.py create mode 100644 backend/app/db/session.py create mode 100644 backend/app/main.py create mode 100644 backend/app/models/__init__.py create mode 100644 backend/app/models/test_user.py create mode 100644 backend/app/repositories/__init__.py create mode 100644 backend/app/schemas/__init__.py create mode 100644 backend/app/services/__init__.py create mode 100644 backend/requirements.txt create mode 100644 backend/run_backend.bat create mode 100644 istruzioni.txt create mode 100644 menu_sito.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..befef02 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/backend/.env.example b/backend/.env.example new file mode 100644 index 0000000..0baa0f7 --- /dev/null +++ b/backend/.env.example @@ -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 diff --git a/backend/activate_backend_env.bat b/backend/activate_backend_env.bat new file mode 100644 index 0000000..280cb31 --- /dev/null +++ b/backend/activate_backend_env.bat @@ -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 diff --git a/backend/app/__init__.py b/backend/app/__init__.py new file mode 100644 index 0000000..d4aa7b2 --- /dev/null +++ b/backend/app/__init__.py @@ -0,0 +1 @@ +# Backend package for the Clinica Veterinaria Formiginese project. diff --git a/backend/app/api/__init__.py b/backend/app/api/__init__.py new file mode 100644 index 0000000..a5f81db --- /dev/null +++ b/backend/app/api/__init__.py @@ -0,0 +1 @@ +# API routers package. diff --git a/backend/app/api/health.py b/backend/app/api/health.py new file mode 100644 index 0000000..01d5288 --- /dev/null +++ b/backend/app/api/health.py @@ -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", + } diff --git a/backend/app/config.py b/backend/app/config.py new file mode 100644 index 0000000..bfa3480 --- /dev/null +++ b/backend/app/config.py @@ -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() diff --git a/backend/app/db/__init__.py b/backend/app/db/__init__.py new file mode 100644 index 0000000..b886c58 --- /dev/null +++ b/backend/app/db/__init__.py @@ -0,0 +1 @@ +# Database package. diff --git a/backend/app/db/base.py b/backend/app/db/base.py new file mode 100644 index 0000000..fa2b68a --- /dev/null +++ b/backend/app/db/base.py @@ -0,0 +1,5 @@ +from sqlalchemy.orm import DeclarativeBase + + +class Base(DeclarativeBase): + pass diff --git a/backend/app/db/init_db.py b/backend/app/db/init_db.py new file mode 100644 index 0000000..d2759b7 --- /dev/null +++ b/backend/app/db/init_db.py @@ -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() diff --git a/backend/app/db/session.py b/backend/app/db/session.py new file mode 100644 index 0000000..bd1a2dc --- /dev/null +++ b/backend/app/db/session.py @@ -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() diff --git a/backend/app/main.py b/backend/app/main.py new file mode 100644 index 0000000..5ad0c70 --- /dev/null +++ b/backend/app/main.py @@ -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) diff --git a/backend/app/models/__init__.py b/backend/app/models/__init__.py new file mode 100644 index 0000000..290db92 --- /dev/null +++ b/backend/app/models/__init__.py @@ -0,0 +1,3 @@ +from app.models.test_user import TestUser + +__all__ = ["TestUser"] diff --git a/backend/app/models/test_user.py b/backend/app/models/test_user.py new file mode 100644 index 0000000..fdcdbfd --- /dev/null +++ b/backend/app/models/test_user.py @@ -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) diff --git a/backend/app/repositories/__init__.py b/backend/app/repositories/__init__.py new file mode 100644 index 0000000..d0dbf07 --- /dev/null +++ b/backend/app/repositories/__init__.py @@ -0,0 +1 @@ +# Data access layer package. diff --git a/backend/app/schemas/__init__.py b/backend/app/schemas/__init__.py new file mode 100644 index 0000000..98781f5 --- /dev/null +++ b/backend/app/schemas/__init__.py @@ -0,0 +1 @@ +# Pydantic schemas package. diff --git a/backend/app/services/__init__.py b/backend/app/services/__init__.py new file mode 100644 index 0000000..f953d42 --- /dev/null +++ b/backend/app/services/__init__.py @@ -0,0 +1 @@ +# Business services package. diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000..b188404 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,6 @@ +fastapi +uvicorn[standard] +sqlalchemy +pydantic +python-dotenv +aiosqlite diff --git a/backend/run_backend.bat b/backend/run_backend.bat new file mode 100644 index 0000000..c8f9697 --- /dev/null +++ b/backend/run_backend.bat @@ -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 diff --git a/istruzioni.txt b/istruzioni.txt new file mode 100644 index 0000000..4977deb --- /dev/null +++ b/istruzioni.txt @@ -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 \ No newline at end of file diff --git a/menu_sito.txt b/menu_sito.txt new file mode 100644 index 0000000..5a6bb27 --- /dev/null +++ b/menu_sito.txt @@ -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 + + \ No newline at end of file