Files
F-r-ldraledigplannerare/PLANNED_DAYS_405_TODO.md
T

83 lines
3.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TODO — Fix `GET /api/planned-days` 405 (planned-days router is incomplete)
**Status:** open · **Area:** backend · **Owner:** _unassigned_ · **Filed:** 2026-06-14
## Symptom
Loading the Dashboard and adding a day in the Calendar both log:
```
"GET /api/planned-days?child_id=3b9b6dad-... HTTP/1.1" 405 Method Not Allowed
```
Adding a day works (`POST /api/planned-days` → 201), but the follow-up refresh
(`GET /api/planned-days?child_id=…`) is rejected, so the calendar/dashboard never
show planned days.
## Root cause
`backend/app/routers/planned_days.py` defines `POST ""` but **no `GET ""`**. FastAPI
returns *405* (not 404) because the path exists for another verb. The list-by-child
endpoint was never finished — the `GET /range` handler (lines ~65–78) is a dead stub
(`pass` body, `= None` defaults on its `service`/`_current_user` deps) and `/range`
also collides with `GET /{planned_leave_day_id}`.
Same router has a second gap: `api.updatePlannedDay` issues `PUT /api/planned-days/{id}`
(used by Calendar edit, `frontend/src/pages/Calendar.tsx:99`), but there is **no PUT
handler** and no `PlanningService.update`. Editing an existing day will 405 once adding works.
## Fix
In `backend/app/services/planning_service.py`:
1. Add `list_by_child`:
```python
async def list_by_child(self, child_id: UUID) -> list[PlannedLeaveDay]:
return await self._repo.list(child_id=child_id)
```
(The SQLite `list()` already filters on `child_id` alone.)
2. Add `update(self, planned_leave_day_id: UUID, day_type: str | None, is_dubbeldag: bool | None) -> PlannedLeaveDay`
— load via `get_by_id` (raise `NotFoundError` if missing), apply provided fields, call `repo.update`.
In `backend/app/routers/planned_days.py`:
3. Add the list route **before** `GET /{planned_leave_day_id}`:
```python
@router.get("", response_model=list[PlannedLeaveDayResponse])
async def list_planned_days(
service: PlanningServiceDep,
_current_user: CurrentUserDep,
child_id: UUID = Query(...),
) -> list[PlannedLeaveDayResponse]:
return [_to_response(d) for d in await service.list_by_child(child_id)]
```
4. Delete the dead `GET /range` stub (lines ~65–78).
5. Add the `PUT /{planned_leave_day_id}` handler using the existing
`PlannedLeaveDayUpdate` model → `service.update(...)` → `_to_response`.
> Route ordering matters: declare `""`, `/workspace/...`, then `/{planned_leave_day_id}`
> last, so the UUID catch-all doesn't swallow the others.
## Verification
From `backend/`:
```bash
uv run ruff check . && uv run ruff format --check . && uv run pytest
```
Add tests:
- `GET /api/planned-days?child_id=…` → 200 with the seeded rows for that child.
- `PUT /api/planned-days/{id}` → 200, fields updated; unknown id → 404.
Manual: add a vacation day in the Calendar → `POST 201` then `GET 200` and the list
refreshes; edit an existing day → `PUT` succeeds.
After code changes: `graphify update .`
## Related
The 405 only blocks the *planned-days* list. The dashboard's empty **metrics /
parental-leave breakdown** is a separate snake_case↔camelCase issue —
see `DASHBOARD_EMPTY_DATA_TODO.md`.