Problem
OnTime-front currently needs only each Schedule's total Preparation Duration for the calendar selected-day UI, but it has to fetch the full preparation list per schedule to calculate that duration.
That creates an N+1 pattern:
- Frontend loads schedules through
GET /schedules?startDate=...&endDate=....
- Calendar extracts visible-day schedule ids.
- For each missing schedule id, frontend calls
GET /schedules/{scheduleId}/preparations.
- Frontend sums preparation step durations through
PreparationEntity.totalDuration.
PR DevKor-github/OnTime-front#558 reduced the UI impact with bounded frontend concurrency, but that is still an API workaround. The server already owns schedule preparation source resolution, so the better contract is for schedule responses to include the computed preparation duration directly.
Frontend evidence
Current frontend code paths:
lib/presentation/calendar/bloc/monthly_schedules_bloc.dart
MonthlySchedulesPreparationsPrefetchRequested receives schedule ids for the visible date.
- It calls
LoadPreparationByScheduleIdUseCase per missing schedule id.
- It then calls
GetPreparationByScheduleIdUseCase and stores preparation.totalDuration in preparationDurationByScheduleId.
lib/data/data_sources/preparation_remote_data_source.dart
getPreparationByScheduleId(scheduleId) performs GET /schedules/{scheduleId}/preparations.
lib/data/models/get_schedule_response_model.dart
- Schedule responses currently include
moveTime, scheduleSpareTime, preparationMode, preparationTemplateId, preparationTemplateName, preparationTemplateDeleted, and preparationFrozen, but no preparation duration field.
Related frontend mitigation:
Proposed API contract
Add a server-computed preparation-duration field to schedule response objects returned by schedule list/detail endpoints.
Preferred field shape:
{
"scheduleId": "...",
"moveTime": 20,
"scheduleSpareTime": 10,
"preparationDuration": 35
}
Field semantics:
preparationDuration is an integer minute count.
- It is the sum of preparation step durations only.
- It excludes
moveTime.
- It excludes
scheduleSpareTime.
- It should be available anywhere the frontend receives a schedule response for calendar/list/detail use.
Source resolution rules
The backend should compute the value from the same preparation source the schedule actually uses:
DEFAULT: sum the user's current default preparation steps for unstarted schedules.
TEMPLATE: sum the linked preparation template's steps for unstarted schedules, including resolvable deleted templates already linked to existing schedules.
CUSTOM: sum the schedule-specific preparation steps.
- Started/frozen schedules: sum the frozen schedule-specific preparation snapshot, not the mutable default/template source.
These rules should stay aligned with the existing preparation template and schedule-start docs.
Frontend follow-up after backend ships
Once the field is available, OnTime-front should:
- Parse the new field in
GetScheduleResponseModel.
- Carry it on
ScheduleEntity or a schedule list view model as Duration(minutes: preparationDuration).
- Use it in
MonthlySchedulesBloc instead of calling GET /schedules/{scheduleId}/preparations just to populate calendar duration badges.
- Keep
GET /schedules/{scheduleId}/preparations for screens that need actual preparation steps, such as edit/detail/preparation flow.
Acceptance criteria
- Schedule list responses include
preparationDuration for each schedule.
- Schedule detail response includes the same field or otherwise exposes the same schedule response shape.
- The value is in minutes and excludes move time and schedule spare time.
- Tests cover
DEFAULT, TEMPLATE, CUSTOM, and started/frozen schedule cases.
- Tests cover deleted-but-linked template resolution if schedule responses can still reference deleted templates.
- API docs are updated with the new response field and source-resolution rules.
- OnTime-front can remove the calendar selected-day preparation N+1 fetch path after adopting this field.
Non-goals
- Do not include full preparation steps in schedule list responses.
- Do not change
moveTime or scheduleSpareTime semantics.
- Do not remove
GET /schedules/{scheduleId}/preparations; detailed preparation screens still need it.
Problem
OnTime-front currently needs only each Schedule's total Preparation Duration for the calendar selected-day UI, but it has to fetch the full preparation list per schedule to calculate that duration.
That creates an N+1 pattern:
GET /schedules?startDate=...&endDate=....GET /schedules/{scheduleId}/preparations.PreparationEntity.totalDuration.PR DevKor-github/OnTime-front#558 reduced the UI impact with bounded frontend concurrency, but that is still an API workaround. The server already owns schedule preparation source resolution, so the better contract is for schedule responses to include the computed preparation duration directly.
Frontend evidence
Current frontend code paths:
lib/presentation/calendar/bloc/monthly_schedules_bloc.dartMonthlySchedulesPreparationsPrefetchRequestedreceives schedule ids for the visible date.LoadPreparationByScheduleIdUseCaseper missing schedule id.GetPreparationByScheduleIdUseCaseand storespreparation.totalDurationinpreparationDurationByScheduleId.lib/data/data_sources/preparation_remote_data_source.dartgetPreparationByScheduleId(scheduleId)performsGET /schedules/{scheduleId}/preparations.lib/data/models/get_schedule_response_model.dartmoveTime,scheduleSpareTime,preparationMode,preparationTemplateId,preparationTemplateName,preparationTemplateDeleted, andpreparationFrozen, but no preparation duration field.Related frontend mitigation:
Proposed API contract
Add a server-computed preparation-duration field to schedule response objects returned by schedule list/detail endpoints.
Preferred field shape:
{ "scheduleId": "...", "moveTime": 20, "scheduleSpareTime": 10, "preparationDuration": 35 }Field semantics:
preparationDurationis an integer minute count.moveTime.scheduleSpareTime.Source resolution rules
The backend should compute the value from the same preparation source the schedule actually uses:
DEFAULT: sum the user's current default preparation steps for unstarted schedules.TEMPLATE: sum the linked preparation template's steps for unstarted schedules, including resolvable deleted templates already linked to existing schedules.CUSTOM: sum the schedule-specific preparation steps.These rules should stay aligned with the existing preparation template and schedule-start docs.
Frontend follow-up after backend ships
Once the field is available, OnTime-front should:
GetScheduleResponseModel.ScheduleEntityor a schedule list view model asDuration(minutes: preparationDuration).MonthlySchedulesBlocinstead of callingGET /schedules/{scheduleId}/preparationsjust to populate calendar duration badges.GET /schedules/{scheduleId}/preparationsfor screens that need actual preparation steps, such as edit/detail/preparation flow.Acceptance criteria
preparationDurationfor each schedule.DEFAULT,TEMPLATE,CUSTOM, and started/frozen schedule cases.Non-goals
moveTimeorscheduleSpareTimesemantics.GET /schedules/{scheduleId}/preparations; detailed preparation screens still need it.