managarten/apps
Till JS 6b8e2c7176 feat(mana/web): encryption phase 6.2/6.3 — settings page + onboarding banner
Two user-facing surfaces for the encryption pipeline that's been
running invisibly since Phase 4. Closes the loop on "we encrypt
your data" by making the claim concrete, verifiable, and rotatable.

vault-instance.ts (new)
  Lazy-singleton wrapper around createVaultClient. The root layout
  was holding a private vault client reference; the settings page
  needs the same instance to call rotate() and read state.
  getVaultClient() builds it on first call from authStore +
  getManaAuthUrl(), reuses it forever after. Phase 3's
  setKeyProvider/getActiveKey wiring means the rest of the data
  layer doesn't need to know about the singleton at all — only
  callers that want to drive lock/unlock/rotate explicitly do.

  +layout.svelte and the new settings/security page both call
  getVaultClient() — the underlying MemoryKeyProvider is shared
  via setKeyProvider, so an unlock from either surface immediately
  reflects in both.

routes/(app)/settings/security/+page.svelte (new)
  Surface for the encryption vault state. Three sections:

    1. STATUS card with a coloured badge:
       - 🔒 Verschlüsselt (green) when unlocked
       - 🔓 Gesperrt (amber) when locked, plus a "Schlüssel jetzt
         laden" button that calls vaultClient.unlock()
       - error states distinguish auth/network/server with
         localised copy and a retry button

       A 1-second poll mirrors external lock/unlock events
       (logout, manual lock from another tab) so the badge stays
       fresh without a hard refresh. Disposed on unmount.

    2. ENCRYPTED FIELDS list — derived from the registry:
       Object.entries(ENCRYPTION_REGISTRY).filter(enabled).map(...)
       Renders one row per table with the field allowlist visible
       in monospace, plus a count summary at the top. The list is
       always honest: if a registry entry is enabled:false (Phase 7
       targets, server-pushed tables, etc.), it does not appear.

    3. ROTATE card (danger styling):
       Two-step confirm before mutating. Calls vaultClient.rotate()
       which the existing Phase 3 wire already routes through
       /api/v1/me/encryption-vault/rotate. Toast on success/failure.
       Explicitly documents that the old MK is GONE and current
       data is NOT auto-re-encrypted — the user accepts that risk.

    4. HONEST DISCLOSURE section: lists what Mana CAN'T see
       (encrypted blobs), what Mana COULD technically see
       (the wrapped MK if a hosting employee actively reaches for
       the KEK), and what's structurally visible (counts,
       timestamps, relationships). Reads better than any policy
       page because it's anchored in the actual data layout.

EncryptionIntroBanner.svelte (new)
  One-time onboarding banner that fires on the first vault unlock
  ever on a given device. Uses localStorage('mana-encryption-intro-
  dismissed') as the persistent flag. Shows a green-bordered card
  bottom-centre explaining at-rest encryption in three sentences,
  with a "Mehr erfahren →" link to /settings/security and an X
  dismiss button.

  Why a banner instead of a toast?
    - Toasts disappear after 3s; a privacy claim deserves longer
      attention.
    - The banner has room for a learn-more link; toasts don't.
    - Dismissing it is an explicit user action, which matches the
      "you understand and accept" social contract.

  Polls vault state every 500ms for up to 30s after mount so it
  fires even if the unlock happens asynchronously after the layout
  finishes rendering. Auto-clears the timer once it shows or after
  the 30s window. SSR-safe: localStorage access is guarded.

  Mounted globally in the root layout next to the existing
  SuggestionToast, OfflineIndicator, PwaUpdatePrompt.

Layout integration
  routes/+layout.svelte:
    - Drops the inline createVaultClient + getManaAuthUrl import
      in favour of getVaultClient() — single source of truth.
    - <EncryptionIntroBanner /> mounted alongside the other
      global UI elements.

Verified: 20 test files, 262/262 tests passing. Pre-existing
TS error in src/routes/(app)/settings/+page.svelte:338
(getSecurityEvents on authStore) is unrelated parallel drift.

Encryption pipeline status: Phase 1-6 complete.
  - 22 tables encrypted at rest covering >85% of user-typed bytes
  - Server-side master key vault with KEK-wrapping (mana-auth)
  - Vault unlock on login, lock on logout
  - Per-record encryptRecord/decryptRecord through every store
  - Settings UI showing status + rotate
  - First-login onboarding banner

Remaining for a hypothetical Phase 7:
  - tasks/calendar.events/habits — title leakage via timeBlocks
  - picture/storage/music — server-pushed, needs API encryption
  - nutriphi/uload/context.documents/questions — store extraction
    needed before they can flow through encryptRecord
  - Recovery code opt-in for true zero-knowledge users (server
    can't even technically decrypt)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 19:54:09 +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 chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +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): encryption phase 6.2/6.3 — settings page + onboarding banner 2026-04-07 19:54:09 +02:00
manacore/apps/web/src/lib feat: rename ManaCore to Mana across entire codebase 2026-04-05 20:00:13 +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