Homepage fixes:
- Add loading state: show TaskListSkeleton while liveQuery loads
- Fix $derived(() => ...) anti-pattern → $derived.by()
- Stabilize date calculations (compute once, not per re-render)
- Remove double error check (mutation errors shown via toast)
TaskItem improvements:
- Show completed-at date (small, 50% opacity) on right side of
completed tasks
- Click completed date to toggle showing created-at date above it
Shared: Add `loading` field to useLiveQueryWithDefault (was missing,
prevented proper loading states in consumers)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Created createManaAuthStore in @manacore/shared-auth-stores that replaces
~350 lines of duplicated auth.svelte.ts per app with a ~10 line factory call.
The factory handles: SSO, passkeys, 2FA, magic links, token management,
password reset, sign up/in/out — everything the old stores did.
Each app only provides devBackendPort and optional onAuthenticated callback.
Before: 21 apps × ~350 lines = 6,800 lines of duplicated auth code
After: 21 apps × ~10 lines = 182 lines total (97% reduction)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merged shared-subscription-types + shared-subscription-ui into
@manacore/subscriptions. Updated imports in 15 web apps.
Package count: 49 → 47
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merged shared-feedback-types + shared-feedback-service + shared-feedback-ui
into a single @manacore/feedback package. Updated imports in all 21 apps.
Before: 3 packages (types, service, ui) with cross-dependencies
After: 1 package with direct imports, no circular refs
Note: ESLint warnings from pre-existing unused vars in chat/mukke
servers are unrelated to this change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shared Go utilities for all ManaCore Go services:
- httputil: WriteJSON, WriteError, DecodeJSON
- envutil: Get, GetInt, GetBool, GetSlice
- 8 tests, all passing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add credits.ts to @manacore/shared-hono as replacement for
CreditClientService from @mana-core/nestjs-integration.
Exports: getBalance, validateCredits, consumeCredits, refundCredits
Calls mana-credits service via MANA_CREDITS_URL + X-Service-Key.
Same API surface as the NestJS version but as pure functions
instead of an @Injectable() service class.
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>
- Todo: Replace manual fetch/state stores with useLiveQuery() for tasks,
projects, and tags. Components use Svelte context instead of store imports.
Stores reduced to mutation-only services. Removes ~200 lines of manual
state management. Enables multi-tab sync and auto-refresh on data changes.
- Tags (all 16 apps): Migrate from API-based createTagStore() to shared
local-first IndexedDB ('manacore-tags'). Tags now work offline and in
guest mode with default seed data. All apps share the same tag DB via
tagLocalStore + useAllTags() + setContext pattern.
- Cleanup: Delete unused Todo API files (projects.ts, labels.ts,
reminders.ts), remove dead labels store, clean up barrel exports.
Apps migrated: Todo, Zitare, Questions, Planta, Clock, Presi, Mukke,
Context, CityCorners, ManaDeck, Chat, Contacts, Calendar, Picture,
Storage, Photos
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both apps are fully local-first via Dexie.js + mana-sync. Their NestJS
backends were pure CRUD wrappers (20 + 31 source files) that are no
longer needed.
Changes:
- Add packages/shared-hono: JWT auth via JWKS (jose), Drizzle DB factory,
health route, generic GDPR admin handler, error middleware
- Migrate zitare lists page from fetch() to listsStore (local-first)
- Rewrite clock timers store from API-based to timerCollection (Dexie)
- Update clock +layout.svelte CommandBar search to use local collections
- Remove zitare-backend + clock-backend from docker-compose, CI/CD,
Prometheus, env generation, setup scripts
- Add docs/TECHNOLOGY_AUDIT_2026_03.md with full repo analysis
Net result: -2 Docker containers, -2 ports, -2728 lines of code
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update consumers to call the new standalone mana-credits service instead
of the credit endpoints embedded in mana-core-auth.
Changes:
- CreditClientService: Add getCreditsUrl() reading MANA_CREDITS_URL
(falls back to MANA_CORE_AUTH_URL for backward compatibility).
All credit calls now use /api/v1/internal/* endpoints.
- BetterAuthService: Replace direct DB inserts for credit balance and
guild pool init with HTTP calls to mana-credits internal API.
Replace local gift redemption with HTTP call.
- .env.development: Add MANA_CREDITS_URL=http://localhost:3060
- CLAUDE.md: Add mana-credits to services list
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add API key authentication to all GPU services (X-API-Key header)
- /health and /docs remain public (no key needed)
- Shared key configured via GPU_API_KEY env variable
- Add VRAM auto-unload for mana-image-gen (5min) and mana-stt (10min)
- FLUX.2 pipeline freed after idle, recovering ~13GB VRAM
- WhisperX models freed after idle, recovering ~3GB VRAM
- Install Piper TTS voices (Thorsten + Kerstin) for local German TTS
- Update @manacore/shared-gpu client to support apiKey parameter
- Add GPU_API_KEY to .env.development
- Document API auth and VRAM management in setup guide
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 21 separate NestJS Matrix bot processes (~2.1 GB RAM, ~4.2 GB Docker images)
with a single Go binary using plugin architecture (8.6 MB binary, ~30 MB RAM).
New services:
- services/mana-matrix-bot/ — Go Matrix bot with 21 plugins (mautrix-go, Redis sessions)
- services/mana-api-gateway-go/ — Go API gateway (rate limiting, API keys, credit billing)
Deleted:
- 21 services/matrix-*-bot/ directories
- packages/bot-services/ and packages/matrix-bot-common/
- Legacy deploy scripts and CI build jobs
Updated:
- docker-compose.macmini.yml: new Go services, legacy bots removed
- CI/CD: change detection + build jobs for Go services
- Root package.json: new dev:matrix, build:matrix, test:matrix scripts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Auth store starts/stops sync on login/logout
- LocalStore queues all existing records for initial sync (guest→auth transition)
- LocalCollection.queueAllForSync() creates pending inserts for all local records
- Skips initial queue if sync cursor exists (already synced before)
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>
Replace old 3-tier model (Plus/Pro/Ultra) with 5 size-based tiers (S/M/L/XL/XXL).
New naming: "Mana Quelle" for subscriptions, "Mana Trank" for one-time purchases.
Create new Stripe products and prices, archive old ones, update all UI and seed data.
Subscription tiers: S (500 Mana, 4.99€), M (1000, 9.99€), L (2000, 19.99€),
XL (4000, 39.99€), XXL (10000, 99.99€). Yearly: 20% discount.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace removed B2B org credit system with consumer-friendly shared
Mana pools. Members spend directly from a guild pool managed by the
Gildenmeister (owner). Supports funding from personal balance,
per-member spending limits, and credit source routing.
New endpoints: /gilden/* (guild CRUD) and /credits/guild/* (pool ops).
POST /credits/use now accepts optional creditSource for guild routing.
Delete broken b2b-journey E2E tests that tested phantom endpoints.
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>
Implement the foundational local-first data layer for ManaCore apps:
- New @manacore/local-store package (Dexie.js IndexedDB, sync engine, Svelte 5 reactive queries)
- New mana-sync Go service (sync protocol, WebSocket push, field-level LWW conflict resolution)
- Todo app migrated as pilot: stores read/write IndexedDB, guest mode with onboarding seed data
- PillNavigation: prominent login pill for unauthenticated users
- SyncIndicator component showing local/syncing/offline status
- GuestWelcomeModal on first visit for Todo app
- Removed demo-mode auth_required checks from Todo components (all writes are now local)
- CSP fix for local development (localhost:3001, localhost:3050)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add proper FK constraint on tags.groupId -> tag_groups.id (onDelete: set null)
- Validate auth token is non-empty before API requests in TagsClient
- Add @IsNotEmpty/@MinLength(1) on tag and tag group name DTOs
- Add @MaxLength on all query params in tag-links DTOs
- Add GetTagsForEntityDto for validated query params on tags-for-entity endpoint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
In production, backends use the internal Docker URL (http://mana-auth:3001) for
MANA_CORE_AUTH_URL but tokens are issued with BASE_URL (https://auth.mana.how) as
the issuer. Accept both to prevent "unexpected iss claim value" errors.
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>
- Add createTagStore factory to @manacore/shared-stores (Svelte 5 runes, backed by @manacore/shared-tags)
- Replace Todo's local TagStrip with shared TagStrip from @manacore/shared-ui
- Replace Todo's labels store with createTagStore wrapper (backward-compatible)
- Remove "Tags" tab from PillNav TabGroup, add it as toggle pill (like Filter)
- Tags pill toggles TagStrip overlay visibility instead of navigating to /tags
- TagStrip has "Tags verwalten" pill linking to /tags management page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The package.json was pointing main/exports to src/index.ts which crashes in production
Docker containers where Node runs CJS and can't handle ESM export tokens.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PillNavigation: add helpHref and themesHref props with help icon in account dropdown
- PillDropdown: add help icon (question mark circle) to iconPaths
- shared-help-types: add getManaFAQs/getManaFeature for shared Mana credit FAQs
- shared-help-types: add getPrivacyFAQs for shared privacy/GDPR/tech independence FAQs
- ManaScore: add Help-Seite and Feedback-Seite as UX criteria, shared-help-ui and
shared-feedback-ui as Core cross-app packages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PasskeyManager.svelte: reusable component for listing, registering,
renaming, and deleting passkeys (German defaults, fully translatable)
- Production env: WEBAUTHN_RP_ID=mana.how and WEBAUTHN_ORIGINS for all
*.mana.how subdomains in docker-compose.macmini.yml
- Local DB: passkeys table created via direct SQL
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>
The createUserSettingsStore was receiving a static auth URL evaluated at
module load time, before window.__PUBLIC_MANA_CORE_AUTH_URL__ was
injected by hooks.server.ts. In production this caused CSP violations
as settings API calls went to localhost:3001 instead of auth.mana.how.
Changes:
- Accept string | (() => string) for authUrl in shared-theme config
- Resolve authUrl lazily at fetch time instead of module load
- Fix fallback to empty string in non-dev environments (was localhost)
- Pass getAuthUrl as getter function in all 17 web apps
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add NutriPhiEvents (mealAdded, mealDeleted, photoAnalyzed, textAnalyzed,
goalsUpdated, favoriteSaved, favoriteUsed) to shared analytics utils.
Add deckDeleted and cardDeleted to ManaDeckEvents. Wire up event calls
in NutriPhi meals store and ManaDeck deck/card stores.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add app-specific Umami event helpers and integrate tracking into:
- Context: 6 events (document create/delete/pin, space create/delete, AI generated)
- SkillTree: 3 events (skill create/delete with branch, XP added with level-up)
- Planta: 4 events (plant analyzed/created/deleted, plant watered)
- Questions: 5 events (question create/delete, research started, collection create/delete)
Updates ManaScore analytics from 3/5 to 4/5 for all four apps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add defaultTranslationsDE/EN and getHelpTranslations() to shared-help-ui
so apps only need to override the subtitle instead of duplicating ~80 lines
- Refactor all 6 existing help pages to use getHelpTranslations()
(Contacts, Calendar, Todo, Storage, Chat, Picture)
- Add help page to Zitare (FAQ, features, contact — no shortcuts)
- Migrate Mukke from custom SettingsPage-based help to shared HelpPage
(FAQ with audio formats, lyrics editor, playlists; features; shortcuts)
All 8 web apps now use the unified shared help system.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace HTTP POST to /api/v1/auth/validate with local JWT verification
using jose + createRemoteJWKSet. Eliminates ~5-20ms HTTP roundtrip per
API request across all backends. JWKS cached automatically by jose.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace copy-pasted appReady/loading/redirect logic in all 13 layouts
with a shared AuthGate component. Supports guest mode, onReady callback
for app-specific data loading, and configurable login redirect.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add HTML sanitization via isomorphic-dompurify in parser layer to prevent XSS
- Replace all hardcoded English strings with translations (FAQSection, KeyboardShortcuts, ChangelogEntry/Section)
- Remove unsafe `as` type casting in loader.ts, use Zod-inferred generics instead
- Add error logging in content loader (replaces silent catch blocks)
- Fix HelpSearch blur handling (mousedown+preventDefault instead of setTimeout hack)
- Add ARIA attributes to HelpSearch for accessibility
- Derive FAQ categories from items instead of hardcoding all 6
- Fix null-safety in GettingStartedGuide.svelte
- Fix unused appId variable in HelpPage.svelte, add scroll-reset on tab switch
- Rebuild Contacts help page as reference implementation using shared HelpPage component
- Add README with quick-start guide, props docs, and translations template
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added to: clock, photos, storage, mukke, planta, picture, skilltree,
nutriphi, chat. Now all 13 web apps show a re-login banner when
token refresh permanently fails.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Base parser: multilingual (DE/EN/FR/ES/IT) date, time, weekday, month parsing
- Base parser: fuzzy/typo tolerance (Levenshtein), recurrence (RRULE), relative time
- Base parser: timezone extraction, date ranges, ordinal dates, confidence scoring
- Base parser: past dates (gestern/yesterday), this/next week distinction
- Base parser: compose helper (createAppParser), multiple @references
- Calendar: event-parser with duration, time ranges, location, all-day, calendar ref
- Calendar: wire up UnifiedBar with onCreate/onParseCreate for quick event creation
- Todo: task-parser multilingual priority keywords (urgent/important/normal/later)
- Planta: plant-parser with acquisition keywords (gekauft/bought/acheté)
- Mukke: song-parser with Artist-Title format, BPM, genre, playlist/project creation
- NutriPhi: meal-parser with meal type detection, add QuickInputBar to layout
- All parsers: 210 tests across 7 test suites, all passing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>