Phase 01: Core Infrastructure & Security - 5 plans in 3 waves - 3 parallel (Wave 1-2), 1 sequential (Wave 3) - Ready for execution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
208 lines
6.6 KiB
Markdown
208 lines
6.6 KiB
Markdown
---
|
|
phase: 01-core-infrastructure-security
|
|
plan: 02
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- backend/app/db/__init__.py
|
|
- backend/app/db/base.py
|
|
- backend/app/db/session.py
|
|
- backend/app/db/models/__init__.py
|
|
- backend/app/db/models/build.py
|
|
- backend/alembic.ini
|
|
- backend/alembic/env.py
|
|
- backend/alembic/script.py.mako
|
|
- backend/alembic/versions/.gitkeep
|
|
- docker-compose.yml
|
|
autonomous: true
|
|
|
|
must_haves:
|
|
truths:
|
|
- "PostgreSQL container starts and accepts connections"
|
|
- "Alembic migrations run without errors"
|
|
- "Database session factory creates async sessions"
|
|
- "Build model persists to database"
|
|
artifacts:
|
|
- path: "backend/app/db/session.py"
|
|
provides: "Async database session factory"
|
|
contains: "async_sessionmaker"
|
|
- path: "backend/app/db/base.py"
|
|
provides: "SQLAlchemy declarative base"
|
|
contains: "DeclarativeBase"
|
|
- path: "backend/app/db/models/build.py"
|
|
provides: "Build tracking model"
|
|
contains: "class Build"
|
|
- path: "backend/alembic/env.py"
|
|
provides: "Alembic migration environment"
|
|
contains: "run_migrations_online"
|
|
- path: "docker-compose.yml"
|
|
provides: "PostgreSQL container configuration"
|
|
contains: "postgres"
|
|
key_links:
|
|
- from: "backend/app/db/session.py"
|
|
to: "backend/app/core/config.py"
|
|
via: "settings.database_url"
|
|
pattern: "settings\\.database_url"
|
|
- from: "backend/alembic/env.py"
|
|
to: "backend/app/db/base.py"
|
|
via: "target_metadata"
|
|
pattern: "target_metadata.*Base\\.metadata"
|
|
---
|
|
|
|
<objective>
|
|
Set up PostgreSQL database with async SQLAlchemy, Alembic migrations, and initial build tracking model.
|
|
|
|
Purpose: Establish the data persistence layer that tracks builds, users, and configurations.
|
|
Output: Running PostgreSQL instance, async session factory, and migration infrastructure with initial Build model.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/home/mikkel/.claude/get-shit-done/workflows/execute-plan.md
|
|
@/home/mikkel/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/phases/01-core-infrastructure-security/01-RESEARCH.md (Pattern 1: Async Database Session Management, Code Examples: Database Migrations with Alembic)
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Set up PostgreSQL with Docker and async session factory</name>
|
|
<files>
|
|
docker-compose.yml
|
|
backend/app/db/__init__.py
|
|
backend/app/db/base.py
|
|
backend/app/db/session.py
|
|
</files>
|
|
<action>
|
|
Create docker-compose.yml:
|
|
- PostgreSQL 18 service (postgres:18-alpine image if available, or postgres:16-alpine)
|
|
- Container name: debate-postgres
|
|
- Environment: POSTGRES_USER=debate, POSTGRES_PASSWORD=debate_dev, POSTGRES_DB=debate
|
|
- Port: 5432:5432
|
|
- Volume: postgres_data for persistence
|
|
- Health check on pg_isready
|
|
|
|
backend/app/db/__init__.py:
|
|
- Empty or re-export key items
|
|
|
|
backend/app/db/base.py:
|
|
- Create SQLAlchemy 2.0 DeclarativeBase
|
|
- Import all models (for Alembic autogenerate)
|
|
- Pattern: `class Base(DeclarativeBase): pass`
|
|
|
|
backend/app/db/session.py:
|
|
- Import settings from core.config
|
|
- Create async engine with connection pooling (from research):
|
|
- pool_size=10
|
|
- max_overflow=20
|
|
- pool_timeout=30
|
|
- pool_recycle=1800
|
|
- pool_pre_ping=True
|
|
- Create async_sessionmaker factory
|
|
- Create `get_db` async generator dependency for FastAPI
|
|
|
|
Update .env.example (if not already done):
|
|
- DATABASE_URL=postgresql+asyncpg://debate:debate_dev@localhost:5432/debate
|
|
</action>
|
|
<verify>
|
|
Run: `cd /home/mikkel/repos/debate && docker compose up -d`
|
|
Wait 5 seconds for postgres to start.
|
|
Run: `docker compose exec postgres pg_isready -U debate`
|
|
Expected: "accepting connections"
|
|
</verify>
|
|
<done>
|
|
PostgreSQL container running, async session factory configured with connection pooling.
|
|
</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Configure Alembic and create Build model</name>
|
|
<files>
|
|
backend/alembic.ini
|
|
backend/alembic/env.py
|
|
backend/alembic/script.py.mako
|
|
backend/alembic/versions/.gitkeep
|
|
backend/app/db/models/__init__.py
|
|
backend/app/db/models/build.py
|
|
</files>
|
|
<action>
|
|
Initialize Alembic in backend directory:
|
|
```bash
|
|
cd backend && alembic init alembic
|
|
```
|
|
|
|
Modify backend/alembic.ini:
|
|
- Set script_location = alembic
|
|
- Remove sqlalchemy.url (we'll set it from config)
|
|
|
|
Modify backend/alembic/env.py:
|
|
- Import asyncio, async_engine_from_config
|
|
- Import settings from app.core.config
|
|
- Import Base from app.db.base (this imports all models)
|
|
- Set sqlalchemy.url from settings.database_url
|
|
- Implement run_migrations_online() as async function (from research)
|
|
- Use asyncio.run() for async migrations
|
|
|
|
Create backend/app/db/models/__init__.py:
|
|
- Import all models for Alembic discovery
|
|
|
|
Create backend/app/db/models/build.py:
|
|
- Build model with fields:
|
|
- id: UUID primary key (use uuid.uuid4)
|
|
- config_hash: String(64), unique, indexed (SHA-256 of configuration)
|
|
- status: Enum (pending, building, completed, failed, cached)
|
|
- iso_path: Optional String (path to generated ISO)
|
|
- error_message: Optional Text (for failed builds)
|
|
- build_log: Optional Text (full build output)
|
|
- started_at: DateTime (nullable, set when build starts)
|
|
- completed_at: DateTime (nullable, set when build finishes)
|
|
- created_at: DateTime with server default now()
|
|
- updated_at: DateTime with onupdate
|
|
- Add index on status for queue queries
|
|
- Add index on config_hash for cache lookups
|
|
|
|
Update backend/app/db/base.py to import Build model.
|
|
|
|
Generate and run initial migration:
|
|
```bash
|
|
cd backend && alembic revision --autogenerate -m "Create build table"
|
|
cd backend && alembic upgrade head
|
|
```
|
|
</action>
|
|
<verify>
|
|
Run: `cd /home/mikkel/repos/debate/backend && alembic current`
|
|
Expected: Shows current migration head.
|
|
Run: `docker compose exec postgres psql -U debate -d debate -c "\\dt"`
|
|
Expected: Shows "builds" table.
|
|
</verify>
|
|
<done>
|
|
Alembic configured for async, Build model created with migration applied.
|
|
</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
1. `docker compose ps` shows postgres container running and healthy
|
|
2. `cd backend && alembic current` shows migration applied
|
|
3. `docker compose exec postgres psql -U debate -d debate -c "SELECT * FROM builds LIMIT 1;"` succeeds (empty result OK)
|
|
4. `ruff check backend/app/db/` passes
|
|
5. Database has builds table with correct columns
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- PostgreSQL 18 running in Docker with health checks
|
|
- Async session factory with proper connection pooling
|
|
- Alembic configured for async migrations
|
|
- Build model exists with config_hash, status, timestamps
|
|
- Initial migration applied successfully
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/01-core-infrastructure-security/01-02-SUMMARY.md`
|
|
</output>
|