Goals
Set hour targets per user / project / period and see live progress rings on the timer composer.
Goals
Goals are the lightweight commitment layer on top of time tracking. Set a target like "10 hours/week on Acme" or "under 5 hours/week on internal admin", and a small progress ring appears on the timer composer whenever the active goal applies.
Screenshot needed — /time/goals page with a list of goals, each showing a colored progress ring, target hours, and the period.
Creating a goal
- Open
/time/goals(the Track group of the time tabs). - Click New goal.
- Configure:
- Scope — workspace-wide, a specific user (default: yourself), a specific project, or both.
- Target hours — the number of hours.
- Period —
daily,weekly, ormonthly. - Comparator —
at_least(you want to hit the target) orat_most(you want to stay under). - Starts on / Ends on — optional date range. Leave open for an ongoing goal.
- Save.
A user can have many goals; a project can have many goals; the timer composer picks the most actionable one for the current entity/project.
Comparator semantics
Two flavors:
| Comparator | Use it for | Color signal |
|---|---|---|
at_least | "Do at least this much" — focused work, project commitments | Primary while below target, green when ≥ 100% |
at_most | "Stay under this much" — internal admin, distraction caps | Primary while under, red when over budget |
The progress ring color shifts at 100% so you can read goal status at a glance.
Where goals show up
Timer composer
Whenever a timer is running and a goal applies to the current (user, project) pair, a small <GoalRing> renders next to the elapsed clock. Hover for the tooltip:
Goal: 7.5 / 10 h this week (75%)
The composer picks the most actionable goal — closest to but below 100% — so you see the one that's most informative right now. If you have multiple goals applying simultaneously, the others are listed on /time/goals.
Goals page
/time/goals shows every goal for the workspace (filtered to yours by default) with:
- The progress ring + integer percent
- Actual / target hours (e.g.
7.5 / 10) - The period window currently being measured
- A compact recent-history sparkline (last 4 periods)
- Edit / delete actions
Period windows
- Daily — current calendar day in workspace timezone.
- Weekly — current week, anchored to
time_tracking_settings.week_start_day(default Monday). - Monthly — current calendar month.
If a goal has starts_on and/or ends_on, those bound the periods that count. Outside the bounds the goal is hidden.
Workspace-wide vs. personal goals
A goal with no user_id (workspace-wide) applies to anyone whose timer matches the project filter. Useful for team-level commitments — "the whole team puts <10h/week on internal admin".
When workspace-wide, the progress ring on the composer reflects the current user's contribution to the goal — but the /time/goals page shows a per-user breakdown.
What counts toward a goal
A time_entries row counts toward a goal when:
- Its
log_datefalls inside the current period window - Its
user_idmatches the goal'suser_id(or the goal has no user filter) - Its
project_idmatches the goal'sproject_id(or the goal has no project filter) - Its
statusissubmittedorapproved(drafts are excluded — Pomodoro-style "I haven't filed it yet" entries don't move the needle)
If you want drafts to count too, that's a workspace setting in /time/settings — useful for early-week visibility before timesheets are submitted.
Notifications
A daily check fires when:
- A weekly
at_leastgoal is below 60% on Friday EOD ("at risk of missing this week's target"). - An
at_mostgoal exceeds 100% mid-period ("you're over budget — slow down").
Both go through the central notificationService (in-app + email/Slack/Teams depending on your channel preferences).