Commit graph

1856 commits

Author SHA1 Message Date
Till JS
f5b9d0a31f feat(recipes): add recipe module with local-first data, encryption, and card UI
New "Rezepte" module following the established scoped-CSS + theme-token
pattern. Includes Dexie schema (v8), encryption for user-typed fields,
3 German seed recipes, search/filter/tag UI, inline creation form, and
expanded detail view with ingredients checklist and numbered steps.

Also documents the frontend styling inconsistency (13/40 ListViews use
Tailwind instead of scoped CSS) in docs/optimizable/ for future cleanup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:45:41 +02:00
Till JS
65160024f7 feat(workbench): improve fullscreen, scene bar styling, and inline scene creation
- PageShell maximized: fill viewport edge-to-edge (max-width none, z-index 95
  above bottom bar, border none), constrain body/header to 48rem centered, Esc
  exits fullscreen
- SceneAppBar: pill-shaped bar and items, match TagStrip font size (0.9375rem),
  visual group bracket for active scene with separator, tab count on all scenes,
  inline name input for new scenes instead of modal dialog
- SceneRenameDialog: remove icon field, simplify to name-only

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:45:09 +02:00
Till JS
971ad37b4a style(landing): use generic tool categories instead of brand names
Some checks are pending
CI / Build mana-api-gateway (push) Blocked by required conditions
CI / Build mana-crawler (push) Blocked by required conditions
CI / Build mana-media (push) Blocked by required conditions
CI / Build mana-credits (push) Blocked by required conditions
CI / Build mana-web (push) Blocked by required conditions
CI / Build chat-backend (push) Blocked by required conditions
CI / Build chat-web (push) Blocked by required conditions
CI / Build todo-backend (push) Blocked by required conditions
CI / Build todo-web (push) Blocked by required conditions
CI / Build calendar-backend (push) Blocked by required conditions
CI / Build calendar-web (push) Blocked by required conditions
CI / Build clock-web (push) Blocked by required conditions
CI / Build contacts-backend (push) Blocked by required conditions
CI / Build contacts-web (push) Blocked by required conditions
CI / Build presi-web (push) Blocked by required conditions
CI / Build storage-backend (push) Blocked by required conditions
CI / Build storage-web (push) Blocked by required conditions
CI / Build telegram-stats-bot (push) Blocked by required conditions
CI / Build nutriphi-backend (push) Blocked by required conditions
CI / Build nutriphi-web (push) Blocked by required conditions
CI / Build skilltree-web (push) Blocked by required conditions
Docker Validate / Validate Dockerfiles (push) Waiting to run
Docker Validate / Build calendar-web (push) Blocked by required conditions
Docker Validate / Build todo-backend (push) Blocked by required conditions
Docker Validate / Build todo-web (push) Blocked by required conditions
Docker Validate / Build zitare-web (push) Blocked by required conditions
Docker Validate / Build mana-auth (push) Blocked by required conditions
Docker Validate / Build mana-sync (push) Blocked by required conditions
Docker Validate / Build mana-media (push) Blocked by required conditions
Mirror to Forgejo / Push to Forgejo (push) Waiting to run
Replaces specific tool names (Todoist, Notion, ChatGPT, etc.) with
generic categories (Aufgaben-App, KI-Assistent, etc.) in the
comparison section.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:43:35 +02:00
Till JS
bfa237d88e style(landing): make flow links subtler with underline instead of pills
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:39:22 +02:00
Till JS
e97d7d10e2 refactor(landing): replace star ratings with flowing text summary
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>
2026-04-13 16:35:02 +02:00
Till JS
ca3087446b feat(landing): add simple/tech toggle on features page
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>
2026-04-13 16:26:39 +02:00
Till JS
aa3f5d6407 feat(landing): add /features USP page with ratings and comparison
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>
2026-04-13 16:07:42 +02:00
Till JS
03bcd5e7f3 fix(ui): update app icons for 12 modules
playground→PencilRuler, questions→Binoculars, skilltree→ArrowsInCardinal,
events→CalendarStar, finance→MoneyWavy, uload→DownloadSimple

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:48:09 +02:00
Till JS
f47ea966df fix(ui): update app icons and add missing i18n labels
Icons: moodlit→SunHorizon, body→Person, cycles→GenderFemale,
notes→Notepad, guides→Books, context→File, who→PersonSimpleCircle,
memoro→Microphone, firsts→NumberCircleOne

Add missing app labels (cycles, body, dreams, journal, firsts, who,
events) in all 5 locales (de/en/fr/it/es).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 21:32:38 +02:00
Till JS
16fef572bf fix(auth): use getValidToken() instead of getAccessToken() for API calls
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>
2026-04-12 21:26:10 +02:00
Till JS
4616798d34 fix(calc): use safe evaluate engine in ListView, add error logging
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>
2026-04-12 20:57:46 +02:00
Till JS
a91a6076cc refactor: rename planta → plants, clean up codebase
- Rename planta module to plants everywhere (routes, modules, API,
  branding, i18n, docker, docs, shared packages)
- Fix package name collisions: @mana/credits-service, @mana/subscriptions-service
  (unblocks turbo)
- Extract layout composables: use-ai-tier-items, use-sync-status-items,
  RouteTierGate (layout 1345→1015 lines)
- Create shared DB pool for apps/api (lib/db.ts), migrate 5 modules
- Add automations module queries.ts with useAllAutomations/useEnabledAutomations
- Remove debug console.log statements from production code
- Rename storage display name: Ablage → Speicher

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:59:44 +02:00
Till JS
c6c19dbc77 feat(moodlit): fullscreen mood on click with visual card redesign
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>
2026-04-12 18:45:31 +02:00
Till JS
d6a1c9fd8b feat(drink): add beverage tracking module with inline editing
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>
2026-04-12 18:41:06 +02:00
Till JS
7314e9b763 fix(docker): add local-stt package to mana-web Dockerfile
Some checks are pending
CI / Build mana-api-gateway (push) Blocked by required conditions
CI / Build mana-crawler (push) Blocked by required conditions
CI / Build mana-media (push) Blocked by required conditions
CI / Build mana-credits (push) Blocked by required conditions
CI / Build mana-web (push) Blocked by required conditions
CI / Build chat-backend (push) Blocked by required conditions
CI / Build chat-web (push) Blocked by required conditions
CI / Build todo-backend (push) Blocked by required conditions
CI / Build todo-web (push) Blocked by required conditions
CI / Build calendar-backend (push) Blocked by required conditions
CI / Build calendar-web (push) Blocked by required conditions
CI / Build clock-web (push) Blocked by required conditions
CI / Build contacts-backend (push) Blocked by required conditions
CI / Build contacts-web (push) Blocked by required conditions
CI / Build presi-web (push) Blocked by required conditions
CI / Build storage-backend (push) Blocked by required conditions
CI / Build storage-web (push) Blocked by required conditions
CI / Build telegram-stats-bot (push) Blocked by required conditions
CI / Build nutriphi-backend (push) Blocked by required conditions
CI / Build nutriphi-web (push) Blocked by required conditions
CI / Build skilltree-web (push) Blocked by required conditions
Docker Validate / Validate Dockerfiles (push) Waiting to run
Docker Validate / Build calendar-web (push) Blocked by required conditions
Docker Validate / Build todo-backend (push) Blocked by required conditions
Docker Validate / Build todo-web (push) Blocked by required conditions
Docker Validate / Build zitare-web (push) Blocked by required conditions
Docker Validate / Build mana-auth (push) Blocked by required conditions
Docker Validate / Build mana-sync (push) Blocked by required conditions
Docker Validate / Build mana-media (push) Blocked by required conditions
Mirror to Forgejo / Push to Forgejo (push) Waiting to run
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>
2026-04-12 16:26:50 +02:00
Till JS
631cdafdb5 feat(voice): route STT through local Whisper when model is loaded
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>
2026-04-12 16:17:56 +02:00
Till JS
14d11272c9 fix(calendar): use button for event rows to fix a11y warnings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:12:37 +02:00
Till JS
949795c267 feat(web): shared FloatingInputBar, migrate 7 modules
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>
2026-04-12 16:08:03 +02:00
Till JS
0deab50a9c feat(todo): minimal ListView redesign with floating input
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>
2026-04-12 16:07:52 +02:00
Till JS
248100d490 fix(web): remove hardcoded white text, use theme tokens for light mode
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>
2026-04-12 16:07:40 +02:00
Till JS
3deee755b3 feat(web): PillNav bar mode, fullscreen, local STT + mic button
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>
2026-04-12 16:05:43 +02:00
Till JS
8c2f9306e9 feat(web): wallpaper system + sticky PageHeader
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>
2026-04-12 16:00:03 +02:00
Till JS
a9c51517eb fix(presi): wire up db:push for presi schema via @mana/api
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>
2026-04-12 14:32:44 +02:00
Till JS
474ba93d70 feat(workbench): dynamic page height + tighter bottom-stack spacing
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>
2026-04-12 14:15:47 +02:00
Till JS
68c2442419 feat(workbench): paper-grain polish — blend-mode, border, stone palette
Some checks are pending
CI / Build mana-api-gateway (push) Blocked by required conditions
CI / Build mana-crawler (push) Blocked by required conditions
CI / Build mana-media (push) Blocked by required conditions
CI / Build mana-credits (push) Blocked by required conditions
CI / Build mana-web (push) Blocked by required conditions
CI / Build chat-backend (push) Blocked by required conditions
CI / Build chat-web (push) Blocked by required conditions
CI / Build todo-backend (push) Blocked by required conditions
CI / Build todo-web (push) Blocked by required conditions
CI / Build calendar-backend (push) Blocked by required conditions
CI / Build calendar-web (push) Blocked by required conditions
CI / Build clock-web (push) Blocked by required conditions
CI / Build contacts-backend (push) Blocked by required conditions
CI / Build contacts-web (push) Blocked by required conditions
CI / Build presi-web (push) Blocked by required conditions
CI / Build storage-backend (push) Blocked by required conditions
CI / Build storage-web (push) Blocked by required conditions
CI / Build telegram-stats-bot (push) Blocked by required conditions
CI / Build nutriphi-backend (push) Blocked by required conditions
CI / Build nutriphi-web (push) Blocked by required conditions
CI / Build skilltree-web (push) Blocked by required conditions
Docker Validate / Validate Dockerfiles (push) Waiting to run
Docker Validate / Build calendar-web (push) Blocked by required conditions
Docker Validate / Build todo-backend (push) Blocked by required conditions
Docker Validate / Build todo-web (push) Blocked by required conditions
Docker Validate / Build zitare-web (push) Blocked by required conditions
Docker Validate / Build mana-auth (push) Blocked by required conditions
Docker Validate / Build mana-sync (push) Blocked by required conditions
Docker Validate / Build mana-media (push) Blocked by required conditions
Mirror to Forgejo / Push to Forgejo (push) Waiting to run
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>
2026-04-11 23:38:30 +02:00
Till JS
47aebe3c3b fix(web): improve HTTP detection for HTTPS redirect
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:48:45 +02:00
Till JS
7ba058c017 fix(web): redirect HTTP to HTTPS to fix Safari CORS hang
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>
2026-04-11 20:38:21 +02:00
Till JS
f3cc853e08 feat(places): clickable tracking label + full address + browser proxy
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>
2026-04-11 20:33:48 +02:00
Till JS
0c1eb623bb feat(places): show reverse-geocoded location label during tracking
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>
2026-04-11 20:26:49 +02:00
Till JS
637333051b feat(pill-nav): collapse user pills into account dropdown + solid pill backgrounds
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>
2026-04-11 17:40:19 +02:00
Till JS
1c94234996 fix(web): point credits/sync API client at credits.mana.how
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>
2026-04-11 17:12:36 +02:00
Till JS
21360d9c18 feat(mana/web): redesign settings page + pill-nav compute selector
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>
2026-04-11 16:40:57 +02:00
Till JS
12bbe29a47 fix(workbench): move @const out of {#if} in AppPagePicker snippet
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 16:27:12 +02:00
Till JS
0ba97672b1 feat: extend geocoding to events, contacts, photos
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>
2026-04-11 16:01:20 +02:00
Till JS
f7835471f4 feat(workbench): match AppPagePicker design to module pages
- 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>
2026-04-11 15:56:00 +02:00
Till JS
e82b5c1449 feat(geocoding): auto-categorize places via Pelias taxonomy
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>
2026-04-11 15:48:24 +02:00
Till JS
2a177ba032 fix(monitoring): add 10 missing modules to blackbox probes + geocoding to status
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>
2026-04-10 23:13:07 +02:00
Till JS
ecfb267280 fix(firsts): remove invalid JS comment from CSS block
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:09:05 +02:00
Till JS
a47a7bfdba feat(places): add self-hosted geocoding with Pelias (DACH)
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>
2026-04-10 23:02:25 +02:00
Till JS
f5ad492371 refactor(workbench): redesign page cards — rounder corners, unified header, remove DnD
- 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>
2026-04-10 23:02:10 +02:00
Till JS
d2c9795405 feat(sync): add sync status PillNav dropdown + onboarding step
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>
2026-04-10 22:51:00 +02:00
Till JS
b8cd33df7a fix(a11y): replace 215 suppression comments with real fixes
Comprehensive a11y sweep that replaces svelte-ignore comments with
proper semantic HTML. Three parallel work streams:

Labels (68 instances, 22 files):
  - 36 labels associated with controls via for/id pairs
  - 32 non-labeling <label> elements changed to <span>/<p>
  Files: LandingEditor (13), todo/settings (7), times/alarms (4),
  inventory/items (4), ViewEditorModal (3), uload (3), plus 16 more.

Div-click + click-keyboard (124 instances, ~67 files):
  - Modal backdrops: added role="presentation", tabindex="-1",
    onkeydown Escape handlers (~30 modals across the codebase)
  - Clickable cards: <div onclick> → <button type="button"> with
    text-left reset (~10 instances)
  - Stop-propagation wrappers: added role="none" (~5 instances)
  - Drag containers: added role="application"/"list"/"toolbar"
  - Contenteditable spans: added role="textbox" + tabindex="0"

Icon buttons (23 instances, 12 files):
  - Color swatches: aria-label="Farbe wählen"
  - Delete buttons: aria-label="Löschen"
  - Edit buttons: aria-label="Bearbeiten"
  - Toggle buttons: aria-label="Umschalten"
  - Other actions: contextual German labels

38 remaining warnings from edge cases (SVG event handlers, nested
roles needing tabindex, drag-drop zones) are suppressed with
comments — these have no clean HTML-semantic fix.

Net: 215 suppressions removed, 38 remain (from 215 → 38 = 82%
real fixes). Zero new warnings introduced.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:43:05 +02:00
Till JS
ed76f53b00 feat(sync): Phase 2 — server-side billing gate, cron charging, email notifications
Server-side gating (mana-sync Go):
- New billing.Checker with 5-minute cache per user
- Middleware wraps POST/GET /sync/{appId} endpoints
- Returns 402 Payment Required when sync subscription inactive
- Fail-open: if mana-credits is unreachable, sync is allowed
- Config: MANA_CREDITS_URL + MANA_SERVICE_KEY env vars

Recurring charge cron (mana-credits):
- Hourly setInterval checks for due sync subscriptions
- Calls chargeRecurring() which debits credits and advances nextChargeAt
- On insufficient credits: pauses subscription, sends email via mana-notify

Email notifications:
- Sends "Cloud Sync pausiert" email via mana-notify when subscription paused
- Uses POST /api/v1/notifications/send with X-Service-Key auth

Client-side 402 handling:
- sync.ts detects 402 from push/pull, fires onBillingRequired callback
- Layout wires callback to reload syncBilling store → shows pause banner

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:28:57 +02:00
Till JS
7102063afc fix(calendar): add timezone fallback in test mock to match Calendar type
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:26:30 +02:00
Till JS
ab62157a98 feat(firsts): add first-times module with dream-to-lived tracking
New module for tracking first-time experiences with two phases:
- Dream: bucket-list items with priority and motivation
- Lived: documented moments with expectation-vs-reality, rating,
  people, places, and media

Includes:
- Full module scaffold (types, collections, queries, store, config)
- ListView with 3 tabs (Timeline, Dreams, People)
- Inline editor + dream-to-lived conversion sheet
- Encryption for all user-typed content
- Dexie schema v6, app-registry, DragType registration
- App icon (amber-rose sparkle) and branding entry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:23:32 +02:00
Till JS
5c2ea614cd feat(credits): add sync billing — monthly credit subscription for cloud sync
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>
2026-04-10 22:21:58 +02:00
Till JS
f9b6720d15 feat: E2E smoke test, lazy widget loading, typed module context
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>
2026-04-10 22:17:57 +02:00
Till JS
4d133fa430 fix(mana/web): resolve 14 pre-existing svelte-check type errors
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>
2026-04-10 19:28:37 +02:00
Till JS
e42968203d feat(journal): add journal module with voice capture, mood tracking, and encryption
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>
2026-04-10 19:23:19 +02:00
Till JS
0f634b2540 refactor(workbench): replace minimize tabs + scene tabs with unified bottom bar
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>
2026-04-10 19:22:35 +02:00