Add per-block agenda overrides for daily sessions

- Add 📝 Agenda button to each block in Today's Schedule on the Dashboard
- Dialog allows setting a free-text activity/note for that block for the current day
- Agenda replaces subject options in the TV center panel while set; clears on session end
- Backend: new SessionBlockAgenda model, PUT /api/sessions/{id}/blocks/{block_id}/agenda
- Agendas included in dashboard snapshot and session_update WS broadcast
- New agenda_update WS event keeps TV in sync live when agenda is saved or cleared
- Update README with feature description, project structure, and WS event table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-19 07:58:30 -07:00
parent d724262e27
commit fdd85d3df5
9 changed files with 246 additions and 17 deletions

View File

@@ -14,6 +14,7 @@ from app.models.child import Child
from app.models.morning_routine import MorningRoutineItem
from app.models.break_activity import BreakActivityItem
from app.models.schedule import ScheduleBlock
from app.models.session_block_agenda import SessionBlockAgenda
from app.models.subject import Subject # noqa: F401 — needed for selectinload chain
from app.models.session import DailySession, TimerEvent
from app.schemas.session import DashboardSnapshot
@@ -109,6 +110,15 @@ async def get_dashboard(tv_token: int, db: AsyncSession = Depends(get_db)):
)
break_activities = [item.text for item in break_result.scalars().all()]
block_agendas: dict[str, str] = {}
if session:
agendas_result = await db.execute(
select(SessionBlockAgenda).where(SessionBlockAgenda.session_id == session.id)
)
block_agendas = {
str(item.block_id): item.text for item in agendas_result.scalars().all()
}
return DashboardSnapshot(
session=session,
child=child,
@@ -121,4 +131,5 @@ async def get_dashboard(tv_token: int, db: AsyncSession = Depends(get_db)):
is_break_active=is_break_active,
break_elapsed_seconds=break_elapsed_seconds,
is_break_paused=is_break_paused,
block_agendas=block_agendas,
)