# Phase 4b — Dashboard Studio + exports: apply

    cp -R phase4b-studio/app/*        ./app/
    cp -R phase4b-studio/resources/*  ./resources/
    cp -R phase4b-studio/tests/*      ./tests/

## bootstrap/app.php — add the alias (next to resolve.organization):
    'platform.admin' => \App\Platform\Http\Middleware\EnsurePlatformAdmin::class,

## routes/web.php — merge routes/studio-web.php, plus add metric CSV export:
    use App\Exports\MetricCsvExport;
    Route::get('/metrics/export', fn (\Illuminate\Http\Request $r) =>
        app(MetricCsvExport::class)->stream($r->user()))->name('metrics.export');

## Sidebar — the admin nav (Dashboard Studio etc.) shows only for platform admins.
Add to resources/js/config/navigation.ts adminNav (already gated by isPlatformAdmin
in the Inertia shared props). Point "Dashboard Studio" at /admin/studio.

## Build + test
    php artisan test --filter='DashboardStudio|MetricQuery'
    node node_modules/vite/bin/vite.js build

## No migrations here — uses Phase 4 tables. Requires Phase 4 applied first.

## How it works
- Only platform admins reach /admin/studio (EnsurePlatformAdmin middleware).
- Admin creates a dashboard, adds KPI widgets from GOVERNED metrics only, publishes.
- LayoutValidator rejects unknown widget types and ungoverned metric refs server-side.
- Admin assigns to organizations; org users then see it under Dashboards.
- Values render through the same MetricQueryService — one number, everywhere.
