5128e1551c
Backend (backend/):
- FastAPI app with layered app/{api,core,crud,db,models,schemas} structure
- TiDB connection via SQLAlchemy. The URL is built with URL.create rather
than string formatting: the password contains '@', which would otherwise be
parsed as the user/host separator and silently truncate the credential.
- Alembic environment wired to Base.metadata and the app settings, so
backend/.env stays the single source of truth for credentials
- /api/health endpoint reporting database reachability
- models/ and crud/ are intentionally empty: no model classes are defined and
no tables are created, at import time or otherwise
Frontend (frontend/):
- Vue 3 + Vite + TypeScript scaffold (create-vue, --bare)
- axios instance with a normalized error shape
- vue-router with a home route and a catch-all 404
- pinia + pinia-plugin-persistedstate; the app store persists selected keys
- Element Plus with its icons registered globally
- dev proxy forwards /api to the FastAPI service on port 8000
The database paper_doc was created in TiDB out of band; no table exists yet.
36 lines
790 B
Python
36 lines
790 B
Python
"""Database engine, session factory, and the FastAPI session dependency."""
|
|
|
|
from collections.abc import Generator
|
|
|
|
from sqlalchemy import create_engine
|
|
from sqlalchemy.orm import Session, sessionmaker
|
|
|
|
from app.core.config import get_settings
|
|
|
|
settings = get_settings()
|
|
|
|
engine = create_engine(
|
|
settings.sqlalchemy_url,
|
|
echo=settings.db_echo,
|
|
pool_pre_ping=settings.db_pool_pre_ping,
|
|
pool_recycle=settings.db_pool_recycle,
|
|
future=True,
|
|
)
|
|
|
|
SessionLocal = sessionmaker(
|
|
bind=engine,
|
|
class_=Session,
|
|
autoflush=False,
|
|
autocommit=False,
|
|
expire_on_commit=False,
|
|
)
|
|
|
|
|
|
def get_db() -> Generator[Session, None, None]:
|
|
"""Yield a session per request and always close it."""
|
|
db = SessionLocal()
|
|
try:
|
|
yield db
|
|
finally:
|
|
db.close()
|