Implement Phase 3: dynamic graph builder, blueprint persistence, and CRUD API
- Add dynamic_graph_builder.py that constructs LangGraph graphs at runtime
from frontend CouncilBlueprint JSON (no more hardcoded graphs in production)
- Add PostgreSQL persistence via SQLAlchemy async with Blueprint model
- Add blueprint CRUD endpoints (POST/GET/PUT/DELETE /api/councils/)
- Add POST /api/councils/{id}/run to execute blueprints dynamically
- Add Alembic migration infrastructure with initial blueprints table
- Add database.py with async engine and SQLite fallback for dev/test
- Fix missing typing-extensions and add aiosqlite dependency
- Add 42 new tests (80/80 total passing) covering dynamic graph building,
blueprint service CRUD, and API integration
https://claude.ai/code/session_014yZUxrPsgZbvkebXbCXR4U
This commit is contained in:
parent
89ba3aacd4
commit
437db4ca68
16 changed files with 1698 additions and 11 deletions
48
backend/database.py
Normal file
48
backend/database.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
"""
|
||||
Database connection management for CouncilOS.
|
||||
|
||||
Provides an async SQLAlchemy engine and session factory backed by PostgreSQL.
|
||||
Falls back to SQLite for development/testing if DATABASE_URL is not set.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
|
||||
DATABASE_URL = os.environ.get(
|
||||
"DATABASE_URL",
|
||||
"sqlite+aiosqlite:///./councilOS_dev.db",
|
||||
)
|
||||
|
||||
# For SQLite async support, replace the driver if needed
|
||||
if DATABASE_URL.startswith("sqlite"):
|
||||
connect_args = {"check_same_thread": False}
|
||||
else:
|
||||
connect_args = {}
|
||||
|
||||
engine = create_async_engine(
|
||||
DATABASE_URL,
|
||||
echo=False,
|
||||
connect_args=connect_args,
|
||||
)
|
||||
|
||||
async_session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||
|
||||
|
||||
async def get_session() -> AsyncSession:
|
||||
"""Dependency that yields an async database session."""
|
||||
async with async_session() as session:
|
||||
yield session
|
||||
|
||||
|
||||
async def init_db() -> None:
|
||||
"""Create all tables. Used at application startup."""
|
||||
from models.blueprint import Base
|
||||
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
|
||||
|
||||
async def close_db() -> None:
|
||||
"""Dispose of the engine connection pool."""
|
||||
await engine.dispose()
|
||||
Loading…
Add table
Add a link
Reference in a new issue