update docs

This commit is contained in:
simon.franken
2026-03-26 09:17:41 +01:00
parent e83d247cf9
commit 8eddbed00b
6 changed files with 217 additions and 419 deletions

View File

@@ -1,6 +1,6 @@
# AGENTS.md — Codebase Guide for AI Coding Agents # AGENTS.md — Codebase Guide for AI Coding Agents
This document describes the structure, conventions, and commands for the `vibe_coding_timetracker` monorepo. Read it in full before making changes. This document describes the structure, conventions, and commands for the `vibe_coding_timetracker` monorepo. **Read it in full before making changes.**
## Repository Structure ## Repository Structure
@@ -18,17 +18,79 @@ This document describes the structure, conventions, and commands for the `vibe_c
├── backend/ # Express REST API (TypeScript + Prisma + PostgreSQL) ├── backend/ # Express REST API (TypeScript + Prisma + PostgreSQL)
│ └── src/ │ └── src/
│ ├── auth/ # OIDC + JWT logic │ ├── auth/ # OIDC + JWT logic
│ ├── config/ # Configuration constants
│ ├── errors/ # AppError subclasses │ ├── errors/ # AppError subclasses
│ ├── middleware/# Express middlewares │ ├── middleware/# Express middlewares
│ ├── prisma/ # Prisma client singleton │ ├── prisma/ # Prisma client singleton
│ ├── routes/ # Express routers (xxx.routes.ts) │ ├── routes/ # Express routers (xxx.routes.ts)
│ ├── schemas/ # Zod validation schemas │ ├── schemas/ # Zod validation schemas
── services/ # Business logic classes (xxx.service.ts) ── services/ # Business logic classes (xxx.service.ts)
│ ├── types/ # TypeScript interfaces
│ └── utils/ # Utility functions
├── ios/ # Native iOS app (Swift/Xcode) ├── ios/ # Native iOS app (Swift/Xcode)
├── timetracker-chart/ # Helm chart for Kubernetes deployment ├── helm/ # Helm chart for Kubernetes deployment
└── docker-compose.yml └── docker-compose.yml
``` ```
## AI Agent Workflow
### Before Making Changes
1. Read this file completely
2. Read `project.md` for feature requirements
3. Read `README.md` for setup instructions
4. Understand the specific task or feature request
### During Development
1. Follow all code conventions in this document
2. Write clean, maintainable code
3. Add inline comments only when necessary for clarity
4. Run linting before completing: `npm run lint`
### After Making Changes
**Always update documentation.** See [Documentation Maintenance](#documentation-maintenance).
## Documentation Maintenance
**Every code change requires a documentation review.** When you modify the codebase, check whether documentation needs updating.
### Documentation Files and Their Purposes
| File | Purpose | Update When |
|------|---------|-------------|
| `AGENTS.md` | Code conventions, commands, architecture patterns | Changing conventions, adding new patterns, modifying architecture |
| `README.md` | Setup instructions, API reference, features list | Adding endpoints, changing environment variables, adding features |
| `project.md` | Requirements, data model, functional specifications | Modifying business logic, adding entities, changing validation rules |
### Update Rules
#### Update `AGENTS.md` When:
- Adding a new coding pattern or convention
- Changing the project structure (new directories, reorganization)
- Adding or modifying build/lint/test commands
- Introducing a new architectural pattern
- Changing state management or error handling approaches
#### Update `README.md` When:
- Adding, removing, or modifying API endpoints
- Changing environment variables or configuration
- Adding new features visible to users
- Modifying setup or installation steps
- Changing the technology stack
#### Update `project.md` When:
- Adding or modifying business requirements
- Changing the data model or relationships
- Adding new validation rules
- Modifying functional specifications
- Updating security or non-functional requirements
### Documentation Format Rules
- Use Markdown formatting
- Keep entries concise and actionable
- Match the existing tone and style
- Use code blocks for commands and code examples
- Maintain alphabetical or logical ordering in lists
## Build, Lint, and Dev Commands ## Build, Lint, and Dev Commands
### Frontend (`frontend/`) ### Frontend (`frontend/`)

32
DOCS.md Normal file
View File

@@ -0,0 +1,32 @@
# Documentation Guide
## Documentation Files
| File | Purpose | When to Update |
|------|---------|----------------|
| `AGENTS.md` | Code conventions, commands, architecture, AI agent workflow | Adding patterns, changing conventions, modifying structure, updating agent workflow |
| `README.md` | Setup instructions, API reference, features list | New endpoints, config changes, new features, technology stack changes |
| `project.md` | Requirements, data model, functional specifications | Business logic changes, new entities, validation rules, UI requirements |
| `DOCS.md` | Documentation standards and index | Documentation process changes, new documentation files |
## Documentation Standards
- Use Markdown formatting
- Keep entries concise and actionable
- Use code blocks for commands and examples
- Match existing tone and style
- Maintain logical ordering in lists
## Maintenance Rules
### AI Agents Must Update Documentation When:
1. Adding new code patterns or conventions
2. Modifying API endpoints or configuration
3. Changing business logic or data models
4. Adding new features or entities
### Review Checklist
- [ ] Documentation reflects code changes
- [ ] Examples are accurate and tested
- [ ] Formatting is consistent
- [ ] No outdated information remains

View File

@@ -10,6 +10,10 @@ A multi-user web application for tracking time spent working on projects. Users
- **Time Tracking** - Start/stop timer with live elapsed time display - **Time Tracking** - Start/stop timer with live elapsed time display
- **Manual Entry** - Add time entries manually for past work - **Manual Entry** - Add time entries manually for past work
- **Validation** - Overlap prevention and end-time validation - **Validation** - Overlap prevention and end-time validation
- **Statistics** - View aggregated time tracking data by project and client
- **Client Targets** - Set hourly targets per client with weekly/monthly periods
- **API Keys** - Generate API keys for external tools and AI agents
- **MCP Integration** - Model Context Protocol endpoint for AI agent access
- **Responsive UI** - Works on desktop and mobile - **Responsive UI** - Works on desktop and mobile
## Architecture ## Architecture
@@ -125,6 +129,27 @@ APP_URL="http://localhost:5173"
- `POST /api/timer/start` - Start timer - `POST /api/timer/start` - Start timer
- `PUT /api/timer` - Update timer (set project) - `PUT /api/timer` - Update timer (set project)
- `POST /api/timer/stop` - Stop timer (creates entry) - `POST /api/timer/stop` - Stop timer (creates entry)
- `POST /api/timer/cancel` - Cancel timer without saving
### Client Targets
- `GET /api/client-targets` - List targets with balance
- `POST /api/client-targets` - Create target
- `PUT /api/client-targets/:id` - Update target
- `DELETE /api/client-targets/:id` - Delete target
- `POST /api/client-targets/:id/corrections` - Add correction
- `DELETE /api/client-targets/:id/corrections/:correctionId` - Delete correction
### API Keys
- `GET /api/api-keys` - List API keys
- `POST /api/api-keys` - Create API key
- `DELETE /api/api-keys/:id` - Revoke API key
### MCP (Model Context Protocol)
- `GET /mcp` - SSE stream for server-initiated messages
- `POST /mcp` - JSON-RPC requests (tool invocations)
## Data Model ## Data Model

View File

@@ -1,285 +0,0 @@
# Client Targets v2 — Feature Requirements
## Overview
This document defines the requirements for the second iteration of the Client Targets feature. The main additions are:
- Targets can be set on a **weekly or monthly** period.
- Each target defines a **fixed weekly working-day pattern** (e.g. Mon + Wed).
- The balance for the **current period** is calculated proportionally based on elapsed working days, so the user can see at any point in time whether they are ahead or behind.
- The **start date** can be any calendar day (no longer restricted to Mondays).
- Manual **balance corrections** are preserved and continue to work as before.
---
## 1. Target Configuration
| Field | Type | Constraints |
|---|---|---|
| `periodType` | `WEEKLY \| MONTHLY` | Required |
| `weeklyOrMonthlyHours` | positive float, ≤ 168 | Required; represents hours per week or per month |
| `workingDays` | array of day names | At least one of `MON TUE WED THU FRI SAT SUN`; fixed repeating pattern |
| `startDate` | `YYYY-MM-DD` | Any calendar day; no longer restricted to Mondays |
| `clientId` | UUID | Must belong to the authenticated user |
**One active target per client** — the unique `(userId, clientId)` constraint is preserved. To change period type, hours, or working days the user creates a new target with a new `startDate`; the old target is soft-deleted. History from the old target is retained as-is and is no longer recalculated.
---
## 2. Period Definitions
| `periodType` | Period start | Period end |
|---|---|---|
| `WEEKLY` | Monday 00:00 of the calendar week | Sunday 23:59 of that same calendar week |
| `MONTHLY` | 1st of the calendar month 00:00 | Last day of the calendar month 23:59 |
---
## 3. Balance Calculation — Overview
The total balance is the **sum of individual period balances** from the period containing `startDate` up to and including the **current period** (the period that contains today).
Each period is classified as either **completed** or **ongoing**.
```
total_balance_seconds = SUM( balance_seconds ) over all periods
```
Positive = overtime. Negative = undertime.
---
## 4. Completed Period Balance
A period is **completed** when its end date is strictly before today.
```
balance = tracked_hours + correction_hours - period_target_hours
```
- `period_target_hours` — see §5 (pro-ration) for the first period; full `weeklyOrMonthlyHours` for all subsequent periods.
- `tracked_hours` — sum of all time entries for this client whose date falls within `[period_start, period_end]`.
- `correction_hours` — sum of manual corrections whose `date` falls within `[period_start, period_end]`.
No working-day logic is applied to completed periods. The target is simply the (optionally pro-rated) hours for that period.
---
## 5. First Period Pro-ration
If `startDate` does not fall on the natural first day of a period (Monday for weekly, 1st for monthly), the target hours for that first period are pro-rated by calendar days.
### Monthly
```
full_period_days = total calendar days in that month
remaining_days = (last day of month) startDate + 1 // inclusive
period_target_hours = (remaining_days / full_period_days) × weeklyOrMonthlyHours
```
**Example:** startDate = Jan 25, target = 40 h/month, January has 31 days.
`remaining_days = 7`, `period_target_hours = (7 / 31) × 40 = 9.032 h`
### Weekly
```
full_period_days = 7
remaining_days = Sunday of that calendar week startDate + 1 // inclusive
period_target_hours = (remaining_days / 7) × weeklyOrMonthlyHours
```
**Example:** startDate = Wednesday, target = 40 h/week.
`remaining_days = 5 (WedSun)`, `period_target_hours = (5 / 7) × 40 = 28.571 h`
All periods after the first use the full `weeklyOrMonthlyHours`.
---
## 6. Ongoing Period Balance (Current Period)
The current period is **ongoing** when today falls within it. The balance reflects how the user is doing *so far* — future working days within the current period are not considered.
### Step 1 — Period target hours
Apply §5 if this is the first period; otherwise use full `weeklyOrMonthlyHours`.
### Step 2 — Daily rate
```
working_days_in_period = COUNT of days in [period_start, period_end]
that match the working day pattern
daily_rate_hours = period_target_hours / working_days_in_period
```
The rate is fixed at the start of the period and does not change as time passes.
### Step 3 — Elapsed working days
```
elapsed_working_days = COUNT of days in [period_start, TODAY] (both inclusive)
that match the working day pattern
```
- If today matches the working day pattern, it is counted as a **full** elapsed working day.
- If today does not match the working day pattern, it is not counted.
### Step 4 — Expected hours so far
```
expected_hours = elapsed_working_days × daily_rate_hours
```
### Step 5 — Balance
```
tracked_hours = SUM of time entries for this client in [period_start, today]
correction_hours = SUM of manual corrections whose date ∈ [period_start, today]
balance = tracked_hours + correction_hours expected_hours
```
### Worked example
> Target: 40 h/month. Working days: Mon + Wed.
> Current month has 4 Mondays and 4 Wednesdays → `working_days_in_period = 8`.
> `daily_rate_hours = 40 / 8 = 5 h`.
> 3 working days have elapsed → `expected_hours = 15 h`.
> Tracked so far: 13 h, no corrections.
> `balance = 13 15 = 2 h` (2 hours behind).
---
## 7. Manual Balance Corrections
| Field | Type | Constraints |
|---|---|---|
| `date` | `YYYY-MM-DD` | Must be ≥ `startDate`; not more than one period in the future |
| `hours` | signed float | Positive = extra credit (reduces deficit). Negative = reduces tracked credit |
| `description` | string | Optional, max 255 chars |
- The system automatically assigns a correction to the period that contains its `date`.
- Corrections in **completed periods** are included in the completed period formula (§4).
- Corrections in the **ongoing period** are included in the ongoing balance formula (§6).
- Corrections in a **future period** (not yet started) are stored and will be applied when that period becomes active.
- A correction whose `date` is before `startDate` is rejected with a validation error.
---
## 8. Edge Cases
| Scenario | Behaviour |
|---|---|
| `startDate` = 1st of month / Monday | No pro-ration; `period_target_hours = weeklyOrMonthlyHours` |
| `startDate` = last day of period | `remaining_days = 1`; target is heavily reduced (e.g. 1/31 × hours) |
| Working pattern has no matches in the partial first period | `elapsed_working_days = 0`; `expected_hours = 0`; balance = `tracked + corrections` |
| Current period has zero elapsed working days | `expected_hours = 0`; balance = `tracked + corrections` (cannot divide by zero — guard required) |
| `working_days_in_period = 0` | Impossible by validation (at least one day required), but system must guard: treat as `daily_rate_hours = 0` |
| Today is not a working day | `elapsed_working_days` does not include today |
| Correction date before `startDate` | Rejected with a validation error |
| Correction date in future period | Accepted and stored; applied when that period is ongoing or completed |
| User changes working days or period type | Must create a new target with a new `startDate`; old target history is frozen |
| Two periods with the same client exist (old soft-deleted, new active) | Only the active target's periods contribute to the displayed balance |
| A month with only partial working day coverage (e.g. all Mondays are public holidays) | No automatic holiday handling; user adds manual corrections to compensate |
---
## 9. Data Model Changes
### `ClientTarget` table — additions / changes
| Column | Change | Notes |
|---|---|---|
| `period_type` | **Add** | Enum: `WEEKLY`, `MONTHLY` |
| `working_days` | **Add** | Array/bitmask of day names: `MON TUE WED THU FRI SAT SUN` |
| `start_date` | **Modify** | Remove "must be Monday" validation constraint |
| `weekly_hours` | **Rename** | → `target_hours` (represents hours per week or per month depending on `period_type`) |
### `BalanceCorrection` table — no structural changes
Date-to-period assignment is computed at query time, not stored.
---
## 10. API Changes
### `ClientTargetWithBalance` response shape
```typescript
interface ClientTargetWithBalance {
id: string
clientId: string
clientName: string
userId: string
periodType: "weekly" | "monthly"
targetHours: number // renamed from weeklyHours
workingDays: string[] // e.g. ["MON", "WED"]
startDate: string // YYYY-MM-DD
createdAt: string
updatedAt: string
corrections: BalanceCorrection[]
totalBalanceSeconds: number // running total across all periods
currentPeriodTrackedSeconds: number // replaces currentWeekTrackedSeconds
currentPeriodTargetSeconds: number // replaces currentWeekTargetSeconds
periods: PeriodBalance[] // replaces weeks[]
}
interface PeriodBalance {
periodStart: string // YYYY-MM-DD (Monday or 1st of month)
periodEnd: string // YYYY-MM-DD (Sunday or last of month)
targetHours: number // pro-rated for first period
trackedSeconds: number
correctionHours: number
balanceSeconds: number
isOngoing: boolean
// only present when isOngoing = true
dailyRateHours?: number
workingDaysInPeriod?: number
elapsedWorkingDays?: number
expectedHours?: number
}
```
### Endpoint changes
| Method | Path | Change |
|---|---|---|
| `POST /client-targets` | Create | Accepts `periodType`, `workingDays`, `targetHours`; `startDate` unconstrained |
| `PUT /client-targets/:id` | Update | Accepts same new fields |
| `GET /client-targets` | List | Returns updated `ClientTargetWithBalance` shape |
| `POST /client-targets/:id/corrections` | Add correction | No change to signature |
| `DELETE /client-targets/:id/corrections/:corrId` | Delete correction | No change |
### Zod schema changes
- `CreateClientTargetSchema` / `UpdateClientTargetSchema`:
- Add `periodType: z.enum(["weekly", "monthly"])`
- Add `workingDays: z.array(z.enum(["MON","TUE","WED","THU","FRI","SAT","SUN"])).min(1)`
- Rename `weeklyHours``targetHours`
- Remove Monday-only regex constraint from `startDate`
---
## 11. Frontend Changes
### Types (`frontend/src/types/index.ts`)
- `ClientTargetWithBalance` — add `periodType`, `workingDays`, `targetHours`; replace `weeks``periods: PeriodBalance[]`; replace `currentWeek*``currentPeriod*`
- Add `PeriodBalance` interface
- `CreateClientTargetInput` / `UpdateClientTargetInput` — same field additions
### Hook (`frontend/src/hooks/useClientTargets.ts`)
- No structural changes; mutations pass through new fields
### API client (`frontend/src/api/clientTargets.ts`)
- No structural changes; payload shapes updated
### `ClientsPage` — `ClientTargetPanel`
- Working day selector (checkboxes: MonSun, at least one required)
- Period type selector (Weekly / Monthly)
- Label for hours input updates dynamically: "Hours/week" or "Hours/month"
- Start date picker: free date input (no week-picker)
- Balance display: label changes from "this week" to "this week" or "this month" based on `periodType`
- Expanded period list replaces the expanded week list
### `DashboardPage`
- "Weekly Targets" widget renamed to "Targets"
- "This week" label becomes "This week" / "This month" dynamically
- `currentWeek*` fields replaced with `currentPeriod*`

View File

@@ -1,128 +0,0 @@
# iOS Authentication & Backend Communication Architecture
## Overview
This document outlines the authentication mechanism and backend communication protocol used by the iOS application. The architecture relies on an API-driven approach where the backend acts as an intermediary (BFF - Backend for Frontend) for an OIDC identity provider. Notably, the backend manages the PKCE (Proof Key for Code Exchange) generation and verification internally, simplifying the mobile client's responsibilities.
## 1. Authentication Flow
The authentication process utilizes `ASWebAuthenticationSession` for a secure, out-of-app browser experience.
### Step 1: Login Initiation
The application initiates the login sequence by launching an ephemeral web session targeting the backend's login endpoint.
* **URL:** `[API_BASE_URL]/auth/login`
* **Query Parameters:**
* `redirect_uri`: `timetracker://oauth/callback`
* **Behavior:** The backend generates PKCE parameters, stores them in an in-memory session tied to a `state` parameter, and redirects the user to the actual Identity Provider (IdP).
### Step 2: User Authentication
The user completes the authentication flow (e.g., entering credentials, 2FA) within the secure web view.
### Step 3: Callback
Upon successful authentication, the backend redirects the browser back to the application using a custom URL scheme.
* **Callback URL:** `timetracker://oauth/callback?code=[auth_code]&state=[state]`
* **Action:** The application intercepts this URL, extracts the `code` and `state` parameters.
### Step 4: Token Exchange
The application immediately exchanges the received code and state for a JWT access token via a backend API call.
* **Endpoint:** `POST /auth/token`
* **Headers:** `Content-Type: application/json`
* **Body (JSON):**
```json
{
"code": "<auth_code>",
"state": "<state>",
"redirect_uri": "timetracker://oauth/callback"
}
```
* **Note:** The `code_verifier` is **not** sent by the client. The backend retrieves the verifier using the `state` parameter from its internal session cache.
* **Success Response:** Returns a `TokenResponse` containing the `access_token` and the `User` object.
## 2. API Communication
All subsequent communication with the backend requires the obtained JWT access token.
### Base Configuration
* **Base URL:** Determined via the `API_BASE_URL` key in `Info.plist`. Defaults to `http://localhost:3001` if missing.
* **Path Resolution:** API paths are appended to the Base URL (e.g., `/clients`, `/time-entries`).
### Standard Request Headers
For authenticated endpoints, the following headers **must** be included:
```http
Authorization: Bearer <access_token>
Content-Type: application/json
Accept: application/json
```
### Response & Error Handling
* **Success (200-299):** Parses the JSON response into the expected model. Empty responses (`Data.isEmpty`) should be handled gracefully (e.g., mapping to a dummy `{}` object or allowing `Void` returns).
* **Unauthorized (401):**
* The access token has expired or is invalid.
* **Action:** The application must immediately clear the local session (keychain, user state) and present the login screen.
* **Standard Errors (400, 500, etc.):**
* The backend typically returns a JSON payload containing an `error` string.
* **Format:** `{"error": "Message detailing the failure"}`
## 3. Storage & Session Management
Security and seamless user experience dictate how the session is managed across app launches.
### Token Storage
* The `access_token` must be stored securely using the **iOS Keychain**.
* **Service Name:** `com.timetracker.app`
* **Key:** `accessToken`
* **Accessibility:** `.whenUnlockedThisDeviceOnly` (prevents extraction when the device is locked and disables iCloud Keychain syncing).
* **In-Memory Cache:** The token is also cached in-memory during the app's lifecycle to minimize Keychain read operations.
### Session Restoration (App Launch)
When the application starts:
1. Read the `accessToken` from the Keychain.
2. If present, make a verification request to `GET /auth/me`.
3. **If `GET /auth/me` succeeds:** Update the local `User` state and transition to the authenticated interface.
4. **If `GET /auth/me` fails (especially 401):** Clear the Keychain and transition to the unauthenticated login interface.
### Logout
When the user explicitly logs out:
1. Send a best-effort `POST /auth/logout` request to the backend.
2. Immediately delete the `accessToken` from the Keychain.
3. Clear the in-memory `User` and token state.
4. Return to the login screen.
## 4. Core Data Models
### Token Response
```json
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"user": { ... }
}
```
### User Model
```json
{
"id": "uuid-string",
"username": "johndoe",
"fullName": "John Doe", // Optional/Nullable
"email": "john@example.com"
}
```
## 5. Reimplementation Requirements List
When rebuilding the iOS application, the following requirements **must** be met to ensure compatibility with the existing backend:
- [ ] **R1. Custom Scheme Configuration:** Register `timetracker://` as a custom URL scheme in the project settings (Info.plist) to handle OAuth redirects.
- [ ] **R2. Ephemeral Web Sessions:** Use `ASWebAuthenticationSession` with `prefersEphemeralWebBrowserSession = true` to prevent Safari from sharing cookies with the app's login flow.
- [ ] **R3. Login Initiation:** The login URL must strictly be `[API_BASE_URL]/auth/login?redirect_uri=timetracker://oauth/callback`.
- [ ] **R4. Token Exchange Parameters:** The callback payload to `POST /auth/token` must include `code`, `state`, and `redirect_uri`. Do not attempt to implement local PKCE generation.
- [ ] **R5. Secure Storage:** The JWT access token must be stored exclusively in the Keychain using the `.whenUnlockedThisDeviceOnly` accessibility level.
- [ ] **R6. Authorization Header:** Every authenticated API request must include the `Authorization: Bearer <token>` header.
- [ ] **R7. Global 401 Interceptor:** Implement a global network interceptor or centralized error handler that catches `401 Unauthorized` responses, clears local storage, and forces a logout.
- [ ] **R8. Session Verification:** On application launch, if a token exists in the Keychain, the app must validate it by calling `GET /auth/me` before allowing access to secure screens.
- [ ] **R9. Error Parsing:** API error responses must be parsed to extract the `{"error": "..."}` message for user-facing alerts.

View File

@@ -40,16 +40,22 @@ A multi-user web application for tracking time spent working on projects. Users
| **Project** | A project belonging to a client | User, belongs to one Client | | **Project** | A project belonging to a client | User, belongs to one Client |
| **TimeEntry** | A completed time tracking record | User (explicit), belongs to one Project | | **TimeEntry** | A completed time tracking record | User (explicit), belongs to one Project |
| **OngoingTimer** | An active timer while tracking is in progress | User (explicit), belongs to one Project (optional) | | **OngoingTimer** | An active timer while tracking is in progress | User (explicit), belongs to one Project (optional) |
| **ClientTarget** | Hourly target for a client per period | User, belongs to one Client |
| **BalanceCorrection** | Manual hour adjustment for a target | Belongs to one ClientTarget |
| **ApiKey** | API key for external tool access | User |
### Relationships ### Relationships
``` ```
User User
├── Client (one-to-many) ├── Client (one-to-many)
── Project (one-to-many) ── Project (one-to-many)
└── TimeEntry (one-to-many, explicit user reference) └── TimeEntry (one-to-many, explicit user reference)
│ └── ClientTarget (one-to-one per client)
│ └── BalanceCorrection (one-to-many)
── OngoingTimer (zero-or-one, explicit user reference) ── OngoingTimer (zero-or-one, explicit user reference)
└── ApiKey (one-to-many)
``` ```
**Important**: Both `TimeEntry` and `OngoingTimer` have explicit references to the user who created them. This is distinct from the project's ownership and is required for future extensibility (see Future Extensibility section). **Important**: Both `TimeEntry` and `OngoingTimer` have explicit references to the user who created them. This is distinct from the project's ownership and is required for future extensibility (see Future Extensibility section).
@@ -127,10 +133,72 @@ User
- Start time - Start time
- End time - End time
- Project - Project
- Optional fields:
- Break minutes (deducted from total duration)
- Description (notes about the work)
- The entry is validated against overlap rules before saving - The entry is validated against overlap rules before saving
--- ---
### 6. Statistics
- User can view aggregated time tracking statistics
- Filters available:
- Date range (start/end)
- Client
- Project
- Statistics display:
- Total working time
- Entry count
- Breakdown by project (with color indicators)
- Breakdown by client
---
### 7. Client Targets
- User can set hourly targets per client
- Target configuration:
- Target hours per period
- Period type (weekly or monthly)
- Working days (e.g., MON-FRI)
- Start date
- Balance tracking:
- Shows current balance vs target
- Supports manual corrections (e.g., holidays, overtime carry-over)
- Only one target per client allowed
---
### 8. API Keys
- User can generate API keys for external tool access
- API key properties:
- Name (for identification)
- Prefix (first characters shown for identification)
- Last used timestamp
- Security:
- Raw key shown only once at creation
- Key is hashed (SHA-256) before storage
- Keys can be revoked (deleted)
---
### 9. MCP Integration
- Model Context Protocol endpoint for AI agent access
- Stateless operation (no session persistence)
- Tools exposed:
- Client CRUD operations
- Project CRUD operations
- Time entry CRUD operations
- Timer start/stop/cancel
- Client target management
- Statistics queries
- Authentication via API keys
---
## API Endpoints (Suggested) ## API Endpoints (Suggested)
### Authentication ### Authentication
@@ -165,8 +233,29 @@ User
- `POST /api/timer/start` — Start timer (creates OngoingTimer) - `POST /api/timer/start` — Start timer (creates OngoingTimer)
- `PUT /api/timer` — Update ongoing timer (e.g., set project) - `PUT /api/timer` — Update ongoing timer (e.g., set project)
- `POST /api/timer/stop` — Stop timer (converts to TimeEntry) - `POST /api/timer/stop` — Stop timer (converts to TimeEntry)
- `POST /api/timer/cancel` — Cancel timer without saving
- `GET /api/timer` — Get current ongoing timer (if any) - `GET /api/timer` — Get current ongoing timer (if any)
### Client Targets
- `GET /api/client-targets` — List targets with computed balance
- `POST /api/client-targets` — Create a target
- `PUT /api/client-targets/{id}` — Update a target
- `DELETE /api/client-targets/{id}` — Delete a target
- `POST /api/client-targets/{id}/corrections` — Add a correction
- `DELETE /api/client-targets/{id}/corrections/{correctionId}` — Delete a correction
### API Keys
- `GET /api/api-keys` — List user's API keys
- `POST /api/api-keys` — Create a new API key
- `DELETE /api/api-keys/{id}` — Revoke an API key
### MCP (Model Context Protocol)
- `GET /mcp` — SSE stream for server-initiated messages
- `POST /mcp` — JSON-RPC requests (tool invocations)
--- ---
## UI Requirements ## UI Requirements
@@ -183,6 +272,9 @@ User
- **Dashboard**: Overview with active timer widget and recent entries - **Dashboard**: Overview with active timer widget and recent entries
- **Time Entries**: List/calendar view of all entries with filters (date range, client, project) - **Time Entries**: List/calendar view of all entries with filters (date range, client, project)
- **Clients & Projects**: Management interface for clients and projects - **Clients & Projects**: Management interface for clients and projects
- **Statistics**: Aggregated time data with filters and breakdowns
- **API Keys**: Create and manage API keys for external access
- **Client Targets**: Set and monitor hourly targets per client
--- ---