Files
mcp-familywall/SPEC.md
T
marcus 6c955d67c8 fix: surface a00.un API errors + document dueDate-clearing limitation (v0.4.15)
- fw_client: detect nested a00.un errors (previously silent-failed as success)
- update_task: add clear_due_date=True parameter that returns a clear error
  explaining the Family Wall API cannot clear dueDate once set
- SPEC.md: document all tested clearing candidates and their API responses,
  add Fehlerstruktur-Varianten section
- Verified: dueDate cannot be removed via any form-encoded value; all invalid
  date strings are rejected via a00.un.un (silently swallowed before this fix)

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

546 lines
25 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 (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` | nicht senden — wird als `undefined` ignoriert (verifiziert per JS-Analyse) |
| `clientId` | weglassen |
| `clientSecret` | weglassen |
| `generateAutologinToken` | weglassen |
| `countryCode` | weglassen |
**Response (Erfolg):**
```json
{ "a00": { "r": { "r": <SessionObject> }, "cn": "log2in" } }
```
`SessionObject` enthält u.a. `tokenCsrf` und `webApiUrl`.
`tokenCsrf` ist die Session-ID identisch zur `JSESSIONID` im Cookie.
**Response (Fehler):**
```json
{ "ex": { "ex": <ErrorObject> } }
{ "un": { "un": <ErrorObject> } }
```
Der Server setzt nach erfolgreichem Login ein Session-Cookie:
Set-Cookie: JSESSIONID=<session-id> (= tokenCsrf)
### Folgecalls (nach Login)
Alle API-Calls nach dem Login benötigen:
| | |
|---|---|
| **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
Content-Type: application/x-www-form-urlencoded
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
POST /api/log2out → Session invalidieren
Credentials (E-Mail + Passwort) werden einmalig via `mcp-familywall setup`
im OS Keyring gespeichert (Keys: `email`, `password`). Kein Keyring-Eintrag
für `session_id`.
## Bekannte Endpoints
### `famlistfamily` Kreise abrufen
POST https://api.familywall.com/api/famlistfamily
Content-Type: application/x-www-form-urlencoded
**Body-Parameter:** keine (verifiziert)
**Response-Struktur (verifiziert):**
```
a00.r.r[] → Kreise
.metaId → eindeutige Kreis-ID (Format family/<id>)
.name → Kreisname
.family_id → numerische Kreis-ID
.members[] → Mitglieder des Kreises
.accountId → numerische Account-ID
.metaId → Mitglieds-ID (Format familymember/<accountId>_<familyId>)
.firstName → Vorname (Display-Name; bevorzugen gegenüber .name)
.name → E-Mail-Adresse (Family Wall Default wenn kein Anzeigename)
.role → Familienrolle (z.B. "Unknown", "Parent", "Child")
.right → Berechtigung (z.B. "SuperAdmin", "Admin", "Member")
.color → Profilfarbe als Hex-String (z.B. "#FF8086")
.medias[0].pictureUrl → Avatar-URL (generierter Default wenn pictureDefault=true)
.identifiers[] → Kontaktdaten
.type → Typ (z.B. "Email")
.value → Wert (z.B. E-Mail-Adresse)
.familyId → Zugehöriger Kreis (= metaId des Kreises)
.isloggedaccount → "true" wenn das der angemeldete Account ist
.joinDate → Beitrittsdatum (ISO 8601)
.lastLoginDate → Letzter Login (ISO 8601)
.locale → Spracheinstellung (z.B. "de_DE")
.timeZone → Zeitzone (z.B. "Europe/Berlin")
.invitations[] → Offene Einladungen (leer wenn keine)
.coverUri → Cover-Bild URL
```
### `taskgettasklists` Listen abrufen
POST https://api.familywall.com/api/taskgettasklists
Content-Type: application/x-www-form-urlencoded
**Body-Parameter:** keine
**Response-Struktur:** zu verifizieren beim ersten echten Call
### `accgetallfamily` Listen + Tasks abrufen
POST https://api.familywall.com/api/accgetallfamily
Content-Type: application/x-www-form-urlencoded
**Body-Parameter:**
| Parameter | Wert |
|---|---|
| `a01call` | `"taskcategorysync"` |
| `a02call` | `"tasksync"` |
Hinweis: `a03call=tasklistsync` ist **kein gültiger Endpoint** — API antwortet mit
"The call tasklistsync is not registered". Nicht verwenden.
`partnerScope`, `a03id`, `withStateBean` werden weggelassen.
**Response-Struktur (verifiziert):**
```
a00 → famlistfamily-Daten (Kreise inkl. members[]) Nebeneffekt
a01.r.r.updatedCreated[] → taskcategorysync (Kategorien/Abteilungen pro Liste)
.metaId → Kategorie-ID (Format taskCategory/<familyId>_<sysId>)
.name → Kategoriename (sprachabhängig, z.B. "Beverages")
.emoji → Emoji-Symbol der Kategorie
.systemCategoryId → numerische System-ID (sprach-unabhängig)
.taskListType → Listentyp der Kategorie (z.B. "SHOPPING_LIST")
**Wichtig:** Alle 171 Kategorien sind SHOPPING_LIST —
es gibt keine TODO-Kategorien in der API
.sortingIndexByTaskList → dict: Listen-ID → Sortierposition
**Achtung:** enthält ALLE Listen-IDs unabhängig vom Typ
→ NICHT für Typ-Filterung verwenden!
Stattdessen: taskListType der Kategorie mit
taskListType der Liste (aus taskgettasklists) vergleichen
.locale → Sprache des Namens (z.B. "de", "en", "ru", "fr", "es",
"it", "nl", "pt", "sv", "ko", "ja")
Jede Sprache = eigener Eintrag mit eigenem metaId/systemCategoryId
**Wichtig:** Custom-Kategorien (rights.canDelete='true') haben
kein locale-Feld gesetzt — sie werden sprachunabhängig
zurückgegeben und dürfen nie über locale gefiltert werden.
.hiddenByTaskList → Liste von Listen-IDs, in denen die Kat. versteckt ist
a02.r.r.updatedCreated[] → tasksync (Tasks)
.metaId → eindeutige Task-ID
.taskId → identisch zu metaId (zweiter Alias)
.text → Aufgabentext
.description → optionale Beschreibung
.taskListId → Zugehörigkeit zur Liste
.complete → "true" / "false" (String, nicht Boolean!)
.categories[] → Listen-Level-Systemkategorie (z.B. SYS-CAT-SHOPPINGLIST);
NICHT die spezifische Task-Kategorie — immer identisch
für alle Tasks einer Liste
.system → "true" (immer System-Kategorie)
.name → Listen-Systemkategorien (z.B. "SYS-CAT-SHOPPINGLIST", "SYS-CAT-TODOS")
.taskCategoryId → spezifische Task-Kategorie (verifiziert): metaId-Format
(z.B. "taskCategory/23431854_200"), null wenn nicht gesetzt
.assignee[] → zugewiesene Mitglieder: [{accountId: "..."}]
.assigneeIds[] → zugewiesene Member-IDs als String-Array (z.B. ["23431898"])
.dueDate → Fälligkeitsdatum (ISO 8601, z.B. "2026-04-30T18:00:00.000Z"; null wenn nicht gesetzt)
.reminder → Erinnerungsregel (Objekt mit reminderUnit, reminderType, reminderValue — nicht das Fälligkeitsdatum!)
.recurrency → Wiederholungsregel (optional)
.sortingIndex → Anzeigereihenfolge
```
**Kategorie-Zuweisung bei taskcreate2 / taskupdate2 (verifiziert):**
| Parameter | Pflicht | Wert |
|---|---|---|
| `taskCategoryId` | nein | Kategorie-MetaId aus `get_categories` (z.B. `taskCategory/23431854_200`) |
Hinweise:
- Wert muss das vollständige metaId-Format `taskCategory/<familyId>_<systemCategoryId>` sein.
Nur der numerische `systemCategoryId`-Teil (z.B. `200`) führt zu API-Fehler
`"cannot find task category id=200"`.
- Das `categories[]`-Feld in der Response zeigt immer `SYS-CAT-SHOPPINGLIST`
(Listen-Level-Systemkategorie, unabhängig vom gesetzten `taskCategoryId`).
Die tatsächliche Task-Kategorie ist im Feld `taskCategoryId` der Task gespeichert.
- Nur für Einkaufslisten (`taskListType=SHOPPING_LIST`) relevant;
TODO-Listen haben keine Kategorien.
## Systembezeichnungen für Listen-Namen
Bekannte Systembezeichnungen werden deutsch übersetzt:
| Systembezeichnung | Deutsch |
|---|---|
| `SYS-CAT-SHOPPINGLIST` | `Einkaufsliste` |
Unbekannte Bezeichnungen werden unverändert zurückgegeben.
Mapping-Tabelle bei Bedarf erweitern.
### `wallget` Aktivitäten (Wall) abrufen
POST https://api.familywall.com/api/wallget
Content-Type: application/x-www-form-urlencoded
**Body-Parameter:**
| Parameter | Wert |
|---|---|
| `nb` | Anzahl Einträge (z.B. `"20"`) |
| `date` | optional, für Paginierung (Datum des letzten Eintrags) |
| `accountId` | optional |
| `type` | optional |
| `nested` | optional |
| `masterNested` | optional |
| `sortBy` | optional |
**Response-Struktur (verifiziert):**
```
a00.r.r[]
.metaId → ID der Aktivität (= wallMessageId)
.refType → Aktivitätstyp (z.B. STATUS, FAMILY_CREATED)
.text → Text (optional, fehlt bei System-Events)
.creationDate → Datum (ISO 8601)
.accountId → Autor-ID
```
**Response-Struktur:** zu verifizieren beim ersten echten Call
### `wallactivityget` Einzelne Aktivität abrufen
POST https://api.familywall.com/api/wallactivityget
Content-Type: application/x-www-form-urlencoded
**Body-Parameter:**
| Parameter | Wert |
|---|---|
| `accountId` | optional |
| `masterNested` | optional |
**Response-Struktur:** zu verifizieren beim ersten echten Call
(Endpoint noch nicht implementiert — für spätere Versionen)
## Fehlerstruktur-Varianten
Die Family Wall API gibt Fehler in zwei verschiedenen Strukturen zurück:
| Struktur | Beispiel | Erkennungsregel |
|---|---|---|
| Top-Level `ex` | `{"ex": {"ex": {...}}}` | `"ex" in body` |
| Top-Level `un` | `{"un": {"un": {...}}}` | `"un" in body` |
| Verschachtelt `a00.un` | `{"a00": {"un": {"un": {...}}}}` | `"un" in body["a00"]` |
Ab v0.4.15 erkennt `fw_client.py` alle drei Varianten und wirft `FamilyWallError`.
Zuvor wurden `a00.un`-Fehler still ignoriert (silent fail), was zu irreführenden
`{"updated": True}`-Antworten bei fehlgeschlagenen Updates führte.
**Bekannte Endpoints mit `a00.un`-Fehlern:**
- `taskupdate2` mit ungültigem `dueDate`-Wert
- `taskcategorydelete` mit falschem Parameter-Namen (obsolet nach v0.4.x-Fix)
## Debug-Logging
Wenn die Umgebungsvariable `FW_DEBUG=1` gesetzt ist, loggt `fw_client.py`
vollständige Request-Bodies und Responses nach stderr. Dient zur Verifikation
offener Punkte (z.B. `type`-Parameter beim Login, Kreis-Felder in Response).
**Wichtig:** Keine Secrets in Debug-Ausgaben (Passwort maskieren).
### `taskcreate2` Task erstellen
POST https://api.familywall.com/api/taskcreate2
Content-Type: application/x-www-form-urlencoded
**Body-Parameter (verifiziert):**
| Parameter | Pflicht | Wert |
|---|---|---|
| `taskListId` | ja | Listen-ID aus `get_lists` (z.B. `taskList/123_456`) |
| `text` | ja | Aufgabentitel |
| `description` | nein | Optionale Beschreibung |
| `taskCategoryId` | nein | Kategorie-MetaId aus `get_categories` (z.B. `taskCategory/23431854_200`) |
| `dueDate` | nein | Fälligkeitsdatum ISO 8601 (z.B. `"2026-04-30T18:00:00"`); gespeichert als `dueDate` im Task-Objekt |
| `assignee` | nein | Member-ID aus `get_members` (z.B. `"23431898"`); für mehrere Zuweisungen: mehrfach senden (`assignee=id1&assignee=id2`); gespeichert als `assigneeIds[]` im Task-Objekt |
**Response-Struktur (verifiziert):**
```
a00.r.r → vollständiges Task-Objekt der neu erstellten Task
.metaId → eindeutige Task-ID (z.B. "task/23431854_726362809")
.taskListId → Listen-ID
.text → Titel
.complete → "false" (immer, direkt nach Erstellung)
```
### `taskupdate2` Task aktualisieren
POST https://api.familywall.com/api/taskupdate2
Content-Type: application/x-www-form-urlencoded
**Body-Parameter (verifiziert):**
| Parameter | Pflicht | Wert |
|---|---|---|
| `metaId` | ja | Task-ID aus `get_tasks` |
| `text` | nein | Neuer Titel (mindestens eines der optionalen Felder erforderlich) |
| `description` | nein | Neue Beschreibung |
| `taskCategoryId` | nein | Kategorie-MetaId aus `get_categories` (z.B. `taskCategory/23431854_200`) |
| `dueDate` | nein | Fälligkeitsdatum ISO 8601 (z.B. `"2026-04-30T18:00:00"`); gespeichert als `dueDate` im Task-Objekt |
| `assignee` | nein | Member-ID aus `get_members` (z.B. `"23431898"`); für mehrere Zuweisungen: mehrfach senden (`assignee=id1&assignee=id2`); leerer String (`""`) entfernt alle Zuweisungen (nicht verifiziert); gespeichert als `assigneeIds[]` im Task-Objekt |
| `taskListId` | nein | Ziel-Listen-ID zum Verschieben des Tasks (verifiziert ändert `taskListId` im Task-Objekt) |
Hinweis: `taskListId` ist optional ohne diesen Parameter bleibt der Task in seiner aktuellen Liste.
**Response-Struktur:** kein spezifischer Rückgabewert Erfolg = kein `ex`/`un`-Key auf Top-Level.
**dueDate Clearing nicht implementierbar (Stand: April 2026):**
Ausgiebig getestete Werte für `dueDate`, die alle fehlschlugen:
| Wert | API-Response |
|---|---|
| `""` (leerer String) | `a00.un.un: " is not a valid Date"` |
| `"null"` | `a00.un.un: "Cannot parse date val=null"` |
| `"0"` | API-Fehler (ungültiges Datum) |
| `"-1"` | `a00.un.un: "-1 is not a valid Date"` |
| `"remove"` / `"clear"` | `a00.un.un: "Cannot parse date val=..."` |
| `"0000-00-00T00:00:00"` | API-Fehler |
| `"1970-01-01T00:00:00"` | **Erfolgreich** setzt dueDate auf Unix-Epoch (kein echtes Clearing!) |
| Separate Parameter (`removeDueDate`, `clearDueDate`, `clearFields`) | werden ignoriert, dueDate bleibt unverändert |
| Feld weglassen (kein `dueDate` in Request) | dueDate bleibt unverändert |
**Wichtig:** Die Fehler werden als `a00.un.un` zurückgegeben (nicht Top-Level `un`).
Der `fw_client` prüfte ursprünglich nur Top-Level `un` → silent fail (ab v0.4.15 behoben:
`a00.un` wird ebenfalls erkannt und als `FamilyWallError` geworfen).
Das `dueDate`-Feld kann einmal gesetzt nicht mehr entfernt werden.
`update_task(clear_due_date=True)` gibt eine klare Fehlermeldung zurück.
### `taskmark` Task als erledigt/offen markieren
POST https://api.familywall.com/api/taskmark
Content-Type: application/x-www-form-urlencoded
**Body-Parameter (verifiziert):**
| Parameter | Pflicht | Wert |
|---|---|---|
| `taskId` | ja | Task-ID aus `get_tasks` (**WICHTIG: `taskId`, nicht `metaId`!**) |
| `complete` | ja | `"true"` oder `"false"` (String, nicht Boolean!) |
**Achtung:** Der Endpoint heißt intern `taskId`, nicht `metaId`.
Falsche Parameter (`metaId`, `id`, `taskMetaId`) werden serverseitig ignoriert
die API antwortet dann mit einem Fehler in `a00.un.un` (nicht Top-Level!),
der vom Standard-Error-Check im fw_client übersehen wird.
**Response-Struktur (verifiziert):**
```
a00.r.r → vollständiges Task-Objekt mit aktuellem Stand (inkl. lastAction: "MARK_COMPLETED")
```
### `metadelete` Objekt löschen
POST https://api.familywall.com/api/metadelete
Content-Type: application/x-www-form-urlencoded
**Body-Parameter (verifiziert):**
| Parameter | Pflicht | Wert |
|---|---|---|
| `id` | ja | Task-ID aus `get_tasks` (**WICHTIG: `id`, nicht `metaId`!**) |
Hinweis: `metadelete` ist ein generischer Lösch-Endpoint für beliebige Objekte (Tasks, etc.).
Entsprechend vorsichtig verwenden.
**Response-Struktur (verifiziert):**
```
a00.r.r → "true" (String)
```
**Fehlerverhalten:** Bei falschem Parameter-Namen (`metaId`, `taskId` etc.) antwortet die API
mit `{"a00": {"un": {"un": {"message": "missing value in: id"}}}}` auf Top-Level ohne `un`-Key
→ wird vom fw_client fälschlich als Erfolg interpretiert. Daher ist der korrekte Parameter-Name
kritisch.
### `taskcategoryput` Kategorie erstellen
POST https://api.familywall.com/api/taskcategoryput
Content-Type: application/x-www-form-urlencoded
**Body-Parameter (verifiziert via FW_DEBUG=1):**
| Parameter | Pflicht | Wert |
|---|---|---|
| `name` | ja | Kategorie-Name (beliebiger String) |
| `emoji` | nein | Icon: Unicode-Emoji-Zeichen (z.B. `🌿`) oder beliebiger String-Code (z.B. `"FOOD"`) — wird as-is gespeichert |
Hinweise:
- Die neue Kategorie wird **allen** Listen der Familie zugeordnet — es gibt keine per-Liste-Einschränkung.
- Benutzerdefinierte Kategorien haben `systemCategoryId=null` und `rights.canDelete='true'`.
- System-Kategorien haben `rights.canDelete=null` — API erlaubt Löschen, aber `delete_category` Tool verweigert es.
**Response-Struktur (verifiziert):**
```
a00.r.r → vollständiges Kategorie-Objekt
.metaId → neue Kategorie-ID (z.B. "taskCategory/23431854_4956637")
.name → Kategorie-Name
.taskListType → "SHOPPING_LIST" (automatisch gesetzt)
.familyId → Familien-ID
.accountId → Account-ID des Erstellers
.rights.canDelete → "true" (custom Kategorien)
.rights.canUpdate → "true" (custom Kategorien)
.emoji → gespeicherter Icon-Wert (falls übergeben)
```
**Fehlerverhalten:** Ohne `name`-Parameter:
```json
{"a00": {"un": {"un": {"FiZClassId": "502", "message": "cat without a name ..."}}}}
```
### `taskcategorydelete` Kategorie löschen
POST https://api.familywall.com/api/taskcategorydelete
Content-Type: application/x-www-form-urlencoded
**Body-Parameter (verifiziert via FW_DEBUG=1):**
| Parameter | Pflicht | Wert |
|---|---|---|
| `id` | ja | Kategorie-MetaId aus `get_categories` (**WICHTIG: `id`, nicht `metaId`!**) |
**Achtung:** Falscher Parameter-Name `metaId` führt zu:
```json
{"a00": {"un": {"un": {"FiZClassId": "502", "message": "In request, missing value in : id"}}}}
```
**Response-Struktur (verifiziert):**
```
a00.r.r → "true" (String)
```
**Wichtig System-Kategorien:** Die API erlaubt technisch das Löschen von System-Kategorien
(`taskCategory/<familyId>_200` etc.), entfernt sie aber nur aus der Familie — nicht global.
Das `delete_category`-MCP-Tool verweigert dies (Schutz via `rights.canDelete`-Check).
Erkennung: custom Kategorien haben `rights.canDelete='true'`; System-Kategorien haben `rights.canDelete=null`.
### `wallmood` Wall-Post liken
POST https://api.familywall.com/api/wallmood
Content-Type: application/x-www-form-urlencoded
**Body-Parameter (verifiziert via FW_DEBUG=1):**
| Parameter | Pflicht | Wert |
|---|---|---|
| `wall_message_id` | ja | Post-ID aus `get_activities` (z.B. `wall/23431854_31119189`) |
| `moodType` | ja | `"STAR"` (einziger bekannter Wert — entspricht dem Like-Button in der App) |
**Verhalten (verifiziert):**
- `wallmood` mit `moodType: "STAR"` ist eine **idempotente SET-Operation** — kein Toggle!
- Mehrfaches Aufrufen mit denselben Parametern hinterlässt denselben Zustand
- `moodType: "LIKE"` wurde serverseitig als `"STAR"` gespeichert → korrekter Wert ist `"STAR"`
- Nur für Post-Typ `STATUS` wirksam; `FAMILY_CREATED` und vermutlich System-Posts ignorieren den Call
**Unlike nicht implementierbar (Stand: April 2026):**
Ausgiebig getestete Ansätze, die alle fehlschlugen:
| Ansatz | Ergebnis |
|---|---|
| `moodType: "NONE"` / `"REMOVE"` / `"DELETE"` / `""` | moodMap unverändert |
| `moodType` ganz weglassen | moodMap unverändert |
| `moodStarShortcut: "false"` als Parameter | moodMap unverändert |
| Alternative Endpoints: `wallmooddelete`, `wallmoodremove`, `wallmoodelete`, `wallunmood`, `wallcommentdelete`, `wallmoodstar`, `wallstar`, `wallreact`, `wallreactdelete` | alle: `"The call X is not registered"` (502) |
| `metadelete` auf Mood-Comment-ID | löscht den Comment, aber `moodStarShortcut` bleibt gesetzt |
Die Web-App nutzt einen Service Worker, der Requests abfängt — der echte Unlike-Payload
ist dadurch nicht per Browser-DevTools inspizierbar. Unlike bleibt bis zur weiteren
Analyse nicht unterstützt.
**Response-Struktur (verifiziert):**
```
a00.r.r → vollständiges Wall-Message-Objekt
.metaId → Post-ID (= wallMessageId)
.wallMessageId → Post-ID (identisch zu metaId)
.refType → Aktivitätstyp (z.B. "STATUS")
.refAction → Letzte Aktion (z.B. "MOOD_STAR")
.text → Post-Text
.postAccountId → Account-ID des Post-Autors
.accountId → Account-ID (identisch)
.moodMap → dict: accountId → ["STAR"] wenn geliked
.moodStarShortcut → "true" wenn Like-Shortcut aktiv
.comments[] → Liste von Kommentaren/Moods
.commentId → Kommentar-ID (Format wallComment/...)
.accountId → Account-ID des Kommentators
.mood → Mood-Typ (z.B. "STAR")
.text → Kommentartext (falls vorhanden)
.creationDate → Erstelldatum (ISO 8601)
.creationDate → Erstelldatum des Posts (ISO 8601)
.modifDate → Letztes Änderungsdatum (ISO 8601)
.familyId → Kreis-ID (Format family/...)
.rights.canUpdate → "true"/"false"
.rights.canDelete → "true"/"false"
```
**Like-Zustand bestimmen (zwei Indikatoren, beide auswerten):**
| Feld | Typ | Bedeutung |
|---|---|---|
| `moodStarShortcut` | `"true"` / `"false"` | Primär: direktes User-Like-Flag für den anfragenden Account |
| `moodMap[accountId]` | `["STAR"]` | Sekundär: accountId → Mood-Liste; enthält `"STAR"` wenn geliked |
Beide Indikatoren können den Like-Zustand korrekt abbilden — je nach API-internem
Speicherpfad ist nur einer gesetzt. Immer beide prüfen.
**Silent-Fail-Szenarien (API antwortet 200, aber Like wird nicht gesetzt):**
- **Self-Like-Restriction**: Eigener Post kann nicht geliked werden
(verifiziert: Account 23431898 kann Post `wall/23431854_31119189` nicht liken,
obwohl API regulär antwortet — `modifDate` bleibt eingefroren)
- **Unsupported Post-Typ**: `FAMILY_CREATED`-Posts ignorieren wallmood-Calls
- **Rate-Limit**: Nach vielen Calls kann die API Still-Fails zurückgeben
Erkennungsmerkmal für Silent-Fail: `modifDate` im Response identisch zum Vorherigen
AND `moodStarShortcut: false` AND `moodMap: {}`.
## Noch zu verifizieren
- ~~Exakter Wert für `type`-Parameter beim Login~~ → nicht senden (verifiziert per JS-Analyse)
- ~~Response-Struktur von `famlistfamily` (Kreise)~~ → a00.r.r[], metaId + name (verifiziert)
- ~~Ob `a03call=tasklistsync` benötigt wird~~ → **nein**, kein gültiger Endpoint (verifiziert)
- Listen-IDs aus `a01.r.r.updatedCreated[].sortingIndexByTaskList`-Keys (verifiziert)
- Listen-Namen und Zähler (remainingTaskNumber, totalTaskNumber) → noch unbekannt
- Kreis-Zuordnung in `accgetallfamily`-Response → noch offen
- ~~Ob `partnerScope` / `withStateBean` benötigt werden~~ → nein (verifiziert)
- Session-Lebensdauer (irrelevant da kein Caching)
- ~~`taskcreate2`: Response-Struktur~~ → `a00.r.r` = vollständiges Task-Objekt (verifiziert)
- ~~`taskupdate2`: ob `taskListId` Pflichtfeld ist~~ → **nein**, nicht erforderlich (verifiziert)
- ~~`taskmark`: korrekter Parameter-Name~~ → **`taskId`** (nicht `metaId`!) (verifiziert)
- ~~`metadelete`: korrekter Parameter-Name + Response-Struktur~~ → **`id`**, Response `"true"` (verifiziert)
- ~~`wallmood`: Parameter-Name `wallId`~~ → **`wall_message_id`** (verifiziert via API-Fehlermeldung)
- ~~`wallmood`: `moodType`-Werte, Toggle vs. explizit, Response-Struktur~~ → verifiziert: idempotentes SET mit `"STAR"`, kein Toggle (siehe oben)
- `wallmood` Unlike: Mechanismus unbekannt — Service Worker verhindert Browser-Inspektion; alle getesteten Ansätze fehlgeschlagen (siehe oben)
- ~~`taskcreate2` / `taskupdate2`: Kategorie-Paramter-Name~~ → **`taskCategoryId`**, Wert = vollständige metaId (verifiziert)
- ~~`taskcategoryput`: Body-Parameter, Response-Struktur~~ → `name` (Pflicht), `emoji` (optional), Response = neues Kategorie-Objekt (verifiziert)
- ~~`taskcategorydelete`: Body-Parameter~~ → **`id`** (nicht `metaId`!), Response = `"true"` (verifiziert)
- ~~`taskcreate2` / `taskupdate2`: Fälligkeitsdatum-Parameter~~ → **`dueDate`**, ISO 8601 String, gespeichert als `dueDate` im Task-Objekt (verifiziert)
- ~~`taskcreate2` / `taskupdate2`: Zuweisung-Parameter~~ → **`assignee`** (Member-ID String; mehrere Werte = mehrfach senden); gespeichert als `assigneeIds[]` (verifiziert)
- ~~`taskupdate2`: Task verschieben~~ → **`taskListId`** als optionaler Parameter setzt neue Liste (verifiziert)
- `taskupdate2`: Alle Zuweisungen entfernen (leere `assignee`-Liste) → noch nicht verifiziert
- ~~`taskupdate2`: `dueDate` entfernen (Clearing)~~**nicht möglich** (verifiziert, April 2026) — alle getesteten Werte werden als ungültiges Datum abgelehnt (siehe unten)