fix: add ResolutionFlow service account to own default tree steps in library

Default/system trees had no author_id (NULL), causing a NOT NULL violation
when syncing steps to step_library.created_by on publish.

- Add is_service_account flag to users table (migration 4f4137ce)
- Add service_account.py: idempotent ensure_service_account() creates
  noreply@resolutionflow.com with unusable password on startup
- Cache service account ID on app.state at lifespan startup
- Add get_service_account_id() FastAPI dep (returns None in tests)
- sync_steps_from_tree: resolve author_id or service_account_id as created_by
- create_tree: set author_id=service_account_id for is_default trees
- Migration 1490781700bc: backfill author_id on 31 existing default trees

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-02-25 23:17:04 -05:00
parent 0002f75232
commit c2b3937e86
8 changed files with 221 additions and 6 deletions

View File

@@ -14,6 +14,7 @@ from app.core.middleware import RequestLoggingMiddleware, ErrorLoggingMiddleware
from app.core.rate_limit import limiter
from app.api.router import api_router
from app.core.scheduler import scheduler, load_all_schedules, _cleanup_expired_ai_conversations
from app.core.service_account import ensure_service_account
# Initialize logging configuration
setup_logging()
@@ -103,6 +104,12 @@ async def lifespan(app: FastAPI):
# Note: In production, use Alembic migrations instead of init_db
# await init_db()
# Ensure service account exists and cache its ID for sync operations
async with async_session_maker() as db:
service_account_id = await ensure_service_account(db)
app.state.service_account_id = service_account_id
logger.info(f"[service_account] Service account ready (id={service_account_id})")
# Start maintenance schedule runner + AI conversation cleanup
scheduler.start()
async with async_session_maker() as db: