Launch Station & Space Management Alignment
Integrate launch-station preview/deployment with space-management analytics
🚀 Launch Station & Space Management Alignment
Last Updated: November 14, 2025
Status: 🎯 INTEGRATION PLAN
Purpose: Complete the build → preview → deploy → manage workflow
🎯 WORKFLOW VISION
USER JOURNEY (Complete):
1. CREATE Universe
→ Dashboard
2. BUILD Structure
→ modular-universe (grid canvas, sections)
3. ADD Content
→ editor-web (pages, widgets)
4. ADD Logic
→ singularity (flows, blocks)
5. PREVIEW Universe ✨
→ launch-station/preview (test before deploy)
6. DEPLOY Universe ✨
→ launch-station/deploy (go live)
7. MANAGE Universe ✨
→ space-management (analytics, data, users)
📊 CURRENT STATE
Launch Station
Location: libs/libs-structural/launch-station/
Current Routes:
/space/:spaceSlug/launch-station
/dashboard → Universe dashboard (potentially mock data?)
/preview/:universeId → Preview page (needs work)
/deploy/:universeId → Deployment wizard (exists)
Issues:
- May be using mock data instead of real universes
- Preview page may not render actual universe structure
- Deployment wizard may not be connected to backend
- No clear entry point from modular-universe
Space Management
Location: modules/space-management/
Current Routes:
/space/:spaceSlug/space-management
(Need to verify what exists)
Issues:
- Not clear what functionality exists
- Needs to show deployed universes
- Should have analytics dashboard
- Should manage universe data (from universe-database-arquitecture.md)
🎯 LAUNCH STATION ENHANCEMENT
1. Universe Dashboard (Real Data)
// components/launch-station-dashboard.component.ts
@Component({
selector: 'lib-launch-station-dashboard',
standalone: true
})
export class LaunchStationDashboardComponent implements OnInit {
private moduleService = inject(UniversalModuleService);
private storage = inject(GgStorage);
// State
universes = signal<UniverseListItem[]>([]);
isLoading = signal(true);
async ngOnInit() {
await this.loadUniverses();
}
async loadUniverses() {
this.isLoading.set(true);
// Load real universes from storage
const spaceId = this.getSpaceId();
const universeModules = await this.moduleService.query({
type: 'universe'
});
this.universes.set(universeModules.map(u => ({
id: u.id,
name: u.name,
status: u.deploymentStatus || 'draft',
lastModified: u.updatedAt,
url: u.deploymentUrl,
thumbnail: u.thumbnail,
moduleCount: u.children?.length || 0
})));
this.isLoading.set(false);
}
previewUniverse(universeId: string) {
this.router.navigate(['/launch-station/preview', universeId]);
}
deployUniverse(universeId: string) {
this.router.navigate(['/launch-station/deploy', universeId]);
}
editUniverse(universeId: string) {
this.router.navigate(['/modular-universe'], {
queryParams: { universe: universeId }
});
}
}
2. Universe Preview (Real Rendering)
// components/universe-preview.component.ts
@Component({
selector: 'lib-universe-preview',
standalone: true
})
export class UniversePreviewComponent implements OnInit {
private moduleService = inject(UniversalModuleService);
private storage = inject(GgStorage);
universeId = input.required<string>();
// State
universe = signal<UniversalModule | null>(null);
layout = signal<LayoutConfiguration | null>(null);
sections = computed(() => this.layout()?.sections || []);
deviceMode = signal<'mobile' | 'tablet' | 'desktop'>('desktop');
async ngOnInit() {
await this.loadUniverseForPreview();
}
async loadUniverseForPreview() {
const universeId = this.universeId();
// Load universe module
const universe = await this.moduleService.get(universeId);
this.universe.set(universe);
// Load layout configuration
const spaceId = this.getSpaceId();
const layoutKey = `modular-universe/layout/${spaceId}/${universeId}/universe`;
const layout = await this.storage.get<LayoutConfiguration>(layoutKey);
this.layout.set(layout);
// Render universe structure
this.renderPreview();
}
renderPreview() {
const layout = this.layout();
if (!layout) return;
// For each section, render assigned module/page
layout.sections.forEach(async section => {
if (section.assignedModuleId) {
const module = await this.moduleService.get(section.assignedModuleId);
if (module.type === 'page') {
// Render page content from editor-web
this.renderPage(section, module);
} else if (module.type === 'navigation') {
// Render navigation module
this.renderNavigation(section, module);
}
// ... handle other module types
}
});
}
async renderPage(section: SectionConfig, pageModule: UniversalModule) {
// Get page content from editor-web storage
const pageKey = `editor-web/page/${pageModule.id}`;
const pageData = await this.storage.get(pageKey);
// Render page widgets in section
// ...
}
changeDeviceMode(mode: 'mobile' | 'tablet' | 'desktop') {
this.deviceMode.set(mode);
}
}
Template:
<!-- universe-preview.component.html -->
<div class="preview-container">
<!-- Device Mode Selector -->
<div class="device-toolbar">
<button
*ngFor="let mode of ['mobile', 'tablet', 'desktop']"
[class.active]="deviceMode() === mode"
(click)="changeDeviceMode(mode)"
>
{{ mode }}
</button>
</div>
<!-- Preview Frame -->
<div
class="preview-frame"
[class.mobile]="deviceMode() === 'mobile'"
[class.tablet]="deviceMode() === 'tablet'"
[class.desktop]="deviceMode() === 'desktop'"
>
<!-- Render universe layout -->
<div
class="universe-container"
[style]="getContainerStyles()"
>
<div
*ngFor="let section of sections()"
class="preview-section"
[style]="getSectionStyles(section)"
>
<!-- Render section content -->
<ng-container *ngIf="section.assignedModuleId">
<lib-module-renderer
[moduleId]="section.assignedModuleId"
/>
</ng-container>
<div *ngIf="!section.assignedModuleId" class="empty-section">
<span>Empty Section: {{ section.name }}</span>
</div>
</div>
</div>
</div>
<!-- Preview Actions -->
<div class="preview-actions">
<button (click)="refreshPreview()" class="btn-secondary">
Refresh
</button>
<button (click)="openFullscreen()" class="btn-secondary">
Fullscreen
</button>
<button (click)="proceedToDeploy()" class="btn-primary">
Deploy This Universe
</button>
</div>
</div>
3. Deployment Wizard (Backend Integration)
// components/deployment-wizard.component.ts
@Component({
selector: 'lib-deployment-wizard',
standalone: true
})
export class DeploymentWizardComponent {
universeId = input.required<string>();
// Wizard steps
currentStep = signal(1);
totalSteps = 5;
// Deployment config
deploymentConfig = signal<DeploymentConfig>({
domain: '',
subdomain: '',
environment: 'production',
buildConfig: {},
envVars: []
});
// Steps
steps = [
{ id: 1, name: 'Verify Build', component: VerifyBuildStepComponent },
{ id: 2, name: 'Domain Configuration', component: DomainConfigStepComponent },
{ id: 3, name: 'Environment Variables', component: EnvVarsStepComponent },
{ id: 4, name: 'Deploy', component: DeployStepComponent },
{ id: 5, name: 'Success', component: SuccessStepComponent }
];
async deployToBackend() {
const config = this.deploymentConfig();
const universeId = this.universeId();
// Call backend deployment API
const result = await this.deploymentService.deploy(universeId, config);
if (result.success) {
// Update universe with deployment info
await this.moduleService.update(universeId, {
deploymentStatus: 'deployed',
deploymentUrl: result.url,
deploymentDate: new Date()
});
// Navigate to success step
this.currentStep.set(5);
}
}
}
🎯 SPACE MANAGEMENT ENHANCEMENT
1. Deployed Universe Dashboard
// components/space-management-dashboard.component.ts
@Component({
selector: 'lib-space-management-dashboard',
standalone: true
})
export class SpaceManagementDashboardComponent {
deployedUniverses = signal<DeployedUniverse[]>([]);
async loadDeployedUniverses() {
// Get universes with deployment status = 'deployed'
const universes = await this.moduleService.query({
type: 'universe',
deploymentStatus: 'deployed'
});
this.deployedUniverses.set(universes.map(u => ({
id: u.id,
name: u.name,
url: u.deploymentUrl,
status: u.deploymentStatus,
deployedAt: u.deploymentDate,
analytics: {
users: 0, // From backend
pageViews: 0, // From backend
storage: 0 // From backend
}
})));
}
manageUniverse(universeId: string) {
this.router.navigate(['/space-management', universeId]);
}
}
2. Universe Data Manager
// components/universe-data-manager.component.ts
@Component({
selector: 'lib-universe-data-manager',
standalone: true
})
export class UniverseDataManagerComponent {
universeId = input.required<string>();
// Data collections for this universe
collections = signal<DataCollection[]>([]);
selectedCollection = signal<DataCollection | null>(null);
collectionData = signal<any[]>([]);
async loadCollections() {
const universeId = this.universeId();
const spaceId = this.getSpaceId();
// Get all collections for this universe
// From universe-database-arquitecture.md:
// universe_{universeId}_users
// universe_{universeId}_products
// universe_{universeId}_orders
// etc.
const collectionNames = await this.storage.listInUniverse(
spaceId,
universeId,
''
);
this.collections.set(collectionNames.map(name => ({
name: name,
count: 0, // Get from backend
lastModified: new Date()
})));
}
async loadCollectionData(collectionName: string) {
const universeId = this.universeId();
const spaceId = this.getSpaceId();
// Query collection data
const data = await this.storage.queryUniverseData(
spaceId,
universeId,
collectionName,
{} // filters
);
this.collectionData.set(data);
}
exportData(format: 'csv' | 'json' | 'excel') {
// Export collection data
}
}
Template:
<!-- universe-data-manager.component.html -->
<div class="data-manager">
<div class="collections-sidebar">
<h3>Collections</h3>
<div
*ngFor="let collection of collections()"
class="collection-item"
[class.active]="selectedCollection()?.name === collection.name"
(click)="loadCollectionData(collection.name)"
>
<span class="collection-name">{{ collection.name }}</span>
<span class="collection-count">{{ collection.count }} records</span>
</div>
</div>
<div class="data-view">
<div *ngIf="selectedCollection()" class="collection-header">
<h2>{{ selectedCollection()?.name }}</h2>
<button (click)="exportData('csv')">Export CSV</button>
<button (click)="exportData('json')">Export JSON</button>
</div>
<div class="data-table">
<table>
<thead>
<tr>
<th *ngFor="let column of getColumns()">{{ column }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of collectionData()">
<td *ngFor="let column of getColumns()">{{ row[column] }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
3. Universe Analytics
// components/universe-analytics-dashboard.component.ts
@Component({
selector: 'lib-universe-analytics-dashboard',
standalone: true
})
export class UniverseAnalyticsDashboardComponent {
universeId = input.required<string>();
metrics = signal<UniverseAnalytics>({
users: {
total: 0,
active: 0,
new: 0
},
pageViews: {
total: 0,
unique: 0,
avgDuration: 0
},
performance: {
avgLoadTime: 0,
errorRate: 0,
uptime: 100
},
storage: {
used: 0,
limit: 0,
collections: 0
}
});
async loadAnalytics() {
const universeId = this.universeId();
// Get analytics from backend
const analytics = await this.analyticsService.getUniverseAnalytics(universeId);
this.metrics.set(analytics);
}
}
🔗 INTEGRATION POINTS
From Modular-Universe to Launch Station
// In modular-universe-builder.component.ts
async previewUniverse() {
const universeId = this.universeId();
// Save current state
await this.saveLayout();
// Navigate to preview
this.router.navigate(['/launch-station/preview', universeId]);
}
async deployUniverse() {
const universeId = this.universeId();
// Save current state
await this.saveLayout();
// Navigate to deployment wizard
this.router.navigate(['/launch-station/deploy', universeId]);
}
From Launch Station to Space Management
// After successful deployment
async onDeploymentSuccess(universeId: string, deploymentUrl: string) {
// Show success message
this.showSuccessMessage(`Universe deployed to ${deploymentUrl}`);
// Offer to manage
const shouldManage = await this.confirmDialog(
'Would you like to manage your deployed universe now?'
);
if (shouldManage) {
this.router.navigate(['/space-management', universeId]);
}
}
🎯 SUCCESS METRICS
Technical
- Preview renders real universe structure
- Deployment connects to backend
- Space management shows real data
- All workflows connected
User Experience
- Preview: < 2 seconds to load
- Deploy: < 60 seconds total process
- Manage: Data visible immediately
- Smooth transitions between tools
Status: ✅ PLAN COMPLETE
Next Action: Implement launch-station enhancements
Timeline: 2-3 weeks
Last Updated: November 14, 2025