BACKEND UNIVERSE ENDPOINTS FIX

Documentation for Plans

Backend Universe Endpoints - Missing 404 Fix

Date: November 17, 2025
Status: ✅ COMPLETE (Needs Railway Deployment)
Priority: 🔥 CRITICAL


Problem Identified

Root Cause: Frontend was trying to sync universes to non-existent backend endpoints, resulting in continuous 404 errors:

PUT /api/spaces/69067c087ebb621cd9ff8c3f/universes/universe_1763422972924 → 404
DELETE /api/spaces/69067c087ebb621cd9ff8c3f/universes/universe_1762191946691 → 404

Why MongoDB wasn't updating: The backend had NO endpoints to handle universe CRUD operations within spaces. The frontend was correctly sending data, but it was hitting non-existent routes.


Solution Implemented

1. Added Universe CRUD Endpoints to SpacesController

File: apis/backend-api/src/app/spaces/spaces.controller.ts

// ========================================
// 🌌 UNIVERSE CRUD ENDPOINTS
// ========================================

/**
 * Create universe in space
 * POST /api/spaces/:spaceId/universes
 */
@Post(':spaceId/universes')
async createUniverse(
  @Request() req: any,
  @Param('spaceId') spaceId: string,
  @Body() universeData: any,
): Promise<any> {
  const userId = req.user.sub;
  console.log('[SpacesController] 🌌 Creating universe:', { spaceId, universeId: universeData.id });
  return this.spacesService.createUniverse(spaceId, userId, universeData);
}

/**
 * Update universe in space
 * PUT /api/spaces/:spaceId/universes/:universeId
 */
@Put(':spaceId/universes/:universeId')
async updateUniverse(
  @Request() req: any,
  @Param('spaceId') spaceId: string,
  @Param('universeId') universeId: string,
  @Body() universeData: any,
): Promise<any> {
  const userId = req.user.sub;
  console.log('[SpacesController] 🌌 Updating universe:', { spaceId, universeId });
  return this.spacesService.updateUniverse(spaceId, userId, universeId, universeData);
}

/**
 * Delete universe from space
 * DELETE /api/spaces/:spaceId/universes/:universeId
 */
@Delete(':spaceId/universes/:universeId')
@HttpCode(HttpStatus.NO_CONTENT)
async deleteUniverse(
  @Request() req: any,
  @Param('spaceId') spaceId: string,
  @Param('universeId') universeId: string,
): Promise<void> {
  const userId = req.user.sub;
  console.log('[SpacesController] 🗑️ Deleting universe:', { spaceId, universeId });
  await this.spacesService.deleteUniverse(spaceId, userId, universeId);
}

2. Implemented Universe CRUD Methods in SpacesService

File: apis/backend-api/src/app/spaces/spaces.service.ts

// ========================================
// 🌌 UNIVERSE CRUD METHODS
// ========================================

/**
 * Create universe in space
 */
async createUniverse(
  spaceId: string,
  userId: string,
  universeData: any,
): Promise<any> {
  // 1. Verify space ownership
  // 2. Add universe ID to space.universeIds array
  // 3. Save universe data to space database
  // 4. Update space.updatedAt timestamp
}

/**
 * Update universe in space
 */
async updateUniverse(
  spaceId: string,
  userId: string,
  universeId: string,
  universeData: any,
): Promise<any> {
  // 1. Verify space ownership
  // 2. Ensure universe ID is in space.universeIds array
  // 3. Update universe data in space database
  // 4. Update space.updatedAt timestamp
}

/**
 * Delete universe from space
 */
async deleteUniverse(
  spaceId: string,
  userId: string,
  universeId: string,
): Promise<void> {
  // 1. Verify space ownership
  // 2. Remove universe ID from space.universeIds array
  // 3. Delete universe data from space database
  // 4. Delete all universe collections
}

Key Features:


3. Added Database Methods in SpaceDatabaseService

File: apis/backend-api/src/app/spaces/space-database.service.ts

/**
 * Save universe data (metadata)
 */
async saveUniverseData(
  spaceId: string,
  universeId: string,
  universeData: any
): Promise<void> {
  const dbName = `space_${spaceId}`;
  const db = this.connection.useDb(dbName);
  const collection = db.collection('universes'); // Central universes metadata collection

  await collection.updateOne(
    { _id: universeId as any },
    {
      $set: {
        ...universeData,
        spaceId,
        updatedAt: new Date()
      },
      $setOnInsert: {
        createdAt: new Date()
      }
    },
    { upsert: true }
  );
}

/**
 * Delete universe data (metadata + collections)
 */
async deleteUniverseData(spaceId: string, universeId: string): Promise<void> {
  // 1. Delete universe metadata from 'universes' collection
  // 2. Delete all universe-specific collections (universe_{id}_pages, etc.)
}

Storage Architecture:


Expected Behavior After Deployment

Before (404 Errors):

Frontend: PUT /api/spaces/:spaceId/universes/:universeId
Backend: 404 Not Found
MongoDB: universeIds = [] (never updates)

After (Success):

Frontend: PUT /api/spaces/:spaceId/universes/:universeId
Backend: 200 OK (universe updated)
         - Updates space.universeIds array
         - Saves universe metadata
         - Updates space.updatedAt
MongoDB: universeIds = ["universe_1763422972924"] ✅

Verification Steps

1. After Railway Deployment

Check Backend Logs (Railway Dashboard):

[SpacesController] 🌌 Updating universe: { spaceId: '69067c087ebb621cd9ff8c3f', universeId: 'universe_1763422972924' }
📥 Received universeIds to update: ["universe_1763422972924"]
✅ Updated space.universeIds to: ["universe_1763422972924"] (1 universes)
✅ Space saved to MongoDB: 69067c087ebb621cd9ff8c3f
✅ Universe updated: universe_1763422972924

2. Check MongoDB (Railway MongoDB Dashboard)

Space Document should show:

{
  "_id": "69067c087ebb621cd9ff8c3f",
  "name": "Xxb7jayp",
  "spaceSlug": "chrome-space-1",
  "ownerId": "68fbe3ac4740d821e041f9df",
  "universeIds": ["universe_1763422972924"], // ✅ NOW POPULATED!
  "settings": { ... },
  "updatedAt": "2025-11-17T22:XX:XX.XXXZ" // ✅ NOW RECENT!
}

Space Database (space_69067c087ebb621cd9ff8c3f):

3. Frontend Console Logs

[SyncEngine] 🔄 Syncing... { operations: 2 }
[SpaceApiService] 🌌 Updating universe: universe_1763422972924
[SpaceApiService] ✅ Universe updated (200 OK) // ✅ NO MORE 404!
[SpaceApiService] 🌌 Updating space: 68fbe3ac4740d821e041f9df
[SpaceApiService] ✅ Space updated (200 OK)
[SyncEngine] ✅ Synced { duration: "200ms" }

Files Changed

Backend Changes:

  1. ✅ apis/backend-api/src/app/spaces/spaces.controller.ts - Added universe CRUD endpoints
  2. ✅ apis/backend-api/src/app/spaces/spaces.service.ts - Implemented universe CRUD methods
  3. ✅ apis/backend-api/src/app/spaces/space-database.service.ts - Added database persistence methods

No Frontend Changes Needed:


Next Steps

Immediate (Required):

  1. Deploy Backend to Railway:

    # Railway auto-deploys on git push to main
    git add apis/backend-api/
    git commit -m "feat: add universe CRUD endpoints to spaces API"
    git push origin main
    
  2. Monitor Railway Deployment:

    • Check build logs for errors
    • Verify server starts successfully
    • Check health endpoint: https://your-backend.railway.app/api/health
  3. Test Universe Creation:

    • Create a new universe in GoGrab Space
    • Watch frontend console for 200 OK (not 404)
    • Check MongoDB for updated universeIds array

Follow-up:

  1. Multi-Browser Test:

    • Create universe in Chrome
    • Open Firefox with same user
    • Verify universe appears in both browsers
  2. Sync Verification:

    • Create universe in Browser 1
    • Wait 5 seconds (sync interval)
    • Check Browser 2 for automatic update

Architecture Notes

Why This Structure?

Space Document (MongoDB gograb-api database):

{
  "_id": "spaceId",
  "universeIds": ["universe1", "universe2"], // ✅ Index/reference only
  "settings": { ... }
}

Universe Data (MongoDB space_{spaceId} database):

// Collection: universes
{
  "_id": "universe1",
  "spaceId": "spaceId",
  "name": "My Universe",
  "description": "...",
  // ... all universe metadata
}

Benefits:


Lessons Learned

  1. Always check Railway logs - Frontend 404s often mean backend routes are missing
  2. Hybrid storage is complex - Space metadata in central DB, universe data in space-specific DB
  3. Frontend was never the problem - The sync system was working perfectly, just hitting non-existent endpoints
  4. MongoDB wasn't updating - Because the backend wasn't processing the requests at all

Status: ✅ Code complete, ⚠️ awaiting Railway deployment
Impact: 🔥 CRITICAL - Fixes universe persistence across browsers
Risk: ✅ LOW - Only adds new endpoints, doesn't modify existing behavior