Motivation
The API needs a typed contract between backend and frontend. Output DTOs define exactly what the frontend receives and ensure consistent serialization from SQLAlchemy models.
Deliverables
Create SenatorDTO with nested CommitteeAssignmentDTO list
Create CommitteeAssignmentDTO (committee_id, committee_name, role)
Create CommitteeDTO with nested SenatorDTO member list
Create LeadershipDTO (id, title, first_name, last_name, email, photo_url, session_number, is_current)
Create NewsDTO (id, title, summary, body, image_url, author_name, date_published, date_last_edited)
Create LegislationDTO with nested LegislationActionDTO list
Create LegislationActionDTO (id, action_date, description, action_type)
Create CalendarEventDTO (id, title, description, start_datetime, end_datetime, location, event_type)
Create CarouselSlideDTO (id, image_url, overlay_text, link_url, display_order, is_active)
Create FinanceHearingConfigDTO with nested FinanceHearingDateDTO list
Create FinanceHearingDateDTO (id, hearing_date, hearing_time, location, description, is_full)
Create StaffDTO (id, first_name, last_name, title, email, photo_url)
Create DistrictDTO with optional nested senator list
Create BudgetDataDTO with recursive children: List[BudgetDataDTO]
Create StaticPageDTO (id, page_slug, title, body, updated_at)
Create AccountDTO (id, email, pid, first_name, last_name, role)
Write tests that instantiate each DTO from mock model data and verify serialization
Important Notes
Reference TDD Section 4.5.1
Depends on SQLAlchemy Models — Core Entities (Admin, Senator, District, Leadership) #3 , SQLAlchemy Models — Content Entities (News, Committee, Staff, Config) #4 , SQLAlchemy Models — Legislation, Events, Carousel, Finance, Budget #5 (needs models to test model_validate / from_attributes)
All schemas go in app/schemas/ as separate files, re-exported from app/schemas/__init__.py
Use pydantic v2 with model_config = ConfigDict(from_attributes=True)
Add pydantic to requirements.txt (it ships with FastAPI but pin it explicitly)
NewsDTO.author_name is a computed field derived from the Admin FK, not stored directly
BudgetDataDTO.children is recursive — use Pydantic's model_rebuild() if forward refs are needed
Motivation
The API needs a typed contract between backend and frontend. Output DTOs define exactly what the frontend receives and ensure consistent serialization from SQLAlchemy models.
Deliverables
SenatorDTOwith nestedCommitteeAssignmentDTOlistCommitteeAssignmentDTO(committee_id, committee_name, role)CommitteeDTOwith nestedSenatorDTOmember listLeadershipDTO(id, title, first_name, last_name, email, photo_url, session_number, is_current)NewsDTO(id, title, summary, body, image_url, author_name, date_published, date_last_edited)LegislationDTOwith nestedLegislationActionDTOlistLegislationActionDTO(id, action_date, description, action_type)CalendarEventDTO(id, title, description, start_datetime, end_datetime, location, event_type)CarouselSlideDTO(id, image_url, overlay_text, link_url, display_order, is_active)FinanceHearingConfigDTOwith nestedFinanceHearingDateDTOlistFinanceHearingDateDTO(id, hearing_date, hearing_time, location, description, is_full)StaffDTO(id, first_name, last_name, title, email, photo_url)DistrictDTOwith optional nested senator listBudgetDataDTOwith recursivechildren: List[BudgetDataDTO]StaticPageDTO(id, page_slug, title, body, updated_at)AccountDTO(id, email, pid, first_name, last_name, role)Important Notes
model_validate/from_attributes)app/schemas/as separate files, re-exported fromapp/schemas/__init__.pypydanticv2 withmodel_config = ConfigDict(from_attributes=True)pydantictorequirements.txt(it ships with FastAPI but pin it explicitly)NewsDTO.author_nameis a computed field derived from the Admin FK, not stored directlyBudgetDataDTO.childrenis recursive — use Pydantic'smodel_rebuild()if forward refs are needed