versione prima dle menu della clincia
This commit is contained in:
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal 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
5
backend/.env.example
Normal 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
|
||||||
22
backend/activate_backend_env.bat
Normal file
22
backend/activate_backend_env.bat
Normal 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
1
backend/app/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Backend package for the Clinica Veterinaria Formiginese project.
|
||||||
1
backend/app/api/__init__.py
Normal file
1
backend/app/api/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# API routers package.
|
||||||
29
backend/app/api/health.py
Normal file
29
backend/app/api/health.py
Normal 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
31
backend/app/config.py
Normal 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()
|
||||||
1
backend/app/db/__init__.py
Normal file
1
backend/app/db/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Database package.
|
||||||
5
backend/app/db/base.py
Normal file
5
backend/app/db/base.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
|
||||||
|
|
||||||
|
class Base(DeclarativeBase):
|
||||||
|
pass
|
||||||
24
backend/app/db/init_db.py
Normal file
24
backend/app/db/init_db.py
Normal 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
25
backend/app/db/session.py
Normal 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
11
backend/app/main.py
Normal 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)
|
||||||
3
backend/app/models/__init__.py
Normal file
3
backend/app/models/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from app.models.test_user import TestUser
|
||||||
|
|
||||||
|
__all__ = ["TestUser"]
|
||||||
12
backend/app/models/test_user.py
Normal file
12
backend/app/models/test_user.py
Normal 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)
|
||||||
1
backend/app/repositories/__init__.py
Normal file
1
backend/app/repositories/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Data access layer package.
|
||||||
1
backend/app/schemas/__init__.py
Normal file
1
backend/app/schemas/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Pydantic schemas package.
|
||||||
1
backend/app/services/__init__.py
Normal file
1
backend/app/services/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Business services package.
|
||||||
6
backend/requirements.txt
Normal file
6
backend/requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
fastapi
|
||||||
|
uvicorn[standard]
|
||||||
|
sqlalchemy
|
||||||
|
pydantic
|
||||||
|
python-dotenv
|
||||||
|
aiosqlite
|
||||||
17
backend/run_backend.bat
Normal file
17
backend/run_backend.bat
Normal 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
21
istruzioni.txt
Normal 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
23
menu_sito.txt
Normal 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
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user