alembic fix

This commit is contained in:
2026-06-01 16:34:07 +03:00
parent e12a9ddfce
commit 4c5da7e4d9
15 changed files with 346 additions and 90 deletions

View File

@@ -18,7 +18,6 @@ from pathlib import Path
# project_root is used for static files mounting
project_root = Path(__file__).resolve().parent.parent.parent
from alembic.config import Config as AlembicConfig
from fastapi import FastAPI, HTTPException, Request, WebSocket, WebSocketDisconnect, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse
@@ -27,8 +26,6 @@ from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.sessions import SessionMiddleware
from typing import Any
from alembic import command as alembic_command
from .api import auth
from .api.routes import (
admin,
@@ -67,10 +64,14 @@ from .models.auth import Role, User
# #region lifespan [C:3] [TYPE Function]
# @BRIEF Async context manager for FastAPI startup/shutdown lifecycle.
# @RELATION CALLS -> [run_alembic_migrations]
# @RELATION CALLS -> [init_db]
# @RELATION CALLS -> [AppDependencies]
# @POST On startup: schema up-to-date, admin exists, scheduler started. On shutdown: scheduler stopped.
# @POST On startup: admin exists, scheduler started. On shutdown: scheduler stopped.
# @RATIONALE Alembic migrations removed from lifespan — they now run exclusively
# in docker/backend.entrypoint.sh (wait_for_db → alembic upgrade head).
# Running migrations in both places added ~5s startup overhead and masked
# partial failures. init_db() remains as a safety net for tables without
# dedicated Alembic migrations (e.g., newly added models during development).
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
@@ -78,9 +79,7 @@ async def lifespan(app: FastAPI):
with belief_scope("startup_event"):
logger.info("🔐 Ensuring encryption key...")
ensure_encryption_key()
logger.info("📦 Running Alembic migrations...")
run_alembic_migrations()
logger.info("🗄️ Initializing database tables...")
logger.info("🗄️ Initializing database tables (safety net)...")
init_db()
logger.info("👤 Bootstrapping admin user...")
ensure_initial_admin_user()
@@ -109,7 +108,6 @@ async def lifespan(app: FastAPI):
scheduler = get_scheduler_service()
scheduler.start()
logger.info("✅ Application startup complete")
logger.info("✅ Application startup complete")
yield
# Shutdown
scheduler.stop()
@@ -185,13 +183,16 @@ def ensure_initial_admin_user() -> None:
# #endregion ensure_initial_admin_user
# #region run_alembic_migrations [C:2] [TYPE Function]
# @BRIEF Applies all pending Alembic migrations against DATABASE_URL.
# DEPRECATED: Migrations now run exclusively in docker/backend.entrypoint.sh.
# Kept for local development (manual invocation).
# @POST All Alembic migrations up to 'head' are applied.
# @SIDE_EFFECT Executes ALTER TABLE / CREATE TABLE via Alembic chain.
# @RATIONALE Single source of truth for schema changes. All column additions,
# drops, renames, and data migrations go through Alembic.
# init_db() runs after to create any tables that don't have
# a standalone Alembic migration yet.
# @DEPRECATED Migrations moved to entrypoint.sh — this function is kept for
# local development only. Do NOT call from lifespan or production code.
def run_alembic_migrations() -> None:
from alembic.config import Config as AlembicConfig
from alembic import command as alembic_command
with belief_scope("run_alembic_migrations"):
try:
alembic_cfg = AlembicConfig("alembic.ini")