The ClientTargetPanel component now properly uses the client prop to access
client.id when creating a new target, instead of trying to access target?.clientId
which would be undefined during creation. This ensures new targets are properly
associated with the correct client.
Add support for monthly and weekly targets with work-day selection:
- Users can now set targets as 'monthly' or 'weekly'
- Users select which days of the week they work
- Balance is calculated per working day, evenly distributed
- Target hours = (periodHours / workingDaysInPeriod)
- Corrections are applied at period level
- Daily balance tracking replaces weekly granularity
Database changes:
- Rename weekly_hours -> target_hours
- Add period_type (weekly|monthly, default=weekly)
- Add work_days (integer array of ISO weekdays, default=[1,2,3,4,5])
- Add constraints for valid period_type and non-empty work_days
Backend:
- Rewrite balance calculation in ClientTargetService
- Support monthly period enumeration
- Calculate per-day targets based on selected working days
- Update Zod schemas for new fields
- Update TypeScript types
Frontend:
- Add period type selector in target form (weekly/monthly)
- Add work days multi-checkbox selector
- Conditional start date input (week vs month)
- Update DashboardPage to show 'this period' instead of 'this week'
- Update ClientsPage to display working days and period type
- Support both weekly and monthly targets in UI
Migration:
- Add migration to extend client_targets table with new columns
- Backfill existing targets with default values (weekly, Mon-Fri)
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.
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.
- 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
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.
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.