Commit Graph
64 Commits
Author SHA1 Message Date
simonfranken a58dfcfa4a fix: clamp ongoing-period corrections to today to prevent future corrections inflating balance
A correction dated in the future (within the current period) was being
added to the balance immediately, while the corresponding expected hours
were not yet counted (elapsed working days only go up to today).

Fix: in the ongoing-period branch, sum only corrections whose date is
<= today, matching the same window used for elapsed working days and
tracked time.
2026-02-24 21:27:03 +01:00
simonfranken 7101f38bc8 feat: implement client targets v2 (weekly/monthly periods, working days, pro-ration)
- Add PeriodType enum and working_days column to ClientTarget schema
- Rename weekly_hours -> target_hours; remove Monday-only constraint
- Add migration 20260224000000_client_targets_v2
- Rewrite computeBalance() to support weekly/monthly periods, per-spec
  pro-ration for first period, ongoing vs completed period logic, and
  elapsed working-day counting (§4–§6 of requirements doc)
- Update Zod schemas and TypeScript input types for new fields
- Frontend: replace WeekBalance with PeriodBalance; update
  ClientTargetWithBalance to currentPeriod* fields
- ClientTargetPanel: period type radio, working-day toggles, free date
  picker, dynamic hours label
- DashboardPage: rename widget to Targets, dynamic This week/This month
  label
2026-02-24 19:02:32 +01:00
simonfranken 3850e2db06 docs: add client targets v2 feature requirements 2026-02-24 18:50:34 +01:00
simonfranken 5b7b8e47cb ui adaptions 2026-02-23 20:59:01 +01:00
simonfranken 7dd3873148 Merge branch 'main' into feature/soft-delete 2026-02-23 17:59:29 +01:00
simonfranken 850f12e09d Merge pull request 'feature/ios-time-entries-rework' (#2) from feature/ios-time-entries-rework into main
Reviewed-on: #2
2026-02-23 16:58:44 +00:00
simonfranken 74999ce265 Merge pull request 'ios-rebuild' (#3) from ios-rebuild into main
Reviewed-on: #3
2026-02-23 16:57:45 +00:00
simonfranken 0c0fbf42ef updates icons 2026-02-23 17:57:25 +01:00
simonfranken 0d116c8c26 Merge branch 'ios-rebuild' into feature/ios-time-entries-rework 2026-02-23 17:29:21 +01:00
simonfranken 25b7371d08 Merge branch 'main' into ios-rebuild 2026-02-23 17:28:51 +01:00
simonfranken d09247d2a5 Merge pull request 'Add Prisma session store for persistent sessions' (#5) from feature/prisma-session-store into main
Reviewed-on: #5
2026-02-23 13:35:21 +00:00
simonfranken d56eed8dde Merge pull request 'Add ability to manually adjust the running timer's start time' (#4) from feature/adjust-timer-start-time into main
Reviewed-on: #4
2026-02-23 09:57:23 +00:00
simonfranken b613fe4edd Replace full-month UICalendarView with compact week strip in time entries 2026-02-21 18:01:02 +01:00
simonfranken 30d5139ad8 update 2026-02-21 14:03:56 +01:00
simonfranken ef38578596 Fix .accentColor ShapeStyle compile error — use Color.accentColor 2026-02-21 13:57:31 +01:00
simonfranken ba4765b8a2 Rebuild iOS app: calendar entries, overtime dashboard, settings tab, full CRUD
- Replace 5-tab layout with 4 tabs: Dashboard, Timer, Entries, Settings
- Dashboard: add Work Time Balance section using /client-targets API, showing
  per-client weekly progress bar, overtime/undertime label and expandable week breakdown
- Time Entries: replace flat list with UICalendarView month grid; tap a day to see
  that day's entries; add filter sheet (date range, project, client); new
  TimeEntryDetailSheet for creating and editing entries; duration shown as Xh Ymin
- Settings tab: user info header, navigation to Clients and Projects, logout button
- ClientsListView: list with NavigationLink to ClientDetailView
- ClientDetailView: inline client editing + full work time target CRUD (create,
  edit, delete target; add/delete balance corrections with date, hours, description)
- ProjectsListView: grouped by client, NavigationLink to ProjectDetailView
- ProjectDetailView: edit name, description, colour, client assignment
- Add ClientTarget, WeekBalance, BalanceCorrection models and APIEndpoints for
  /client-targets routes
- Update TimeInterval formatter: add formattedShortDuration (Xh Ymin / Xmin / <1min)
  used throughout app; keep formattedDuration for live timer display
2026-02-21 13:51:41 +01:00
simonfranken d37170fc5d Disable stop timer button when no project is selected 2026-02-20 18:19:58 +01:00
simonfranken fc3b7d7c2c adds group 2026-02-20 17:45:32 +01:00
simonfranken 32cb200408 Fix iOS timer widget not displaying active timers
The widget was failing to decode the cached timer data because WidgetTimer
struct didn't match the OngoingTimer JSON structure saved by the app.

Changes:
- Added missing fields (project, createdAt, updatedAt) to WidgetTimer
- Added WidgetProjectReference struct for nested project data
- Fixed project name to use project.name instead of projectId
- Added project color support
- Increased refresh interval from 15 min to 1 min for live updates
2026-02-20 15:57:16 +01:00
simonfranken e0dd2f1fbc Merge branch 'main' into feature/ios-delete-confirmation 2026-02-20 15:35:02 +01:00
simonfranken a39f8b07df Add delete confirmation dialogs for clients, projects, and time entries
- Add confirmation alert when deleting clients with warning about
deleted dependencies (projects and time entries)
- Add confirmation alert when deleting projects with warning about
deleted time entries
- Add confirmation alert when deleting time entries
- All alerts include item name and emphasize action cannot be undone
2026-02-20 15:32:40 +01:00
simonfranken ed8a160a49 update 2026-02-20 15:24:10 +01:00
simonfranken f42de3353c Fix iOS time display and add timer unit labels
Times were always showing 0 because ISO8601DateFormatter with default
options does not parse fractional seconds, but Prisma/Node.js serialises
dates as "2026-02-20T09:00:00.000Z" (with .000). Every date(from:) call
silently returned nil, so elapsedTime and duration always fell back to 0.

- Date+Extensions: fromISO8601 now tries .withFractionalSeconds first,
  then falls back to whole seconds — single place to maintain
- OngoingTimer.elapsedTime: use Date.fromISO8601() instead of bare formatter
- TimeEntry.duration: use Date.fromISO8601() instead of bare formatters
- TimerView: add TimerUnitLabels view showing h/min/sec column headers
  under the monospaced clock digits
2026-02-20 14:53:30 +01:00
simonfranken da0cd302bf Fix OIDC web flow redirect URI not being sent to IDP
The /login route was not passing an explicit redirect_uri to the IDP for
the web flow, so openid-client would silently pick a default which could
resolve to localhost:3001 if OIDC_REDIRECT_URI was not set.

- AuthSession.redirectUri is now required (non-optional)
- createAuthSession() requires a redirectUri; detects native vs web via
  the timetracker:// scheme prefix instead of presence/absence of the arg
- /login route resolves the URI explicitly: request param for native
  flows, config.oidc.redirectUri for web flows
- getAuthorizationUrl() reads redirect_uri from session, no longer
  accepts it as a separate argument
- handleCallback() uses session.redirectUri directly, removing the
  fallback to config.oidc.redirectUri
2026-02-20 14:32:23 +01:00
simonfranken f758aa2fcd Add iOS redirect URI and JWT secret to Helm chart
Add backend.oidc.iosRedirectUri (default: timetracker://oauth/callback) and
backend.jwt.secret to values.yaml and wire them into the backend deployment
as OIDC_IOS_REDIRECT_URI and JWT_SECRET env vars. Update NOTES.txt to surface
both values post-install.
2026-02-20 11:17:18 +01:00
simonfranken e51dd58a6b Fix remaining ProjectListResponse reference in TimeEntryFormView 2026-02-19 19:07:36 +01:00
simonfranken 39d6ea00d9 Fix iOS list response decoding to match plain-array backend responses
GET /clients and GET /projects return bare arrays, not wrapped objects.
Remove ClientListResponse and ProjectListResponse wrapper structs and
update ClientsViewModel, ProjectsViewModel, and TimerViewModel to decode
[Client] and [Project] directly.
2026-02-19 19:05:43 +01:00
simonfranken 48cd82ab4f Fix token loss: cache JWT in-memory, log keychain errors
Keychain writes silently failed (missing keychain-access-groups entitlement
on simulator), causing the token to disappear between handleTokenResponse
and the first API call. The in-memory cache ensures the token is always
available within the session; the keychain still persists it across launches
when entitlements allow.
2026-02-19 19:00:16 +01:00
simonfranken 062af3b2da Add AuthManager OSLog tracing and fix URL construction in APIEndpoints 2026-02-19 18:58:31 +01:00
simonfranken 1aac76af4a Add detailed logging to auth flow on backend and iOS 2026-02-19 18:55:00 +01:00
simonfranken f1f60ef685 Pass OIDC_IOS_REDIRECT_URI and JWT_SECRET to backend container 2026-02-19 18:49:32 +01:00
simonfranken bb2e51cd0a Add JWT_SECRET and OIDC iOS redirect vars to env template 2026-02-19 18:47:19 +01:00
simonfranken 946cd35832 Replace IDP token passthrough with backend-issued JWT for iOS auth
iOS clients now exchange the OIDC authorization code for a backend-signed
HS256 JWT via POST /auth/token. All subsequent API requests authenticate
using this JWT as a Bearer token, verified locally — no per-request IDP
call is needed. Web frontend session-cookie auth is unchanged.
2026-02-19 18:45:03 +01:00
simonfranken 1ca76b0fec fix 2026-02-18 22:58:41 +01:00
simonfranken b3db7cbd7b fix 2026-02-18 22:50:37 +01:00
simonfranken f218552d48 fix 2026-02-18 22:47:44 +01:00
simonfranken 0d084cd546 update 2026-02-18 22:45:38 +01:00
simonfranken 5f23961f50 fix 2026-02-18 22:43:08 +01:00
simonfranken 7e8e220e3b update 2026-02-18 22:37:49 +01:00
simonfranken ed180500a6 fix 2026-02-18 21:54:21 +01:00
simonfranken 165b1b9c67 fix 2026-02-18 21:53:43 +01:00
simonfranken 2534011506 fix 2026-02-18 21:53:01 +01:00
simonfranken 4c0d8be018 fix 2026-02-18 21:51:43 +01:00
simonfranken b66b433c08 fix 2026-02-18 21:48:55 +01:00
simonfranken 7659b01614 adds git ignore 2026-02-18 21:45:09 +01:00
simonfranken 4e49741dfa adds ios 2026-02-18 21:35:32 +01:00
simonfranken 4b0cfaa699 increases limit for corrections 2026-02-18 20:32:40 +01:00
simonfranken 51c003cb0d update 2026-02-18 20:18:55 +01:00
simonfranken 859420c5d6 fix 2026-02-18 20:15:11 +01:00
simonfranken 8b45fffd6e update 2026-02-18 20:09:38 +01:00
simonfranken 01502122b2 Revert "update"
This reverts commit 5c86afd640.
2026-02-18 20:05:32 +01:00
simonfranken 6b3d0c342e fix 2026-02-18 19:44:54 +01:00
simonfranken d2328fc8d6 fix 2026-02-18 19:40:39 +01:00
simonfranken 658a70f3ac fix 2026-02-18 19:31:47 +01:00
simonfranken c3d1dcab4c update 2026-02-18 19:21:49 +01:00
simonfranken 5c86afd640 update 2026-02-18 19:19:42 +01:00
simonfranken 9b783037ff impoves docker 2026-02-18 19:02:29 +01:00
simonfranken 61545bcf1b update 2026-02-18 18:49:07 +01:00
simonfranken 27ec450d3b adds helm chart 2026-02-16 23:02:49 +01:00
simonfranken 64fd134044 improvements 2026-02-16 19:54:15 +01:00
simonfranken 81b4a8ead2 small UI fix 2026-02-16 19:36:15 +01:00
simonfranken c516a097a3 small adaptions 2026-02-16 19:28:23 +01:00
simonfranken 9206453394 adds statistics 2026-02-16 19:15:23 +01:00
simonfranken 2311cd8265 fix 2026-02-16 18:25:09 +01:00