S252 Handoff
Documentation for Sessions
S252 Handoff — Vitto Studio & Platform Generation
What S252 Accomplished
S252 took vitto-studio from "everything empty" to "live preview renders real generated platforms with CRUD data." The session fixed 3 major infrastructure layers:
1. SSE Event Pipeline (was: 3/15 events forwarded → now: all)
File: libs/libs-ai/vitto-chat/src/lib/services/vitto-chat-engine.service.ts:555-565
VittoChatEngineService now forwards ALL module-gen.*, pipeline.*, generation.*, phase.* SSE events to the studio via moduleGenEvents$. Previously only started/completed/failed were forwarded — the studio was blind to file writes, pipeline progress, manifest creation, etc.
2. Git Provider Unification (was: GitLab-hardcoded → now: provider-agnostic)
Files:
APIs/backend-api/src/app/git-provider/git-provider.controller.ts— injectsGIT_PROVIDER_SERVICEtokenAPIs/backend-api/src/app/git-provider/git-provider.constants.ts— extracted token to break circular importAPIs/backend-api/src/app/git-provider/remote-git-provider.service.ts— unwraps Hetzner's{ files: [...] }/{ branches: [...] }wrappersAPIs/backend-api/src/app/studio/universe-git.service.ts— full rewrite, delegates toGitProviderServiceinterfaceAPIs/backend-api/src/app/studio/studio.module.ts— importsGitProviderModule
3. Live Preview in Blob URL (was: black screen → now: renders Angular app)
Files:
libs/libs-structural/platform-preview/src/lib/services/preview-server.service.ts— prerequisite script loads zone.js + @angular/compiler BEFORE main.js; monkey-patches history API; inlines CSS; strips import maplibs/libs-structural/platform-preview/src/lib/services/bundler-filesystem.service.ts— removed compiler preload from HTML; added environment stubs; app shell useswithHashLocation()libs/libs-structural/platform-preview/src/lib/config/sdk-preview-stubs.ts— FormBuilder from CDN (inside stub string);useCrudListhasformatDate/formatDateTime/formatCurrency; fetch timeout 8s; loading state always resolves
4. Other Fixes
- Deploy panel: public
spaceId/universeIdsignals onGitStateService - Module tree click wired to
CanvasSelectionService - Entity hydration from universe structure (skeleton entities)
- Pipeline activity feed during generation
- Enhanced empty states across all panels
- setTimeout → timer() (3 violations)
- SafeAny replacement (13 occurrences)
- console.log cleanup in ModularityModule
svc:systemObjectId guard in UsersService + PlatformUserServiceremapAppFilesFromVfs()supportsapps/{name}/src/pattern
What Still Needs Work (User's 6 Requirements)
Requirement 1: "Everything renders"
Current state: 4 of 5 modules render correctly. Club-dashboard has Module not found errors for ../../services/club-dashboard-api.service — deeply nested relative imports that fail intermittently in rspack's memfs.
Root causes to investigate:
loadModuleFilesFromRepo()fetches files one-by-one via HTTP. If any request fails/times out, that file silently disappears from VFS (catchError(() => of(null))). No retry, no logging of which files failed.- File:
libs/libs-structural/vitto-studio/src/lib/services/vfs-sync.service.ts:523-533 - Fix: Add retry (1x) and log failed file paths.
- File:
inlineAngularComponentResources()processes.component.tsfiles but doesn't remove consumed.html/.scssfiles from the enriched map. These files get passed to rspack, which processes them via the CSS rule andasset/sourcerule, potentially causing resolution conflicts.- File:
libs/libs-structural/platform-preview/src/lib/services/bundler-filesystem.service.ts:651-708 - Fix: After inlining, delete consumed
.html/.scsskeys from the files map.
- File:
rspack's
dynamicImportMode: 'eager'means ALL lazyimport()calls in routes get resolved at compile time. If ANY module has a resolution error, the ENTIRE compilation may partially fail (some modules compile, others don't).- This is by design (blob URLs can't load chunks). The fix is generation quality — ensure generated code uses resolvable imports.
Generation quality improvements needed:
- Generated components should use barrel re-exports (
index.ts) instead of deep relative imports.../../services/club-dashboard-api.service→../../services(resolves toindex.tswhich re-exports). - The generation prompt (
implement.prompt.md/ module-gen-phase.executor.ts) should instruct: "All imports within a module MUST use the module's barrel exports where possible."
Requirement 2: "Everything works, including custom CRUD"
Current state: List views work (real data from MongoDB via UniverseDataService stub). Form views render but save may not work — the useCrudForm.onSubmit() calls apiService.create() which calls UniverseDataService.create() which does fetch(POST /api/spaces/{spaceId}/universes/{universeId}/data/{collection}/insert).
Issues:
The
UniverseDataServicestub uses hardcodedhttp://localhost:3000/api— won't work in production. Should use the page's origin or a configurable base URL.- File:
sdk-preview-stubs.ts:1796 - Fix: Use
window.location.originor detect from__SPACE_ID__context.
- File:
After save,
window.location.hash = '#/' + basePath + '/list'navigates back. This works withwithHashLocation()but the hash format must match the synthesized routes. Verify: does#/squad-management/listmatch the route{ path: 'list', ... }under{ path: 'squad-management', ... }?Delete operations use
confirm()which may be blocked in sandboxed iframes. Thesandboxattribute includesallow-popupsbutconfirm()is not a popup — it's a modal dialog. Check ifallow-modalsis needed (it's not a standard sandbox token —confirm()should work withallow-same-origin).Edit mode:
useCrudFormreads the entity ID from the URL hash viagetIdFromHash(). This function parseswindow.location.hashto extract the ID. Verify this works with the synthesized route structure.
Requirement 3: "Renders quickly"
Current state: Preview shows "Ready when you are" → then compiles (~400ms) → renders. On page reload, there's a flash sequence: empty state → base template → generated platform (because VFS loads from develop first, then tryLatestGenerationBranch switches to feature branch).
Fixes needed:
Merge generated code to
develop— this is the #1 fix. The DEPLOY phase inbackend-vitto-apicreates a feature branch and commits, but never merges todevelop. If code lived ondevelop, the VFS would load it directly without the branch-detection dance.- File:
APIs/backend-vitto-api/src/app/module-generation/phases/module-gen-phase.executor.ts - The S253 agent owns this file. Coordinate.
- File:
Cache compiled preview — store the blob URL in
sessionStorageorIndexedDBkeyed by{spaceId}/{universeId}/{branch}/{lastCommitSha}. On reload, show the cached preview instantly while recompilation happens in the background.- File:
libs/libs-structural/platform-preview/src/lib/services/preview-server.service.ts
- File:
Debounce already increased from 150ms to 800ms in S252, but still shows the base template briefly if VFS loads fast. The fundamental fix is merging to
developso there's only one compilation.rspack compilation is ~400ms — this is fast enough. The bottleneck is VFS hydration (HTTP calls to fetch each file individually from Hetzner). Consider: fetch ALL module files in a single batch API call instead of one-by-one.
Requirement 4: "Platform is performant"
Current state: The generated platform runs in a blob URL iframe with CDN externals (Angular, RxJS, zone.js from esm.sh). First load is slow because the browser fetches ~10 CDN modules. Subsequent navigations within the preview are instant.
Fixes needed:
CDN pre-warming — in the prerequisite script, prefetch critical CDN modules with
<link rel="modulepreload">tags for@angular/core,@angular/common,@angular/router,rxjs.- File:
preview-server.service.ts— add<link>tags to<head>during HTML assembly.
- File:
SDK stubs are large (~2000 lines) — they get bundled into main.js. Consider splitting into separate files per package and using rspack aliases to resolve them. This would reduce main.js parse time.
CSS is inlined in
<head>— this is fine for small apps but could grow. Consider lazy-loading module-specific styles.
Requirement 5: "Changes persist"
Current state: Changes made in the preview (CRUD data) persist in MongoDB via the real backend API. But code changes (editing components, styles) do NOT persist — the VFS is in-memory and the preview compiles from VFS.
What needs to work:
Data persistence ✅ — CRUD operations go through
UniverseDataService→ real backend → MongoDB.Code persistence — when a user edits code in the Code tab or via Vitto, the change must:
- Update the VFS (in-memory) — ✅ already works
- Commit to the git repo (Hetzner) — partially works via
StudioGitService.commitToUniverse() - Trigger preview recompilation — ✅ the
vfs.lastFileChange()effect triggers rebuild
The gap: step 2 (committing edits to git) needs to be wired.
VfsSyncServicehascommitFileToRepo()which callsStudioApiService.commitFileToRepo(). This needs to be triggered when the user saves in the Code editor.
Requirement 6: "Can make changes via Vitto and via editing tool"
Current state:
- Vitto chat can trigger new generations but can't edit existing files.
- Code tab shows file content but editing isn't wired to save.
- Visual editor (
VisualEditorService+StudioVittoBridgeService) has click-to-select infrastructure but no edit-and-save flow.
What needs to be built:
Vitto code editing — Vitto needs a tool that reads a file from VFS, modifies it, writes it back to VFS, and commits to git. The tool should be
edit_file(path, content)registered in the Vitto agent's tool set. The backend already has the git commit endpoint.Code tab editor — wire the
UxCodeEditorComponent(Monaco) to save on Ctrl+S:- Update VFS:
vfs.updateFileContent(nodeId, newContent) - Commit to git:
studioGit.commitToUniverse(spaceId, universeId, [{ path, content }]) - Preview auto-recompiles via the
lastFileChangeeffect.
- Update VFS:
Visual editor — the
VisualEditorServicealready handles click-to-select in the preview iframe (viaPreviewBridgeService). What's missing:- Property panel binding — when a component is selected, show its
@Input()properties - Style editing — inline style changes sent back to the component file
- Template editing — drag-drop or click-to-add components This is a large feature — recommend a separate session.
- Property panel binding — when a component is selected, show its
Architecture Reference
Preview Compilation Chain
VfsSyncService (loads files from Hetzner git)
→ PreviewService.compileRspack()
→ detectModulesInVfs() (regex scan for modules/{slug}/src/*.routes.ts)
→ BundlerFilesystemService.enrichForWorker()
→ synthesizeAppShell() (main.ts, app.config.ts, app.routes.ts, app.component.ts, index.html)
→ stripAuthGuards()
→ compileScssFiles()
→ inlineAngularComponentResources()
→ synthesizeSdkStubs() (replaces @libs-* imports with stub implementations)
→ BundlerService.compile() → Worker postMessage
→ rspack-compiler.worker.js → rspack WASM → assets (main.js + main.css)
→ PreviewServerService.updateAssets()
→ prerequisite script (zone.js + compiler CDN, history API patch)
→ resolve bare specifiers (CDN_ONLY_MAP)
→ inline CSS
→ strip import map
→ blob URL → iframe
Git Provider Chain
Frontend (StudioApiService / GitStateService)
→ backend-ai-api StudioRepoController (relay)
→ backend-api GitProviderController
→ GIT_PROVIDER_SERVICE (injection token)
→ RemoteGitProviderService (Hetzner) [if PLATFORM_GIT_SERVER_URL set]
→ LocalGitProviderService (filesystem) [if LOCAL_REPOS_ROOT set]
→ GitLabProviderService (GitLab API) [fallback]
Key Files
| File | Purpose |
|---|---|
libs/libs-ai/vitto-chat/src/lib/services/vitto-chat-engine.service.ts |
SSE event forwarding to studio |
libs/libs-structural/vitto-studio/src/lib/services/preview.service.ts |
Preview compilation orchestrator |
libs/libs-structural/vitto-studio/src/lib/services/vfs-sync.service.ts |
VFS hydration from git |
libs/libs-structural/vitto-studio/src/lib/services/studio-generation-listener.service.ts |
SSE event handler, VFS writer |
libs/libs-structural/platform-preview/src/lib/services/bundler-filesystem.service.ts |
File enrichment, app shell synthesis, SDK stubs injection |
libs/libs-structural/platform-preview/src/lib/services/preview-server.service.ts |
Blob URL assembly, CDN specifier resolution |
libs/libs-structural/platform-preview/src/lib/services/bundler.service.ts |
rspack worker orchestration |
libs/libs-structural/platform-preview/src/lib/config/sdk-preview-stubs.ts |
SDK library stub implementations (~2000 lines) |
libs/libs-structural/platform-preview/src/lib/config/esm-cdn-map.ts |
CDN URL map for Angular/RxJS/third-party |
apps/gograb-space/src/rspack-compiler.worker.js |
rspack WASM compilation worker |
APIs/backend-api/src/app/git-provider/git-provider.controller.ts |
Provider-agnostic git REST API |
APIs/backend-api/src/app/studio/universe-git.service.ts |
Provider-agnostic universe git operations |
APIs/backend-api/src/app/data/data.controller.ts |
Universe data CRUD (MongoDB) |
Critical Constraints (Blob URL Preview)
- No import maps — blob: URLs don't support import maps. rspack embeds full CDN URLs via
module ${url}externals. - No history API —
history.pushState/replaceStatethrows SecurityError. Monkey-patched in prerequisite script. - No external CSS —
<link rel="stylesheet">can't resolve relative URLs. CSS inlined as<style>. - No code splitting — blob: URLs can't load chunk files.
dynamicImportMode: 'eager'bundles everything into main.js. - @angular/compiler must load BEFORE main.js parse — static class initializers run at parse time. Handled by separate prerequisite
<script>tag. - SDK stubs live inside template literal strings — NOT as top-level imports. Top-level imports would crash the main app (FormBuilder outside DI context).
Env Vars (Git Provider Selection)
PLATFORM_GIT_SERVER_URL=https://sandbox.gograb.space → RemoteGitProviderService
PLATFORM_GIT_API_KEY=... → X-API-Key header
LOCAL_REPOS_ROOT=/tmp/test-platforms → LocalGitProviderService
# Neither set → GitLabProviderService (fallback)
Recommended Session Plan
Session A: Generation Quality & DEPLOY Phase
- Fix DEPLOY phase to auto-merge feature branch → develop
- Improve generation prompts: barrel exports, flat imports, no deep
../../paths - Ensure generated modules match SDK stub API surface (all methods exist)
- Add generation validation: after committing files, verify they compile in rspack
Session B: Code Editing & Persistence
- Wire Code tab save (Monaco Ctrl+S → VFS update → git commit → preview recompile)
- Add Vitto
edit_filetool for AI-driven code changes - Implement draft branch system for unsaved edits
- Add file diff viewer before committing
Session C: Preview Performance & Polish
- CDN module preloading (
<link rel="modulepreload">) - Preview cache in sessionStorage/IndexedDB
- Batch file fetching (single API call for all module files)
- Remove consumed .html/.scss files from enriched map after inlining
- Add file fetch retry (1x) with logging of failed files
Session D: Visual Editor
- Property panel binding for selected components
- Inline style editing
- Template drag-drop editing
- Visual changes → VFS update → git commit → preview recompile