Files
qavion-time-tracker-assessment/NEXT_STEPS.md

4.7 KiB

Next Steps

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

Features

User creation / deletion UI

Users are seeded via Flyway (V2__seed_demo_data.sql) and the selected user's name/default rate can be edited from the top bar. A POST /api/users endpoint with a "New User" form, plus optional delete support, would complete the CRUD cycle. Straightforward to add following the same pattern as project creation.

Time entry edit smoke coverage

Editing existing time entries is implemented end-to-end (PUT /api/time-entries/{id}, TimeEntryForm edit mode, and the WeeklyView Edit button). Add explicit frontend and/or MockMvc smoke coverage for the edit path so regressions are caught.

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 tests cover the repository date-range query, service cost/budget logic, one end-to-end MockMvc flow, and a few validation cases for user/project updates. Gaps to fill:

  • Dedicated @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.