2026 03 07 Vitto Mobile Separation Design

Documentation for Plans

Vitto Mobile/Extension Separation - Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Make vitto-mobile render only chat + observatory (same as chrome extension), while desktop keeps the full app.

Architecture: Rename /panel-v2 route to /vitto-mobile, auto-redirect Capacitor mobile to it, hide the header on that route. No new components or apps — reuses existing VittoPanelUnifiedComponent.

Tech Stack: Angular 20 routing, Capacitor bridge detection, Chrome Extension sidepanel

Date: 2026-03-07 Session: 188.2 Status: Approved

Problem

The vitto-mobile (Capacitor) app renders the full gograb-ai Angular app — dashboard, navigation header, all routes — instead of a focused experience. The vitto-chrome-extension already solves this by loading only /panel-v2 (chat + observatory), but mobile doesn't follow the same pattern.

Goal: Mobile should render only what the extension renders (chat + observatory), while desktop continues to get the full app.

Current Architecture

Host Load Method What It Renders
Desktop (Tauri) Bundled WebView, full app All routes (dashboard, vitto, observatory, etc.)
Chrome Extension iframe to /panel-v2 Chat + Observatory tabs only
Mobile (Capacitor) Bundled WebView, full app All routes (same as desktop) - problem

Key insight: vitto-mobile has no Angular code of its own — it's a Capacitor shell pointing to dist/apps/gograb-ai/browser. All rendering decisions happen inside gograb-ai.

Solution: Route Rename + Mobile Auto-Redirect

Change 1: Rename route /panel-v2 to /vitto-mobile

File: apps/gograb-ai/src/app/app.routes.ts

Change 2: Update Chrome Extension iframe URL

File: apps/vitto-chrome-extension/sidepanel/sidepanel.js

Change 3: Auto-redirect mobile to /vitto-mobile

File: apps/gograb-ai/src/app/core/guards/desktop-auth.guard.ts

Change 4: Hide header on /vitto-mobile route

File: apps/gograb-ai/src/app/app.component.ts

What Does NOT Change

Rendering Matrix (After)

Host Default Route Header Available Routes
Desktop (Tauri) /dashboard Full header + nav All routes
Chrome Extension /vitto-mobile (iframe) Hidden (embedded) /vitto-mobile only
Mobile (Capacitor) /vitto-mobile (redirect) Hidden (fullscreen) /vitto-mobile + /welcome + /auth/desktop
Browser /dashboard Full header + nav All routes

Risk Assessment


Implementation Plan

Task 1: Rename /panel-v2 route to /vitto-mobile + add backwards-compat redirect

Files:

Step 1: Update route definition

Change the panel-v2 route to vitto-mobile and add a redirect from the old path:

{
  // Session 188.2: Renamed from /panel-v2 — unified Chat + Observatory for mobile + extension
  path: 'vitto-mobile',
  canActivate: [appAuthGuard],
  loadComponent: () => import('./pages/vitto-chat-panel/vitto-panel-unified.component').then(m => m.VittoPanelUnifiedComponent),
  title: 'Vitto',
},
// Session 188.2: Backwards compat — old /panel-v2 links still work
{ path: 'panel-v2', redirectTo: 'vitto-mobile', pathMatch: 'full' },

Step 2: Verify — run yarn serve:gograb-ai and confirm:

Step 3: Commit

git add apps/gograb-ai/src/app/app.routes.ts
git commit -m "feat: rename /panel-v2 route to /vitto-mobile (S188.2)"

Task 2: Update Chrome Extension to use /vitto-mobile

Files:

Step 1: Update buildFrameUrl() and its JSDoc

/**
 * Build iframe URL — always /vitto-mobile
 */
function buildFrameUrl(tab, authStatus) {
  // ... same params logic ...
  return `${AI_APP_URL}/vitto-mobile?${params.toString()}`;
}

Step 2: Verify — reload Chrome extension, confirm sidepanel loads /vitto-mobile in iframe

Step 3: Commit

git add apps/vitto-chrome-extension/sidepanel/sidepanel.js
git commit -m "feat: update chrome extension to use /vitto-mobile route (S188.2)"

Task 3: Hide header on /vitto-mobile route

Files:

Step 1: Add /vitto-mobile to fullscreen route check and chat input check

const isFullscreenRoute = (url: string) =>
  url.startsWith('/welcome') || url.startsWith('/auth/desktop') || url.startsWith('/login') || url.startsWith('/vitto-mobile');

const hasChatInput = (url: string) =>
  url.startsWith('/panel') || url.startsWith('/vitto/chat') || url.startsWith('/vitto-mobile');

Step 2: Verify — navigate to /vitto-mobile in browser, confirm header is hidden

Step 3: Commit

git add apps/gograb-ai/src/app/app.component.ts
git commit -m "feat: hide header on /vitto-mobile route for clean mobile UX (S188.2)"

Task 4: Auto-redirect mobile (Capacitor) to /vitto-mobile

Files:

Step 1: Split desktop and mobile in auth guard

Replace the combined isDesktop || isMobile block with separate logic:

// Desktop (Tauri) — full app experience
if (isDesktop) {
  if (hasActiveSession()) return true;
  return router.createUrlTree(['/welcome']);
}

// Mobile (Capacitor) — focused chat+observatory
if (isMobile) {
  if (hasActiveSession()) {
    // Session 188.2: Mobile gets focused chat+observatory, not full dashboard
    if (state.url === '/dashboard' || state.url === '/') {
      return router.createUrlTree(['/vitto-mobile']);
    }
    return true;
  }
  return router.createUrlTree(['/welcome']);
}

Step 2: Update DesktopWelcomeComponent post-auth navigation (3 locations)

Change all three navigate(['/dashboard']) to:

this.router.navigate([this.capBridge.isMobileApp() ? '/vitto-mobile' : '/dashboard'], { replaceUrl: true });

Step 3: Verify — mock isMobileApp() returning true, confirm mobile lands on /vitto-mobile

Step 4: Commit

git add apps/gograb-ai/src/app/core/guards/desktop-auth.guard.ts apps/gograb-ai/src/app/pages/desktop-welcome/desktop-welcome.component.ts
git commit -m "feat: auto-redirect mobile to /vitto-mobile after auth (S188.2)"

Task 5: Final verification

Test Expected
Browser: / Redirects to /dashboard with full header
Browser: /vitto-mobile Full-screen chat+observatory, no header
Browser: /panel-v2 Redirects to /vitto-mobile
Extension: open sidepanel Loads /vitto-mobile in iframe with auth params
Mobile (mock): / Guard redirects to /vitto-mobile
Desktop (Tauri): / Redirects to /dashboard with full header