Files
mcp-familywall/SPEC.md
T
marcus 311f37d72b feat(lists): implement create_list + delete_list (v0.5.0)
Adds two new MCP tools:
- create_list(name, list_type, shared_to_all, color, emoji)
  POST taskcreatelist; returns full list object incl. metaId
- delete_list(list_id) – with canDelete safety guard
  POST taskdeletelist; param 'id' (same pattern as metadelete)

Both endpoints verified via FW_DEBUG=1 on 2026-04-16.
SPEC.md and CLAUDE.md updated with verified parameter names
and response structures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 12:26:16 +02:00

370 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Family Wall API Spezifikation
Erarbeitet durch Browser-Traffic-Analyse und React-Fiber-Analyse (April 2026).
Es gibt keine offizielle API-Dokumentation.
## Base URL
https://api.familywall.com/api
## Authentifizierung
### Login
POST https://api.familywall.com/api/log2in
Content-Type: application/x-www-form-urlencoded
**Request-Parameter:**
| Parameter | Wert |
|---|---|
| `identifier` | E-Mail-Adresse |
| `password` | Passwort |
| `type` | `"email"` (verifiziert) |
**Response (Erfolg):**
```json
{ "r": { "r": <SessionObject> } }
```
**Response (Fehler):**
```json
{ "ex": { "ex": <ErrorObject> } }
{ "un": { "un": <ErrorObject> } }
```
Der Server setzt nach erfolgreichem Login ein Session-Cookie:
`Set-Cookie: JSESSIONID=<session-id>`
### Folgecalls (nach Login)
| | |
|---|---|
| **Cookie** | `JSESSIONID=<session-id>` |
| **Header** | `Tokencsrf: <session-id>` (identisch zur JSESSIONID) |
| **Content-Type** | `application/x-www-form-urlencoded` |
### Logout
POST https://api.familywall.com/api/log2out
Keine Parameter. Session wird serverseitig invalidiert.
### Session-Strategie
Kein Session-Caching. Jeder MCP-Tool-Call führt folgende Sequenz aus:
```
POST /api/log2in → Session-ID
POST /api/<endpoint> → Nutzdaten (ggf. mehrere Calls in einer Session)
POST /api/log2out → Session invalidieren
```
Credentials (E-Mail + Passwort) werden einmalig via `mcp-familywall setup`
im OS Keyring gespeichert (Keys: `email`, `password`).
## Fehlerbehandlung
### Silent-Fail Warnung
Die API gibt Fehler manchmal NICHT auf Top-Level zurück, sondern eingebettet:
```json
{"a00": {"un": {"un": {"message": "missing value in: taskId"}}}}
```
`fw_client.py` prüft beide Ebenen (`a00.un.un` und Top-Level `ex`/`un`)
und wirft `FamilyWallError`. Nie eine Response als Erfolg werten ohne
beide Fehlerebenen zu prüfen.
### Sentinel-Wert `$empty`
Das FiZ-Server-Framework nutzt `$empty` als Sentinel-String um optionale
Felder zu löschen. Alle anderen Werte (`""`, `null`, `"null"`, `"0"`,
`"-1"`, `"remove"`, `"clear"`, Epoch-Timestamps) werden vom Server mit
`"is not a valid Date"` abgelehnt.
**Aktuell genutzt für:**
- `dueDate=$empty` → löscht Fälligkeitsdatum in `taskupdate2`
**Gefunden durch:** React-Fiber-Analyse des nativen `datetime-local`-Inputs
nach Klick auf "Löschen" im Custom-Datepicker wird der Input-Wert auf
`"$empty"` gesetzt, was beim Speichern an die API gesendet wird.
## Bekannte Endpoints
### `famlistfamily` Kreise + Mitglieder abrufen
POST https://api.familywall.com/api/famlistfamily
**Body-Parameter:** keine
**Response-Struktur:**
```
a00.r.r[] → Kreise
.metaId → Kreis-ID (z.B. "family/23431854")
.name → Kreis-Name
.members[] → Mitglieder des Kreises
.accountId → numerische User-ID
.firstName → Anzeigename (bevorzugen)
.name → E-Mail als Fallback
.role → Familienrolle (Parent/Child/Unknown)
.right → Berechtigung (SuperAdmin etc.)
.color → Profilfarbe (#RRGGBB)
.medias[0].pictureUrl → Avatar-URL
.identifiers[type=Email].value → E-Mail-Adresse
```
### `accgetallfamily` Listen, Tasks, Kategorien abrufen
POST https://api.familywall.com/api/accgetallfamily
**Body-Parameter:**
| Parameter | Wert |
|---|---|
| `a01call` | `"taskcategorysync"` |
| `a02call` | `"tasksync"` |
**Response-Struktur:**
```
a00.r.r[] → Kategorien (taskcategorysync)
.metaId → Kategorie-ID
.name → Kategoriename (Systembezeichnung)
.taskListType → SHOPPING_LIST oder TODOS
.sortingIndexByTaskList → Sortierreihenfolge pro Liste
.rights.canDelete → "true" = custom, null = System
.locale → Sprachcode (de/en/fr/...), fehlt bei custom
a02.r.r.updatedCreated[] → Tasks (tasksync)
.metaId → Task-ID
.text → Aufgabentext
.description → optionale Beschreibung
.taskListId → Listen-ID
.complete → "true" / "false" (String!)
.taskCategoryId → Kategorie-ID (optional)
.dueDate → Fälligkeitsdatum (ISO 8601, optional)
.assignee[] → Liste von Member-IDs (optional)
.assigneeIds[] → alternativ zu assignee[]
```
### `wallget` Wall-Aktivitäten abrufen
POST https://api.familywall.com/api/wallget
**Response-Struktur:**
```
a00.r.r[]
.metaId → Post-ID (z.B. "wall/23431854_31119189")
.type → STATUS, FAMILY_CREATED, etc.
.text → Post-Text
.modifDate → Timestamp (ISO 8601)
.creator.accountId → Author-ID
.moodMap → {"<accountId>": ["STAR"]} für Likes
.moodStarShortcut → true wenn geliked
.comments[] → Kommentare
```
### `taskcreate2` Task erstellen
POST https://api.familywall.com/api/taskcreate2
**Body-Parameter:**
| Parameter | Pflicht | Wert |
|---|---|---|
| `taskListId` | ja | Listen-metaId |
| `text` | ja | Aufgabentext |
| `description` | nein | Beschreibung |
| `taskCategoryId` | nein | Kategorie-metaId (vollständig, z.B. `taskCategory/23431854_200`) |
| `dueDate` | nein | ISO 8601 (z.B. `2026-04-30T18:00:00`) |
| `assignee` | nein | Member-accountId, mehrfach sendbar für mehrere Zuweisungen |
**Response:**
```
a00.r.r → vollständiges Task-Objekt
.metaId → neue Task-ID
```
### `taskupdate2` Task aktualisieren
POST https://api.familywall.com/api/taskupdate2
**Body-Parameter:**
| Parameter | Pflicht | Wert |
|---|---|---|
| `metaId` | ja | Task-metaId |
| `text` | nein | neuer Titel |
| `description` | nein | neue Beschreibung |
| `taskCategoryId` | nein | neue Kategorie-metaId |
| `dueDate` | nein | ISO 8601 oder `$empty` zum Löschen |
| `assignee` | nein | Member-accountId (mehrfach sendbar), `""` zum Entfernen aller |
| `taskListId` | nein | neue Listen-metaId (verschiebt Task) |
**Hinweis:** `taskListId` ist NICHT Pflicht beim Update.
**Response:**
```
a00.r.r → vollständiges Task-Objekt
```
### `taskmark` Task abhaken/wiedereröffnen
POST https://api.familywall.com/api/taskmark
**Body-Parameter:**
| Parameter | Wert |
|---|---|
| `taskId` | Task-metaId ⚠️ nicht `metaId`! |
| `complete` | `"true"` oder `"false"` (String!) |
**Response:**
```
a00.r.r → Task-Objekt mit lastAction: "MARK_COMPLETED"
```
### `metadelete` Task löschen
POST https://api.familywall.com/api/metadelete
**Body-Parameter:**
| Parameter | Wert |
|---|---|
| `id` | Task-metaId ⚠️ nicht `metaId`! |
**Response:**
```
a00.r.r → "true" (String)
```
### `wallmood` Post liken
POST https://api.familywall.com/api/wallmood
**Body-Parameter:**
| Parameter | Wert |
|---|---|
| `wall_message_id` | Post-metaId ⚠️ nicht `wallId` oder `id`! |
| `moodType` | `"STAR"` für Like |
**Bekannte Einschränkungen:**
- Unlike: Endpoint/Parameter unbekannt (Service Worker verschlüsselt Request-Body)
- Self-Like: API antwortet 200, macht aber serverseitig nichts
- `moodType="NONE"` und andere Werte haben keine Wirkung
**Response:**
```
a00.r.r → Wall-Objekt mit moodMap, refAction: "MOOD_STAR"
```
### `taskcategoryput` Kategorie erstellen/aktualisieren
POST https://api.familywall.com/api/taskcategoryput
**Body-Parameter:**
| Parameter | Pflicht | Wert |
|---|---|---|
| `name` | ja | Kategoriename |
| `emoji` | nein | Unicode-Emoji oder beliebiger String |
**Hinweis:** Kategorien sind family-wide `listId` hat keine Wirkung.
**Response:**
```
a00.r.r → Kategorie-Objekt mit metaId
```
### `taskcategorydelete` Kategorie löschen
POST https://api.familywall.com/api/taskcategorydelete
**Body-Parameter:**
| Parameter | Wert |
|---|---|
| `id` | Kategorie-metaId ⚠️ nicht `metaId`! |
**Hinweis:** System-Kategorien (`rights.canDelete=null`) können technisch
gelöscht werden, sind dann aber dauerhaft weg und nicht wiederherstellbar.
MCP-Server schützt dagegen durch Check auf `rights.canDelete`.
### `taskcreatelist` Liste erstellen
POST https://api.familywall.com/api/taskcreatelist
**Body-Parameter:**
| Parameter | Pflicht | Wert |
|---|---|---|
| `name` | ja | Listen-Name (max 200 Zeichen) |
| `taskListType` | ja | `"SHOPPING_LIST"` oder `"TODOS"` |
| `sharedToAll` | nein | `"true"` / `"false"` (default: `"true"`) |
| `color` | nein | Hex-Farbwert z.B. `"#4784EC"` |
| `emoji` | nein | Unicode-Emoji z.B. `"🛒"` |
**Response:**
```
a00.r.r → vollständiges Listen-Objekt
.metaId → neue Listen-ID (z.B. "taskList/23431854_29759623")
.name → Listen-Name
.taskListType → SHOPPING_LIST oder TODOS
.sharedToAll → "true" / "false"
.rights.canDelete → "true" (user-created lists)
```
**Verifiziert am:** 2026-04-16 via FW_DEBUG=1
### `taskdeletelist` Liste löschen
POST https://api.familywall.com/api/taskdeletelist
**Body-Parameter:**
| Parameter | Wert |
|---|---|
| `id` | Listen-metaId ⚠️ nicht `listId` oder `taskListId`! |
**Response:**
```
a00.r.r → "true" (String)
```
**Hinweis:** Löscht die Liste und alle enthaltenen Tasks unwiderruflich.
System-Listen (`rights.canDelete` fehlt oder `null`) sind nicht löschbar.
MCP-Server prüft dies vor dem Löschen via `taskgettasklists`.
**Verifiziert am:** 2026-04-16 via FW_DEBUG=1
### `taskgettasklists` Listen abrufen (alternativ)
POST https://api.familywall.com/api/taskgettasklists
Wird intern zur Verifikation von `taskListType` genutzt.
## Systembezeichnungen für Listen-Namen
| Systembezeichnung | Deutsch |
|---|---|
| `SYS-CAT-SHOPPINGLIST` | `Einkaufsliste` |
| `SYS-CAT-TODOLIST` | `Aufgaben` |
## Debug-Logging
Wenn die Umgebungsvariable `FW_DEBUG=1` gesetzt ist, loggt `fw_client.py`
vollständige Request-Bodies und Responses nach stderr.
**Wichtig:** Keine Secrets in Debug-Ausgaben (Passwort maskieren).
**Wann FW_DEBUG=1 nutzen:**
- Neue Endpoints verifizieren
- Parameter-Namen unbekannt
- Silent-Fail debuggen
- Service Worker blockiert Browser-DevTools
## Service Worker
Die Family Wall Web-App registriert einen Service Worker der bestimmte
HTTP-Requests abfängt und modifiziert bevor sie das Netzwerk erreichen.
Betroffen sind u.a. Unlike-Calls und möglicherweise andere schreibende
Operationen.
**Folge:** Browser-DevTools Network-Tab und JS-Interceptoren (XHR/Fetch)
zeigen nicht den echten Request-Body für diese Calls.
**Lösung:** `FW_DEBUG=1` auf MCP-Server-Seite zeigt was tatsächlich gesendet wird.
## Offene Punkte
- Unlike-Endpoint (Service Worker blockiert Analyse)
- Erinnerungen (reminder) nur Premium-Account
- Wiederholungen (repeat) nur Premium-Account
- Sortierung von Kategorien via API