Files
qavion-time-tracker-assessment/NEXT_STEPS.md
T
achim 7877dc0631 docs: update README with features and design notes; add NEXT_STEPS
README now covers features list, run instructions, design rationale
(integer money/duration, read-time cost resolution, soft budget
enforcement, Flyway-only schema, API shape).

NEXT_STEPS.md catalogs deferred work: user CRUD UI, rate snapshots,
notes field, CSV export, auth, pagination, Playwright e2e, i18n,
dark mode, bookmarkable URLs, full backend test pyramid.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 11:57:46 +02:00

4.6 KiB

Next Steps

Items that were out of scope for the initial 6-hour build, with notes on how to approach each.

Features

User management UI

Currently, users are seeded via Flyway (V2__seed_demo_data.sql). A POST /api/users endpoint with a "New User" form in the frontend would complete the CRUD cycle. Straightforward to add following the same pattern as project creation.

Edit existing time entry (project-create form was shipped; entry edit is partially done)

The backend PUT /api/time-entries/{id} endpoint exists. The frontend TimeEntryForm handles editing when editEntry is passed. Wire up the Edit button per entry row in WeeklyView — already scaffolded, just needs end-to-end smoke-testing.

Notes / description field on time entries

Add a TEXT column to time_entries (new Flyway migration), expose it in the DTOs, and add a textarea to TimeEntryForm. Straightforward schema change.

Rate history — audit-stable costs

Currently, cost is computed at read time from the current project/user hourly rate. If a rate changes, historical costs change retroactively. To fix: add hourly_rate_cents_snapshot INTEGER NOT NULL to time_entries, resolve and snapshot the rate in TimeEntryService.create(). Historical queries then use the snapshot instead of joining to current rates.

CSV export of reports

Add a GET /api/reports/weekly.csv?userId=&week= and /monthly.csv endpoint that streams text/csv. Frontend adds a "Download CSV" button that opens the URL in a new tab.

Technical quality

Full backend test pyramid

The current happy-path tests cover the repository date-range query, service cost/budget logic, and one end-to-end MockMvc flow. Gaps to fill:

  • @WebMvcTest controller-slice tests for validation error responses (400 on invalid fields).
  • More @DataJpaTest cases (zero entries, multiple users, rate fallback).
  • @SpringBootTest with Testcontainers so tests do not depend on an externally-running PostgreSQL.

Frontend end-to-end tests (Playwright)

A Playwright suite covering the golden paths:

  1. Log a time entry → verify it appears in the weekly view.
  2. Create a project → verify it appears in the project list.
  3. Exceed a project budget → verify the budget banner appears.

Pagination of time entries

GET /api/time-entries returns all entries in a date range. For large datasets, add Spring Data pagination (Pageable parameter) and a "Load more" button or cursor in the frontend.

UX improvements

Delete confirmation modal

Currently confirm() is used for delete. Replace with a small Tailwind dialog / Headless UI Dialog for a consistent UX.

Bookmarkable week/month URLs

Weekly and monthly views use component state for the selected period. Moving the period to the URL (e.g., /weekly/2026-W20, /monthly/2026-05) enables bookmarking and browser back/forward. React Router v7 useParams + useNavigate is the implementation path.

Validation error UI polish

Form errors are shown as a banner above the form. Inline per-field errors (below each input) would be more discoverable.

Architecture

Authentication & per-user data isolation

No auth in the current build — user is selected via a dropdown. For production, add Spring Security with JWT or session-based auth. The user_id on time_entries already supports per-user isolation; the API just needs to enforce it from the authenticated principal.

Per-project currency

Add currency CHAR(3) NOT NULL DEFAULT 'EUR' to projects. The aggregation queries then need currency-aware math; cross-currency totals on the monthly report would require a conversion rate or report per-currency totals separately.

Time zone awareness

time_entries.entry_date is a LocalDate (no zone). If users span time zones, "today" must be resolved from the user's local zone rather than the server's. Pass a timeZone parameter or derive it from the authenticated user's profile.

Dark mode

Tailwind v4 supports prefers-color-scheme media queries via the dark: variant. Add @media (prefers-color-scheme: dark) styles or a toggle stored in localStorage.

i18n (de/en)

Hardcoded strings are in English; currency formatting uses German locale (de-DE). Introduce react-intl or a similar library and extract string constants. Language preference lives in user settings or Accept-Language.

Performance

  • N+1 in ProjectService.findAll(): one aggregate query for all projects avoids it (already done via aggregateAllByProject). No further action needed at small scale.
  • Large datasets: consider materialized views or a dedicated reporting aggregate table updated via a database trigger or scheduled job.