Phase 1: Foundation - 3 plans created - 9 total tasks defined - Ready for execution Plan 01: Project scaffolding (pyproject.toml, pre-commit, src layout) Plan 02: SQLAlchemy models (Project, Discussion, Round, Message, Consensus) Plan 03: Database setup and model tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
184 lines
5 KiB
Markdown
184 lines
5 KiB
Markdown
---
|
|
phase: 01-foundation
|
|
plan: 03
|
|
type: execute
|
|
---
|
|
|
|
<objective>
|
|
Create database module with async session management and write model tests.
|
|
|
|
Purpose: Enable database operations and validate models work correctly.
|
|
Output: Working database.py with async session factory, passing model tests.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
~/.claude/get-shit-done/workflows/execute-phase.md
|
|
~/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@SPEC.md
|
|
@CLAUDE.md
|
|
@src/moai/core/models.py
|
|
|
|
**Tech choices:**
|
|
- SQLAlchemy 2.0 async (create_async_engine, AsyncSession)
|
|
- aiosqlite for async SQLite
|
|
- pytest-asyncio for async tests
|
|
|
|
**From CLAUDE.md:**
|
|
- Testing: pytest, target 80%+ coverage on core logic
|
|
- Database: SQLAlchemy + SQLite, upgrades to PostgreSQL in Phase 2
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create database module with async session management</name>
|
|
<files>src/moai/core/database.py</files>
|
|
<action>
|
|
Create src/moai/core/database.py with:
|
|
|
|
**Imports:** sqlalchemy.ext.asyncio (create_async_engine, AsyncSession, async_sessionmaker), contextlib
|
|
|
|
**Module-level:**
|
|
- DATABASE_URL: str = "sqlite+aiosqlite:///./moai.db" (default, can be overridden)
|
|
- engine: AsyncEngine = None (initialized lazily)
|
|
- async_session_factory: async_sessionmaker = None
|
|
|
|
**Functions:**
|
|
1. init_db(url: str | None = None) -> None:
|
|
- Creates engine with echo=False
|
|
- Creates async_session_factory
|
|
- Stores in module globals
|
|
- Use: `create_async_engine(url, echo=False)`
|
|
|
|
2. async create_tables() -> None:
|
|
- Imports Base from models
|
|
- Runs `async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all)`
|
|
|
|
3. @contextlib.asynccontextmanager
|
|
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
|
- Yields session from factory
|
|
- Handles commit on success, rollback on exception
|
|
- Pattern: `async with async_session_factory() as session: yield session; await session.commit()`
|
|
|
|
4. async def close_db() -> None:
|
|
- Disposes engine: `await engine.dispose()`
|
|
|
|
Add module docstring explaining session management pattern.
|
|
</action>
|
|
<verify>python -c "from moai.core.database import init_db, create_tables, get_session, close_db"</verify>
|
|
<done>Database module importable with all functions</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Create model tests with in-memory database</name>
|
|
<files>tests/test_models.py</files>
|
|
<action>
|
|
Create tests/test_models.py with:
|
|
|
|
**Fixtures:**
|
|
- @pytest.fixture
|
|
async def db_session():
|
|
- init_db("sqlite+aiosqlite:///:memory:")
|
|
- await create_tables()
|
|
- async with get_session() as session: yield session
|
|
- await close_db()
|
|
|
|
**Test cases:**
|
|
|
|
1. test_create_project:
|
|
- Create Project(name="Test Project", models=["claude", "gpt"])
|
|
- Add to session, commit
|
|
- Assert id is set (UUID string), name correct, models correct
|
|
|
|
2. test_create_discussion_with_project:
|
|
- Create Project, add Discussion linked to it
|
|
- Assert discussion.project_id matches project.id
|
|
- Assert project.discussions contains the discussion
|
|
|
|
3. test_create_full_discussion_chain:
|
|
- Create Project -> Discussion -> Round -> Message
|
|
- Verify all relationships work
|
|
- Verify cascade (all linked when navigating relationships)
|
|
|
|
4. test_create_consensus:
|
|
- Create Discussion with Consensus
|
|
- Assert discussion.consensus is set
|
|
- Assert consensus.discussion links back
|
|
|
|
5. test_project_cascade_delete:
|
|
- Create Project with Discussion with Round with Message
|
|
- Delete Project
|
|
- Assert all children deleted (cascade)
|
|
|
|
Use pytest.mark.asyncio on all async tests.
|
|
Import all models and database functions.
|
|
</action>
|
|
<verify>pytest tests/test_models.py -v passes all tests</verify>
|
|
<done>5 model tests passing, cascade behavior verified</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 3: Add .gitignore entries and verify full test suite</name>
|
|
<files>.gitignore</files>
|
|
<action>
|
|
Update .gitignore to add:
|
|
|
|
```
|
|
# Database
|
|
*.db
|
|
*.sqlite
|
|
*.sqlite3
|
|
|
|
# Python
|
|
__pycache__/
|
|
*.pyc
|
|
.pytest_cache/
|
|
.coverage
|
|
htmlcov/
|
|
|
|
# Virtual environments
|
|
.venv/
|
|
venv/
|
|
|
|
# IDE
|
|
.idea/
|
|
.vscode/
|
|
*.swp
|
|
```
|
|
|
|
Then run full test suite with coverage to verify everything works together.
|
|
</action>
|
|
<verify>pytest --cov=moai --cov-report=term-missing shows coverage, all tests pass</verify>
|
|
<done>.gitignore updated, tests pass with coverage report</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
Before declaring plan complete:
|
|
- [ ] `pytest tests/test_models.py -v` passes all 5 tests
|
|
- [ ] `pytest --cov=moai --cov-report=term-missing` runs successfully
|
|
- [ ] `ruff check src tests` passes
|
|
- [ ] Database file (moai.db) is gitignored
|
|
- [ ] Phase 1 complete: scaffolding, models, database all working
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
|
|
- All tasks completed
|
|
- All tests pass
|
|
- No linting errors
|
|
- Phase 1: Foundation complete
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/01-foundation/01-03-SUMMARY.md` with:
|
|
- Summary of all 3 plans in Phase 1
|
|
- Final verification that foundation is complete
|
|
- Ready for Phase 2: Bot Core
|
|
</output>
|