Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions KLEER_LEARNINGS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Learnings — Kleer Cutover

Living document for durable discoveries, constraints, and implementation guidance during the Kleer migration.

---

## Product And Scope Decisions

- Milltime is being fully removed. There is no backward-compatibility period and no dual-provider support in this branch.
- Toki remains a project-based work logging UI in the first Kleer release.
- Kleer events without `client-project` exist, but they will be skipped rather than modeled in Toki.
- The old `AttestLevel(None/Week/Month)` model is being replaced with a direct status model:
- `open`
- `approved`
- `certified`
- Weekly stats stay, but flex/komptid is removed until a documented balance endpoint is confirmed.

## Codebase Patterns To Reuse

### Backend

- The time-tracking backend already uses the right architecture for this cutover:
- domain models and ports in `toki-api/src/domain/`
- provider adapter in `toki-api/src/adapters/outbound/`
- per-request service creation in `toki-api/src/factory.rs`
- The composition root is the only place that should know about concrete provider types.
- Timer history storage stays local and should not be redesigned for this migration.
- The current time-tracking flow is the reference for request-scoped service creation, but all Milltime-specific auth, cookies, and encryption should be deleted.

### Frontend

- Time tracking state currently assumes cookie-backed provider auth and provider-specific copy.
- Query and mutation types live in:
- `app/src/lib/api/queries/time-tracking.ts`
- `app/src/lib/api/mutations/time-tracking.ts`
- The status model is used in multiple time-tracking UI components, not just the API types. Expect coordinated changes in:
- list view
- timeline view
- lock warnings
- stats

## Kleer API Findings

### Authentication

- Kleer authentication is token-based and per-request.
- There is no session concept in the API docs.
- Preferred auth transport is the `X-token` header.
- Credentials needed by Toki:
- `token`
- `companyId`
- optional `baseUrl` for test environment support

### Environments

- Production API base URL: `https://api.kleer.se/v1`
- Test API base URL: `https://test-api.kleer.se/v1`
- The docs state the same token/login can be used in both environments.

### Confirmed Time-Tracking Endpoints

- `GET /v1/company/{companyId}/user/me`
- `GET /v1/company/{companyId}/client-project?filter=active`
- `GET /v1/company/{companyId}/activity`
- `PUT /v1/company/{companyId}/event`
- `GET /v1/company/{companyId}/event`
- `GET /v1/company/{companyId}/event/{eventId}`
- `POST /v1/company/{companyId}/event/{eventId}`
- `DELETE /v1/company/{companyId}/event/{eventId}`
- `GET /v1/company/{companyId}/event/statuses`

### Confirmed Payroll Endpoint For Weekly Stats

- `GET /v1/company/{companyId}/payroll/user/{userId}/schedule/{startDate}/to/{endDate}`
- This returns `payroll-user-schedule-metadatas` entries with:
- `date`
- `level-of-employment`
- `gross-hours`
- `net-hours`
- `actual-hours`
- Use `net-hours` as the scheduled-hours source for Toki weekly stats.

### Event Model Findings

- `event-writable` in the XSD includes:
- `foreign-id`
- `user`
- `activity`
- optional `client-project`
- optional `child`
- `date`
- `hours`
- `comment`
- optional `internal-comment`
- `client-project` is optional. This is why projectless events must be explicitly handled.
- The documented event statuses are already the right product concept:
- `Open`
- `Approved`
- `Certified`

### Project And Activity Restrictions

- Kleer projects can restrict activities at the project level.
- Projects can also define user-specific allowed activities.
- Toki activity loading should not just return all activities for every project; it should respect those project restrictions.

## Migration-Specific Guidance

- Use JSON only. Do not add XML support in Toki.
- Keep provider response/request structs in the `kleer/` crate, not in domain code.
- Prefer direct status handling end-to-end:
- backend domain field `status`
- frontend field `status`
- API values `open | approved | certified`
- Do not synthesize flex/komptid from worked minus scheduled hours.
- Do not keep the Milltime route semantics if they only existed to work around Milltime behavior. Example: edit flows can update the same Kleer event id directly.

## Relevant Repo Touchpoints

### Backend

- `toki-api/src/factory.rs`
- `toki-api/src/router.rs`
- `toki-api/src/main.rs`
- `toki-api/src/domain/models/timer.rs`
- `toki-api/src/domain/ports/outbound/time_tracking.rs`
- `toki-api/src/domain/services/time_tracking.rs`
- `toki-api/src/adapters/inbound/http/time_tracking.rs`
- `toki-api/src/adapters/inbound/http/responses.rs`
- `toki-api/src/routes/time_tracking/authenticate.rs`
- `toki-api/src/routes/time_tracking/calendar.rs`

### Frontend

- `app/src/lib/api/queries/time-tracking.ts`
- `app/src/lib/api/mutations/time-tracking.ts`
- `app/src/hooks/useTimeTrackingStore.tsx`
- `app/src/hooks/useTimeTrackingData.tsx`
- `app/src/routes/_layout/time-tracking/index.tsx`
- `app/src/routes/_layout/time-tracking/-components/time-entries-list.tsx`
- `app/src/routes/_layout/time-tracking/-components/timeline-view.tsx`
- `app/src/routes/_layout/time-tracking/-components/not-locked-alert.tsx`
- `app/src/routes/_layout/time-tracking/-components/time-stats.tsx`

## Verification Commands

```bash
cargo check -p kleer
SQLX_OFFLINE=true just check
just tsc
just lint
just check-all
```

## Update Log

Add new durable learnings here as implementation progresses.
Loading