232 Universe Space Database Duplication Research

Documentation for Sessions

S232: Universe/Space Database Duplication — Root Cause Analysis & Fixes

Date: 2026-03-18
Session: 232
Status: Implemented


Problem Summary

Multiple issues observed in MongoDB:

  1. Duplicate space databases: space_chrome-space-1 and space_chrome-space-1_79fe44376823 for the same logical space
  2. Duplicate universes in gograb-api: Multiple documents in gograb-api.universes with same spaceId: "chrome-space-1"
  3. Double-prefixed collections: universe_universe_1772912869184_wly1ktx_matchs, universe_universe_1772912869184_wly1ktx_players

Root Causes

1. Space Database Resolver — Slug vs ObjectId (PRIMARY)

Location: backend-api/src/app/spaces/space-database/services/space-database-resolver.service.ts

Cause: resolveSpaceDatabaseName(spaceId) used findById(spaceId) only. When spaceId was a slug (e.g. "chrome-space-1") instead of MongoDB ObjectId:

Result: Same space accessed via slug vs ObjectId → two different databases.

Callers passing slug:

2. Entity Schema Service — Hardcoded Legacy Format

Location: backend-api/src/app/data/entity-schema.service.ts

Cause: Used space_${spaceId} directly, bypassing the resolver entirely. When spaceId was a slug, created/accessed space_chrome-space-1.

Fix: Inject SpaceDatabaseService and use resolveSpaceDatabaseName(spaceId).

3. gograb-api.universes Legacy Merge

Location: backend-api/src/app/spaces/space-database/services/space-database-universe.service.ts

Cause: listUniversesInSpace merges universes from:

  1. Space database universes collection
  2. gograb-api.universes with { spaceId }

When spaceId was slug, gograb-api query returned legacy documents with spaceId: "chrome-space-1". E2E tests and legacy flows may have written to gograb-api.universes with slug as spaceId.

Note: Resolver fix ensures we now resolve slug → ObjectId before any DB access. The gograb-api.universes merge remains for backward compatibility but should receive consistent spaceId.

4. universe_universe_ Double Prefix (Fixed S232)

Cause: Some code path passes universeId that already includes universe_ prefix, and another layer prepends universe_ again. Example: universeId = "universe_1772912869184_wly1ktx" → universe_${universeId} → universe_universe_....

Fix: (1) collection-name.util.ts now strips all leading universe_ prefixes before adding one, ensuring exactly one prefix. (2) space-module-database.service.ts uses buildCollectionName(universeId, 'modules') instead of manual universe_${universeId}_modules. (3) Verification script checks for manual universe_${id}_ construction.


Implemented Fixes

Fix 1: Space Database Resolver — Slug Resolution

File: space-database-resolver.service.ts

Fix 2: Entity Schema Service — Use Resolver

File: entity-schema.service.ts


Migration Script (S232)

Run to consolidate orphan DBs and fix double-prefix collections:

yarn migrate:space-db:sot --dry-run   # Preview
yarn migrate:space-db:sot             # Execute

Script: tools/scripts/database/migrate-space-db-to-sot.ts

Additional Fixes (S232)

Cleanup Recommendations (Manual)

  1. Orphan databases: Use yarn migrate:space-db:sot (see above).

  2. gograb-api.universes: Audit documents with spaceId: "chrome-space-1". Update spaceId to canonical ObjectId or migrate to space DB. Consider deprecating the gograb-api.universes merge.

  3. Double-prefixed collections: Migration script renames universe_universe_* → universe_*.


API Audit Summary

API Uses Resolver Bypasses Notes
backend-api data.controller, space-database-*, space-modules (getCollectionAsync), deployment.service entity-schema.service (fixed) All space DB access now via resolver
backend-ai-api N/A (no direct space DB) spaceAIDB uses own naming Uses spaceId for analytics; ensure ObjectId
backend-vitto-api Calls backend-api HTTP N/A Passes spaceId from session; ensure ObjectId from platform

Verification Scripts (SSoT Enforcement)

Run before merge to ensure no new bypasses:

yarn verify:db:naming

Script: tools/scripts/database/verify-space-database-naming.ts

Checks:

Collection naming: All MongoDB universe collections MUST use buildCollectionName(universeId, collection) from collection-name.util.ts. Manual universe_${...}_ construction risks double-prefix (universe_universe_*).


References