Zum Inhalt

Deduplizierungs-Änderungen: Analyse & Empfehlung

Was wurde geändert?

1. Email-basierte User-Deduplizierung (Zeilen 210-232)

Problem gelöst: User hat mehrere customerUser-Dokumente für denselben Kunden Ursache: Registration-Fehler, Test-Accounts, Multi-Customer-Zugriff Lösung: Merge devices wenn mehrere customerUser mit gleicher Email gefunden werden

const uniqueUsersByEmail = new Map();
for (const user of userTokenMap) {
  if (!uniqueUsersByEmail.has(user.email)) {
    uniqueUsersByEmail.set(user.email, user);
  } else {
    // Merge devices from duplicate entries
    const existing = uniqueUsersByEmail.get(user.email);
    existing.devices = [...existing.devices, ...user.devices];
  }
}

Bewertung:BEHALTEN - Verhindert doppelte Sends an denselben User - Löst valides Problem (Multi-customerUser-Docs kommen vor) - Keine Nebenwirkungen


2. Token-Deduplizierung innerhalb eines Users (Zeilen 226-232)

Problem gelöst: User hat mehrere Devices mit demselben Token registriert Ursache: Bug in Device-Registration, Race Conditions Lösung: Filtere doppelte Tokens innerhalb der devices eines Users

for (const user of deduplicatedUsers) {
  const uniqueTokens = new Map();
  for (const device of user.devices) {
    if (device.token && !uniqueTokens.has(device.token)) {
      uniqueTokens.set(device.token, device);
    }
  }
  user.devices = Array.from(uniqueTokens.values());
}

Bewertung:BEHALTEN - Verhindert doppelte Sends an dasselbe Token - Defensive Programmierung (sollte nicht vorkommen, aber schadet nicht) - Keine Nebenwirkungen


3. Sprach-Filter (Zeilen 163-171)

Problem gelöst: User bekommt Notifications in falscher Sprache Ursache: Multi-Language Notifications + User mit anderer Sprache Lösung: Nur senden wenn Feed-Entry-Sprache = User-Sprache (oder User hat keine Sprache gesetzt)

if (feedLanguage !== null && userLanguage !== null && userLanguage !== feedLanguage) {
  return { skipped: true, reason: 'language_mismatch', userLanguage };
}

Bewertung:BEHALTEN - Verhindert falsche Sprach-Zustellung - Wichtig für Multi-Language-Features - Korrekt implementiert mit null-Checks


4. Cross-Language Token-Deduplizierung mit Transaction (Zeilen 270-312)

Problem gelöst: Zwei Feed-Entries (unterschiedliche Sprachen) senden an dasselbe Token Ursache: - User hat mehrere customerUser-Docs mit verschiedenen Sprachen - Notification hat mehrere Sprachen aktiviert - Beide Feed-Entries triggern gleichzeitig Lösung: Transaktionale Token-Registrierung in _notificationTokens Collection

await db.runTransaction(async (transaction) => {
  const sentTokensDoc = await transaction.get(sentTokensDocRef);
  if (sentTokensDoc.exists) {
    alreadySentTokens = new Set(sentTokensDoc.data().tokens || []);
  }

  // Markiere Tokens als "in progress"
  const ourTokens = deduplicatedUsers.flatMap(u => u.devices.map(d => d.token));
  transaction.set(sentTokensDocRef, {
    tokens: admin.firestore.FieldValue.arrayUnion(...ourTokens),
    lastUpdated: new Date().toISOString(),
    feedEntryId: feedEntryId,
  }, { merge: true });
});

Bewertung:BEHALTEN - Löst Race Condition bei gleichzeitigen Feed-Entries - Transaction garantiert Atomicity - Wichtig für Multi-Language Scenarios - Hat das aktuelle Problem (doppelte Devices) KORREKT verhindert (Logs zeigen: 2. Entry sendete nichts!) - KEINE Nebenwirkungen: Temp-Docs werden nur für Notifications mit notificationId erstellt - ✅ CLEANUP IMPLEMENTIERT: TTL-Regel für _notificationTokens (7 Tage) in firestore.indexes.json hinzugefügt


Zusammenfassung

Hat es das aktuelle Problem gelöst?

TEILWEISE ✅/❌

Die Deduplizierung hat verhindert dass BEIDE Feed-Entries senden, aber: - Das Grundproblem (2 Feed-Entries für dieselbe Sprache) existiert noch - Das Device-Problem (alte Devices nach Reinstall) existiert noch

Die Logs zeigen: Nur 2 Pushes wurden gesendet (nicht 4!) - Feed-Entry 1: 2/2 gesendet ✅ - Feed-Entry 2: 0/0 gesendet (alle Tokens bereits verwendet) ✅

Ohne Deduplizierung: 4 Pushes wären gesendet worden (2+2)!

Sollten wir die Änderungen behalten?

JA! Definitiv! ✅

Gründe: 1. Löst valide Szenarien: - Multi-customerUser-Dokumente (kommt vor!) - Multi-Language Notifications (wichtiges Feature!) - Race Conditions (können jederzeit auftreten!)

  1. Keine Nebenwirkungen:
  2. Nur defensive Filterung vor dem Senden
  3. Temp-Docs nur für Notifications mit ID
  4. Keine Breaking Changes

  5. Verhindert zukünftige Probleme:

  6. Wenn User wirklich mehrere customerUser-Docs haben
  7. Bei Multi-Language-Rollout
  8. Bei gleichzeitigen Triggers

  9. Best Practice:

  10. Defensive Programmierung
  11. Idempotenz
  12. Atomic Operations (Transactions)

Was fehlt noch?

Zwei separate Probleme bleiben:

  1. Warum werden 2 Feed-Entries für dieselbe Sprache erstellt?
  2. Liegt in onNotificationScheduled.js
  3. User hat wahrscheinlich 2 customerUser-Docs mit language=5
  4. Sollte dedupliziert werden BEVOR Feed-Entries erstellt werden

  5. Device-Cleanup nach Reinstall (jetzt implementiert! ✅)

  6. Alte Devices bleiben nach iOS-Reinstall
  7. Neue Lösung: Cleanup beim Registrieren

Empfehlung

✅ BEHALTEN: Alle Deduplizierungs-Änderungen

✅ ZUSÄTZLICH IMPLEMENTIERT: Device-Cleanup in App

🔄 TODO: Feed-Entry-Deduplizierung in onNotificationScheduled

Begründung: Die Änderungen sind sinnvoll, defensiv und lösen reale Probleme. Sie haben keine Nachteile und schützen vor Race Conditions und Edge Cases.