Enhanced Phantom Universe Cleanup Solution
Comprehensive fix for phantom universe IDs persisting across browsers
Enhanced Phantom Universe Cleanup Solution
Problem Statement
External browsers were continuing to reference deleted universes, causing:
- 404 errors when trying to fetch non-existent universes
TypeError: Cannot read properties of undefinedin backend logs- Phantom universe IDs persisting in
space.universeIdsarray
Root Cause
The sync engine was not properly cleaning up phantom universe IDs when it detected that universes no longer exist in MongoDB. While the previous fix handled the client-side cleanup, it didn't update the sync engine to properly propagate these cleanups across all browsers.
Solution Implementation
1. Enhanced Sync Engine Cleanup
File: libs/libs-foundational/core-angular/src/lib/services/sync-engine.service.ts
// Track universes to remove during sync
const universesToRemove: string[] = [];
// When universe not found (404 or null response)
if (!backendUniverse || error.status === 404) {
universesToRemove.push(universeId);
// Remove from local storage
await this.storage.remove(universeKey);
await this.storage.remove(layoutKey);
}
// After checking all universes, clean up space.universeIds
if (universesToRemove.length > 0) {
mergedSpace.universeIds = mergedSpace.universeIds.filter(
id => !universesToRemove.includes(id)
);
// Save cleaned space and queue sync
await this.storage.put(spaceKey, mergedSpace);
await this.storage.put(spaceSlugKey, mergedSpace);
// Queue update to sync cleanup to backend
await this.queueOperation({
id: `space-cleanup-${Date.now()}`,
operation: 'update',
entity: 'space',
key: spaceKey,
data: mergedSpace,
timestamp: Date.now(),
retries: 0
});
}
2. Enhanced Delete Universe Method
File: libs/libs-foundational/core-angular/src/lib/services/space.service.ts
async deleteUniverse(universeId: string): Promise<void> {
// ... existing delete logic ...
// Also remove layout data
const layoutKey = `modular-universe/layout/${universeId}/universe`;
await this.storage.remove(layoutKey);
// Broadcast deletion to other tabs/browsers
try {
this.realtimeSync.broadcastUniverseUpdate(universeId, {
action: 'delete',
universeId
});
} catch (broadcastError) {
// Optional broadcast, don't fail if not available
}
}
3. Proactive Phantom Cleanup
File: libs/libs-foundational/core-angular/src/lib/services/space.service.ts
private async cleanupPhantomUniverseIds(): Promise<void> {
const space = this._currentSpace();
if (!space) return;
const validIds: string[] = [];
const phantomIds: string[] = [];
// Check each universe ID for actual data
for (const universeId of space.universeIds) {
const universeData = await this.storage.get(`universe_${universeId}`);
if (universeData) {
validIds.push(universeId);
} else {
phantomIds.push(universeId);
}
}
// Clean up if phantoms found
if (phantomIds.length > 0) {
space.universeIds = validIds;
space.updatedAt = new Date().toISOString();
await this.syncEngine.write(`space_${space.ownerId}`, space, 'space');
await this.cacheSpaceSlugVariant(space);
this._currentSpace.set(space);
}
}
// Called automatically in loadUniverses() when phantoms detected
Key Improvements
- Bidirectional Cleanup: Sync engine now cleans phantom IDs when pulling from backend
- Layout Cleanup: Properly removes both universe data AND layout data
- Broadcast Deletion: Notifies other tabs/browsers immediately
- Proactive Detection: Automatically detects and cleans phantoms during load
- Queue Sync: Ensures cleanup propagates to backend and other browsers
Testing
- Create a universe in Browser A
- Delete the universe in Browser A
- Check Browser B - universe should disappear
- Refresh Browser B - deleted universe should not reappear
- Check MongoDB -
space.universeIdsshould not contain deleted ID
Benefits
- ✅ No more 404 errors for deleted universes
- ✅ Consistent data across all browsers
- ✅ Automatic cleanup without user intervention
- ✅ Proper cascade deletion (universe + layout)
- ✅ Real-time sync of deletions