BE-CAL-API-002: Implement calendar day-view query API

- Add GET /calendar/day endpoint with optional ?date= query param
- Returns unified CalendarDayResponse merging real slots + virtual plan slots
- New CalendarSlotItem schema supports both real (id) and virtual (virtual_id) slots
- Excludes inactive slots (skipped/aborted) from results
- All slots sorted by scheduled_at ascending
- Helper functions for real/virtual slot conversion
This commit is contained in:
zhi
2026-03-31 07:18:56 +00:00
parent 751b3bc574
commit c75ded02c8
2 changed files with 168 additions and 1 deletions

View File

@@ -2,6 +2,7 @@
BE-CAL-004: MinimumWorkload read/write schemas.
BE-CAL-API-001: TimeSlot create / response schemas.
BE-CAL-API-002: Calendar day-view query schemas.
"""
from __future__ import annotations
@@ -152,3 +153,46 @@ class TimeSlotCreateResponse(BaseModel):
"""Response after creating a slot — includes the slot and any warnings."""
slot: TimeSlotResponse
warnings: list[WorkloadWarningItem] = Field(default_factory=list)
# ---------------------------------------------------------------------------
# Calendar day-view query (BE-CAL-API-002)
# ---------------------------------------------------------------------------
class CalendarSlotItem(BaseModel):
"""Unified slot item for day-view — covers both real and virtual slots.
* For **real** (materialized) slots: ``id`` is set, ``virtual_id`` is None.
* For **virtual** (plan-generated) slots: ``id`` is None, ``virtual_id``
is the ``plan-{plan_id}-{date}`` identifier.
"""
id: Optional[int] = Field(None, description="Real slot DB id (None for virtual)")
virtual_id: Optional[str] = Field(None, description="Virtual slot id (None for real)")
user_id: int
date: date
slot_type: str
estimated_duration: int
scheduled_at: str # HH:MM:SS ISO format
started_at: Optional[str] = None
attended: bool
actual_duration: Optional[int] = None
event_type: Optional[str] = None
event_data: Optional[dict[str, Any]] = None
priority: int
status: str
plan_id: Optional[int] = None
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class Config:
from_attributes = True
class CalendarDayResponse(BaseModel):
"""Response for a single-day calendar query."""
date: date
user_id: int
slots: list[CalendarSlotItem] = Field(
default_factory=list,
description="All slots for the day, sorted by scheduled_at ascending",
)