Docs: catch up to auth discovery, settings screen and sync fixes

Document the four features that landed on main in b44bc8c..85c790e:

- AGENTS.md: post-MVP section now covers server-driven auth discovery
  (GET /api/config, AUTH_PASSWORD_ENABLED 403 enforcement,
  OIDC_GENERIC_DISPLAY_NAME), the settings screen with GET/PUT /api/me,
  and the critical Android sync/data-safety fixes (pull-all-lists,
  client HLC tick per server op, no destructive migration, ProGuard
  rules). Repo structure updated (httpapi config.go/me.go, ui/settings),
  roadmap entries added, open-points list extended with test backlog for
  the new endpoints.
- API.md: new sections for GET /api/config (public) and GET/PUT /api/me;
  403 responses documented for register/login when password auth is off.
- SYNC.md: client pull loop (every tracked list, op_log pruning) and the
  client HLC discipline (tick per incoming server op) that keeps LWW
  correct across devices with skewed clocks.
- README: highlights for auth discovery/OIDC-only mode and the settings
  screen.
This commit is contained in:
Tronax 2026-08-22 09:45:45 +02:00
parent 67033e561c
commit cdc0c785b9
Signed by: Tronax
SSH key fingerprint: SHA256:2pKKXDZucWvaF/GzXNz0FY53EAO1YDLN80bqS+TTz/o
4 changed files with 100 additions and 9 deletions

View file

@ -33,6 +33,8 @@ Create a new email/password account.
"user": { "id": "<uuid>", "email": "user@example.com", "display_name": "Max" }
}
```
- **403 Forbidden**: The server runs with `AUTH_PASSWORD_ENABLED=false`
(OIDC-only); use `POST /auth/oidc` instead. Check `GET /api/config` first.
### `POST /auth/login`
Authenticate with email/password.
@ -41,6 +43,7 @@ Authenticate with email/password.
{ "email": "user@example.com", "password": "secretpassword" }
```
- **Response (200 OK)**: Same shape as register.
- **403 Forbidden**: Password login disabled (see register).
### `POST /auth/oidc`
Authenticate via Google or custom OpenID Connect provider.
@ -55,6 +58,45 @@ Revoke active session token. Returns `204 No Content`.
---
## Server Config (`/api/config`)
### `GET /api/config`
Public (no auth). Returns the auth methods this server offers so the app can
render the right login form before connecting. Driven by `AUTH_PASSWORD_ENABLED`
and the `OIDC_*` env vars; `display_name` for the generic provider comes from
`OIDC_GENERIC_DISPLAY_NAME` (e.g. "Authentik", "Keycloak").
- **Response (200 OK)**:
```json
{
"auth": {
"password_enabled": true,
"oidc": {
"google": { "enabled": false, "display_name": "Google" },
"generic": { "enabled": true, "issuer": "https://idp.example.com", "display_name": "Authentik" }
}
}
}
```
---
## Profile (`/api/me`)
### `GET /api/me`
Returns the authenticated user's own profile.
- **Response (200 OK)**:
```json
{ "id": "<uuid>", "email": "user@example.com", "display_name": "Max" }
```
### `PUT /api/me`
Updates editable profile fields (currently `display_name`).
- **Request**: `{ "display_name": "Max Mustermann" }`
- Omitted field → unchanged; empty string `""` → clears the field.
- **Response (200 OK)**: the updated profile (same shape as GET).
---
## Lists (`/api/lists`)
All list endpoints return `404 Not Found` when the authenticated user is neither

View file

@ -56,6 +56,17 @@ All state modifications are represented as structured operations:
Each operation carries a `(client_id, client_seq)` tuple enforced by a `UNIQUE` constraint in Postgres (`op_log`). Re-sent requests return previous `(seq, hlc_ts)` assignments without duplicating side effects.
- **Cursor Pull (`GET /api/lists/{id}/ops?since={seq}`)**:
Clients track `max(server_seq)` locally. Incremental sync fetches ops where `seq > cursor`, sorted by monotonic server sequence `seq ASC`.
- **Client pull loop**:
The `SyncWorker` pulls for **every** tracked list on each run (not only lists with pending outbox ops), so remote edits on "quiet" (e.g. shared/joined) lists arrive reliably. Old synced `op_log` rows are pruned locally to bound growth.
### Client HLC discipline
On every incoming server op the client advances its local HLC with
`tick(op.hlc_ts)`. This is essential for LWW correctness across devices with
skewed clocks: without it, a fast-clock device would permanently win conflicts
while a slow-clock device's own edits would be silently rejected by the
`hlc_ts <` projection guard. The same rule applies on the server (`opstore`
ticks the server HLC per incoming op).
---