Commit Graph

35 Commits

Author SHA1 Message Date
simon.franken
ddb0926dba Implement soft-delete for client targets and balance corrections
Deleting a target or correction sets deletedAt instead of hard-deleting.
Creating a target for a user+client that has a soft-deleted record
reactivates it (clears deletedAt, applies new weeklyHours/startDate)
rather than failing the unique constraint. All reads filter deletedAt = null
on the target, its corrections, and the parent client.
2026-02-23 15:48:07 +01:00
simon.franken
1b0f5866a1 Restore onDelete: Cascade on Project->Client and TimeEntry->Project
Direct database deletes should still cascade to avoid orphaned records.
The migration now only adds the three deleted_at columns without touching
the existing FK constraints.
2026-02-23 15:32:31 +01:00
simon.franken
159022ef38 Exclude client targets for soft-deleted clients
findAll and findById filter on client.deletedAt = null so targets
belonging to a soft-deleted client are invisible. The create guard
also rejects soft-deleted clients. The raw SQL balance query now
excludes soft-deleted time entries and projects from tracked totals.
2026-02-23 15:24:58 +01:00
simon.franken
1a7d13d5b9 Implement soft-delete for clients, projects, and time entries
Replace hard deletes with deletedAt timestamp flags on all three entities.
Deleting a client or project only sets its own deletedAt; child records are
excluded implicitly by filtering on parent deletedAt in every read query.
Raw SQL statistics queries also filter out soft-deleted parents.
FK ON DELETE CASCADE removed from Project→Client and TimeEntry→Project.
2026-02-23 15:21:13 +01:00
simon.franken
685a311001 Add break time feature to time entries
- Add breakMinutes field to TimeEntry model and database migration
- Users can now add break duration (minutes) to time entries
- Break time is subtracted from total tracked duration
- Validation ensures break time cannot exceed total entry duration
- Statistics and client target balance calculations account for breaks
- Frontend UI includes break time input in TimeEntryFormModal
- Duration displays show break time deduction (e.g., '7h (−1h break)')
- Both project/client statistics and weekly balance calculations updated
2026-02-23 14:39:30 +01:00
simon.franken
078dc8c304 Add Prisma session store for persistent sessions 2026-02-23 11:39:09 +01:00
simon.franken
06596dcee9 Add cancel (discard) timer feature
Allows users to discard a running timer without creating a time entry.
A trash icon in the timer widget reveals a confirmation step ('Discard / Keep')
to prevent accidental data loss. Backend exposes a new DELETE /api/timer
endpoint that simply deletes the ongoingTimer row.
2026-02-23 10:41:50 +01:00
simon.franken
7358fa6256 Add ability to manually adjust the running timer's start time
Allows users to retroactively correct the start time of an ongoing timer
without stopping it. A pencil icon in the timer widget opens an inline
time input pre-filled with the current start time; confirming sends the
new time to the backend which validates it is in the past before persisting.
2026-02-23 10:32:38 +01:00
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
1aac76af4a Add detailed logging to auth flow on backend and iOS 2026-02-19 18:55:00 +01:00
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
1ca76b0fec fix 2026-02-18 22:58:41 +01:00
b3db7cbd7b fix 2026-02-18 22:50:37 +01:00
f218552d48 fix 2026-02-18 22:47:44 +01:00
0d084cd546 update 2026-02-18 22:45:38 +01:00
5f23961f50 fix 2026-02-18 22:43:08 +01:00
7e8e220e3b update 2026-02-18 22:37:49 +01:00
4b0cfaa699 increases limit for corrections 2026-02-18 20:32:40 +01:00
51c003cb0d update 2026-02-18 20:18:55 +01:00
859420c5d6 fix 2026-02-18 20:15:11 +01:00
01502122b2 Revert "update"
This reverts commit 5c86afd640.
2026-02-18 20:05:32 +01:00
d2328fc8d6 fix 2026-02-18 19:40:39 +01:00
658a70f3ac fix 2026-02-18 19:31:47 +01:00
5c86afd640 update 2026-02-18 19:19:42 +01:00
9b783037ff impoves docker 2026-02-18 19:02:29 +01:00
simon.franken
0f6e55302a update 2026-02-18 16:08:42 +01:00
simon.franken
4cce62934e adds targets 2026-02-18 14:27:44 +01:00
simon.franken
6a6a3ba00b refactoring 2026-02-18 10:26:15 +01:00
64fd134044 improvements 2026-02-16 19:54:15 +01:00
9206453394 adds statistics 2026-02-16 19:15:23 +01:00
2311cd8265 fix 2026-02-16 18:25:09 +01:00
simon.franken
fc06dac40e update 2026-02-16 17:12:47 +01:00
simon.franken
a9228d19c8 fix 2026-02-16 16:09:07 +01:00
simon.franken
d3b8df3deb fix 2026-02-16 11:01:07 +01:00
simon.franken
7d678c1c4d creates application 2026-02-16 10:15:27 +01:00