From 481b6d618eb2a2c9c6c34e6a8201898e40597079 Mon Sep 17 00:00:00 2001 From: Felipe Cardoso Date: Fri, 28 Feb 2025 09:26:25 +0100 Subject: [PATCH] Refactor and reorganize Alembic and database configuration. Moved Alembic files into the `app/alembic` directory and updated related paths. Consolidated database configuration in `config.py`, leveraging environment variables and ensuring centralized management. Updated Docker Compose to include `.env` files, providing a more consistent environment setup. --- backend/__init__.py | 0 backend/alembic.ini | 2 +- backend/{ => app}/alembic/README | 0 backend/app/alembic/__init__.py | 0 backend/{ => app}/alembic/env.py | 26 ++++++---- backend/{ => app}/alembic/script.py.mako | 0 .../7396957cbe80_initial_empty_migration.py | 0 backend/app/alembic/versions/__init__.py | 0 backend/app/config.py | 29 ----------- backend/app/core/config.py | 48 +++++++++++++++++++ backend/app/core/database.py | 6 +-- docker-compose.dev.yml | 2 + docker-compose.yml | 2 + 13 files changed, 74 insertions(+), 41 deletions(-) create mode 100644 backend/__init__.py rename backend/{ => app}/alembic/README (100%) create mode 100644 backend/app/alembic/__init__.py rename backend/{ => app}/alembic/env.py (75%) rename backend/{ => app}/alembic/script.py.mako (100%) rename backend/{ => app}/alembic/versions/7396957cbe80_initial_empty_migration.py (100%) create mode 100644 backend/app/alembic/versions/__init__.py delete mode 100644 backend/app/config.py create mode 100644 backend/app/core/config.py diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/alembic.ini b/backend/alembic.ini index 5006c25..eb4b134 100644 --- a/backend/alembic.ini +++ b/backend/alembic.ini @@ -1,5 +1,5 @@ [alembic] -script_location = alembic +script_location = app/alembic sqlalchemy.url = postgresql://postgres:postgres@db:5432/app [loggers] diff --git a/backend/alembic/README b/backend/app/alembic/README similarity index 100% rename from backend/alembic/README rename to backend/app/alembic/README diff --git a/backend/app/alembic/__init__.py b/backend/app/alembic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/alembic/env.py b/backend/app/alembic/env.py similarity index 75% rename from backend/alembic/env.py rename to backend/app/alembic/env.py index 36112a3..5b616e5 100644 --- a/backend/alembic/env.py +++ b/backend/app/alembic/env.py @@ -1,10 +1,24 @@ +import sys from logging.config import fileConfig +from pathlib import Path from sqlalchemy import engine_from_config from sqlalchemy import pool from alembic import context +# Get the path to the app directory (parent of 'alembic') +app_dir = Path(__file__).resolve().parent.parent +# Add the app directory to Python path +sys.path.append(str(app_dir.parent)) + +# Import Core modules +from app.core.config import settings +from app.core.database import Base + +# Import all models to ensure they're registered with SQLAlchemy +from app.models import * + # this is the Alembic Config object, which provides # access to the values within the .ini file in use. config = context.config @@ -16,14 +30,10 @@ if config.config_file_name is not None: # add your model's MetaData object here # for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata -target_metadata = None +target_metadata = Base.metadata -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. +# Override the SQLAlchemy URL with the one from settings +config.set_main_option("sqlalchemy.url", settings.database_url) def run_migrations_offline() -> None: @@ -75,4 +85,4 @@ def run_migrations_online() -> None: if context.is_offline_mode(): run_migrations_offline() else: - run_migrations_online() + run_migrations_online() \ No newline at end of file diff --git a/backend/alembic/script.py.mako b/backend/app/alembic/script.py.mako similarity index 100% rename from backend/alembic/script.py.mako rename to backend/app/alembic/script.py.mako diff --git a/backend/alembic/versions/7396957cbe80_initial_empty_migration.py b/backend/app/alembic/versions/7396957cbe80_initial_empty_migration.py similarity index 100% rename from backend/alembic/versions/7396957cbe80_initial_empty_migration.py rename to backend/app/alembic/versions/7396957cbe80_initial_empty_migration.py diff --git a/backend/app/alembic/versions/__init__.py b/backend/app/alembic/versions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/config.py b/backend/app/config.py deleted file mode 100644 index b34ffde..0000000 --- a/backend/app/config.py +++ /dev/null @@ -1,29 +0,0 @@ -from pydantic_settings import BaseSettings -from typing import Optional, List - - -class Settings(BaseSettings): - PROJECT_NAME: Optional[str] = "App" - VERSION: Optional[str] = "1.0.0" - API_V1_STR: Optional[str] = "/api/v1" - - # Database configuration - DATABASE_URL: Optional[str] = None - - # JWT configuration - SECRET_KEY: Optional[str] = None - ALGORITHM: Optional[str] = "HS256" - ACCESS_TOKEN_EXPIRE_MINUTES: Optional[int] = 30 - - # CORS configuration - BACKEND_CORS_ORIGINS: Optional[List[str]] = ["http://localhost:3000"] # Frontend URL - - # Admin user - FIRST_SUPERUSER_EMAIL: Optional[str] = None - FIRST_SUPERUSER_PASSWORD: Optional[str] = None - - class Config: - env_file = ".env" - - -settings = Settings() \ No newline at end of file diff --git a/backend/app/core/config.py b/backend/app/core/config.py new file mode 100644 index 0000000..d674792 --- /dev/null +++ b/backend/app/core/config.py @@ -0,0 +1,48 @@ +from pydantic_settings import BaseSettings +from typing import Optional, List + + +class Settings(BaseSettings): + PROJECT_NAME: str = "App" + VERSION: str = "1.0.0" + API_V1_STR: str = "/api/v1" + + # Database configuration + POSTGRES_USER: str = "postgres" + POSTGRES_PASSWORD: str = "postgres" + POSTGRES_HOST: str = "localhost" + POSTGRES_PORT: str = "5432" + POSTGRES_DB: str = "app" + DATABASE_URL: Optional[str] = None + + @property + def database_url(self) -> str: + """ + Get the SQLAlchemy database URL. + If DATABASE_URL is explicitly set, use that. + Otherwise, construct from components. + """ + if self.DATABASE_URL: + return self.DATABASE_URL + self.DATABASE_URL = f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}" + return self.DATABASE_URL + + # JWT configuration + SECRET_KEY: str = "your_secret_key_here" + ALGORITHM: str = "HS256" + ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 + + # CORS configuration + BACKEND_CORS_ORIGINS: List[str] = ["http://localhost:3000"] + + # Admin user + FIRST_SUPERUSER_EMAIL: Optional[str] = None + FIRST_SUPERUSER_PASSWORD: Optional[str] = None + + class Config: + env_file = ".env" + env_file_encoding = "utf-8" + case_sensitive = True + + +settings = Settings() \ No newline at end of file diff --git a/backend/app/core/database.py b/backend/app/core/database.py index adfb7b9..22d743a 100644 --- a/backend/app/core/database.py +++ b/backend/app/core/database.py @@ -1,11 +1,11 @@ from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker -import os -SQLALCHEMY_DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@db:5432/app") +from app.core.config import settings -engine = create_engine(SQLALCHEMY_DATABASE_URL) +# Use the database URL from settings +engine = create_engine(settings.database_url) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 5c848ba..e24cc27 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -28,6 +28,8 @@ services: - backend_dev_modules:/app/.venv ports: - "8000:8000" + env_file: + - .env environment: - DATABASE_URL=${DATABASE_URL} - SECRET_KEY=${SECRET_KEY} diff --git a/docker-compose.yml b/docker-compose.yml index e8bad19..2185f75 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,6 +21,8 @@ services: context: ./backend dockerfile: Dockerfile target: production + env_file: + - .env environment: - DATABASE_URL=${DATABASE_URL} - SECRET_KEY=${SECRET_KEY}