rebase
This commit is contained in:
11
CHANGELOG.md
11
CHANGELOG.md
@@ -4,6 +4,17 @@ All notable changes to AI-RPG are documented here.
|
|||||||
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.5] — 2026-06-20
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **app/main.py**: added `create_all_tables(engine)` call at the start of `lifespan`. Without this, the backend started but crashed on every DB query with `relation "settings" does not exist` because tables were never created in PostgreSQL. Tables are now created idempotently on every startup via `Base.metadata.create_all` ( SQLAlchemy skips tables that already exist).
|
||||||
|
- **app/main.py**: also added `seed_builtin_presets(session)` call so the 2 builtin presets (Classic Fantasy, Deep Space Outpost) are seeded on first startup, not just settings.
|
||||||
|
- **app/migrations/versions/**: renamed `001_initial_schema.py` → `_001_initial_schema.py`. Python module names cannot start with a digit, so `from app.migrations.versions.001_initial_schema import create_all_tables` was a SyntaxError. The leading underscore is a conventional marker for "internal" modules.
|
||||||
|
- **README.md**: updated references to the renamed migration file.
|
||||||
|
|
||||||
|
### Why this happened
|
||||||
|
The lifespan handler was supposed to run DB migrations as its first step, but I forgot to wire it up. The `seed_default_settings()` call immediately tried to `SELECT FROM settings` against a fresh PostgreSQL database with no tables. SQLAlchemy 2.x's `create_all` is idempotent (skips existing tables), so this is safe to call on every startup — equivalent to `alembic upgrade head` for our single-migration MVP.
|
||||||
|
|
||||||
## [1.0.4] — 2026-06-20
|
## [1.0.4] — 2026-06-20
|
||||||
|
|
||||||
### Fixed (proper fix for CORS env parsing)
|
### Fixed (proper fix for CORS env parsing)
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ pip install -r requirements.txt
|
|||||||
docker compose up -d db qdrant
|
docker compose up -d db qdrant
|
||||||
|
|
||||||
# Применить миграции (создаёт все таблицы)
|
# Применить миграции (создаёт все таблицы)
|
||||||
python -c "import asyncio; from app.db import get_engine; from app.migrations.versions.001_initial_schema import create_all_tables; asyncio.run(create_all_tables(get_engine()))"
|
python -c "import asyncio; from app.db import get_engine; from app.migrations.versions._001_initial_schema import create_all_tables; asyncio.run(create_all_tables(get_engine()))"
|
||||||
|
|
||||||
# Запустить backend
|
# Запустить backend
|
||||||
uvicorn app.main:app --reload --port 8000
|
uvicorn app.main:app --reload --port 8000
|
||||||
@@ -187,7 +187,7 @@ ai-rpg/
|
|||||||
│ │ ├── init_db.py # init_db(session)
|
│ │ ├── init_db.py # init_db(session)
|
||||||
│ │ ├── init_qdrant.py # re-export init_qdrant_collections
|
│ │ ├── init_qdrant.py # re-export init_qdrant_collections
|
||||||
│ │ ├── seed.py # builtin presets (fantasy, sci-fi)
|
│ │ ├── seed.py # builtin presets (fantasy, sci-fi)
|
||||||
│ │ └── versions/001_initial_schema.py
|
│ │ └── versions/_001_initial_schema.py
|
||||||
│ ├── config.py # Settings (pydantic-settings)
|
│ ├── config.py # Settings (pydantic-settings)
|
||||||
│ ├── db.py # async engine + session factory
|
│ ├── db.py # async engine + session factory
|
||||||
│ └── main.py # FastAPI app + lifespan
|
│ └── main.py # FastAPI app + lifespan
|
||||||
|
|||||||
25
app/main.py
25
app/main.py
@@ -35,6 +35,20 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
|||||||
_logger.info("app_starting", version=__version__, debug=cfg.debug)
|
_logger.info("app_starting", version=__version__, debug=cfg.debug)
|
||||||
|
|
||||||
# Startup -------------------------------------------------------------
|
# Startup -------------------------------------------------------------
|
||||||
|
# Step 0: Create all DB tables (idempotent — equivalent to alembic upgrade head).
|
||||||
|
# This must run BEFORE any settings query, otherwise seed_default_settings
|
||||||
|
# crashes with "relation 'settings' does not exist".
|
||||||
|
from app.db import get_engine
|
||||||
|
from app.migrations.versions._001_initial_schema import create_all_tables
|
||||||
|
|
||||||
|
try:
|
||||||
|
engine = get_engine()
|
||||||
|
await create_all_tables(engine)
|
||||||
|
_logger.info("db_tables_ready")
|
||||||
|
except Exception as e: # noqa: BLE001
|
||||||
|
_logger.error("db_tables_create_failed", error=str(e))
|
||||||
|
# Continue anyway — /api/health will reflect the broken state
|
||||||
|
|
||||||
sm = get_sessionmaker()
|
sm = get_sessionmaker()
|
||||||
try:
|
try:
|
||||||
async with sm() as session:
|
async with sm() as session:
|
||||||
@@ -61,12 +75,21 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
|||||||
print(f"===========================\n")
|
print(f"===========================\n")
|
||||||
else:
|
else:
|
||||||
_logger.info("admins_present", count=admins_count)
|
_logger.info("admins_present", count=admins_count)
|
||||||
# 4) Init Qdrant collections
|
# 4) seed builtin presets (idempotent)
|
||||||
|
from app.migrations.seed import seed_builtin_presets
|
||||||
|
|
||||||
|
try:
|
||||||
|
await seed_builtin_presets(session)
|
||||||
|
_logger.info("presets_seeded")
|
||||||
|
except Exception as e: # noqa: BLE001
|
||||||
|
_logger.warning("presets_seed_failed", error=str(e))
|
||||||
|
# 5) Init Qdrant collections
|
||||||
from app.core.settings_service import get_setting
|
from app.core.settings_service import get_setting
|
||||||
|
|
||||||
dim = int(await get_setting(session, "embeddings.dimension") or 256)
|
dim = int(await get_setting(session, "embeddings.dimension") or 256)
|
||||||
try:
|
try:
|
||||||
await init_qdrant_collections(dim)
|
await init_qdrant_collections(dim)
|
||||||
|
_logger.info("qdrant_collections_ready", dimension=dim)
|
||||||
except Exception as e: # noqa: BLE001
|
except Exception as e: # noqa: BLE001
|
||||||
_logger.warning("qdrant_init_failed", error=str(e))
|
_logger.warning("qdrant_init_failed", error=str(e))
|
||||||
except Exception as e: # noqa: BLE001
|
except Exception as e: # noqa: BLE001
|
||||||
|
|||||||
Reference in New Issue
Block a user