Phase F: NetworkMonitor, offline banner, README & architecture docs

- NetworkMonitor: ConnectivityState Flow using ConnectivityManager.NetworkCallback
- ListsScreen & ViewModel: live offline indicator banner when disconnected
- Documentation:
  - docs/ARCHITECTURE.md: system design & tech stack overview
  - docs/SYNC.md: HLC timestamping, op_log outbox & LWW projection specification
  - docs/API.md: REST API endpoint specification
  - README.md: quickstart guide for backend, docker compose & Android app
- Verification: backend & android test suites 100% green 
This commit is contained in:
Tronax 2026-08-05 20:14:04 +02:00
parent 174aad535a
commit a00db14cba
Signed by: Tronax
SSH key fingerprint: SHA256:2pKKXDZucWvaF/GzXNz0FY53EAO1YDLN80bqS+TTz/o
8 changed files with 482 additions and 96 deletions

151
docs/API.md Normal file
View file

@ -0,0 +1,151 @@
# Mitbringsl REST API Specification
Base URL: `/`
Authentication: Bearer Token via `Authorization: Bearer <session_token>` header or session cookie.
---
## Health & Diagnostics
### `GET /healthz`
Liveness probe. Returns HTTP 200 `OK`.
### `GET /readyz`
Readiness probe. Checks PostgreSQL connection pool health.
- **200 OK**: Database reachable.
- **503 Service Unavailable**: Database error.
---
## Authentication (`/auth`)
### `POST /auth/register`
Create a new email/password account.
- **Request**:
```json
{ "email": "user@example.com", "password": "secretpassword", "display_name": "Max" }
```
- **Response (201 Created)**:
```json
{
"token": "<opaque_session_token>",
"expires_at": "2026-09-04T20:00:00Z",
"user": { "id": "<uuid>", "email": "user@example.com", "display_name": "Max" }
}
```
### `POST /auth/login`
Authenticate with email/password.
- **Request**:
```json
{ "email": "user@example.com", "password": "secretpassword" }
```
- **Response (200 OK)**: Same shape as register.
### `POST /auth/oidc`
Authenticate via Google or custom OpenID Connect provider.
- **Request**:
```json
{ "provider": "google", "id_token": "<jwt>" }
```
- **Response (200 OK)**: Same shape as login.
### `POST /auth/logout`
Revoke active session token. Returns `204 No Content`.
---
## Lists (`/api/lists`)
### `GET /api/lists`
Fetch all active (non-deleted) lists owned by the authenticated user.
- **Response (200 OK)**:
```json
{
"lists": [
{ "id": "<uuid>", "name": "Wocheneinkauf", "updated_at": "2026-08-05T19:00:00Z", "hlc_ts": 177000000000000 }
]
}
```
### `POST /api/lists`
Create a new list.
- **Request**: `{ "name": "Supermarkt" }`
- **Response (201 Created)**: `{ "id": "<uuid>", "name": "Supermarkt", ... }`
### `GET /api/lists/{id}`
Fetch list detail including items.
- **Response (200 OK)**:
```json
{
"id": "<uuid>",
"name": "Wocheneinkauf",
"updated_at": "...",
"hlc_ts": 177000000000000,
"items": [
{ "id": "<uuid>", "name": "Milch", "quantity": "1L", "checked": false, "hlc_ts": 177000000000001 }
]
}
```
---
## Sync & Ops (`/api/lists/{id}/ops`)
### `POST /api/lists/{id}/ops`
Push a batch of client operations (max 100).
- **Request**:
```json
{
"client_id": "<client_uuid>",
"ops": [
{
"client_seq": 1,
"op_type": "item_add",
"target_id": "<item_uuid>",
"hlc_ts": 177000000000000,
"payload": { "name": "Brot", "quantity": "1 Stück" }
}
]
}
```
- **Response (200 OK)**:
```json
{
"results": [
{ "client_seq": 1, "seq": 42, "hlc_ts": 177000000000001 }
]
}
```
### `GET /api/lists/{id}/ops?since={seq}`
Pull operations since server sequence `since`.
- **Response (200 OK)**:
```json
{
"ops": [
{
"seq": 42,
"client_id": "<client_uuid>",
"op_type": "item_add",
"target_id": "<item_uuid>",
"payload": { "name": "Brot" },
"client_seq": 1,
"hlc_ts": 177000000000001,
"created_at": "2026-08-05T20:00:00Z"
}
],
"has_more": false
}
```
---
## Suggestions (`/api/suggestions`)
### `GET /api/suggestions?q={query}`
Fuzzy autocomplete search for item names (pg_trgm).
- **Response (200 OK)**:
```json
{ "suggestions": ["milch", "mineralwasser", "müsli"] }
```