# Backend and Data Flow

## Overview

The backend integration is intentionally split into three stages:

1. transport and DTOs in `thulur_api`
2. mapping and orchestration in `RemoteThulurApiRepository`
3. UI-facing use cases and ViewModels in `domain` and `presentation`

This keeps HTTP details out of the feature layer while still avoiding a large, abstract service architecture.

## Request pipeline

```mermaid
sequenceDiagram
    participant UI as Screen / ViewModel
    participant UC as Domain use case
    participant Repo as RemoteThulurApiRepository
    participant API as ThulurApi
    participant Method as Specific method class
    participant BE as Thulur backend

    UI->>UC: invoke use case
    UC->>Repo: call repository function
    Repo->>API: request raw DTOs
    API->>Method: execute HTTP method
    Method->>BE: HTTP request
    BE-->>Method: JSON response
    Method-->>API: DTO
    API-->>Repo: DTO
    Repo-->>UC: domain model
    UC-->>UI: result
```

## Transport layer

### Main files

- `thulur_api/ThulurApi.kt`
- `thulur_api/client/ThulurHttpClientFactory.kt`
- `thulur_api/config/ThulurApiConfig.kt`
- `thulur_api/methods/*`
- `thulur_api/dtos/*`

### `ThulurApi`

`ThulurApi` is the single public facade used by the rest of the application for backend access.

It currently exposes methods for:

- desktop auth start and code exchange
- daily feed
- article paragraphs and rating
- settings read and patch
- followed feeds and full feed catalog
- current user
- auth sessions and termination
- thread history
- general chat
- thread chat

### HTTP client behavior

The Ktor client is configured to:

- expect successful responses
- attach `Authorization: Bearer <token>` when a session token exists
- clear the current session on `401 Unauthorized`
- ignore unknown JSON keys
- omit explicit nulls in JSON serialization

Timeouts:

- default request timeout: `15s`
- chat request timeout: `60s`

## Method organization

Each backend capability lives in a dedicated method file. This keeps request paths, parameters, and HTTP verbs localized.

Examples:

- `methods/daily_feed/DailyFeedMethod.kt`
- `methods/chat/GeneralChatMethod.kt`
- `methods/chat/ThreadChatMethod.kt`
- `methods/auth/DesktopAuthStartMethod.kt`
- `methods/auth/DesktopAuthExchangeMethod.kt`
- `methods/settings/GetSettingsMethod.kt`
- `methods/settings/PatchSettingsMethod.kt`

## Repository layer

### Main file

- `data/repository/RemoteThulurApiRepository.kt`

### Responsibilities

The repository translates raw DTOs into domain models used by ViewModels and screens.

Important mapping behavior:

- maps feed, thread, article, user, settings, session, and chat DTOs into domain models
- merges backend `isRead` values with the local read-article cache
- maps quality-tier strings into `ArticleQuality`
- treats the sentinel date `9999-12-31` as "not shown" for daily-feed first-seen dates
- converts patch operations from domain settings models into DTO payloads

## Session and authorization flow

### Session sources

The HTTP client does not own session state directly. It reads the current token from `CurrentSessionProvider`.

### Session invalidation

If any request returns `401 Unauthorized`, the client calls the `onUnauthorized` callback supplied by DI. In this project that callback clears the current session.

That means a transport-level auth failure eventually pushes the app back to the unauthenticated flow through root state.

## Read article state flow

The app combines backend data with a local in-memory cache for read state.

### Why this exists

The article reader can optimistically mark an article as read locally after a successful rating submission, even before the next backend feed fetch reflects that change.

### Where it happens

- cache implementation: `data/session/InMemoryReadArticlesCache.kt`
- repository merge: `RemoteThulurApiRepository.kt`
- feed/history observers: `DailyFeedViewModel.kt`, `ThreadHistoryViewModel.kt`

## Data flow by feature

## Daily feed

Flow:

1. `DailyFeedViewModel` calls `GetDailyFeedUseCase`
2. use case calls `RemoteThulurApiRepository.getDailyFeed`
3. repository calls `ThulurApi.getDailyFeed`
4. `DailyFeedMethod` performs `GET /users/me/daily_feed`
5. repository maps DTOs into `DailyFeed` and `DailyFeedThread`
6. ViewModel turns the result into UI content state

## Chat

Flow:

1. `ChatViewModel` selects general or thread mode
2. matching use case calls repository
3. repository calls `ThulurApi.sendGeneralChatMessage` or `sendThreadChatMessage`
4. method performs the POST request with chat timeout override
5. response is mapped into `ChatReply`
6. ViewModel transforms it into assistant UI messages

## Settings patch

Flow:

1. `SettingsViewModel` applies optimistic local state
2. `PatchUserSettingsUseCase` calls repository
3. repository maps `PatchUserSettings` into `UpdateUserSettingsDto`
4. `PatchSettingsMethod` sends the patch request
5. response is mapped back into `UserSettings`
6. ViewModel merges confirmed values with any other still-pending fields

## Desktop auth

```mermaid
sequenceDiagram
    participant User
    participant App as Desktop app
    participant Browser
    participant API as Thulur backend
    participant Callback as Local callback server

    User->>App: Submit email
    App->>API: POST /auth/desktop/start
    API-->>App: browserUrl
    App->>Browser: Open browserUrl
    Browser->>API: Complete passkey flow
    API->>Callback: Redirect to local callback URL
    Callback-->>App: code + state
    App->>API: POST /auth/exchange
    API-->>App: bearer token
```

## Where to make changes

### New backend endpoint

Add or update:

1. DTOs in `thulur_api/dtos`
2. a method in `thulur_api/methods`
3. `ThulurApi` interface and implementation
4. repository mapping
5. domain models or use cases if needed
6. ViewModel/screen usage

### Backend response shape changed

Start here:

1. DTO definition
2. repository mapping
3. any downstream UI assumptions

### Auth/token behavior changed

Open:

- `ThulurHttpClientFactory.kt`
- `CurrentSessionProviderImpl.kt`
- `BrowserPasskeyAuthenticator.jvm.kt`
- `AppRootScreenModel.kt`
