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>
|
||
|---|---|---|
| .. | ||
| apps | ||
| .gitignore | ||
| CLAUDE.md | ||
| README.md | ||
Mana Apps
A unified application ecosystem built on a shared authentication system, supporting multiple branded applications across web and mobile platforms.
Overview
Mana Apps is a monorepo containing web and mobile applications that provide organization management, team collaboration, and credit transfer capabilities. The system supports multiple branded applications (Memoro, Cards, Storyteller, Mana) through a flexible multi-tenant architecture.
Applications
- Web App (
apps/web) - SvelteKit-based web application - Mobile App (
apps/mobile) - React Native (Expo) app for iOS, Android, and web - Landing (
apps/landing) - Landing page (planned)
Features
- 🔐 Unified authentication with Supabase
- 🏢 Organization management with role-based access
- 👥 Team collaboration and member management
- 💰 Mana credit system with transfers and balance tracking
- 🎨 Multi-brand support with configurable themes
- 📱 Cross-platform (Web, iOS, Android)
- 🔄 Real-time updates across all platforms
- 🧪 Comprehensive testing with Vitest and Playwright
Quick Start
Prerequisites
- Node.js 20+
- pnpm (for web app)
- npm (for mobile app)
- Supabase account with project configured
- Expo CLI (for mobile development)
Setup
-
Clone the repository
git clone <repository-url> cd mana-core-apps -
Web App Setup
cd apps/web pnpm install cp .env.example .env # Edit .env with your Supabase credentials pnpm dev -
Mobile App Setup
cd apps/mobile npm install cp .env.example .env # Edit .env with your Supabase credentials npm start
Project Structure
mana-core-apps/
├── apps/
│ ├── web/ # SvelteKit web application
│ │ ├── src/
│ │ │ ├── routes/ # File-based routing
│ │ │ │ ├── (auth)/ # Public auth pages
│ │ │ │ └── (app)/ # Protected pages
│ │ │ ├── lib/
│ │ │ │ ├── components/
│ │ │ │ ├── config/ # Multi-app configuration
│ │ │ │ ├── server/ # Server-only utilities
│ │ │ │ └── types/
│ │ │ └── hooks.server.ts # Auth middleware
│ │ └── package.json
│ │
│ ├── mobile/ # React Native (Expo) app
│ │ ├── app/ # File-based routing (Expo Router)
│ │ │ ├── (drawer)/ # Drawer navigation
│ │ │ ├── auth/ # Auth screens
│ │ │ └── _layout.tsx # Root layout with auth
│ │ ├── components/ # React components
│ │ ├── utils/ # Utilities (Supabase, storage)
│ │ └── package.json
│ │
│ └── landing/ # Landing page (planned)
│
├── CLAUDE.md # Developer documentation
└── README.md # This file
Technology Stack
Web App (apps/web)
| Category | Technology |
|---|---|
| Framework | SvelteKit 2 with Svelte 5 (Runes) |
| Language | TypeScript |
| Styling | TailwindCSS 3 with PostCSS |
| Database | Supabase (PostgreSQL) |
| Auth | Supabase Auth with SSR |
| Testing | Vitest (unit) + Playwright (E2E) |
| Build Tool | Vite |
Mobile App (apps/mobile)
| Category | Technology |
|---|---|
| Framework | Expo 52 with React Native 0.76 |
| Language | TypeScript |
| Routing | Expo Router 4 (file-based) |
| Styling | NativeWind (TailwindCSS for RN) |
| Navigation | React Navigation (drawer, tabs) |
| Database | Supabase |
| Build | EAS Build |
| Platforms | iOS, Android, Web |
Development
Web App Commands
cd apps/web
# Development
pnpm dev # Start dev server (http://localhost:5173)
pnpm build # Build for production
pnpm preview # Preview production build
# Code Quality
pnpm check # Type-check with svelte-check
pnpm check:watch # Type-check in watch mode
pnpm lint # Check formatting and lint
pnpm format # Format code with Prettier
# Testing
pnpm test # Run unit tests (Vitest)
pnpm test:ui # Run tests with UI
pnpm test:e2e # Run E2E tests (Playwright)
Mobile App Commands
cd apps/mobile
# Development
npm start # Start Expo dev server
npm run ios # Run on iOS simulator
npm run android # Run on Android emulator
npm run web # Run web version (http://localhost:19006)
# Building
npm run build:dev # Build dev client
npm run build:preview # Build for internal testing
npm run build:prod # Build for production
# Code Quality
npm run lint # Lint and check formatting
npm run format # Fix linting and format code
# Setup
npm run prebuild # Generate native projects
Environment Configuration
Both apps require Supabase configuration. Create .env files based on .env.example:
Web App (apps/web/.env)
PUBLIC_SUPABASE_URL=your_supabase_project_url
PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
MIDDLEWARE_URL=https://mana-middleware-111768794939.europe-west3.run.app
PUBLIC_APP_NAME=Mana Web
NODE_ENV=development
Mobile App (apps/mobile/.env)
EXPO_PUBLIC_SUPABASE_URL=your_supabase_project_url
EXPO_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
Architecture
Multi-Tenant System
The system supports multiple branded applications sharing the same authentication backend:
- Memoro - Voice recordings and memory management
- Cards - AI-powered flashcard learning
- Storyteller - Creative writing with AI assistance
- Mana - Central account and organization management
App configurations are centralized in apps/web/src/lib/config/apps.ts, defining branding, features, and routing for each application.
Authentication Flow
Web (SvelteKit):
- Server-side authentication using
@supabase/ssr - Middleware in
hooks.server.tshandles session validation - Protected routes in
(app)group require authentication - JWT validation via
safeGetSession()before allowing access
Mobile (Expo):
- Client-side authentication using
@supabase/supabase-js - Custom memory storage for session persistence
AuthProviderinapp/_layout.tsxmanages auth state- Automatic navigation based on authentication status
Database Schema
Key tables:
users- User profiles (linked viaauth_idto Supabase Auth)organizations- Organization entitiesuser_roles- User-organization relationships with rolesteams- Team entities within organizationsteam_members- User-team membershipscredit_transactions- Mana credit transfer history
See CLAUDE.md for detailed architecture documentation.
Testing
Web App
cd apps/web
# Unit tests
pnpm test # Run all tests
pnpm test:ui # Open Vitest UI
# E2E tests
pnpm test:e2e # Run Playwright tests
pnpm test:e2e --ui # Run with Playwright UI
Mobile App
Mobile testing is primarily done through Expo Go or development builds:
cd apps/mobile
npm start # Start dev server
# Then press 'i' for iOS or 'a' for Android
Deployment
Web App
Vercel (Recommended):
cd apps/web
vercel
Netlify:
cd apps/web
netlify deploy
Mobile App
iOS and Android (via EAS):
cd apps/mobile
# Preview build (internal testing)
npm run build:preview
# Production build
npm run build:prod
Configure EAS in eas.json with your build profiles.
Contributing
- Create a feature branch from
main - Make your changes
- Run linting and tests
- Submit a pull request
Code Style
- Use TypeScript for type safety
- Follow ESLint and Prettier configurations
- Write tests for new features
- Use conventional commit messages
Documentation
- CLAUDE.md - Comprehensive developer guide for Claude Code
- apps/web/README.md - Web-specific documentation
- Individual component documentation in source files
Support
For questions or issues, please contact the development team or open an issue in the repository.
License
Private - All rights reserved