From d622ac5a6b7c7f946e983e1ca46f9cf56df3877a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80?= <78488229+viktor138irk@users.noreply.github.com> Date: Fri, 8 May 2026 03:52:14 +0900 Subject: [PATCH] Add safe schema patches for MVP database updates --- app/db.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/app/db.py b/app/db.py index d951c76..0298be3 100644 --- a/app/db.py +++ b/app/db.py @@ -1,5 +1,5 @@ from collections.abc import Generator -from sqlalchemy import create_engine +from sqlalchemy import create_engine, inspect, text from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker from app.core import get_settings @@ -25,3 +25,36 @@ def init_db() -> None: from app import models # noqa: F401 Base.metadata.create_all(bind=engine) + apply_safe_schema_patches() + + +def apply_safe_schema_patches() -> None: + """Tiny compatibility layer for the early MVP. + + SQLAlchemy create_all creates missing tables but does not alter existing ones. + During rapid MVP iterations this keeps old server databases from breaking + when a new column is added. + """ + inspector = inspect(engine) + if 'bot_state' in inspector.get_table_names(): + existing = {column['name'] for column in inspector.get_columns('bot_state')} + patches = [] + if 'live_acknowledged' not in existing: + patches.append("ALTER TABLE bot_state ADD COLUMN live_acknowledged BOOLEAN NOT NULL DEFAULT FALSE") + if 'emergency_stop' not in existing: + patches.append("ALTER TABLE bot_state ADD COLUMN emergency_stop BOOLEAN NOT NULL DEFAULT FALSE") + if 'trade_mode' not in existing: + patches.append("ALTER TABLE bot_state ADD COLUMN trade_mode VARCHAR(16) NOT NULL DEFAULT 'demo'") + if 'enabled' not in existing: + patches.append("ALTER TABLE bot_state ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT FALSE") + if 'trade_style_mode' not in existing: + patches.append("ALTER TABLE bot_state ADD COLUMN trade_style_mode VARCHAR(32) NOT NULL DEFAULT 'balanced'") + if 'min_signal_score' not in existing: + patches.append("ALTER TABLE bot_state ADD COLUMN min_signal_score FLOAT NOT NULL DEFAULT 65.0") + if 'max_open_positions' not in existing: + patches.append("ALTER TABLE bot_state ADD COLUMN max_open_positions INTEGER NOT NULL DEFAULT 3") + if 'max_quote_per_trade' not in existing: + patches.append("ALTER TABLE bot_state ADD COLUMN max_quote_per_trade FLOAT NOT NULL DEFAULT 100.0") + with engine.begin() as conn: + for patch in patches: + conn.execute(text(patch))