- Add AuthErrorCode union and typed twoFactorRedirect/retryAfter fields on AuthResult so the frontend can branch on stable codes instead of locale-dependent error strings.
- Extend signInWithPasskey with an optional { conditional } flag, threaded through to @simplewebauthn/browser via useBrowserAutofill, so hosts can opt into WebAuthn Conditional UI (passkey suggestions inline in the email autofill dropdown).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace $effect + liveQuery().subscribe() with useLiveQueryWithDefault
in 6 dashboard modules (todo, calendar, contacts, habits, notes, finance)
to prevent cascading $state writes exceeding Svelte 5 effect depth limit
- Defer checkInlineSuggestion in Dexie hooks via setTimeout to avoid
cross-table reads within a single-table transaction scope
- Add 5s timeout to trySSO fetch calls so app loads in guest mode when
mana-auth is unreachable
- Fix guestMode reactivity by declaring with $state()
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolves event name collisions in the unified app (e.g. view_changed,
deck_created, search_performed) by adding a `module` property to every
tracked event via createModuleTracker. Also fixes duplicate tracking in
Planta routes (now only tracked in mutations.ts).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add locale prop (de/en) to PasswordStrength, ChangePassword,
SecurityOnboarding, AuditLog, AuthGate tier screen
- Add 13 new i18n keys to LoginTranslations for 2FA, lockout, magic link
- Fix date formatting to use locale in AuditLog
- Rewrite ForgotPasswordPage to Tailwind (matching Login/Register)
- Fix HTML injection in ForgotPasswordPage (remove @html with email)
- Guard DEV credentials behind isDevMode check in LoginPage
- Extend AuthResult type with twoFactorRedirect and retryAfter
- Remove as any casts in LoginPage
- Replace scoped CSS with Tailwind in AuthGate tier-denied screen
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces a tiered access control system so apps can be released
gradually (founder → alpha → beta → public) without extra infrastructure.
Users are gated at the AuthGate level based on their tier vs the app's
requiredTier. All apps remain deployed and reachable, but only users
with sufficient tier can enter.
- Add accessTier enum + column to users schema (default: 'public')
- Add tier claim to JWT payload in better-auth config
- Add requiredTier field to ManaApp interface + all 25 apps
- Add hasAppAccess(), getAccessibleManaApps(), ACCESS_TIER_LABELS
- Update AuthGate with tier check + access denied screen
- Update getPillAppItems + Home page to filter by user tier
- Update all 22 app layouts to pass user tier to PillNav
- Add admin API: GET/PUT /api/v1/admin/users/:id/tier
- Document access tier system in CLAUDE.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TypeScript's ReturnType<> inference truncates large object literals,
showing only ~27 of 37 methods. This caused 5 apps to skip type-check
because verifyTwoFactor, signInWithPasskey, sendMagicLink, etc. were
invisible to consumers.
Fix: Define explicit AuthServiceInterface with all 37 methods and use
it as the return type of createAuthService(). This ensures all methods
are visible regardless of object literal size.
Verified: chat/web and presi/web now pass svelte-check for auth methods.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Session management:
- GET /auth/sessions and DELETE /auth/sessions/:id endpoints
- listSessions() and revokeSession() in shared-auth client
- SessionManager component: active sessions list with device info,
"Aktuell" badge, revoke individual or all other sessions
- Integrated in ManaCore settings page
Account lockout UX:
- Dedicated amber lockout banner (distinct from generic rate-limit)
- "Konto vorübergehend gesperrt" with MM:SS countdown
- "Passwort zurücksetzen" link as alternative action
- formatCountdown helper for clean time display
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Password strength (zxcvbn-ts):
- PasswordStrength component with 4-segment color bar and German feedback
- Lazy-loaded with 150ms debounce to avoid SSR/bundle issues
- Integrated into RegisterPage and ChangePassword components
Magic Links (passwordless email):
- Better Auth magicLink plugin (10-minute expiry)
- sendMagicLinkEmail() in email service (German template)
- Passthrough route for /magic-link/* endpoints
- sendMagicLink() in shared-auth client
- "Login-Link per E-Mail senden" button on all 20 login pages
- All 21 auth stores have sendMagicLink() method
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Passkey Conditional UI: autocomplete="username webauthn" on email
field enables browser passkey suggestions in autofill dropdown
2. Trust Device checkbox: "Diesem Gerät 30 Tage vertrauen" option
during 2FA verification (uses Better Auth trust_device cookie)
3. Local QR code generation: replaced external api.qrserver.com with
local qrcode package for 2FA setup (no external dependency)
4. SecurityOnboarding component: post-registration wizard suggesting
passkey setup to new users
5. ChangePassword component: reusable password change form with
validation, visibility toggles, and changePassword() in authService
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements passwordless authentication via passkeys using @simplewebauthn:
Backend (mana-core-auth):
- New passkeys table in auth schema (credentialId, publicKey, counter, etc.)
- PasskeyService with registration/authentication flows and challenge storage
- 7 new API endpoints (register, authenticate, list, delete, rename)
- createSessionAndTokens helper for non-password auth flows
- Security event types for passkey operations
Client (shared-auth):
- signInWithPasskey() and registerPasskey() with dynamic @simplewebauthn/browser imports
- isPasskeyAvailable() browser capability check
- Passkey management methods (list, delete, rename)
UI (shared-auth-ui):
- Passkey button on LoginPage with key icon, shown when browser supports WebAuthn
- Divider between passkey and email/password form
App integration:
- All 19 web app auth stores have isPasskeyAvailable() and signInWithPasskey()
- All 19 web app login pages pass passkeyAvailable and onSignInWithPasskey props
- rpID=mana.how in production enables cross-app passkey usage (SSO-compatible)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No external auth providers to keep authentication fully self-sovereign
and avoid dependency on third-party services. Removes Google Sign-In,
Apple Sign-In components, utilities, endpoints, translations, and
mobile dependencies across all apps and shared packages.
Google/Apple integrations for data sync (Contacts import, Calendar sync)
are intentionally preserved as they serve a different purpose.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Users now see an amber banner with a re-login button instead of a
broken empty page when their session expires. Uses pub/sub events
from tokenManager, integrated in todo, calendar, zitare, contacts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
setupFetchInterceptor now accepts a urls[] array instead of wrapping
globalThis.fetch twice (once for auth URL, once for backend URL).
Backward compatible - backendUrl still works, mapped to urls internally.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add inline Umami tracking to @manacore/shared-auth authService for
login, signup, logout, SSO, and social auth events. Tracks both
success and failure with auth method metadata.
This automatically covers all web apps without any per-app code
changes. No-ops silently in environments without Umami (mobile, SSR).
Tracked events: login, login_failed, signup, signup_failed, logout,
password_reset_requested (with method: email/google/apple/sso)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The signIn() method only called the custom /api/v1/auth/login endpoint
which returns JWT tokens but doesn't set a session cookie. Without the
cookie, cross-subdomain SSO (trySSO) can never find an active session.
Now also calls Better Auth's native /api/auth/sign-in/email with
credentials:'include' after successful login, which sets the session
cookie with Domain=.mana.how for cross-subdomain SSO.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add shared-pwa, qr-export, and wallpaper-generator packages
to the Docker build context for manacore-web.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Single Sign-On (SSO) support across all mana.how subdomains:
- Add trySSO() method to @manacore/shared-auth that exchanges session
cookies for JWT tokens
- Add /api/v1/auth/session-to-token endpoint to mana-core-auth service
- Update all 15 web apps to try SSO during auth initialization
SSO Flow:
1. User logs in on any app (e.g., calendar.mana.how)
2. Session cookie is set with Domain=.mana.how
3. When visiting another app (e.g., todo.mana.how), it checks for
local tokens first
4. If no local tokens, tries SSO via session cookie
5. Session cookie is exchanged for JWT tokens via new endpoint
6. User is automatically authenticated
Apps updated: calendar, chat, clock, contacts, manacore, manadeck,
nutriphi, picture, planta, presi, questions, skilltree, storage,
todo, zitare
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ability to resend verification email when login fails with
"Email not verified" error. Implemented across all 14 apps using
Mana Core Auth.
Changes:
- Add POST /api/v1/auth/resend-verification endpoint to mana-core-auth
- Add resendVerificationEmail method to shared-auth client
- Update LoginPage component with resend UI and translations
- Add resendVerificationEmail to all app auth stores
- Add translations for de, en, fr, es, it
- Add PlantaLogo to shared-branding
- Migrate planta login to shared LoginPage component
- Add GET /api/auth/reset-password/:token endpoint to handle email links
- Create password-reset-redirect store to track source app URLs
- Include callbackURL in reset emails for proper app redirection
- Add redirectTo parameter to forgotPassword in shared-auth
- Create /reset-password page in calendar app with DE/EN translations
- Update calendar authStore with resetPasswordWithToken method
Fixes 404 error when clicking password reset link from email
Add sourceAppUrl tracking during registration to redirect users back
to the app they registered from after email verification. Includes
URL validation for security (only *.mana.how, mana.how, localhost).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Merge till-dev branch containing:
- Planta plant care tracking application
- Clock backend with alarms, timers, world clocks
- Zitare backend with favorites and lists
- Various app improvements and fixes
- Auth system updates
- Infrastructure improvements
Note: Some type-check issues may need resolution after merge.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add required name field (min 2 chars) to all registration forms to fix
Better Auth validation error. Updates backend DTO, shared-auth service,
shared-auth-ui RegisterPage component, i18n translations, and all app
auth stores and register pages.
Create new shared package for Better Auth type definitions:
- UserRole, JWTPayload, CurrentUserData types
- Type guards: isValidUserRole, isValidOrganizationRole
- Utility functions: jwtPayloadToCurrentUser
- userAdditionalFields for client type inference
Migrate shared packages to use centralized types:
- @manacore/shared-auth re-exports from new package
- @manacore/shared-nestjs-auth uses new package as dependency
- Fix 121 accessibility warnings across 9 web apps (manacore, clock, chat,
manadeck, calendar, zitare, contacts, picture, todo)
- Add proper ARIA attributes (role, tabindex, aria-label) to interactive elements
- Add onkeydown handlers alongside onclick for keyboard accessibility
- Add svelte-ignore comments for intentional patterns (modals, dropdowns)
- Update svelte-check threshold from error to warning in pre-commit hook
- Fix script compatibility for bash 3.x (remove associative arrays)
- Add comprehensive documentation for svelte-check patterns and fixes
All web apps now pass svelte-check with 0 errors and 0 warnings.
Pre-commit hooks will block any future commits with warnings.
- Add backendUrl parameter to initializeWebAuth() for interceptor config
- Expand isTokenExpiredResponse() to match more error patterns:
- "invalid token", "token validation failed", "claim" (jose errors)
- ERR_JWT_EXPIRED error code
- Update all web apps to pass backendUrl for automatic refresh:
- picture (3006), chat (3002), zitare (3007), contacts (3015)
- calendar (3014), clock (3017), todo (3018)
- Fix API client default port in picture web app
This prevents users from being randomly signed out when JWT expires.
The interceptor now catches 401 responses and automatically refreshes
the token before retrying the request.
- Add ContactSelector, ContactBadge, ContactAvatar to shared-ui
- Add ContactsClient API service to shared-auth
- Add ContactReference, ContactSummary types to shared-types
- Todo: Add assignee and involvedContacts to tasks with UI in TaskEditModal
- Todo: Display contacts in TaskItem and KanbanTaskCard
- Calendar: Add AttendeeSelector with RSVP status support
- Calendar: Integrate attendees in EventForm
- Calendar: Add task drag-drop to calendar views (Day/Week/MultiDay)
- Contacts: Add ContactTasks component to show related tasks
- Backend: Add findByContact endpoint to Todo task service
- UI polish: glassmorphism styling, keyboard navigation, auto-focus
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add referral code input to RegisterPage with live validation
- Create ReferralWidget for dashboard with stats, code sharing, and tier display
- Extend authService.signUp to accept optional referralCode parameter
- Add validateReferralCode function to authStore
- Create referrals.ts API service for frontend
- Add 'referral' widget type to dashboard configuration
- Fix drizzle.config.ts to include 'referrals' schema filter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add password reset functionality to mana-core-auth using Better Auth
- Add forgot-password and reset-password endpoints with DTOs
- Update shared-auth package with resetPassword method and endpoint
- Update manacore-web auth store with resetPassword method
- Refactor reset-password pages to use mana-core-auth instead of Supabase
- Remove Supabase dependencies from manacore-web package.json
- Remove Supabase server code (hooks.server.ts, supabase.ts, API routes)
- Update Dockerfile to remove shared-supabase dependency
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Auth fixes:
- Update fetchInterceptor skip patterns for ManaCore auth endpoints
- Fix URL matching to compare full origins instead of partial matches
- Update token manager state after successful login
- Remove Supabase session dependency from layouts
- Use authStore for auth state in route layouts
Dashboard fixes:
- Add network error detection in base-client to prevent infinite retries
- Update all 9 dashboard widgets to not retry on service unavailable
- Add /api/v1 prefix to all backend service URLs (chat, calendar, contacts, todo, zitare, picture, manadeck)
Commands:
- Add dev:manacore:backends to start all 9 dashboard backends
- Add dev:manacore:full to start web + all backends together
- Update COMMANDS.md with new commands and backend port table
Auth service:
- Fix TypeScript error: crossApp → cross_app in referrals schema
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
crypto.randomUUID() requires HTTPS (secure context). Staging uses HTTP,
so add fallback using crypto.getRandomValues() which works in insecure
contexts.
Fallback chain:
1. crypto.randomUUID() - native, requires HTTPS
2. crypto.getRandomValues() - works on HTTP
3. Math.random() - last resort fallback
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add svelte-i18n configuration with SSR support to all web apps
- Create LanguageSelector component for each app with brand colors
- Add German and English locale files
- Integrate language switcher into login pages via headerControls snippet
- Fix Tailwind v4 @source directives for shared package scanning
- Update AppSlider styling to match login container design
Apps updated:
- Memoro (gold #f8d62b)
- Märchenzauber (pink #FF6B9D)
- ManaDeck (purple #8b5cf6)
- ManaCore (indigo #6366f1)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>