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!)
- Keine Nebenwirkungen:
- Nur defensive Filterung vor dem Senden
- Temp-Docs nur für Notifications mit ID
-
Keine Breaking Changes
-
Verhindert zukünftige Probleme:
- Wenn User wirklich mehrere customerUser-Docs haben
- Bei Multi-Language-Rollout
-
Bei gleichzeitigen Triggers
-
Best Practice:
- Defensive Programmierung
- Idempotenz
- Atomic Operations (Transactions)
Was fehlt noch?¶
Zwei separate Probleme bleiben:
- Warum werden 2 Feed-Entries für dieselbe Sprache erstellt?
- Liegt in
onNotificationScheduled.js - User hat wahrscheinlich 2 customerUser-Docs mit language=5
-
Sollte dedupliziert werden BEVOR Feed-Entries erstellt werden
-
Device-Cleanup nach Reinstall (jetzt implementiert! ✅)
- Alte Devices bleiben nach iOS-Reinstall
- 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.