mana-kotlin-event-sync/CHANGELOG.md
Till JS a63340c271 0.9.1 — Factory verdrahtet syncConsentLoader automatisch bei requireSyncConsent
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 16:27:26 +02:00

5.9 KiB

Changelog

0.9.1 — 2026-06-23

  • Fix: createEventSyncEngine-Factory verdrahtet den syncConsentLoader jetzt automatisch gegen mana-auth (fetchSyncConsent), wenn config.requireSyncConsent gesetzt ist. Damit reicht in der App das eine Config-Flag — kein manuelles Loader-Wiring nötig (Parität zu iOS, wo die Engine den Settings-GET selbst macht). In 0.9.0 fehlte die Durchreichung über die Factory.

0.9.0 — 2026-06-23

  • Cloud-Sync-Opt-in-Gate (DSGVO Art. 25), Parität zu Web + iOS. Neues EventSyncConfig.requireSyncConsent (Default false → abwärtskompatibel, kein Verhaltenswechsel für nicht-adoptierende Apps). Ist es gesetzt, synct die Engine nur mit expliziter Nutzer-Einwilligung mit dem Server: ohne Zustimmung läuft sie lokal-only (anonym, Events stauen in der Outbox), auch bei Login — authMode() liefert dann Anonymous. Die Einwilligung wird beim start() über den injizierten syncConsentLoader geladen (Helper fetchSyncConsent(...) liest mana-auth GET /api/v1/settings; App-Override vor globaler Präferenz, fehlend = aus; gleiche Quelle wie Web). Neu: EventSyncEngine.setSyncConsent(granted) (Konto-Toggle: true claimt anonyme Events + startet Sync wie signIn, false stoppt den Server-Sync, lokale Daten bleiben), syncConsentRequired, hasSyncConsent, pure parseSyncConsent(json, appId). Schließt die Inkonsistenz, dass Native bisher per Default synct, Web aber Opt-in ist.

0.8.0 — 2026-06-17

  • 402-Handling (kein aktives Cloud-Sync-Abo). EventSyncError.SubscriptionRequired (Server 402), EventSyncEngine.onSyncRequired-Hook + isSyncRequired(). Push/Pull behandeln 402 sauber: Events BLEIBEN in der Outbox (kein Verlust, KEIN Attempt-Increment), event-getriggerte Push/Pull werden unterdrückt, der Poll prüft weiter (force) → Auto-Recovery, sobald das Abo aktiv ist. Wire-Parität zu @mana/event-sync 0.9.0 + mana-swift-event-sync 0.9.0. Siehe ../mana/docs/SYNC_SETTINGS.md.

0.7.0 — 2026-06-16

  • EventSyncEngine.purgeAggregatePrefix(idPrefix) + EventStore.purgeByAggregatePrefix (Default no-op, InMemory override) — lokaler Klartext-Wipe per aggregateId-Prefix (A3). RoomEventStore-Override im Adapter.

0.6.0 — 2026-06-16

  • EventSyncEngine.shredScope(scopeId, shredAfterIso?) — App-API zum Crypto-Shredding eines Scope-Sub-Keys (Mandant löschen). null → sofort (privat/Art. 17), sonst geplant (Firma/GeBüV-Frist). Via injizierter shredScopeImpl (Factory baut ScopeVaultClient).

0.5.0 — 2026-06-16

  • Per-Mandant-Crypto-Shredding (A3), Parität zu @mana/event-sync 0.7.0 + mana-swift-event-sync 0.6.0: CryptoContext + optionale suspend- context-Varianten von encryptPayload/decryptPayload (Default forwarden zur synchronen Basis → bestehende Provider + Tests unverändert). ScopeVaultClient (Ktor: getOrMint/get/shred gegen /encryption-vault/scopes/:appId/:scopeId/key, 404→ScopeNotFoundException, 410→ScopeShreddedException). ScopedCryptoProvider (delegiert pro Scope an eine MasterKeyCryptoProvider- Instanz mit dem Sub-Key, Mutex-Cache, Master-Fallback; geschreddert → wirft). createScopedKeyProviderFromVault. EventSyncConfig.scopeResolver → Factory baut den Scoped-Provider; Context an emit/pull/reencrypt durchgereicht. Wire identisch enc:1:, abwärtskompatibel, bestehende Tests grün.

0.4.0 — 2026-06-10

  • Decrypt-Failures sichtbar statt Silent-Skip (Parität zu @mana/event-sync 0.6.0 + mana-swift-event-sync): Ein nicht- entschlüsselbares Event aus dem Pull wurde bisher via runCatching{}.getOrNull() still verworfen — die App sah nie, dass ihr Daten fehlen (der enc:1-Footgun). Jetzt:
    • persistenter Zähler in Meta (decrypt-failure-count, …-last-at, …-last-event), abfragbar via stats() → decryptFailures / decryptFailureLastAt, Reset via clearDecryptFailures();
    • neuer Hook onDecryptFailure: ((DecryptFailure) -> Unit)? pro Event, zusätzlich feuert onError mit EventSyncError.DecryptFailed(eventId);
    • decryptPulledPayload(payload, eventId, provider) wirft auch, wenn der Provider den Ciphertext unangetastet durchreicht (NoOp ohne Key) — vorher wäre der enc:1:-String als „Plaintext" in der Projektion gelandet. Der Pull-Cursor wandert trotz Failures weiter — Sync hängt nicht fest.

0.2.0 — 2026-06-04 (Phase 2 Teil 2)

  • EventSyncEngine — vollständige Orchestrierung (Port von Swift): Anonymous-First-Identität, Emit (lokal + Outbox + Crypto-Wire), Pull-Loop (decrypt + Projektion + Cursor), signIn-Claim (anon→sub Re-Attribution + Re-Encrypt + Drain), Poll-Timer, Soft-Fail, Schema-Outdated-Stop, Crypto-Degraded-Outbox-Pause, Aggregate-Change-Listener.
  • EventStore (Interface) + InMemoryEventStore — Event-Log + Outbox + Meta + Retention; Room-Adapter folgt im App-Modul.
  • SyncTransport / SyncWebSocket — Abstraktionen; SyncHttpClient implementiert SyncTransport.
  • createEventSyncEngine(...) — Produktions-Verdrahtung (HTTP + Vault).
  • EventSyncConfig / AuthMode / ClaimResult / EngineStats / AnonymousRetention.
  • 36 Tests (inkl. Crypto-Roundtrip über zwei Geräte, signIn-Claim, Schema-Outdated). Braucht mana-kotlin-core 0.2.0.

0.1.0 — 2026-06-04 (Phase 2 Teil 1)

Erstes Skelett. Phase 2 (Teil 1) des Android-Plans (WORDECK_ANDROID_GREENFIELD.md).

  • MasterKeyCryptoProvider (AES-GCM-256) + NoOpCryptoProvider — wire- kompatibel zu Swift/TS, byte-genau bewiesen per WebCrypto-Golden-Vektor.
  • VaultClient + createMasterKeyProviderFromVault (Key-Fetch, ZK-Erkennung).
  • EventEnvelope + ActorContext + flexibler Long-Serializer (sequenceNumber als String oder Zahl).
  • Ulid (Port der Swift-Generierung).
  • SyncHttpClient (append/pull gegen mana-sync, 422→SchemaOutdated).
  • 26 Tests grün.

Offen (Teil 2): WebSocket-Client, Room-EventStorage, EventSyncEngine.