BUGFIX Circular Dependency
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
Bug Fix: Circular Dependency in Layout Detection
Problem
When viewing modules inside a Galaxy, dragging and dropping a module would incorrectly trigger the Layout Zone renderer, showing a semi-transparent overlay instead of creating a proper module card.
Root Cause
Circular Dependency:
// BROKEN: layoutModule depends on childModules
readonly layoutModule = computed(() => {
const modules = this.childModules(); // ❌ Circular!
return modules.find(m => m.type === 'layout');
});
// childModules is used in the template
// layoutModule is used to determine isLayoutMode
// isLayoutMode determines which template to render
// → Circular dependency!
Incorrect Scope Detection:
The original implementation looked for layout modules with !m.parentId, which only works at the universe level. When inside a Galaxy or World, layout modules SHOULD have a parentId, but they weren't being detected correctly.
Solution
1. Remove Circular Dependency
Changed layoutModule to query allModules directly instead of depending on childModules():
// FIXED: layoutModule queries allModules directly (no circular dependency)
readonly layoutModule = computed(() => {
const level = this.level();
const parentId = this.parentId();
const allModules = this.modules(); // ✅ Direct access
let layoutInScope: UniversalModule | undefined;
if (level === 'universe') {
// At universe level, look for top-level layout
layoutInScope = allModules.find(m => m.type === 'layout' && !m.parentId);
} else if (level === 'galaxy') {
// Inside galaxy, look for layout with this galaxy as parent
layoutInScope = allModules.find(m => m.type === 'layout' && m.parentId === parentId);
} else if (level === 'world') {
// Inside world, look for layout with this world as parent
layoutInScope = allModules.find(m => m.type === 'layout' && m.parentId === parentId);
}
return layoutInScope;
});
2. Context-Aware Layout Detection
Now the layout detection is scope-aware:
- Universe level: Looks for
type === 'layout'with!parentId - Galaxy level: Looks for
type === 'layout'withparentId === galaxyId - World level: Looks for
type === 'layout'withparentId === worldId
This means:
- You can have a layout at the universe level (divides the entire space)
- You can have a layout inside a specific galaxy (divides that galaxy)
- You can have a layout inside a specific world (divides that world)
- Each layout only affects its own scope
Testing
Test 1: Empty Galaxy (No Layout)
- Navigate inside a Galaxy
- No layout module exists with
parentId === galaxyId isLayoutMode()should befalse- Canvas renders free-form module cards (not zones)
- Drag-drop from library creates normal module cards ✅
Test 2: Galaxy with Layout
- Navigate inside a Galaxy
- Drag "Layout" module from library → Drop on canvas
- Layout created with
parentId === galaxyId isLayoutMode()becomestrue- Canvas switches to zone renderer ✅
- Subsequent drops go into zones ✅
Test 3: Universe with Layout
- Navigate to Universe level
- Drag "Layout" module → Drop
- Layout created with
parentId === null - Canvas shows zones dividing the entire universe ✅
Expected Console Output (Fixed)
Before Drop (Empty Galaxy):
🔍 [childModules] Computing: { level: 'galaxy', parentId: 'mod_...', totalModules: 5 }
⭐ [galaxy level] Filtered modules: 0 []
📐 No layout module found
🔧 Layout mode: false
After Dropping "World" Module:
🎯 Canvas Drop Event: DragEvent { ... }
📍 Creating module at position: { canvasX: 250, canvasY: 300 }
✅ Module created: world-1234567890
✅ Loaded 6 total modules
⭐ [galaxy level] Filtered modules: 1 [{ id: 'mod_...', name: 'world-...', type: 'world' }]
📐 No layout module found
🔧 Layout mode: false
After Dropping "Layout" Module:
🎯 Canvas Drop Event: DragEvent { ... }
📍 Creating module at position: { canvasX: 250, canvasY: 300 }
✅ Module created: layout-1234567890
✅ Loaded 7 total modules
⭐ [galaxy level] Filtered modules: 2 [{ id: 'mod_...', name: 'world-...', type: 'world' }, { id: 'mod_...', name: 'layout-...', type: 'layout' }]
🎯 Layout detected in current scope: { id: 'mod_...', name: 'layout-...', level: 'galaxy', parentId: 'mod_galaxy' }
📐 Layout config loaded: { template: 'custom', zones: [...] }
🔧 Layout mode: true
Files Changed
libs/universe-map/src/lib/components/canvas/universal-canvas/universal-canvas.component.ts- Lines 206-254: Refactored
layoutModule,layoutConfig,isLayoutModecomputed signals - Added context-aware layout detection (universe/galaxy/world scopes)
- Removed circular dependency between
layoutModuleandchildModules
- Lines 206-254: Refactored
Impact
✅ Fixed: Drag-drop now creates proper module cards (not layout zones) when no layout exists ✅ Fixed: Layout detection works correctly at all levels (universe, galaxy, world) ✅ Fixed: No more circular dependency between computed signals ✅ Improved: Better console logging for debugging layout detection ✅ Maintained: Layout zones still work when a layout module is present
Date: November 11, 2025
Bug: Circular Dependency + Incorrect Layout Scope
Status: Fixed ✅