""" Public dashboard endpoint — no authentication required. Used by the TV view to get the initial session snapshot before WebSocket connects. """ from datetime import date from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from sqlalchemy.orm import selectinload from app.dependencies import get_db from app.models.child import Child from app.models.schedule import ScheduleBlock from app.models.session import DailySession, TimerEvent from app.schemas.session import DashboardSnapshot router = APIRouter(prefix="/api/dashboard", tags=["dashboard"]) @router.get("/{child_id}", response_model=DashboardSnapshot) async def get_dashboard(child_id: int, db: AsyncSession = Depends(get_db)): child_result = await db.execute(select(Child).where(Child.id == child_id, Child.is_active == True)) child = child_result.scalar_one_or_none() if not child: raise HTTPException(status_code=404, detail="Child not found") # Get today's active session session_result = await db.execute( select(DailySession) .where( DailySession.child_id == child_id, DailySession.session_date == date.today(), DailySession.is_active == True, ) .options(selectinload(DailySession.current_block)) .limit(1) ) session = session_result.scalar_one_or_none() blocks = [] completed_ids = [] if session and session.template_id: blocks_result = await db.execute( select(ScheduleBlock) .where(ScheduleBlock.template_id == session.template_id) .order_by(ScheduleBlock.order_index) ) blocks = blocks_result.scalars().all() events_result = await db.execute( select(TimerEvent).where( TimerEvent.session_id == session.id, TimerEvent.event_type == "complete", ) ) completed_ids = [e.block_id for e in events_result.scalars().all() if e.block_id] return DashboardSnapshot( session=session, child=child, blocks=blocks, completed_block_ids=completed_ids, )