Files
time_to_leave/CHECKLIST.md
T
fegger 77b8c6db98 Rewrite implementation checklist and fix runtime bugs
Update CHECKLIST.md and REWRITE_PLAN.md to reflect the current
post-rewrite status and remaining tasks.

- Add input validation to /api/hafas route to enforce request shape
  and cap results
- Fix SSR crash in useBikeRoute by using relative fetch URLs
- Wire CalendarPanel to fetch calendar events and merge them into the
  global events store
2026-05-10 03:09:38 +02:00

87 lines
4.3 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.
# TimeToLeave — Implementation Checklist
> **Source:** [REWRITE_PLAN.md](./REWRITE_PLAN.md)
> **Total:** 4 phases, 14 steps, ~5 hours estimated effort
---
## Phase 1 — Unblock Runtime (~45 min)
Fix bugs that crash the app or lose user data.
| Step | ✅ Implemented | ✔️ Reviewed | Notes |
|------|:--------------:|:-----------:|-------|
| **Step 1: Fix SSR Crash in `useBikeRoute`** (~10 min) | [x] | [x] | Relative URL fetch replaces `window.location.href` — SSR-safe. `isMounted` guard intact. |
| **Step 2: Wire Calendar Events into `EventsStore`** (~15 min) | [x] | [x] | `CalendarPanel.tsx` merges via `useEffect` when calendar events arrive. `mergeEvents()` converts `CalendarEvent` (string `eventTime`) → `Event` (Date `eventTime`). Bonus: localStorage persistence with rehydration. |
| **Step 3: Add Input Validation to `/api/hafas`** (~20 min) | [x] | [x] | Validates `svcReqL` array shape, method allowlist (TripSearch/LocMatch), caps `numF` at 10. Extra type guard on `svcReq.meth` (`typeof svcReq.meth !== 'string'`) exceeds spec. |
---
## Phase 2 — Deduplicate Code (~2 hours)
Eliminate duplicated logic so each integration has one source of truth.
- [ ] **Step 4: Consolidate HAFAS Journey Parsing** (~40 min)
- Move `parseHafasJourneys` from `useJourneys.ts` into `hafas-client.ts` and export it; import from `useJourneys.ts` (Option A — minimal risk)
- Files: `src/lib/hafas-client.ts`, `src/hooks/useJourneys.ts`
- [ ] **Step 5: Wire API Routes to Use Library Clients** (~30 min)
- Replace raw `fetch()` in `api/geocode/route.ts` with `GeocodingClient`, and in `api/bike-route/route.ts` with `BikeRoutingClient` (module-level singleton, proper error handling)
- Files: `src/app/api/geocode/route.ts`, `src/app/api/bike-route/route.ts`
- [ ] **Step 6: Remove Dead Code** (~5 min)
- Delete `src/lib/live-status-utils.ts` entirely; remove its export from `src/lib/index.ts`
- File: `src/lib/live-status-utils.ts`, `src/lib/index.ts`
- [ ] **Step 7: Create Missing Test Setup File** (~10 min)
- Create `src/test/setup.ts` with `import "@testing-library/jest-dom/vitest"` so jsdom matchers are registered globally
- File: `src/test/setup.ts`
---
## Phase 3 — Performance & UX (~1.5 hours)
- [ ] **Step 8: Add Debounce to Lookup Hooks** (~25 min)
- Wrap fetch in a 400 ms `setTimeout` with `AbortController` cleanup in `useGeocode.ts` and `useDestinationStation.ts` to prevent per-keystroke API calls
- Files: `src/hooks/useGeocode.ts`, `src/hooks/useDestinationStation.ts`
- [ ] **Step 9: Pre-Group Calendar Events by Date** (~20 min)
- Build a `Map<string, Event[]>` keyed by `YYYY-MM-DD` via `useMemo` in `CalendarView.tsx`; replace per-cell `filter()` with O(1) map lookup
- File: `src/app/calendar/CalendarView.tsx`
- [ ] **Step 10: Add Dark Mode Toggle** (~20 min)
- Create `useTheme.ts` hook (persist to `localStorage`, respect `prefers-color-scheme`); add sun/moon toggle button to `Header.tsx`
- Files: `src/hooks/useTheme.ts` (new), `src/app/layout/Header.tsx`
- [ ] **Step 11: Fix Bike Route Steps** (~5 min)
- Add `steps: "true"` to the query params in `BikeRoutingClient.getBikeRoute()` so OSRM returns turn-by-turn steps
- File: `src/lib/bike-routing-client.ts`
---
## Phase 4 — Monitoring & Testing (~1 hour)
- [ ] **Step 12: Add Correlation IDs to API Errors** (~15 min)
- Generate a short UUID (`randomUUID().slice(0, 8)`) in each API route's catch block; log it server-side and include it in the JSON error response
- Files: all `src/app/api/*/route.ts`
- [ ] **Step 13: Add Hook Tests** (~30 min)
- Create `useJourneys.test.ts` and `useBikeRoute.test.ts` — mock `global.fetch`, test state transitions (loading → success, loading → error)
- Files: `src/hooks/__tests__/useJourneys.test.ts`, `src/hooks/__tests__/useBikeRoute.test.ts`
- [ ] **Step 14: Add Component Tests** (~15 min)
- Create `EventCard.test.tsx` and `CalendarView.test.tsx` — render with mock data, verify key elements are in the document
- Files: `src/app/event/__tests__/EventCard.test.tsx`, `src/app/calendar/__tests__/CalendarView.test.tsx`
---
## Summary
| Phase | Steps | Est. Time |
|-------|-------|-----------|
| 1 — Unblock Runtime | 13 | ~45 min |
| 2 — Deduplicate Code | 47 | ~2 hours |
| 3 — Performance & UX | 811 | ~1.5 hours |
| 4 — Monitoring & Testing | 1214 | ~1 hour |
| **Total** | **14** | **~5 hours** |