diff --git a/entrypoint.sh b/entrypoint.sh index 3317bdc..78028b3 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,6 +1,9 @@ #!/bin/bash set -e # Exit on any error +# Ensure data directory exists +mkdir -p /app/data + echo "Running database migrations..." if uv run alembic upgrade head; then echo "Database migrations completed successfully" diff --git a/migrations/env.py b/migrations/env.py index 36a8965..1c8b403 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -4,12 +4,13 @@ This module configures Alembic to work with the Flask application and SQLAlchemy models. """ +import os from logging.config import fileConfig +from pathlib import Path from alembic import context - -# Import Flask app and database before configuring Alembic -from src.app import create_app, db +from flask import Flask +from flask_sqlalchemy import SQLAlchemy # this is the Alembic Config object, which provides # access to the values within the .ini file in use. @@ -20,8 +21,31 @@ config = context.config if config.config_file_name is not None: fileConfig(config.config_file_name) -# Configure database URL from Flask config -app = create_app() +# Create minimal Flask app for migrations (without session initialization) +# This avoids Flask-Session trying to create tables before migrations run +app = Flask(__name__) +BASE_DIR = Path(__file__).parent.parent +DATA_DIR = BASE_DIR / "data" +DATA_DIR.mkdir(parents=True, exist_ok=True) + +app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( + "DATABASE_URL", f"sqlite:///{DATA_DIR / 'sneaky-klaus.db'}" +) +app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + +db = SQLAlchemy() +db.init_app(app) + +# Import all models to register them with SQLAlchemy metadata +with app.app_context(): + from src.models import ( # noqa: F401 + Admin, + Exchange, + MagicToken, + Participant, + RateLimit, + ) + config.set_main_option("sqlalchemy.url", app.config["SQLALCHEMY_DATABASE_URI"]) # Add your model's MetaData object here for 'autogenerate' support diff --git a/src/app.py b/src/app.py index bbbac19..0b33386 100644 --- a/src/app.py +++ b/src/app.py @@ -51,8 +51,10 @@ def create_app(config_name: str | None = None) -> Flask: bcrypt.init_app(app) csrf.init_app(app) - # Initialize session with SQLAlchemy backend - app.config["SESSION_SQLALCHEMY"] = db + # Initialize session with filesystem backend + # Ensure session directory exists + session_dir = Path(app.config.get("SESSION_FILE_DIR", data_dir / "sessions")) + session_dir.mkdir(parents=True, exist_ok=True) session.init_app(app) # Register blueprints diff --git a/src/config.py b/src/config.py index dfccd38..bc93a25 100644 --- a/src/config.py +++ b/src/config.py @@ -25,8 +25,9 @@ class Config: ) SQLALCHEMY_TRACK_MODIFICATIONS = False - # Session management - SESSION_TYPE = "sqlalchemy" + # Session management (filesystem-based to avoid race conditions with SQLAlchemy) + SESSION_TYPE = "filesystem" + SESSION_FILE_DIR = DATA_DIR / "sessions" SESSION_PERMANENT = True SESSION_USE_SIGNER = True SESSION_KEY_PREFIX = "sk:" @@ -90,6 +91,10 @@ class TestConfig(Config): # Use in-memory database for tests SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:" + # Use filesystem session with temp directory for tests + SESSION_TYPE = "filesystem" + SESSION_FILE_DIR = Path("/tmp/sneaky-klaus-test-sessions") + # Disable CSRF for easier testing WTF_CSRF_ENABLED = False