diff --git a/apps/mana/apps/web/src/lib/components/llm/SourceBadge.svelte b/apps/mana/apps/web/src/lib/components/llm/SourceBadge.svelte
new file mode 100644
index 000000000..a394cf40a
--- /dev/null
+++ b/apps/mana/apps/web/src/lib/components/llm/SourceBadge.svelte
@@ -0,0 +1,62 @@
+
+
+{#if settings.showSourceInUi}
+
+
+ {tierLabel(tier)}
+ {#if latencyMs !== undefined}
+ · {latencyMs}ms
+ {/if}
+
+{/if}
diff --git a/apps/mana/apps/web/src/lib/components/onboarding/OnboardingWizard.svelte b/apps/mana/apps/web/src/lib/components/onboarding/OnboardingWizard.svelte
index 018c883af..071e7d92b 100644
--- a/apps/mana/apps/web/src/lib/components/onboarding/OnboardingWizard.svelte
+++ b/apps/mana/apps/web/src/lib/components/onboarding/OnboardingWizard.svelte
@@ -5,6 +5,7 @@
import WelcomeStep from './steps/WelcomeStep.svelte';
import ProfileStep from './steps/ProfileStep.svelte';
import AppsStep from './steps/AppsStep.svelte';
+ import AiTierStep from './steps/AiTierStep.svelte';
import CreditsStep from './steps/CreditsStep.svelte';
import CompleteStep from './steps/CompleteStep.svelte';
import { Check } from '@mana/shared-icons';
@@ -22,6 +23,7 @@
{ id: 'welcome', label: 'Willkommen', component: WelcomeStep },
{ id: 'profile', label: 'Profil', component: ProfileStep },
{ id: 'apps', label: 'Apps', component: AppsStep },
+ { id: 'ai-tier', label: 'KI', component: AiTierStep },
{ id: 'credits', label: 'Credits', component: CreditsStep },
{ id: 'complete', label: 'Fertig', component: CompleteStep },
];
diff --git a/apps/mana/apps/web/src/lib/components/onboarding/steps/AiTierStep.svelte b/apps/mana/apps/web/src/lib/components/onboarding/steps/AiTierStep.svelte
new file mode 100644
index 000000000..4560f5844
--- /dev/null
+++ b/apps/mana/apps/web/src/lib/components/onboarding/steps/AiTierStep.svelte
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
Wie soll Mana KI nutzen?
+
+ Mana bietet KI-Funktionen auf vier Ebenen — von "gar keine" bis zu allem. Du entscheidest,
+ welche Schichten dein Vertrauen haben.
+
+
+
+
+
+
+
+
+
Lokal (ohne KI) — immer aktiv
+
+ Datum-Erkennung, Suche und einfache Klassifikation laufen offline ohne KI. Brauchst du
+ nichts auswählen — das ist immer da.
+
+
+
+
+
+
+
+ {#each cards as card}
+ {@const enabled = settings.allowedTiers.includes(card.tier)}
+
!card.disabled && toggleTier(card.tier)}
+ disabled={card.disabled}
+ class="w-full rounded-xl border p-4 text-left transition-all {enabled
+ ? 'border-primary bg-primary/5 ring-1 ring-primary/30'
+ : 'border-border bg-card hover:border-primary/40'} {card.disabled
+ ? 'cursor-not-allowed opacity-50'
+ : 'cursor-pointer'}"
+ >
+
+
+
+
+
+
+
{card.title}
+
+ {card.tagline}
+ {#if enabled}
+
+ aktiv
+
+ {/if}
+
+
{card.description}
+ {#if card.disabled && card.disabledHint}
+
+ {card.disabledHint}
+
+ {/if}
+
+
+
+ {/each}
+
+
+
+ {#if settings.allowedTiers.length > 0}
+
+ Reihenfolge:
+ {settings.allowedTiers.map((t) => tierLabel(t)).join(' → ')} → Lokal (Fallback)
+
+ {/if}
+
+
+
+
+ Du kannst diese Auswahl jederzeit in den Einstellungen ändern. Es ist auch komplett okay, hier
+ nichts auszuwählen — KI-Funktionen sind in Mana optional und alle Kern-Features funktionieren
+ ohne sie.
+
+
+
diff --git a/apps/mana/apps/web/src/lib/components/settings/AiSettings.svelte b/apps/mana/apps/web/src/lib/components/settings/AiSettings.svelte
new file mode 100644
index 000000000..def9c1042
--- /dev/null
+++ b/apps/mana/apps/web/src/lib/components/settings/AiSettings.svelte
@@ -0,0 +1,324 @@
+
+
+
+
+
+
+
+
+
KI-Optionen
+
+ Wähle, welche KI-Schichten Mana verwenden darf — von gar keiner bis zu allen
+
+
+
+
+
+
+
+
+
+
Lokal (ohne KI) — immer aktiv
+
+ Mana funktioniert auch ganz ohne KI: Datum-Erkennung, Suche und einfache Klassifikation
+ laufen über klassische Algorithmen. Manche Funktionen sind dann begrenzt, dafür ist alles
+ 100% offline und kostet nichts.
+
+
+
+
+
+
+
+ {#each tierCards as card}
+ {@const enabled = isEnabled(card.tier)}
+ {@const tierBlocked = card.tier === 'browser' && !webgpuSupported}
+
!tierBlocked && toggleTier(card.tier)}
+ disabled={tierBlocked}
+ class="w-full rounded-xl border p-4 text-left transition-all {enabled
+ ? 'border-primary bg-primary/5 ring-1 ring-primary/30'
+ : 'border-border bg-card hover:border-primary/40'} {tierBlocked
+ ? 'cursor-not-allowed opacity-50'
+ : 'cursor-pointer'}"
+ >
+
+
+
+
+
+
+
{card.title}
+ {#if enabled}
+ aktiv
+ {/if}
+
+
{card.subtitle}
+
+ {#each card.bullets as bullet}
+
+ •
+ {bullet}
+
+ {/each}
+
+ {#if card.warning}
+
+
+ {card.warning}
+
+ {/if}
+
+
+ {#if card.tier === 'browser' && enabled && webgpuSupported}
+
+ {#if browserCacheReady}
+ ✓ Modell geladen
+ {:else if localLlmStatus.current.state === 'downloading'}
+
+ Lade {defaultModelInfo.displayName} ({(
+ localLlmStatus.current.progress * 100
+ ).toFixed(0)}%)…
+
+ {:else}
+ {
+ e.stopPropagation();
+ loadBrowserModel();
+ }}
+ disabled={loadingBrowser}
+ class="rounded-md bg-primary px-3 py-1 text-xs font-medium text-primary-foreground disabled:opacity-50"
+ >
+ {loadingBrowser
+ ? 'Lade…'
+ : `Modell laden (~${defaultModelInfo.downloadSizeMb} MB)`}
+
+ {/if}
+
+ {/if}
+
+ {#if card.tier === 'browser' && tierBlocked}
+
+ WebGPU nicht verfügbar in deinem Browser. Funktioniert in Chrome/Edge 113+ oder
+ Safari 18+.
+
+ {/if}
+
+ {#if card.tier === 'cloud' && enabled && !settings.cloudConsentGiven}
+
e.stopPropagation()}
+ onkeydown={(e) => e.stopPropagation()}
+ role="presentation"
+ >
+
+ Bestätigung erforderlich
+
+
+ Cloud-Anfragen senden deine Inhalte an Google. Bitte bestätige, dass du das
+ verstanden hast und akzeptierst.
+
+
{
+ e.stopPropagation();
+ setCloudConsent(true);
+ }}
+ class="mt-2 rounded-md bg-amber-600 px-3 py-1 text-xs font-medium text-white hover:bg-amber-700"
+ >
+ Verstanden, Cloud aktivieren
+
+
+ {/if}
+
+ {#if card.tier === 'cloud' && enabled && settings.cloudConsentGiven}
+
+ ✓ Cloud-Zustimmung erteilt
+ {
+ e.stopPropagation();
+ setCloudConsent(false);
+ }}
+ class="text-muted-foreground hover:text-foreground"
+ >
+ Zurücknehmen
+
+
+ {/if}
+
+
+
+ {/each}
+
+
+
+
+ Aktuelle Reihenfolge:
+ {#if settings.allowedTiers.length === 0}
+ Nur lokal (ohne KI) — die meisten KI-Funktionen sind begrenzt.
+ {:else}
+ {settings.allowedTiers.map((t) => tierLabel(t)).join(' → ')} → Lokal (Fallback)
+ {/if}
+
+
+
+
+
+ setFallback((e.currentTarget as HTMLInputElement).checked)}
+ class="mt-0.5 h-4 w-4 rounded border-border"
+ />
+
+
Bei Fehler auf "Lokal" zurückfallen
+
+ Wenn die gewählte KI-Schicht eine Anfrage nicht beantworten kann, versucht Mana es mit der
+ lokalen Variante (sofern verfügbar). Aus: zeigt stattdessen einen Fehler an.
+
+
+
+
+
+ setShowSource((e.currentTarget as HTMLInputElement).checked)}
+ class="mt-0.5 h-4 w-4 rounded border-border"
+ />
+
+
Quelle bei jedem KI-Resultat anzeigen
+
+ Zeigt unter jeder KI-generierten Antwort eine kleine Markierung wie "Auf deinem Gerät"
+ oder "via Google Gemini" — damit du immer siehst, wo deine Daten gerade verarbeitet
+ wurden.
+
+
+
+
+
diff --git a/apps/mana/apps/web/src/routes/(app)/settings/+page.svelte b/apps/mana/apps/web/src/routes/(app)/settings/+page.svelte
index 8b60acace..0c8ac30ab 100644
--- a/apps/mana/apps/web/src/routes/(app)/settings/+page.svelte
+++ b/apps/mana/apps/web/src/routes/(app)/settings/+page.svelte
@@ -3,6 +3,7 @@
import { onMount } from 'svelte';
import { Button, Input, Card, PageHeader, GlobalSettingsSection } from '@mana/shared-ui';
import { PasskeyManager, TwoFactorSetup, AuditLog, SessionManager } from '@mana/shared-auth-ui';
+ import AiSettings from '$lib/components/settings/AiSettings.svelte';
import {
User,
CurrencyCircleDollar,
@@ -343,6 +344,11 @@
+
+
+
+
+