Removes all star ratings from the features page. Replaces the card
grid summary with a flowing paragraph of clickable keyword links
that scroll to each feature section. Both simple and tech views
updated.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrites all USP texts for non-technical users (no jargon like
IndexedDB, tables, AES-GCM-256). Adds a "Für alle / Technik" toggle
switch that swaps between user-friendly marketing copy and deep
technical architecture details. Toggle state persists in localStorage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a comprehensive features page listing all 12 USPs of the Mana
platform with usefulness ratings (3-5 stars), detail bullet points,
and a cost comparison section (Mana vs individual tools). Also fixes
a devlog content schema error (category 'fix' -> 'bugfix') and adds
a footer link to the new page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
getAccessToken() reads the stored JWT without checking expiry, causing
401s when the token ages out — especially for services not covered by
the fetch interceptor (credits, events, api, etc.). getValidToken()
checks validity first and refreshes automatically when needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The workbench ListView was using Function() (effectively eval) with
aggressive sanitizing that stripped valid characters, causing every
calculation to fail with a generic "Fehler". Now uses the same safe
parser as the standard calculator page. Also adds console.error
logging and shows result before persisting to DB.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clicking a mood now opens it immediately in fullscreen (browser
Fullscreen API, z-index above all UI). Preview step removed.
Cards redesigned with full gradient backgrounds, live animations,
gradient overlays, and hover border highlight.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New module for tracking all beverages (water, coffee, tea, juice, alcohol, etc.)
with daily progress bar, quick-tap presets, and inline editing of quantity/date/time.
Includes: module config, types, collections with guest seed (5 presets),
queries, store, ListView with context menus, route, app-registry registration,
Dexie schema v7, encryption registry, shared-branding icon/app entry.
Also extends docs/future/MODULE_IDEAS.md with additional module ideas.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Docker build failed because @mana/local-stt was added as a
workspace dependency but not COPYed into the build context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
transcribeAudio() now checks localSTT.isReady before falling back to
the server-side mana-stt proxy. When local STT is active, audio blobs
are decoded to Float32Array via AudioContext.decodeAudioData() and
transcribed entirely on-device. The returned model field shows
"Whisper Tiny (lokal)" or similar so every module (dreams, memoro,
habits) displays which backend was used — no module code changed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract the floating pill-shaped input bar (text + optional voice)
into a shared component at $lib/components/FloatingInputBar.svelte.
Migrate todo, calendar, dreams, notes, journal, memoro and contacts
from inline forms / VoiceCaptureBar to the unified bottom bar.
Calendar now shows all upcoming events with relative date labels
(Heute, Morgen, weekday name, or short date).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stripped stats counters, filter tabs, and VoiceCaptureBar. Now shows
a flat list with round monochrome checkboxes, inline due-date badges
(Überfällig/Heute/date), completed tasks below a divider with
completion timestamp, and a pill-shaped FloatingInputBar at the
bottom with integrated voice input.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PageShell header icon/title had opacity: 0.5 — removed for full
visibility. Moodlit, Zitare, Skilltree and BaseListView used
text-white/* classes that were invisible in light mode — migrated
to hsl(var(--color-foreground/muted-foreground)) tokens.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PillNav overhaul:
- Dropdown-as-bar: theme/AI/sync/user menus render as horizontal
bars in the bottom stack (PillDropdownBar) instead of floating
popovers. New onOpenBar/activeBarId props on PillNavigation.
- iconOnly pills: tags/search/workbench-tabs pills show only icons.
Home pill removed. New iconOnly flag on PillNavItem.
- Segmented toggle groups: items sharing a `group` id render as a
single segmented pill (e.g. Light/Dark/System triple).
- Fullscreen mode: press "f" to hide all bottom chrome, Esc to exit.
- QuickInputBar + bottom bar visibility toggles via new pills.
- Progress ring on AI trigger pill during model download
(conic-gradient ::after, follows pill border-radius).
@mana/local-stt — new package for browser-local speech-to-text:
- Whisper models via transformers.js v4 (WebGPU + WASM fallback)
- Same Web Worker architecture as @mana/local-llm
- Two models: Whisper Tiny (150 MB) and Whisper Small (950 MB)
- Reactive Svelte 5 bindings (getLocalSttStatus, loadLocalStt, transcribe)
Voice-to-text integration:
- useLocalStt() composable: mic capture via AudioContext +
ScriptProcessor, resample to 16kHz mono, feed into Whisper worker
- Mic button in QuickInputBar (leftAction slot) with
recording/loading/transcribing states + pulse animation
- Transcribed text injected into InputBar via new injectedText prop
- STT model selector in AI bar alongside LLM tier controls
Also: vite.config.ts server.fs.allow expanded to monorepo root
so workspace package workers resolve in dev.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wallpaper system with four sources (predefined images, CSS gradients,
custom uploads via mana-media, and theme default). Configurable per-scene
or globally, with overlay controls (blur + opacity) and hover preview.
Adds sticky prop to shared PageHeader component and applies it across
themes, settings, credits, subscription, help, and profile pages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The presi module's schema was defined inline in routes.ts but had no
working db:push mechanism — the old references to @presi/server and
@presi/backend no longer exist after consolidation. Extracts schema
into its own file, adds a dedicated drizzle config, and updates the
setup script so tables are actually created.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PageShell cards now fill the available viewport between the workbench
top padding and the bottom chrome instead of using a static 60vh.
Height is calculated via two CSS vars published by the layout <main>:
height: calc(100dvh - var(--bottom-chrome-height) - var(--workbench-reserved-y))
--bottom-chrome-height reacts to pill-nav collapse, tag strip toggle
and bottom-bar mount state. --workbench-reserved-y (2.5rem) folds the
wrapper padding + buffer into a single non-chrome offset. dvh handles
Safari's retractable address bar. Inline height from resize-drag still
overrides as before.
Bottom-stack bars now use a uniform `gap: 0.25rem` instead of ad-hoc
per-child padding-bottom, giving consistent 4px spacing between all
bars. Wrapper vertical padding reduced from py-4/py-8 to py-2/py-3
and main's bottom buffer from +32px to +8px — cards gain ~72px of
usable vertical space on a typical viewport.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switch PageShell's per-theme paper overlay from a ::before +
mix-blend-mode + opacity stack to direct background-blend-mode on the
element itself. The old approach had invisibility issues in dark mode
and stacking-context quirks that made the grain disappear entirely.
background-blend-mode against background-color is the simpler, more
reliable primitive.
utils.ts auto-switches multiply → overlay in dark mode (dark × dark is
essentially invisible) while leaving other blend modes as-is. The
opacityLight/opacityDark knobs are gone from the paper config since
background-blend-mode has no opacity slot — tune via blendMode choice
instead.
Visual tuning pass:
- Card border bumped from 1px box-shadow ring to a real 2px border
with background-clip: border-box so the paper texture reads
continuously across the edge. Alpha 0.12 light / 0.28 dark (black).
- Drop shadow deepened (0 8px 24px + 0 3px 8px) for more card lift.
- Stone theme cooled toward real slate-blue: hue 200 → 212, saturation
bumped ~10pts across the palette. Stone was reading as warm-neutral
grey, now it's a proper cold blue.
- Texture remap: Lume → paper-004 (strongest grain, 480px tile for
coarser fiber), Stone → cardboard-002 (linen), Lavender → paper-001
(freed up after Stone claimed cardboard-002).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When users type 'mana.how' (no scheme), Safari and other browsers default
to HTTP. Cloudflare/cloudflared serves the page over HTTP without
rewriting the scheme. The browser then sends 'Origin: http://mana.how'
on every fetch, but mana-auth CORS only allows 'https://mana.how'.
Result: every auth request fails, the SSO check throws, AuthGate hangs
on the loading spinner forever, and the page never finishes loading.
Fix: detect HTTP requests in hooks.server.ts via cf-visitor /
x-forwarded-proto / event.url.protocol and 301-redirect to HTTPS before
serving any content. Localhost is exempted for dev.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three related fixes for the workbench tracking overlay:
1. **Same-origin proxy at /api/v1/geocode/[...path]/+server.ts.**
mana-geocoding is intentionally NOT exposed via Cloudflare, so the
browser can't reach it directly — localhost:3018 is unreachable from
a visitor's device. Same-origin proxy fixes this: the browser talks
to https://mana.how/api/v1/geocode/*, SvelteKit forwards to
http://mana-geocoding:3018 over the docker network. Pattern copied
from the existing /api/v1/who/[...path] proxy.
2. **`formatFullAddress()` in $lib/geocoding** builds a compact line
with street+housenumber, postal code, city, and 2-letter country
code (DE/AT/CH) — e.g. "Hafenstraße 2, 78462 Konstanz, DE". Maps
German and English OSM country names to ISO 3166-1 alpha-2.
3. **Clickable, inline-editable tracking label in ListView.** The
tracking overlay used to show "47.6630, 9.1750" while tracking was
active. Now it shows the venue name + full address with ISO country
code, tapping it switches to an autocomplete input so the user can
fix the location when GPS snaps to the wrong building. Debounced
reverse-geocode on position change (1.5 s + 10 m precision), edits
are kept local — the current tracking position drives the label
but user corrections override until the next significant move.
The client lib now uses relative URLs in the browser (same-origin
proxy) and absolute URLs only from Node/SSR (via env var or localhost
fallback). geocoding unit tests still pass (42/42 green).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When tracking is active the workbench ListView used to show only raw
coordinates ("47.6630, 9.1750"). Now a human-readable location label
appears above the coords ("Münster Café" or "Konstanz, Germany"),
fed from the shared reverse-geocoding endpoint.
To avoid hammering the geocoding service while the user is stationary
and their GPS jitters by a few metres, the effect debounces to 1.5 s
and rounds coordinates to 4 decimal places (~10 m) before checking
whether a new reverse lookup is needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Profile/Settings/Spiral/Credits move out of the standalone nav pills and
into the user-menu dropdown so the bottom bar stays compact. The dropdown
now also renders for guests (login users) — auth-only items (Profil,
Mana, Feedback, Logout) get filtered out, and a primary-styled "Anmelden"
entry replaces Logout. Themes is dropped from the dropdown since it
already has its own theme-variant pill.
New PillNavigation props: creditsHref, guestMenuLabel. New PillDropdown
icon paths: creditCard, spiral. New PillDropdownItem flag: primary
(prominent CTA styling), used for the guest Anmelden item.
All .glass-pill classes across PillNavigation, PillDropdown, PillTabGroup,
PillTagSelector, PillViewSwitcher, PillTimeRangeSelector, PillToolbar,
AppDrawer and ExpandableToolbar move from rgba+backdrop-blur to solid
theme tokens (hsl(var(--color-card)) / --color-border / --color-foreground)
so pills are fully opaque and follow the active theme variant instead of
having a frosted look that varied by background.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The frontend was calling /api/v1/credits/* and /api/v1/sync/* on
auth.mana.how, but those routes live on credits.mana.how (mana-credits
service). Add getManaCreditsUrl() helper, inject the URL via
hooks.server.ts, allow it in the CSP connect-src, and update both API
clients (credits.ts + sync.ts) to use it.
Also: pass MANA_CREDITS_URL + MANA_SERVICE_KEY to mana-sync so its
billing middleware can reach mana-credits at http://mana-credits:3002.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Settings page now uses a sidebar layout with category buttons (Profil,
Allgemein, KI, Sicherheit, Credits, Daten & Sync), an inline search field
that jumps to the matching section, and componentized sections under
lib/components/settings/. Each section owns its own data loading; the
+page.svelte shrinks from 617 to ~85 lines as a thin orchestrator.
The pill-nav AI tier dropdown now renders an icon per option (cpu, server,
cloud) and a power icon for the off state, and the "KI-Einstellungen"
shortcut deep-links to /settings#ai-options which auto-selects the KI tab
and scrolls to the panel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract the geocoding client from the places module into a shared
lib at $lib/geocoding so all modules can use it, then wire it into
three new consumers:
- **Events** — Address autocomplete in the edit form. When a
suggestion is picked, locationLat/locationLon are stored alongside
the plaintext location string. The view mode now shows an embedded
OpenStreetMap iframe centered on the event location. Coordinates
are plaintext for map rendering; the location text stays encrypted.
- **Contacts** — Adds a secondary "Adresse suchen…" input above the
existing street/PLZ/city/country fields. Picking a suggestion
fills all four fields at once and captures plaintext lat/lon on
the contact. Enables future "contacts near me" features.
- **Photos** — Replaces the static "Auf Karte anzeigen" Google Maps
link with a reverse-geocoded human label ("Konzil Restaurant,
Konstanz") computed from EXIF gpsLatitude/gpsLongitude on the
fly. Falls back to "Wird ermittelt…" during the lookup and keeps
the OpenStreetMap link as a secondary action.
All three modules import from $lib/geocoding; the places module's
internal geocoding.ts is deleted in favor of the shared location.
Type-check: 0 errors across 6514 files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bump PickerOverlay border-radius from 0.375rem to 1.25rem to match
PageShell — picker now visually aligns with the page cards next to it
- Replace colored dots in AppPagePicker with monochrome app icons
(uses each app's icon component from the registry, currentColor)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pelias hides the 'category' field from API responses unless the
caller filters by categories=... explicitly — a default intended for
keyword search that strips category metadata from address queries.
Patch the Pelias API's geojsonify_place_details.js so the category
array is returned on every feature (food, retail, transport, …),
mounted into the container as a read-only volume override.
Rewrite category-map.ts to map Pelias' OSM taxonomy to our 7
PlaceCategories using a priority-ordered list so a restaurant
tagged ['food','retail','nightlife'] resolves to 'food' (the most
specific), not 'shopping'.
Verified with Konstanz test queries:
Konzil Restaurant → food
Bahnhof Konstanz → transit
Physiotherapie-Schule → work
MX-Park → leisure
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Blackbox web probes were missing: body, journal, dreams, firsts,
cycles, events, finance, places, who, news, mail. These modules
exist in mana-apps.ts and are deployed but were never added to
prometheus.yml — so they didn't show on status.mana.how.
Also adds mana-geocoding and mana-events to the internal SvelteKit
status page health checks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New mana-geocoding service (port 3018) wraps a self-hosted Pelias
instance with LRU caching and OSM→PlaceCategory auto-mapping.
All geocoding queries stay within our infrastructure — no user
location data leaves the network.
Places module integration:
- Address autocomplete search in ListView (creates place with
name, coords, address, category in one step)
- Address search + reverse geocoding button in DetailView
- Auto-fill address via reverse geocoding during tracking
- OSM category mapping (amenity:restaurant→food, shop:*→shopping, etc.)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Increase border-radius to 1.25rem for page cards and add button
- Merge toolbar bar and header into single row (title left, actions right)
- Remove drag-and-drop reorder in favor of arrow buttons
- Make window action icons larger (24px bold) with more spacing
- Title icon monochrome with reduced opacity
- Remove onReorder prop and handleReorder from all carousel consumers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PillNavigation sync dropdown:
- New cloud icon pill showing sync status (Lokal/Sync/Pausiert)
- Dropdown with contextual actions: activate, top up credits, settings
- Shows next charge date when active
- Only visible for authenticated users
Onboarding wizard:
- New SyncStep between AI tier and Credits steps
- Explains local-first model: data always stays local, sync is optional
- Interval selection (monthly 30 / quarterly 90 / yearly 360 credits)
- Activate button with balance check and error handling
- Also fixed missing AiTierStep rendering in wizard template
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cloud Sync is now a paid feature: 30 credits/month (90/quarter, 360/year).
Users start in local-only mode and opt-in via Settings > Cloud Sync.
1 Credit = 1 Cent, so sync costs ~0.30€/month.
When credits run out, sync is paused (not deleted) and an in-app banner
prompts the user to top up. Local data is always preserved.
Backend (mana-credits):
- New sync_subscriptions table in credits schema
- SyncBillingService with activate/deactivate/chargeRecurring
- User-facing routes: GET/POST /api/v1/sync/{status,activate,deactivate,change-interval}
- Internal routes for server-side checks and cron triggers
Frontend (mana web):
- Sync API client + reactive sync-billing store
- syncEnabled parameter gates createUnifiedSync() — sync only starts when active
- Settings sync page with interval selection and activate/deactivate
- Pause banner in app layout when credits insufficient
Also: removed CALDAV_SYNC/GOOGLE_SYNC operations (not needed),
updated CLOUD_SYNC cost from 5 to 30 credits/month.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three medium-sized improvements:
1. E2E Smoke Test (e2e/smoke.spec.ts)
Two Playwright tests that exercise the critical happy path:
- "boot → dashboard → navigate → verify": opens /, /todo,
/notes, /habits, /calc in sequence, verifies each renders
content, checks for console errors.
- "module routing: all core routes respond": iterates 11 core
routes (/todo, /calendar, /contacts, /notes, /habits, /calc,
/chat, /body, /dreams, /finance, /moodlit) and asserts no
SvelteKit error page or crash. Runs in guest mode using the
existing dismissWelcomeModal helper.
2. Lazy Widget Loading (WidgetContainer.svelte)
Dashboard widgets are now lazy-mounted via IntersectionObserver.
Offscreen widgets render a small pulse placeholder until they
scroll into the viewport (with 200px rootMargin for pre-loading).
Once visible, the widget stays mounted permanently. This defers
liveQuery subscriptions for the ~13 dashboard widgets so only
the ~3-4 above-the-fold widgets fire IndexedDB reads on initial
mount — the rest activate as the user scrolls.
3. Typed Module Context (lib/data/module-context.ts)
`createModuleContext<T>(key)` returns a `{ provide, consume }`
pair that wraps Svelte's setContext/getContext with compile-time
type safety. Replaces the manual
`getContext<{readonly value: T[]}>('key')` pattern that was
duplicated across every layout/page boundary with a fragile
inline type annotation. Example usage added for the body module
(body/context.ts) — other modules can adopt incrementally.
Turborepo type-check task was already in place (turbo.json + root
package.json). No changes needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sweep of type errors accumulated from parallel development that
were blocking the production build's pre-push svelte-check gate.
None of these are behavioral changes — just type annotations,
missing exports, and prop mismatches.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New module at modules/journal/ with daily freeform entries, 8 mood states
(emoji picker), tag system, "on this day" historical recaps, streak tracking,
word count, favorites, and STT voice capture via VoiceCaptureBar. Title and
content encrypted at rest (AES-GCM-256). Registered in module-registry,
crypto registry, seed-registry, app-registry, and shared-branding.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removes the minimize/restore system entirely (scenes make it redundant)
and merges the top-level SceneTabs into a single inline bottom bar that
renders inside the layout's bottom-stack.
Chrome tab-group style: active scene shows its app tabs inline after it,
inactive scenes appear as compact pills. App tabs show module icons
instead of color dots, no fullscreen/close buttons (use context menu).
Architecture:
- New bottomBarStore (svelte $state) lets pages inject a component into
the layout's bottom-stack without a Svelte slot mechanism
- SceneAppBar component extracted for clean separation
- PageCarousel stripped to pure carousel (no scene/bar responsibilities)
- bottomChromeHeight accounts for the bar when present (+36px)
Removed: minimized field from WorkbenchSceneApp/CarouselPage, Minus
button from PageShell, minimizeApp/restoreApp from store, onMinimize/
onRestore from context menu builder, SceneTabs component usage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extend the unified TimeBlock system to 3 more modules.
New TimeBlockTypes: listening, mood, rehearsal
New SourceModules: music, moodlit, presi
- music: incrementPlayCount() creates 'listening' block with song title,
artist, and duration-based endDate
- moodlit: add startMoodSession/endMoodSession with live 'mood' blocks
using the mood's primary color
- presi: add startRehearsal/endRehearsal with live 'rehearsal' blocks
for presentation practice sessions
- Update analytics colors/labels, calendar filters, dashboard widgets
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The credit system was overengineered for the local-first architecture:
- Productivity micro-credits (task/event/contact creation at 0.02 credits) made no sense
since these operations happen locally in IndexedDB with zero server cost and were never enforced
- Guild pool system (6 DB tables, spending limits, membership checks) had no active users
- Gift system had 5 types (simple/personalized/split/first_come/riddle) when 2 suffice
Now credits are only charged for operations that actually cost money: AI API calls and
premium features (sync, exports). This makes the value proposition clear to users.
Changes:
- Remove 8 productivity operations + CreditCategory.PRODUCTIVITY from @mana/credits
- Delete guild pool service, routes, schema (3 files); remove guild refs from 8 backend files
- Simplify gifts to simple + personalized only; remove bcrypt/riddle/portions logic
- Update all frontend pages (credits dashboard, gift create/redeem, public gift page)
- Update shared-hono consumeCredits() to remove creditSource parameter
- Update mana-credits CLAUDE.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>