""" Sidebar navigation data builder. Loads domains > areas > projects hierarchy for the sidebar tree. """ from sqlalchemy import text from sqlalchemy.ext.asyncio import AsyncSession async def get_sidebar_data(db: AsyncSession) -> dict: """Build full sidebar navigation data.""" # Domains result = await db.execute(text(""" SELECT id, name, color FROM domains WHERE is_deleted = false ORDER BY sort_order, name """)) domains = [dict(r._mapping) for r in result] # Areas grouped by domain result = await db.execute(text(""" SELECT id, domain_id, name FROM areas WHERE is_deleted = false ORDER BY sort_order, name """)) areas = [dict(r._mapping) for r in result] # Projects grouped by domain/area result = await db.execute(text(""" SELECT id, domain_id, area_id, name, status FROM projects WHERE is_deleted = false AND status != 'archived' ORDER BY sort_order, name """)) projects = [dict(r._mapping) for r in result] # Counts for badges result = await db.execute(text(""" SELECT count(*) FROM capture WHERE is_deleted = false AND processed = false """)) capture_count = result.scalar() or 0 result = await db.execute(text(""" SELECT count(*) FROM daily_focus WHERE is_deleted = false AND focus_date = CURRENT_DATE AND completed = false """)) focus_count = result.scalar() or 0 # Build tree structure domain_tree = [] for d in domains: d_areas = [a for a in areas if str(a["domain_id"]) == str(d["id"])] d_projects = [p for p in projects if str(p["domain_id"]) == str(d["id"])] # Projects under areas for a in d_areas: a["projects"] = [p for p in d_projects if str(p.get("area_id", "")) == str(a["id"])] # Projects directly under domain (no area) standalone_projects = [p for p in d_projects if p.get("area_id") is None] domain_tree.append({ "id": d["id"], "name": d["name"], "color": d.get("color", "#4F6EF7"), "areas": d_areas, "standalone_projects": standalone_projects, }) return { "domain_tree": domain_tree, "capture_count": capture_count, "focus_count": focus_count, }