From 8eddbed00bf45d122b8bcb4410052e0101c0d68f Mon Sep 17 00:00:00 2001 From: "simon.franken" Date: Thu, 26 Mar 2026 09:17:41 +0100 Subject: [PATCH] update docs --- AGENTS.md | 68 +++++- DOCS.md | 32 +++ README.md | 25 +++ docs/client-targets-v2-requirements.md | 285 ------------------------- docs/ios-authentication.md | 128 ----------- project.md | 98 ++++++++- 6 files changed, 217 insertions(+), 419 deletions(-) create mode 100644 DOCS.md delete mode 100644 docs/client-targets-v2-requirements.md delete mode 100644 docs/ios-authentication.md diff --git a/AGENTS.md b/AGENTS.md index 6a3b3f5..b28a3ea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # 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 @@ -18,17 +18,79 @@ This document describes the structure, conventions, and commands for the `vibe_c ├── backend/ # Express REST API (TypeScript + Prisma + PostgreSQL) │ └── src/ │ ├── auth/ # OIDC + JWT logic +│ ├── config/ # Configuration constants │ ├── errors/ # AppError subclasses │ ├── middleware/# Express middlewares │ ├── prisma/ # Prisma client singleton │ ├── routes/ # Express routers (xxx.routes.ts) │ ├── 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) -├── timetracker-chart/ # Helm chart for Kubernetes deployment +├── helm/ # Helm chart for Kubernetes deployment └── 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 ### Frontend (`frontend/`) diff --git a/DOCS.md b/DOCS.md new file mode 100644 index 0000000..b0202d6 --- /dev/null +++ b/DOCS.md @@ -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 diff --git a/README.md b/README.md index a902ad5..38cfb24 100644 --- a/README.md +++ b/README.md @@ -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 - **Manual Entry** - Add time entries manually for past work - **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 ## Architecture @@ -125,6 +129,27 @@ APP_URL="http://localhost:5173" - `POST /api/timer/start` - Start timer - `PUT /api/timer` - Update timer (set project) - `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 diff --git a/docs/client-targets-v2-requirements.md b/docs/client-targets-v2-requirements.md deleted file mode 100644 index ab15d56..0000000 --- a/docs/client-targets-v2-requirements.md +++ /dev/null @@ -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 (Wed–Sun)`, `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: Mon–Sun, 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*` diff --git a/docs/ios-authentication.md b/docs/ios-authentication.md deleted file mode 100644 index a3b8983..0000000 --- a/docs/ios-authentication.md +++ /dev/null @@ -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": "", - "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 -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 ` 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. \ No newline at end of file diff --git a/project.md b/project.md index 01514c5..d6cc496 100644 --- a/project.md +++ b/project.md @@ -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 | | **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) | +| **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 ``` User ├── Client (one-to-many) - │ └── Project (one-to-many) - │ └── TimeEntry (one-to-many, explicit user reference) + │ ├── Project (one-to-many) + │ │ └── 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). @@ -127,10 +133,72 @@ User - Start time - End time - Project +- Optional fields: + - Break minutes (deducted from total duration) + - Description (notes about the work) - 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) ### Authentication @@ -165,8 +233,29 @@ User - `POST /api/timer/start` — Start timer (creates OngoingTimer) - `PUT /api/timer` — Update ongoing timer (e.g., set project) - `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) +### 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 @@ -183,6 +272,9 @@ User - **Dashboard**: Overview with active timer widget and recent entries - **Time Entries**: List/calendar view of all entries with filters (date range, client, project) - **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 ---