InvoiceHistoryTable refetch: refreshKey prop (number) incremented by parent on checkNow success — triggers useEffect re-run; simpler than ref/callback
ExportFileList data: derives filenames from history items via onItemsLoaded callback from InvoiceHistoryTable; avoids second fetch
Password blank on load: configToForm() always sets password=''; placeholder shows bullet dots as UX hint; T-07-12 compliant
VehicleTable test mock fix: mockResolvedValueOnce for initial load (Hans Müller), mockResolvedValue for refetch (Max Mustermann)
CsvImportButton replace confirm: inline two-step (click Importieren → show confirm block → click Ersetzen) not a full modal; per UI-SPEC
Vehicles route split: settings/page.tsx has tab bar; Fahrzeuge tab is a <Link> to /modules/dkv-fleet/vehicles (own route); VehicleTable imported from settings/components/
duration
completed
tasks
files_created
files_modified
8min
2026-06-26T22:41:27Z
3
11
0
Phase 07 Plan 05: DKV Fleet Module Frontend — Summary
Typed fetch client (dkv-api.ts) and all three UI surfaces delivered: Surface A (module main page with history table + export list + "Jetzt prüfen" trigger), Surface B Tab 1 (InboxConfigForm with show/hide password and Active toggle), and Surface B Tab 2 (VehicleTable CRUD with CsvImportButton merge/replace). All STRIDE threat mitigations from the plan are implemented. VehicleTable covered by 5 passing Vitest tests (TDD RED→GREEN).
Tasks Completed
Task
Name
Commit
Key Files
1
dkv-api client + StatusBadge + Surface A main page
The page holds a refreshKey state (number). After a successful checkNow() call, the page increments refreshKey by 1. InvoiceHistoryTable receives refreshKey as a prop and includes it in its useEffect dependency array — this triggers a fresh fetchHistory() call.
Additionally, InvoiceHistoryTable accepts an onItemsLoaded(items) callback. After each fetch, it calls this with the loaded items. The page stores these items in historyItems state and passes them to ExportFileList, which derives the 10 most recent unique export filenames from them. This avoids a second network request for export files.
Password Blank on Load (T-07-12)
configToForm() always maps the server response to password: '' — the password field is never pre-filled. The server only returns hasPassword: boolean. The password field shows placeholder="••••••••" as a UX hint when hasPassword is true (inferred from the config). The password is only included in the saveConfig payload when form.password !== ''.
TDD Gate Compliance
RED commit: c739d27 (VehicleTable.test.tsx only, fails with import error)
GREEN commit: 4d81b8b (VehicleTable.tsx + CsvImportButton.tsx + fix)
Issue: The edit-row test called mockFetchVehicles.mockResolvedValue([Hans]) then immediately mockFetchVehicles.mockResolvedValue([Max]). The second call overwrote the first, making the initial component mount return Max Mustermann instead of Hans Müller. waitFor(() => getByText('Hans Müller')) timed out.
Fix: Changed the first mockResolvedValue to mockResolvedValueOnce so the initial mount uses Hans Müller; subsequent calls (refetch after update) use the Max Mustermann value.
None. All API client functions are fully wired to real /dkv/* endpoints (Plan 04). All UI interactions call the corresponding dkv-api functions. The module is fully operable once the backend containers are running.
Threat Flags
None. All T-07-12 to T-07-15 mitigations from the plan's threat register are implemented:
T-07-12: Password blank-on-load in configToForm(); hasPassword-only interface field
T-07-13: exportFileUrl() + encodeURIComponent; no client-built paths
T-07-14: All backend strings via React text nodes; StatusBadge uses title attribute