# Database Setup & Initialization Guide ## Overview This guide walks you through setting up the Orion database from scratch. Whether you're a new developer joining the team or need to reset your local database, this document covers everything you need to know. --- ## Table of Contents 1. [Prerequisites](#prerequisites) 2. [First-Time Setup](#first-time-setup) 3. [Database Reset (Clean Slate)](#database-reset-clean-slate) 4. [Verifying Your Setup](#verifying-your-setup) 5. [Common Issues & Solutions](#common-issues-solutions) 6. [Database Migrations](#database-migrations) 7. [Seeding Data](#seeding-data) --- ## Prerequisites ### Required Software - **Python 3.11+** - **Alembic** (installed via `requirements.txt`) - **SQLite** (built into Python) or **PostgreSQL** (for production-like setup) ### Environment Setup ```bash # 1. Clone the repository git clone cd orion-repo # 2. Create virtual environment python -m venv venv # 3. Activate virtual environment # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate # 4. Install dependencies pip install -r requirements.txt ``` --- ## First-Time Setup ### Step 1: Configure Database Connection Create or update `.env` file in project root: ```env # Database Configuration DATABASE_URL=sqlite:///./orion.db # For PostgreSQL (production): # DATABASE_URL=postgresql://user:password@localhost:5432/orion # Other required settings SECRET_KEY=your-secret-key-here-change-in-production ALGORITHM=HS256 ACCESS_TOKEN_EXPIRE_MINUTES=30 ``` --- ### Step 2: Initialize Alembic (First Time Only) **If `alembic/` folder doesn't exist:** ```bash # Initialize Alembic alembic init alembic ``` **Configure `alembic.ini`:** ```ini # alembic.ini # Find this line and update: sqlalchemy.url = sqlite:///./orion.db # Or for PostgreSQL: # sqlalchemy.url = postgresql://user:password@localhost:5432/orion ``` **Configure `alembic/env.py`:** ```python # alembic/env.py # Add this near the top (after imports) import sys from pathlib import Path # Add project root to Python path sys.path.append(str(Path(__file__).parents[1])) # ============================================================================ # CRITICAL: Import ALL database models here # ============================================================================ from models.database.user import User from models.database.store import Store from models.database.store_domain import StoreDomain from models.database.store_theme import StoreTheme from models.database.customer import Customer from models.database.team import Team, TeamMember, TeamInvitation from models.database.product import Product from models.database.marketplace_product import MarketplaceProduct from models.database.inventory import Inventory from models.database.order import Order from models.database.marketplace_import_job import MarketplaceImportJob # Import Base from app.core.database import Base # Set target metadata target_metadata = Base.metadata ``` --- ### Step 3: Generate Initial Migration ```bash # Generate migration from your models alembic revision --autogenerate -m "Initial migration - all tables" # You should see output listing all detected tables: # INFO [alembic.autogenerate.compare] Detected added table 'users' # INFO [alembic.autogenerate.compare] Detected added table 'stores' # INFO [alembic.autogenerate.compare] Detected added table 'store_themes' # etc. ``` --- ### Step 4: Apply Migration ```bash # Apply the migration to create all tables alembic upgrade head # You should see: # INFO [alembic.runtime.migration] Running upgrade -> abc123def456, Initial migration - all tables ``` --- ### Step 5: Seed Initial Data Create an admin user and test store: ```bash python scripts/seed_database.py ``` **Or manually:** ```python # Run Python interactive shell python # Then execute: from app.core.database import SessionLocal from models.database.user import User from models.database.store import Store from middleware.auth import AuthManager from datetime import datetime, timezone db = SessionLocal() auth_manager = AuthManager() # Create admin user admin = User( username="admin", email="admin@orion.lu", hashed_password=auth_manager.hash_password("admin123"), role="admin", is_active=True, created_at=datetime.now(timezone.utc), updated_at=datetime.now(timezone.utc) ) db.add(admin) db.flush() # Create test store store = Store( store_code="TESTSTORE", subdomain="teststore", name="Test Store", description="Development test store", owner_user_id=admin.id, contact_email="contact@teststore.com", is_active=True, is_verified=True, created_at=datetime.now(timezone.utc), updated_at=datetime.now(timezone.utc) ) db.add(store) db.commit() print("āœ… Admin user and test store created!") db.close() exit() ``` --- ### Step 6: Start the Application ```bash # Start FastAPI server python -m uvicorn app.main:app --reload # Server should start on http://localhost:8000 ``` **Test the setup:** - Admin login: http://localhost:8000/admin/login - Username: `admin` - Password: `admin123` --- ## Database Reset (Clean Slate) Use this when you want to completely reset your database and start fresh. āš ļø **WARNING:** This will delete ALL data! Make a backup if needed. --- ### Quick Reset Script (Windows PowerShell) **Create `scripts/reset_database.ps1`:** ```powershell # scripts/reset_database.ps1 Write-Host "šŸ—‘ļø Database Reset Script" -ForegroundColor Cyan Write-Host "This will delete ALL data!" -ForegroundColor Red $confirm = Read-Host "Type 'YES' to continue" if ($confirm -ne "YES") { Write-Host "Aborted." -ForegroundColor Yellow exit } Write-Host "" Write-Host "Step 1: Backing up current database..." -ForegroundColor Yellow if (Test-Path orion.db) { $backupName = "orion_backup_$(Get-Date -Format 'yyyyMMdd_HHmmss').db" Copy-Item orion.db $backupName Write-Host "āœ“ Backup created: $backupName" -ForegroundColor Green } Write-Host "" Write-Host "Step 2: Removing old migrations..." -ForegroundColor Yellow Remove-Item alembic\versions\*.py -Exclude __init__.py -ErrorAction SilentlyContinue Remove-Item -Recurse -Force alembic\versions\__pycache__ -ErrorAction SilentlyContinue # Ensure __init__.py exists if (-not (Test-Path alembic\versions\__init__.py)) { New-Item -Path alembic\versions\__init__.py -ItemType File | Out-Null } Write-Host "āœ“ Old migrations removed" -ForegroundColor Green Write-Host "" Write-Host "Step 3: Deleting database..." -ForegroundColor Yellow Remove-Item orion.db -ErrorAction SilentlyContinue Write-Host "āœ“ Database deleted" -ForegroundColor Green Write-Host "" Write-Host "Step 4: Generating new migration..." -ForegroundColor Yellow alembic revision --autogenerate -m "Initial migration - all tables" Write-Host "āœ“ Migration generated" -ForegroundColor Green Write-Host "" Write-Host "Step 5: Applying migration..." -ForegroundColor Yellow alembic upgrade head Write-Host "āœ“ Migration applied" -ForegroundColor Green Write-Host "" Write-Host "Step 6: Verifying tables..." -ForegroundColor Yellow python -c @" import sqlite3 conn = sqlite3.connect('orion.db') cursor = conn.cursor() cursor.execute('SELECT name FROM sqlite_master WHERE type=\"table\" ORDER BY name;') tables = [t[0] for t in cursor.fetchall()] print('\nšŸ“Š Tables created:') for t in tables: print(f' āœ“ {t}') print(f'\nāœ… Total: {len(tables)} tables') if 'store_themes' in tables: print('āœ… store_themes table confirmed!') conn.close() "@ Write-Host "" Write-Host "Step 7: Seeding initial data..." -ForegroundColor Yellow python scripts/seed_database.py Write-Host "" Write-Host "āœ… Database reset complete!" -ForegroundColor Green Write-Host "" Write-Host "Next steps:" -ForegroundColor Cyan Write-Host " 1. Start server: python -m uvicorn app.main:app --reload" -ForegroundColor White Write-Host " 2. Login: http://localhost:8000/admin/login" -ForegroundColor White Write-Host " 3. Username: admin | Password: admin123" -ForegroundColor White ``` **Run it:** ```powershell # First time only - allow script execution Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser # Run the reset .\scripts\reset_database.ps1 ``` --- ### Quick Reset Script (Linux/Mac Bash) **Create `scripts/reset_database.sh`:** ```bash #!/bin/bash # scripts/reset_database.sh echo "šŸ—‘ļø Database Reset Script" echo "āš ļø This will delete ALL data!" read -p "Type 'YES' to continue: " confirm if [ "$confirm" != "YES" ]; then echo "Aborted." exit 1 fi echo "" echo "Step 1: Backing up current database..." if [ -f orion.db ]; then backup_name="orion_backup_$(date +%Y%m%d_%H%M%S).db" cp orion.db "$backup_name" echo "āœ“ Backup created: $backup_name" fi echo "" echo "Step 2: Removing old migrations..." find alembic/versions -type f -name "*.py" ! -name "__init__.py" -delete rm -rf alembic/versions/__pycache__ touch alembic/versions/__init__.py echo "āœ“ Old migrations removed" echo "" echo "Step 3: Deleting database..." rm -f orion.db echo "āœ“ Database deleted" echo "" echo "Step 4: Generating new migration..." alembic revision --autogenerate -m "Initial migration - all tables" echo "āœ“ Migration generated" echo "" echo "Step 5: Applying migration..." alembic upgrade head echo "āœ“ Migration applied" echo "" echo "Step 6: Verifying tables..." python -c " import sqlite3 conn = sqlite3.connect('orion.db') cursor = conn.cursor() cursor.execute('SELECT name FROM sqlite_master WHERE type=\"table\" ORDER BY name;') tables = [t[0] for t in cursor.fetchall()] print('\nšŸ“Š Tables created:') for t in tables: print(f' āœ“ {t}') print(f'\nāœ… Total: {len(tables)} tables') if 'store_themes' in tables: print('āœ… store_themes table confirmed!') conn.close() " echo "" echo "Step 7: Seeding initial data..." python scripts/seed_database.py echo "" echo "āœ… Database reset complete!" echo "" echo "Next steps:" echo " 1. Start server: python -m uvicorn app.main:app --reload" echo " 2. Login: http://localhost:8000/admin/login" echo " 3. Username: admin | Password: admin123" ``` **Run it:** ```bash chmod +x scripts/reset_database.sh ./scripts/reset_database.sh ``` --- ### Manual Reset Steps If you prefer to run commands manually: ```bash # 1. Backup (optional) cp orion.db orion_backup.db # Windows: copy orion.db orion_backup.db # 2. Remove migrations rm alembic/versions/*.py # Windows: Remove-Item alembic\versions\*.py -Exclude __init__.py touch alembic/versions/__init__.py # Windows: New-Item -Path alembic\versions\__init__.py # 3. Delete database rm orion.db # Windows: Remove-Item orion.db # 4. Generate migration alembic revision --autogenerate -m "Initial migration - all tables" # 5. Apply migration alembic upgrade head # 6. Seed data python scripts/seed_database.py ``` --- ## Verifying Your Setup ### Check Alembic Status ```bash # Check current migration version alembic current # Should show: # (head) ``` ### Verify Tables Exist **Using Python:** ```python import sqlite3 conn = sqlite3.connect('orion.db') cursor = conn.cursor() # List all tables cursor.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;") tables = cursor.fetchall() print("šŸ“Š Database Tables:") for table in tables: print(f" āœ“ {table[0]}") # Check specific table structure cursor.execute("PRAGMA table_info(store_themes);") columns = cursor.fetchall() print("\nšŸ“‹ store_themes columns:") for col in columns: print(f" - {col[1]} ({col[2]})") conn.close() ``` ### Test Database Connection ```bash # Start Python shell python # Test connection from app.core.database import SessionLocal, engine from sqlalchemy import text db = SessionLocal() result = db.execute(text("SELECT name FROM sqlite_master WHERE type='table';")) tables = [row[0] for row in result] print("āœ… Database connection successful!") print(f"šŸ“Š Tables found: {len(tables)}") for table in tables: print(f" - {table}") db.close() exit() ``` ### Test Application Startup ```bash # Start server python -m uvicorn app.main:app --reload # Should see: # INFO: Uvicorn running on http://127.0.0.1:8000 # INFO: Application startup complete. ``` **No errors = successful setup!** --- ## Common Issues & Solutions ### Issue 1: "No such table" Error **Symptom:** ``` sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: store_themes ``` **Solution:** ```bash # 1. Check if model is imported in alembic/env.py # Open alembic/env.py and verify: from models.database.store_theme import StoreTheme # 2. Regenerate migration alembic revision --autogenerate -m "Add missing tables" # 3. Apply migration alembic upgrade head ``` --- ### Issue 2: "Target database is not up to date" **Symptom:** ``` ERROR [alembic.util.messaging] Target database is not up to date. ``` **Solution:** ```bash # Option 1: Stamp to current head alembic stamp head # Option 2: Check and upgrade alembic current # See current version alembic upgrade head # Upgrade to latest # Option 3: Full reset (see Database Reset section) ``` --- ### Issue 3: Database Locked **Symptom:** ``` sqlite3.OperationalError: database is locked ``` **Solution:** ```bash # 1. Stop the FastAPI server (Ctrl+C) # 2. Kill any Python processes # Windows: taskkill /F /IM python.exe # Linux/Mac: pkill python # 3. Close any database browser applications # 4. Try again alembic upgrade head ``` --- ### Issue 4: Migration File Conflicts **Symptom:** ``` Multiple head revisions are present ``` **Solution:** ```bash # Option 1: Merge migrations alembic merge heads -m "Merge migrations" alembic upgrade head # Option 2: Clean reset (recommended for development) # See Database Reset section above ``` --- ### Issue 5: Import Errors in alembic/env.py **Symptom:** ``` ModuleNotFoundError: No module named 'models' ``` **Solution:** Check `alembic/env.py` has correct path setup: ```python # alembic/env.py (top of file) import sys from pathlib import Path # Add project root to Python path sys.path.append(str(Path(__file__).parents[1])) ``` --- ## Database Migrations ### Creating New Migrations When you add/modify models: ```bash # 1. Update your model file (e.g., models/database/store_theme.py) # 2. Generate migration alembic revision --autogenerate -m "Add new field to store_themes" # 3. Review the generated migration # Check: alembic/versions/_add_new_field_to_store_themes.py # 4. Apply migration alembic upgrade head ``` --- ### Migration Best Practices āœ… **DO:** - Review generated migrations before applying - Use descriptive migration messages - Test migrations on development database first - Keep migrations small and focused - Commit migrations to version control āŒ **DON'T:** - Edit applied migrations (create new ones instead) - Delete migration files from version control - Skip migration review - Combine unrelated changes in one migration --- ### Rolling Back Migrations ```bash # Downgrade one version alembic downgrade -1 # Downgrade to specific revision alembic downgrade # Downgrade to base (empty database) alembic downgrade base ``` --- ## Seeding Data ### Development Data Seed **Create `scripts/seed_database.py`:** ```python # scripts/seed_database.py """ Seed the database with initial development data. """ from app.core.database import SessionLocal from models.database.user import User from models.database.store import Store from app.core.security import get_password_hash from datetime import datetime, timezone def seed_database(): """Seed database with initial data.""" db = SessionLocal() try: print("🌱 Seeding database...") # Check if admin already exists existing_admin = db.query(User).filter(User.username == "admin").first() if existing_admin: print("āš ļø Admin user already exists, skipping...") return # Create admin user admin = User( username="admin", email="admin@orion.lu", hashed_password=get_password_hash("admin123"), is_admin=True, is_active=True, created_at=datetime.now(timezone.utc), updated_at=datetime.now(timezone.utc) ) db.add(admin) db.flush() print(f"āœ“ Admin user created (ID: {admin.id})") # Create test store store = Store( store_code="TESTSTORE", subdomain="teststore", name="Test Store", description="Development test store", owner_user_id=admin.id, contact_email="contact@teststore.com", is_active=True, is_verified=True, created_at=datetime.now(timezone.utc), updated_at=datetime.now(timezone.utc) ) db.add(store) db.flush() print(f"āœ“ Test store created: {store.store_code}") db.commit() print("\nāœ… Database seeded successfully!") print("\nšŸ“ Login Credentials:") print(" URL: http://localhost:8000/admin/login") print(" Username: admin") print(" Password: admin123") except Exception as e: db.rollback() print(f"āŒ Error seeding database: {e}") raise finally: db.close() if __name__ == "__main__": seed_database() ``` **Run it:** ```bash python scripts/seed_database.py ``` --- ### Production Data Migration For production, create separate seed scripts: ```python # scripts/seed_production.py # - Create only essential admin user # - No test data # - Strong passwords from environment variables ``` --- ## Quick Reference ### Essential Commands ```bash # Check migration status alembic current # Generate new migration alembic revision --autogenerate -m "Description" # Apply migrations alembic upgrade head # Rollback one migration alembic downgrade -1 # View migration history alembic history # Seed database python scripts/seed_database.py # Start server python -m uvicorn app.main:app --reload ``` --- ### File Locations ``` project/ ā”œā”€ā”€ alembic/ │ ā”œā”€ā”€ versions/ # Migration files here │ │ └── __init__.py │ ā”œā”€ā”€ env.py # Alembic configuration (import models here!) │ └── script.py.mako ā”œā”€ā”€ app/ │ └── core/ │ └── database.py # Database connection ā”œā”€ā”€ models/ │ └── database/ # SQLAlchemy models │ ā”œā”€ā”€ user.py │ ā”œā”€ā”€ store.py │ ā”œā”€ā”€ store_theme.py │ └── ... ā”œā”€ā”€ scripts/ │ ā”œā”€ā”€ seed_database.py # Development seed │ └── reset_database.ps1 # Reset script ā”œā”€ā”€ alembic.ini # Alembic config ā”œā”€ā”€ orion.db # SQLite database (gitignored) └── .env # Environment variables (gitignored) ``` --- ## Getting Help ### Internal Resources - **Architecture Guide:** `docs/PROPER_ARCHITECTURE_GUIDE.md` - **Exception Handling:** `docs/EXCEPTION_PATTERN_EXPLAINED.md` - **Admin Feature Guide:** `docs/ADMIN_FEATURE_INTEGRATION_GUIDE.md` ### External Resources - [Alembic Documentation](https://alembic.sqlalchemy.org/) - [SQLAlchemy Documentation](https://docs.sqlalchemy.org/) - [FastAPI Documentation](https://fastapi.tiangolo.com/) --- ## Contributing When adding new models: 1. āœ… Create the model in `models/database/` 2. āœ… Import it in `alembic/env.py` 3. āœ… Generate migration: `alembic revision --autogenerate -m "Add XYZ model"` 4. āœ… Review the migration file 5. āœ… Test locally: `alembic upgrade head` 6. āœ… Commit both model and migration files --- **Last Updated:** 2025-10-27 **Maintainer:** Development Team **Questions?** Contact the team lead or check internal documentation.