managarten/apps
Till JS 45958ad885 feat(mana/web): global requireAuth() gate for guest-blocked features
The unified Mana app runs most modules in a "guest mode": you can
open a module, look around, type a quick note, etc. without an
account. But anything that touches an *encrypted* table (dreams
voice capture, memoro recordings, notes, todo, calendar events, …)
needs the user to be logged in — the encryption vault only unlocks
against a Mana Auth session, and writing to those tables without
it throws `VaultLockedError` at the very last step of the action.

Before this commit, every entry point into an encryption-required
action would silently let the guest go through the whole flow
(record audio, wait for transcription, open the dexie write) and
then explode with a stack-trace error. The user lost work and
didn't know why. The dreams voice capture flow surfaced this
during the 2026-04-08 STT debugging session.

The fix is a global imperative gate: `requireAuth({ feature, reason })`.
Call sites await it before the action; it returns immediately if the
user is already authenticated, otherwise pops a global modal that
asks the guest to log in or cancel. Promise-based, so callers
decide what to do with `false` (silent abort, restore state, own
toast).

  $lib/auth/require-auth.svelte.ts          new — store + helper
  $lib/components/auth/AuthRequiredModal.svelte  new — global modal
  routes/+layout.svelte                     mount the modal once
  packages/shared-utils/src/analytics.ts    new ManaEvents.featureBlockedByAuth
                                            event for conversion tracking

Wired into the two voice-capture entry points that actually exhibited
the bug:

  modules/dreams/ListView.svelte  → feature: 'dreams-voice-capture'
  routes/(app)/memoro/+page.svelte → feature: 'memoro-voice-capture'

Both gate on `requireAuth()` BEFORE the mic permission request, so
guests see the friendly "Konto erforderlich" modal instead of
recording → transcribing → crashing.

Design choices documented in detail in the require-auth.svelte.ts
header comment:
  - Imperative function (not a button wrapper component) so it
    works in event handlers, store actions, keyboard shortcuts,
    drag-drop handlers — anywhere async code runs.
  - Single global modal mounted once in the root layout, no
    portal/z-index gymnastics; two simultaneous prompts replace
    each other (the most recent one wins).
  - Checks `authStore.isAuthenticated`, not vault-unlocked state —
    the user-facing concept is "I need an account", not "I need
    a working encryption vault". Vault-unlock failures (network
    error etc.) are a separate bug class with their own UX.
  - The modal navigates to `/login?next=<current path>` so the
    user lands back on the same page after logging in. The
    Promise resolves `false` on navigation; the user re-clicks
    the original button after coming back, and the second click
    sees `isAuthenticated === true` and proceeds without a modal.
    Re-triggering the original action across a navigation cycle
    would require restoring half-recorded mic state — not worth
    the complexity, and the second click is a clean UX.

How to wire a new entry point (4 lines):

    import { requireAuth } from '$lib/auth/require-auth.svelte';

    async function handleCreateThing() {
      const ok = await requireAuth({
        feature: 'create-thing',
        reason: 'Things werden verschlüsselt gespeichert. Dafür brauchst du ein Mana-Konto.',
      });
      if (!ok) return;
      // ...existing logic
    }

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:36:38 +02:00
..
api feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
calc/packages/shared chore: delete 25 web-archived directories, remove stale stubs, clean workspace config 2026-04-03 13:03:49 +02:00
calendar chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
cards chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
chat chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
citycorners chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
contacts chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
context chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
docs docs: Phase 9 documentation roundup — close encryption-shaped doc gaps 2026-04-08 11:47:59 +02:00
guides chore: delete 25 web-archived directories, remove stale stubs, clean workspace config 2026-04-03 13:03:49 +02:00
inventar chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
mana feat(mana/web): global requireAuth() gate for guest-blocked features 2026-04-08 15:36:38 +02:00
manavoxel chore(workspace): unify vitest to ^4.1.2 across all packages 2026-04-07 13:58:29 +02:00
matrix chore(workspace): unify vitest to ^4.1.2 across all packages 2026-04-07 13:58:29 +02:00
memoro chore(workspace): unify vitest to ^4.1.2 across all packages 2026-04-07 13:58:29 +02:00
moodlit feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
mukke feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
news chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
nutriphi chore(workspace): unify vitest to ^4.1.2 across all packages 2026-04-07 13:58:29 +02:00
photos chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
picture chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
planta chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
presi chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
questions feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
skilltree chore: delete 25 web-archived directories, remove stale stubs, clean workspace config 2026-04-03 13:03:49 +02:00
storage chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
times chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
todo chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
traces feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +02:00
uload chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
zitare/packages/content chore: delete 25 web-archived directories, remove stale stubs, clean workspace config 2026-04-03 13:03:49 +02:00