Commit graph

143 commits

Author SHA1 Message Date
Till JS
4d5a96e21b perf(invoices): lazy-load pdf-lib + swissqrbill, -516 KB on route
/(app)/invoices/[id] route bundle drops from **534 KB → 18.6 KB** by
moving PDF rendering behind dynamic imports.

Changes:
  - views/DetailView.svelte: `await import('../pdf/renderer')` inside
    renderPdf() + downloadPdf(), cached in a module-local ref.
  - components/SendModal.svelte: same for openAndDownload().
  - pdf/scor.ts (new): generateSCORReference extracted so the
    invoices store can derive a reference string without pulling
    swissqrbill/svg + pdf-lib into the list-view bundle.
  - pdf/qr-bill.ts: re-exports generateSCORReference from scor.ts
    for backward compatibility.
  - stores/invoices.svelte.ts: imports from ../pdf/scor (light) instead
    of ../pdf/qr-bill (heavy).
  - index.ts: drop re-export of the PDF renderer from the module
    barrel so `import ... from '$lib/modules/invoices'` never drags
    pdf-lib in.

The heavy chunk (pdf-lib + swissqrbill, ~576 KB) now only loads when
a user actually opens an invoice detail — list views, create flow, and
all other routes stay lean.

20/20 qr-bill tests pass; svelte-check clean.

Bonus: scripts/audit-icon-usage.mjs (+ pnpm run audit:icon-usage)
audits @mana/shared-icons imports. Reveals 204 distinct icons across
the codebase, 199 of them at default weight but paying for all 6
Phosphor weights. Biggest offender: app-registry/apps.ts with 69
static icon imports accounting for ~290 KB of the shared 466 KB icon
chunk. Migration path for that is documented in
docs/optimizable/bundle-analysis.md §2 — next session's work.

docs/optimizable/bundle-analysis.md also updated with the root (app)
layout (260 KB) investigation notes (start/stop lifecycle hooks to
defer via idleCallback).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:03:53 +02:00
Till JS
3b85d7d3d2 chore(bundle): add bundle-size audit + snapshot inventory
scripts/audit-bundle.mjs reads `.svelte-kit/output/client/_app/immutable`
after a prod build and reports:
  - Total size + category breakdown (entry / nodes / chunks / workers /
    assets).
  - Top N JS files with content heuristics (transformers.js, zxcvbn,
    tiptap, pdf-lib, swissqrbill, rrule, suncalc, Phosphor icon paths,
    Vite __vite__mapDeps metadata, etc).
  - Route mapping for `nodes/*.js` by parsing the server manifest's
    `leaf:` entries, so node 118 is identified as /(app)/invoices/[id].
  - ⚠ flag on chunks/ ≥ 200 KB (shared, potentially eager).

Current snapshot (docs/optimizable/bundle-analysis.md):
  entry   92 KB  |  nodes   2.77 MB  |  chunks   5.59 MB
  workers 22.3 MB (ONNX WASM, lazy)  |  total   31.8 MB

Already healthy:
  - 92 KB entry (no critical-path bloat).
  - 22 MB transformers.js WASM is worker-scoped — only fetched on first
    /llm-test or memoro voice use.
  - zxcvbn (1.25 MB combined dict + keyboard graphs) correctly behind a
    dynamic import in PasswordStrength.svelte.

Follow-up opportunities logged:
  1. /invoices/[id] = 534 KB — split swissqrbill + pdf-lib via dynamic
     import.
  2. @mana/shared-icons = 317 + 149 KB SVG path chunks — migrate to
     tree-shakable per-icon imports or lazy-load.
  3. Root (app) layout = 260 KB — check for module bleed into shared
     shell.

Report-only. Run with `pnpm run audit:bundle`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:52:08 +02:00
Till JS
68c0eb2892 chore(test + audit): add test-coverage audit + wire audit:all
#6 test coverage (pivot to reporting): 34/653 tests currently fail
(in-flight spaces-foundation migrations). Hard coverage thresholds
aren't enforceable until the suite is green, so this session ships a
file-presence audit instead of line-coverage gates.

  - scripts/audit-test-coverage.mjs — counts .svelte + .ts source files
    vs .test.ts + .spec.ts per module. Reports total ratio, lists
    modules with 0 tests + ≥3 source files (prioritised by size).
  - pnpm run audit:test-coverage  wires it into audit:*.
  - docs/optimizable/test-health.md — state + prevention path + top
    untested modules ranked by impact.

Current baseline: 2.6% file-level coverage. 66/78 modules have zero
tests. Biggest untested: times (32 src), articles (29), events (27),
inventory + skilltree (20 each).

#8 audit:all: single entry point for the reporting audits. Runs
port-drift + i18n-coverage + test-coverage in --summary mode. Distinct
from validate:all (which is gates, not reports).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:38:12 +02:00
Till JS
4d91e2daad chore(services): add port-drift audit
Each services/*/CLAUDE.md declares `## Port: NNNN` — the authoritative
per-service port spec (docs/PORT_SCHEMA.md is explicitly partially
aspirational). This audit verifies:

  1. Declared port appears as a literal in the service's own source
     (catches: moved port in code but forgot to update CLAUDE.md).
  2. No two services claim the same port (catches: accidental
     collision when scaffolding new services).

Current state: ✓ 15 services, all declared ports found in code, zero
collisions (mana-auth/geocoding/stt/tts/image-gen/voice-bot/mail/
credits/user/subscriptions/analytics/events/news-ingester/ai/research).

Report-only; not a CI gate. Run with `pnpm run audit:port-drift`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:22:37 +02:00
Till JS
eec369bd04 chore(i18n): add coverage audit + migration inventory
Translation infrastructure (@mana/shared-i18n + svelte-i18n + 35
per-module locale files with ~3500 lines across de/en/it/fr/es) is fully
wired, but 65/78 modules still hardcode German in .svelte templates
rather than calling {$_('module.key')}.

Adds:
  - scripts/audit-i18n-coverage.mjs — scans lib/modules/**/*.svelte for
    hardcoded German keywords (Abbrechen, Speichern, Löschen, etc.) in
    files that don't import $_(). Reports per-module hit counts,
    bucket (FULL/PARTIAL/NONE), and whether the locale file exists.
    Supports --summary and --top N flags.
  - pnpm run audit:i18n-coverage  wires it into the audit:* family
    (reporting only, not a CI gate — existing debt would fail
    validate:all otherwise).
  - docs/optimizable/i18n-migration-inventory.md — priority list,
    per-module workflow, and prevention plan.

Top offenders: broadcast (26 hits), articles (24), events (23),
invoices (22), quiz (20), stretch (20), library (19), profile (17),
skilltree (15, PARTIAL), calendar (14, PARTIAL). Modules without a
locale file (broadcast/articles/events/invoices/…) need the locale
stubs scaffolded first.

Real string migration is per-site careful work (key naming, 5-language
parity, UI visual QA) and is left for per-module follow-up sessions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:16:55 +02:00
Till JS
430aa30cbf refactor(theming): re-apply theme validator suite after parallel rebase
The plan-doc commits 129971ffc + 9db044178 dropped the
audit-theme-tokens → validate-theme-variables rename, the
validate-theme-tokens → validate-theme-utilities rename, the new
validate-theme-parity script, brand-literals.md, and the corresponding
package.json + lint-staged.config.js + themes.css wiring. The files
still existed on disk (git mv changes survived) but were untracked.

Restore the validator suite so `pnpm run validate:all` works again:
  - validate:theme-variables (CSS var names: --muted → --color-muted)
  - validate:theme-utilities (Tailwind: no white/N, no neutral palette)
  - validate:theme-parity    (every --color-* in :root ⇔ .dark + each
                              [data-theme="..."])

All three wired into validate:all and lint-staged. `pnpm run validate:all`
is clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:07:48 +02:00
Till JS
86c205ffc5 refactor(theming): migrate remaining 12 ListViews to theme tokens
Replace raw white-alpha Tailwind utilities across the last 12 module
ListViews that were flagged by validate-theme-tokens: citycorners,
guides, inventory, memoro, picture, plants, playground, presi,
questions, times, uload, who. Also replace semantic color hex/names
(bg-yellow-500/20, bg-green-400, text-blue-400, bg-teal-600, etc.)
with success/warning/error/primary tokens.

Per-deck brand colors in who/ListView (#a855f7 purple/historical,
#ec4899 pink/women, #f59e0b amber/antiquity, #0ea5e9 blue/inventors)
stay as hex — those are domain semantics, not theme intent.

Wire validate:theme-tokens into validate:all so future regressions
fail the local pre-push gate. All 76 module ListViews now pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 15:29:43 +02:00
Till JS
a2a43b1d5a refactor(theming): migrate 6 ListViews + ai-missions badges to theme tokens
Replace raw white-alpha Tailwind utilities (text-white/x, bg-white/x,
border-white/x) with canonical theme tokens (text-foreground, bg-muted,
border-border, etc.) in cards, context, food, moodlit, storage, music
ListViews. Replace hardcoded hex badge/dot/phase colors in ai-missions
with success/warning/error/primary tokens.

Fix two transition-all bugs (food:160, moodlit:223) that prevented CSS
custom property colors from resolving on first paint under theme switches.

Add scripts/validate-theme-tokens.mjs to prevent regression; run via
pnpm run validate:theme-tokens. Not yet in validate:all — 12 modules
still use raw white utilities (citycorners, guides, inventory, memoro,
picture, plants, playground, presi, questions, times, uload, who).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 15:23:55 +02:00
Till JS
8dbc850beb chore(ci): add \validate:all\ + fix undefined \validate:monorepo\ reference
\`ci.yml\` had a \`pnpm run validate:monorepo\` step that referenced a
script defined nowhere in the repo — CI would fail at that step
whenever the validate job ran. Replacing it with a new bundled
\`validate:all\` script closes that gap and gives contributors a single
local command that mirrors what CI enforces.

- New \`validate:all\` chains the three fast repo-invariant checks
  (turbo recursion, pgSchema isolation, crypto registry) with fail-fast
  semantics. Runtime ~1s — suitable as a pre-push gate.
- \`validate:dockerfiles\` intentionally left out: its current output
  is 41 pre-existing "MISSING" warnings on two web Dockerfiles, which
  look like a validator-vs-wildcard-COPY mismatch rather than real
  issues. Keeping it as a standalone script so those can be
  triaged separately without blocking \`validate:all\`.
- ci.yml: four separate validate steps collapsed into one. The step
  rename also removes the dead \`validate:monorepo\` call.

Verified: \`pnpm run validate:all\` exits 0 in ~1s — 138 packages
scanned for turbo recursion, 727 TypeScript files for raw pgTable,
190 Dexie tables classified in the crypto registry (85 encrypted,
105 allowlisted plaintext).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:01:54 +02:00
Till JS
248137ec43 chore(mobile): remove 6 of 7 mobile apps — keep only memoro
Six Expo mobile apps lagged behind their web counterparts and haven't
shipped updates. Keeping them in the repo kept CI noisy (the context/
mobile type errors were only unmasked after yesterday's postinstall
fix), and they blocked other cleanup (parallel lockfile entries, dead
scripts). Removing them since the web surface under mana.how is the
active product.

Deleted (~175 MB, ~700 files):
- apps/cards/apps/mobile
- apps/chat/apps/mobile
- apps/context/apps/mobile      (the one still failing type-check)
- apps/mana/apps/mobile
- apps/picture/apps/mobile
- apps/traces/apps/mobile

Kept: apps/memoro/apps/mobile (the only actively-developed mobile app,
tied to the audio-recording native module).

Cleanup:
- Dropped 6 `dev:*:mobile` scripts from root package.json that pointed
  at the deleted apps. Other `dev:*:mobile` entries (quotes, contacts,
  calendar, mail, moodlit, finance, figgos) already pointed at
  non-existent apps before this change — out of scope, a separate
  dead-script sweep.
- Root CLAUDE.md: updated the "per-product mobile apps exist" prose
  and the repo-layout diagram to reflect the memoro-only reality.
- apps/mana/CLAUDE.md: removed the `mobile/` entry from the apps/
  layout box, noted the deletion date, and updated the tech-stack
  table to point at the memoro mobile app as the sole Expo surface.

No CI workflow or turbo.json references touched — none existed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 15:31:47 +02:00
Till JS
d1d37749f7 fix(install): remove silent || true from postinstall + narrow filter
The root postinstall was `node scripts/generate-env.mjs || true &&
pnpm run build:packages || true`. Two failures were being swallowed:

1. shared-auth's build has been broken for a while. shared-types
   re-exports its submodules with explicit `.ts` extensions
   (`export * from './theme.ts'`), which only works for downstream
   consumers that set `allowImportingTsExtensions: true`. shared-auth
   didn't — tsc emitted TS5097 on every re-export, the build failed,
   `|| true` hid it, every `pnpm install` appeared clean.

2. The filter `@mana/*` matches everything in the workspace, including
   `@mana/web` — the full 27-module SvelteKit build. On postinstall
   this kicked off vite, which OOM-aborted during SW generation.
   That's the original reason `|| true` was added, judging by shape.

Fixes:
- Dropped the `.ts` suffix from shared-types/src/index.ts re-exports.
  shared-types is consumed in bundler-mode tsconfigs everywhere, so no
  extension is the portable form. shared-types' own `tsc --noEmit`
  still passes.
- Narrowed the filter from `@mana/*` (name-glob, matches apps) to
  `./packages/*` (path-glob, only workspace packages). Scope drops
  from 133 → 39 projects; build:packages now runs cleanly in ~15s.
- Removed both `|| true` guards. A broken postinstall now fails
  loudly instead of producing a half-built state nobody notices.

Verified: `pnpm install` completes exit 0 in 13s; all 39 packages
build green.

Closes audit item #37 (postinstall swallows errors).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 14:58:59 +02:00
Till JS
5ec1dfc747 chore(db): enforce pgSchema isolation with a lint script
The "every Drizzle table uses pgSchema" rule was documented in
.claude/guidelines/database.md (added yesterday as part of Concern 5)
but enforced only by convention. A new service could slip a raw
\`pgTable()\` past review and collide in the default \`public\` schema
of \`mana_platform\`, and nothing would surface the mistake until a
production migration failed.

- \`scripts/validate-pg-schema-isolation.mjs\` scans every tracked
  TypeScript file under services/, apps/api/, packages/ for call sites
  of \`pgTable(\` (not imports — imports can still be useful for types).
  Strips comments before matching so doc-examples like "use \`pgTable()\`"
  don't trigger false positives.
- Wired as \`pnpm run validate:pg-schema\` and a new CI step in the
  validate job (right after the turbo-recursion check). 721 files
  scan clean today.
- Removed an unused \`pgTable\` import in mana-subscriptions that would
  have been the only import of the symbol remaining after this change.
- Updated .claude/guidelines/database.md — the old verification blurb
  said "no automated lint rule yet", now points at the enforcer.

Drift verified: injecting a synthetic \`pgTable('bad', {})\` into
subscriptions.ts failed with a clear file:line violation pointing at
the database guideline.

Closes the "no automated lint rule" gap noted in the database guideline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 14:45:59 +02:00
Till JS
1eda3f5395 chore(turbo): lint against recursive \turbo run\ calls in child packages
CLAUDE.md flagged this as "CRITICAL" — a child package.json defining
e.g. \`"build": "turbo run build"\` causes a 10+ minute CI hang with
thousands of duplicate task spawns. The rule was documented but never
enforced, so it re-emerged every couple of months as someone copied a
parent script pattern.

- \`scripts/validate-no-recursive-turbo.mjs\` walks every tracked
  package.json (via \`git ls-files\`, so node_modules is auto-skipped)
  and fails if any non-root package has build/type-check/lint/test/
  test:coverage/check scripts containing \`turbo run\`. \`dev\` stays
  allowed — delegating it from a parent is the intended ergonomic.
- Wired as \`pnpm run validate:turbo\` + a new CI step in the validate
  job (before type-check — fails fast).
- CLAUDE.md §Turborepo updated to point at the enforcer and call out
  the full task list (test/test:coverage/check were missing from the
  original prose).

Verified: 138 non-root package.json files scan clean. Drift simulation
(injecting \`"build": "turbo run build"\` into apps/mana/apps/web) fails
with a clear message pointing at the offending file + script + fix.

This closes audit item #32 from the architecture review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 14:39:32 +02:00
Till JS
c7af693c6d feat(crypto): Phase C — build-time registry ↔ Dexie audit
Before: adding a new Dexie table left the encryption decision implicit.
If you forgot to register it, the table silently shipped in plaintext
forever — no error, no warning, no footprint anywhere. The architecture
audit flagged this as the root of Concern 1.

- `scripts/audit-crypto-registry.mjs` parses database.ts's `.stores()`
  blocks and registry.ts's entries, then enforces three invariants:
    1. Every Dexie table is either in the encryption registry OR in the
       new `plaintext-allowlist.ts` — one conscious classification per
       table.
    2. No dead registry entries (referring to tables that no longer
       exist in Dexie).
    3. No table appears in both — single authoritative source.
- `plaintext-allowlist.ts` auto-seeded from current state. 105 entries,
  each tagged `// TODO: audit` as an invitation to review whether the
  table truly holds nothing sensitive. The allowlist is intentionally
  a separate file so additions are reviewable on their own (not buried
  inside database.ts schema bumps).
- Wired into `pnpm run check:crypto` + CI validate job — a new table
  now fails the PR check instead of slipping past review.
- `check:crypto:seed` regenerates the allowlist if ever needed.

Verified: drift simulation (removing aiMissions from the allowlist)
fails the audit with a clear message pointing at the missing
classification. Current state passes: 187 Dexie tables, 82 encrypted,
105 explicit plaintext.

Concern 1 is now fully closed (A: typed registry entries, B: dev-mode
runtime drift check, C: build-time audit enforcing coverage).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 14:36:32 +02:00
Till JS
4b8defcc4a chore(ci): add v8 test coverage tracking (non-blocking baseline)
CI previously ran `pnpm run test || true` — test failures were silently
swallowed with no artifact, so we had no visibility into what was actually
passing across 1,296 test files.

- New `test:coverage` turbo pipeline task + root script; packages that opt
  in by declaring their own `test:coverage` get picked up automatically.
- Wired up three high-value Vitest targets: apps/mana/apps/web (main
  frontend, ~590 tests), shared-ui (Svelte component library), and
  shared-storage (S3 client). Each emits lcov.info + coverage-summary.json
  + browsable HTML.
- apps/mana/apps/web `"test"` was running in watch mode (just `vitest`),
  which hangs under turbo orchestration — changed to `vitest run` and
  added `test:watch` for the interactive case.
- CI uploads coverage artifacts (14-day retention) regardless of whether
  tests passed. `continue-on-error: true` replaces `|| true` so a failed
  suite shows up as a warning annotation on the PR rather than being
  invisible. Flip to a hard gate once main is green for a full week.
- Testing guideline documents the pattern + the template vitest config
  + the planned 80% threshold.
- ESLint flat-config `vitest.config.ts` ignore only matched at the root;
  widened to `**/vitest.config.{ts,js,mjs}` so nested configs don't trip
  the project-service parser.

Coverage baseline produced locally:
  shared-storage:  91.37% lines (6 files, 123 tests)
  shared-ui:        2.87% lines (mostly Svelte components, untested)
  apps/mana/web:    9/59 test files fail — pre-existing, not regression

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 19:21:14 +02:00
Till JS
fc028fa8f0 chore(lint): audit:theme-tokens guard against bare --muted / --theme-* drift
Three naming conventions had drifted through the monorepo (--muted, --theme-*,
--color-*). Only the last is defined in the Mana theme; the others silently
fell back to nothing and stopped tracking theme variants. Today's cleanup
migrated ~100 files, but nothing stopped the drift from creeping back.

- scripts/audit-theme-tokens.mjs scans ~3k source files and fails if any
  references a bare shadcn token or a --theme-* prefix, with an allowlist
  for known-literal module brand colors (news-research, agent templates)
- wire into pnpm script and lint-staged (runs once per commit touching
  *.{svelte,css}, ignores per-file args)
- design-ux.md guideline: fix stale --color-destructive entry (Mana uses
  --color-error), add explicit "never bare tokens" warning with examples

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 00:58:13 +02:00
Till JS
115afea519 chore(dev): wire SearXNG + mana-search into dev:mana:all
News Research's web-search backend (mana-search → SearXNG) was missing
from the standard dev stack — a "Finden" click failed with a connect
error until the standalone services/mana-search/docker-compose.dev.yml
was started by hand.

- docker-compose.dev.yml: add `searxng` (Port 8080), config mounted
  read-only from the service tree. Reuses the shared mana-redis,
  no second cache instance needed.
- package.json: docker:up + docker🆙infra include searxng;
  dev:mana:servers spawns dev:search alongside the other 6 servers;
  dev:search now passes PORT=3021 + REDIS auth so it talks to the
  shared password-protected mana-redis instead of defaulting to a
  no-auth localhost:6379

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:31:29 +02:00
Till JS
c5a4c5158f fix(mana-crawler): default DATABASE_URL to mana_platform in dev
The Go binary's config.go hardcoded "postgresql://…/mana" as the
DATABASE_URL fallback, but no database named "mana" exists locally
or in the macmini compose stack — the platform DB is mana_platform.
Anyone running the crawler without an explicit override got a
"database \"mana\" does not exist" crash at startup. The dev:crawler
script in package.json had been papering over this by setting
DATABASE_URL explicitly; drop that override now that the binary
default is correct.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 18:18:19 +02:00
Till JS
0ef650d94a chore(dev): run mana-credits locally and gift sync to dev users
Two halves of the same "why is sync inactive in dev" fix:

- package.json: new dev:credits script and mana-credits added to
  the dev:mana:servers concurrently group. The service was never
  started by pnpm dev:mana:all, so the frontend's
  GET /api/v1/sync/status failed, syncBilling.load() caught the
  error and defaulted to inactive — while mana-sync (Go) was
  actually fail-open on the billing check, making the UI
  indicator lie about the backend state.
- scripts/dev/setup-dev-user.sh: after the existing
  email-verify + tier-lift UPDATE, upsert a row into
  credits.sync_subscriptions with is_gifted=true. Mirrors what
  POST /api/v1/admin/sync/:id/gift would do, so every new dev
  user gets Cloud Sync from the first login without a separate
  admin call. The credits schema lives inside mana_platform, so
  no new database needed — just a second statement in the same
  psql heredoc.

Existing dev users (tills95, tilljkb, rajiehq) were backfilled
manually with the same INSERT … ON CONFLICT DO UPDATE once;
future runs of setup-dev-user.sh stay idempotent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 18:09:26 +02:00
Till JS
7f1520d6f4 chore(dev): wire mana-crawler into the local dev stack
Three small config changes so the Kontext "Aus URL" flow (next commit)
is runnable from a plain `pnpm dev:mana:all`:

- package.json: include mana-crawler in the dev:mana:servers
  concurrently group, and pass DATABASE_URL=…/mana_platform so the
  Go binary doesn't try to connect to a non-existent `mana` DB (its
  hardcoded default).
- .env.development: publish MANA_CRAWLER_URL=http://localhost:3023
  (the crawler's default binary port — the macmini container is
  a 3014 override, kept only in docker-compose). Also surface
  MANA_LLM_DEFAULT_MODEL for the summariser.
- docker-compose.macmini.yml: inject MANA_CRAWLER_URL + the
  default-model env into the mana-api container so production
  can reach the internal crawler and pick the summariser model
  consistently.

No runtime code touched.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:23:54 +02:00
Till JS
851a281e5a refactor: rename zitare -> quotes (Zitate)
Zitare was opaque Latin/Italian-flavored branding. Renamed to clear
English "quotes" (DE: Zitate) matching short-concrete-noun cluster.

- Module, routes, API, i18n, standalone landing app, plans dirs
- Dexie tables: quotesFavorites, quotesLists, quotesListTags,
  customQuotes (dropped redundant "quotes" prefix on the last)
- Logo QuotesLogo, theme quotes.css, search provider, dashboard
  widget QuoteWidget
- German user-facing label "Zitate" (English brand stays Quotes)

Pre-launch, no data migration needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 20:59:16 +02:00
Till JS
b857063120 refactor: rename eventstream -> activity, cycles -> period
eventstream was confusingly branded "Events" in the app registry,
colliding with the real events calendar module. Renamed to activity
(DE: Aktivität) since it's a live activity feed across all modules.

cycles -> period (DE: Periode) makes the menstrual-tracking module
self-describing. Tables cycles/cycleDayLogs/cycleSymptoms renamed to
periods/periodDayLogs/periodSymptoms; field cycleId -> periodId;
TimeBlockType 'cycle' -> 'period'; domain event CycleDayLogged ->
PeriodDayLogged. Generic "cycle" usages (billing, lifecycle, breath,
bicycle, import cycles) left untouched.

Constant disambiguation: prior DEFAULT_PERIOD_LENGTH (bleeding days)
renamed to DEFAULT_BLEEDING_DAYS; prior DEFAULT_CYCLE_LENGTH (28d full
cycle) is now DEFAULT_PERIOD_LENGTH.

Pre-launch, no data migration needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 19:45:43 +02:00
Till JS
53b3746b98 refactor: rename nutriphi module to food (Essen)
Complete rename across the entire monorepo pre-launch:
- Module, routes, API, i18n, standalone landing app directories
- All code identifiers, display names, logo component
- German user-facing label: "Essen" (English brand stays "Food")
- Dexie table nutriFavorites -> foodFavorites
- Infra configs (docker-compose, cloudflared, nginx, wrangler)

Zero residue of nutriphi remains. No data migration needed (pre-launch).

Follow-up: run pnpm install, update Cloudflare DNS
(food.mana.how), rename Cloudflare Pages project.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:30:07 +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
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
d7dc5388b9 fix(dx): shortcut mana-media dev startup chain
Skip two intermediate pnpm invocations — go directly to
bun run --hot in the inner apps/api directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 18:41:44 +02:00
Till JS
45790ffbb8 refactor(mana): rename inventar → inventory across the codebase
The workbench-registry app id 'inventar' did not match its
@mana/shared-branding MANA_APPS counterpart 'inventory', so the tier-
gating join in apps/web/src/lib/app-registry/registry.ts silently
failed for the inventory module — it fell into the "no MANA_APPS
entry, default visible" fallback and was effectively un-gated. The
codebase had also voted overwhelmingly for 'inventar' (53 files) vs
'inventory' (3 files in shared-branding), so the long-standing
mismatch was just bookkeeping debt waiting to bite.

Pre-release, no live data, so the cleanest fix is to align everything
on the English 'inventory':

- Workbench-registry id, module.config.ts appId, module folder, route
  folder and i18n locale folder all renamed via git mv
- Standalone apps/inventar/ workspace package renamed
- All imports, store identifiers (InventarEvents → InventoryEvents,
  INVENTAR_GUEST_SEED, inventarModuleConfig), i18n keys and href/goto
  paths follow the rename
- The German display label "Inventar" is preserved everywhere it is a
  user-visible string (page titles, i18n values, toast labels)
- Dexie table prefixes (invCollections, invItems, …) are unchanged
- Drive-by fix: ListView.svelte was querying non-existent
  inventarCollections/inventarItems tables — corrected to the actual
  invCollections/invItems names from module.config
- The "inventar ↔ inventory id mismatch" workaround comment in
  registry.ts is removed since the mismatch no longer exists

module-registry.ts also picks up the user's parallel newsModuleConfig
addition because both edits land in the same import block — keeping
them split would have left the build in an inconsistent state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 15:50:24 +02:00
Till JS
38a02b77a8 chore(dev): add setup-dev-user script for local founder accounts
Local mana-auth has no built-in admin seed and `requireEmailVerification`
turned on with no real SMTP — every developer ends up writing the same
"register + UPDATE auth.users" SQL incantation by hand. Bundles it
into one idempotent script + a pnpm alias.

  pnpm setup:dev-user                       # creates 3 default accounts
  ./scripts/dev/setup-dev-user.sh foo bar   # creates / repairs one

What it does per user:
  1. POST /api/v1/auth/register on mana-auth (so Better Auth's
     signUpEmail handles password hashing the way the runtime
     expects — no hand-rolled scrypt)
  2. UPDATE auth.users SET email_verified = true, access_tier = 'founder'
     so the new user can immediately log in AND exercise every
     tier-gated module without a tier upgrade dance

Idempotent: existing users get tier + verification re-applied without
touching the password. Re-running after a partial setup is safe.

Defaults to three accounts (tills95 / tilljkb / rajiehq @gmail.com,
all with password "Aa-123456789") so the next dev doesn't have to
remember anything. Override via `TIER=alpha` / `DB_HOST=...` env
vars when needed.

Two preflight gates fail loud: psql in PATH + mana-auth reachable
on :3001. ON_ERROR_STOP=1 in psql so a bad SQL run doesn't get
silently swallowed.

Replaces the dangling `seed:dev-user` package.json alias that pointed
at a `pnpm --filter @mana/auth db:seed:dev` script that was never
created — clean rename to `setup:dev-user` to match the existing
`setup:env` / `setup:db` family.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 12:23:15 +02:00
Till JS
12be86b5e6 chore: remove abandoned per-product workspace artifacts
Three independent dead-code cleanups bundled together because they
all touch dev scripts in the root package.json:

1. games/voxelava/ + games/worldream/ — orphaned game stubs
   ~5886 LOC of Svelte components, route handlers, and types with
   no root package.json in either directory, no CI references, no
   docker-compose entry, no mana-apps registry presence. The
   matching root scripts dev:worldream:web + worldream:dev pointed
   to a @worldream/web filter that doesn't exist as a workspace
   member. games/arcade and games/whopixels remain untouched.

2. apps/memoro/* — clean stale @memoro/web references
   apps/memoro/apps/web/ was removed during the consolidation; the
   memoro frontend now lives in apps/mana/apps/web/src/lib/modules/
   memoro/. But several scripts still pointed at the deleted
   filter:
     - root: dev:memoro:web (deleted), dev:memoro:app + :full
       rewritten to drop the :web piece (server + audio-server
       only)
     - apps/memoro/package.json: dev:web removed, top-level dev
       script removed (filtered @memoro/* which would have hit
       the dead web filter)

3. apps/memoro/apps/server: declare @mana/notify-client dep
   src/lib/notify.ts:6 has been importing @mana/notify-client
   without declaring it in package.json — works by accident via
   hoisted node_modules in the workspace. Add the dep so the
   import is properly tracked. Found while verifying that
   notify-client (which has 0 declared consumers) was actually
   safe to keep.

Tracked as items #18, #19, #29 in
docs/REFACTORING_AUDIT_2026_04.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:56:51 +02:00
Till JS
4fce6a3ede feat(env): persistent dev secrets via .env.secrets override
Local dev secrets like MANA_STT_API_KEY had no persistent home — they
lived only in the gitignored, generator-overwritten per-app .env files.
Every `pnpm setup:env` wiped them, so devs had to re-paste keys after
any env regeneration. Same recurring friction for MANA_LLM_API_KEY,
MANA_AUTH_KEK, OAuth keys, etc.

New layer: `.env.secrets` at the repo root.

- Gitignored, optional, never required for the build to pass
- Read by generate-env.mjs AFTER .env.development; non-empty values
  override the matching key, so the merged result drives every per-app
  .env the generator writes
- Empty values fall through to the .env.development defaults — a
  freshly-copied .env.secrets.example is a no-op
- One source of truth for all dev secrets, propagated to every app
  with one `pnpm setup:env`

Files:
- `.env.secrets.example` — committed template documenting all known
  secret keys (mana-stt, mana-llm, auth KEK, sync JWT, MinIO, third-
  party APIs). Devs `cp .env.secrets.example .env.secrets` and fill in.
- `.gitignore` — ignores .env.secrets, allows .env.secrets.example
- `scripts/generate-env.mjs` — loads .env.secrets if present, prints
  "Loaded N secrets from .env.secrets" so devs see the override
  taking effect
- `scripts/setup-secrets.mjs` + `pnpm setup:secrets` — convenience
  script that SSHes to mana-server, greps the prod .env for the keys
  defined in .env.secrets.example, and writes them locally. Confirms
  before overwriting an existing .env.secrets unless --force is set;
  reports which keys couldn't be found on the remote so devs know
  what's left to fill manually
- `docs/LOCAL_DEVELOPMENT.md` + `docs/ENVIRONMENT_VARIABLES.md` —
  walk-through and architecture diagram update

Verified end-to-end:
- `rm .env.secrets apps/mana/apps/web/.env && pnpm setup:env` →
  STT key empty (no regression for devs who haven't opted in)
- `pnpm setup:secrets --force && pnpm setup:env` →
  STT key propagated, "Loaded 3 secrets from .env.secrets" in output
- POST /api/v1/voice/transcribe with a real audio file →
  full transcript back via gpu-stt.mana.how, end-to-end working

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:50:37 +02:00
Till JS
8e8b6ac65f fix(mana-auth) + chore: rewrite /api/v1/auth/login JWT mint, remove Matrix stack
This commit bundles two unrelated changes that were swept together by an
accidental `git add -A` in another working session. Documented here so the
history reflects what's actually inside.

═══════════════════════════════════════════════════════════════════════
1. fix(mana-auth): /api/v1/auth/login mints JWT via auth.handler instead
   of api.signInEmail
═══════════════════════════════════════════════════════════════════════

Previous attempt (commit 55cc75e7d) tried to fix the broken JWT mint in
/api/v1/auth/login by switching the cookie name from `mana.session_token`
to `__Secure-mana.session_token` for production. That was necessary but
not sufficient: Better Auth's session cookie value isn't just the raw
session token, it's `<token>.<HMAC>` where the HMAC is derived from the
better-auth secret. Reconstructing the cookie from auth.api.signInEmail's
JSON response only gave us the raw token, so /api/auth/token's
get-session middleware still couldn't validate it and the JWT mint kept
silently failing.

Real fix: do the sign-in via auth.handler (the HTTP path) rather than
auth.api.signInEmail (the SDK path). The handler returns a real fetch
Response with a Set-Cookie header containing the fully signed cookie
envelope. We capture that header verbatim and forward it as the cookie
on the /api/auth/token request, which now passes validation and mints
the JWT correctly.

Verified end-to-end on auth.mana.how:

  $ curl -X POST https://auth.mana.how/api/v1/auth/login \
      -d '{"email":"...","password":"..."}'
  {
    "user": {...},
    "token": "<session token>",
    "accessToken": "eyJhbGciOiJFZERTQSI...",   ← real JWT now
    "refreshToken": "<session token>"
  }

Side benefits:
- Email-not-verified path is now handled by checking
  signInResponse.status === 403 directly, no more catching APIError
  with the comment-noted async-stream footgun.
- X-Forwarded-For is forwarded explicitly so Better Auth's rate limiter
  and our security log see the real client IP.
- The leftover catch block now only handles unexpected exceptions
  (network errors etc); the FORBIDDEN-checking logic in it is dead but
  harmless and left in for defense in depth.

═══════════════════════════════════════════════════════════════════════
2. chore: remove the entire self-hosted Matrix stack (Synapse, Element,
   Manalink, mana-matrix-bot)
═══════════════════════════════════════════════════════════════════════

The Matrix subsystem ran parallel to the main Mana product without any
load-bearing integration: the unified web app never imported matrix-js-sdk,
the chat module uses mana-sync (local-first), and mana-matrix-bot's
plugins duplicated features the unified app already ships natively.
Keeping it alive cost a Synapse + Element + matrix-web + bot container
quartet, three Cloudflare routes, an OIDC provider plugin in mana-auth,
and a steady drip of devlog/dependency churn.

Removed:
- apps/matrix (Manalink web + mobile, ~150 files)
- services/mana-matrix-bot (Go bot with ~20 plugins)
- docker/matrix configs (Synapse + Element)
- synapse/element-web/matrix-web/mana-matrix-bot services in
  docker-compose.macmini.yml
- matrix.mana.how/element.mana.how/link.mana.how Cloudflare tunnel routes
- OIDC provider plugin + matrix-synapse trustedClient + matrixUserLinks
  table from mana-auth (oauth_* schema definitions also removed)
- MatrixService import path in mana-media (importFromMatrix endpoint)
- Matrix notification channel in mana-notify (worker, metrics, config,
  channel_type enum, MatrixOptions handler)
- Matrix entries from shared-branding (mana-apps + app-icons),
  notify-client, the i18n bundle, the observatory map, the credits
  app-label list, the landing footer/apps page, the prometheus + alerts
  + promtail tier mappings, and the matrix-related deploy paths in
  cd-macmini.yml + ci.yml

Devlog/manascore/blueprint entries that mention Matrix are left intact
as historical record. The oauth_* + matrix_user_links Postgres tables
stay on existing prod databases — code can no longer write to them, drop
them in a follow-up migration if you want them gone for real.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 16:32:13 +02:00
Till JS
216746721e feat(events): add mana-events service + public RSVP flow (Phase 1b)
New Hono+Bun service at services/mana-events on port 3065 with two
schemas in mana_platform: events_published (snapshots) and public_rsvps
(unauthenticated responses), plus a per-token hourly rate-limit bucket.

- Host endpoints (JWT) for publish/update/unpublish/list-rsvps
- Public endpoints for snapshot fetch + RSVP upsert with rate limiting
- New /rsvp/[token] page outside the auth gate, SSR-loads the snapshot
- Client store wires publishEvent/unpublishEvent to the server, syncs
  snapshot updates after edits, and deletes the snapshot on event delete
- DetailView polls GET /events/:id/rsvps every 30s while open and lets
  hosts import a public response into their local guest list
- generate-env, setup-databases.sh, .env.development, hooks.server.ts,
  package.json wired for local dev
2026-04-07 14:27:48 +02:00
Till JS
22a73943e1 chore: complete ManaCore → Mana rename (docs, go modules, plists, images)
Final cleanup of references missed in previous rename commits:

- Dockerfiles: PUBLIC_MANA_CORE_AUTH_URL → PUBLIC_MANA_AUTH_URL
- Go modules: github.com/manacore/* → github.com/mana/* (7 go.mod files)
- launchd plists: com.manacore.* → com.mana.* (14 files renamed + content)
- Image assets: *_Manacore_AI_Credits* → *_Mana_AI_Credits* (11 files)
- .env.example files: ManaCore brand strings → Mana
- .prettierignore: stale apps/manacore/* paths → apps/mana/*
- Markdown docs (CLAUDE.md, /docs/*): mana-core-auth → mana-auth, etc.

Excluded from rename: .claude/, devlog/, manascore/ (historical content),
client testimonials, blueprints, npm package refs (@mana-core/*).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:26:10 +02:00
Till JS
878424c003 feat: rename ManaCore to Mana across entire codebase
Complete brand rename from ManaCore to Mana:
- Package scope: @manacore/* → @mana/*
- App directory: apps/manacore/ → apps/mana/
- IndexedDB: new Dexie('manacore') → new Dexie('mana')
- Env vars: MANA_CORE_AUTH_URL → MANA_AUTH_URL, MANA_CORE_SERVICE_KEY → MANA_SERVICE_KEY
- Docker: container/network names manacore-* → mana-*
- PostgreSQL user: manacore → mana
- Display name: ManaCore → Mana everywhere
- All import paths, branding, CI/CD, Grafana dashboards updated

No live data to migrate. Dexie table names (mukkePlaylists etc.)
preserved for backward compat. Devlog entries kept as historical.

Pre-commit hook skipped: pre-existing Prettier parse error in
HeroSection.astro + ESLint OOM on 1900+ files. Changes are pure
search-replace, no logic modifications.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:00:13 +02:00
Till JS
47d893794e chore: rename mukke to music in infra, scripts, and CI/CD
Update remaining mukke references in root package.json scripts,
docker-compose files, Grafana dashboards, Prometheus config,
CD pipeline, cloudflared config, deploy scripts, load tests,
and mana-auth user-data service.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:47:57 +02:00
Till JS
8218037841 feat: add shared Phosphor IconPicker, migrate habits from emoji to icons, add photos upload
- Add curated icon registry (73 Phosphor icons, 8 categories) in shared-icons
- Add DynamicIcon atom and IconPicker molecule in shared-ui
- Migrate habits module from emoji strings to Phosphor icon names
- Add Dexie version(2) migration for emoji→icon field rename
- Replace inline SVGs in habits with Phosphor components
- Add drag-and-drop photo upload to Photos workbench ListView
- Add blob: to CSP img-src for upload previews
- Add dev:media script and include mana-media in dev:manacore:servers
- Add ./toast export to shared-ui package.json

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 21:37:01 +02:00
Till JS
c5906e4c29 fix: update all dev scripts to use unified API server
Replace 15 individual dev:*:server scripts with single dev:api command.
Update all dev:*:full, dev:*:app, dev:*:local scripts to start the
unified API server (apps/api) instead of archived individual servers.

dev:manacore:servers now starts: auth + sync + api (3 processes instead of 8)
dev:manacore:full now works without errors.

Removed: wisekeep scripts (project archived), broken server references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 11:51:46 +02:00
Till JS
7ba82472b2 feat(manacore/web): wire TagField, FavoriteButton, ColorPicker into module UIs
Add shared TagField component (ID-based wrapper for TagSelector).
Wire TagField into: calendar EventForm, times EntryForm, cards
CreateDeckModal, contacts detail page. Wire FavoriteButton into
contacts list (replaces inline Star toggle). Add ColorPicker to
cards CreateDeckModal for deck color selection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:20:46 +02:00
Till JS
e870270734 refactor: consolidate Clock app into Times
Merge the standalone Clock app (alarms, countdown timers, stopwatch,
world clock, pomodoro) into the Times app as a unified time management
application.

Times standalone app:
- Add 3 new collections (alarms, countdownTimers, worldClocks) to timesStore
- Add Clock types and constants to @times/shared
- Add 6 new stores (alarms, countdown-timers, world-clocks, stopwatch, session-*)
- Add 5 new routes under /clock/* (dashboard, alarms, timers, stopwatch, world-clock)
- Extend layout with Clock context providers and navigation items
- Add clock.* i18n namespace (de/en)
- Add WorldMap and CircularProgress components

Manacore unified app:
- Merge clock module into times module (stores, queries, types, components)
- Move Clock DB tables under times appId (timeAlarms, timeCountdownTimers, timeWorldClocks)
- Update search provider, splitscreen registry, dashboard widgets
- Add redirects from /clock/* to /times/clock/*
- Remove @clock/shared dependency

Cleanup:
- Archive Clock app to apps-archived/clock/
- Remove dev:clock:* scripts from root package.json
- Remove Clock from mana-apps.ts, update Times description
- Update CLAUDE.md documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:04:07 +02:00
Till JS
da3a140f21 update(infra): mana-stt WhisperX + diarization, mana-notify templates, CD pipeline updates
mana-stt: add WhisperX service with CUDA GPU support, speaker diarization, and auto-fallback chain.
mana-notify: add locale fallback and default templates for task reminders.
CD: update deployment pipeline and docker-compose configuration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:56:26 +02:00
Till JS
3fa218cbe0 chore(memoro): remove old NestJS backends (Phase 8+9)
Delete apps/memoro/apps/backend/ (NestJS) and apps/memoro/apps/audio-backend/
(NestJS) — all functionality has been ported to the new Hono/Bun servers
(apps/server/ and apps/audio-server/).

Also clean up root and memoro package.json scripts to remove references
to the old @memoro/backend and @memoro/audio-backend packages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 11:21:03 +02:00
Till JS
a02dceb51c feat(guides): ImportModal, share button, CLAUDE.md, server dev scripts
- ImportModal: 3-tab (URL/Text/AI) import UI with preview before saving
- Guide detail: share button → generates 7-day shareable link with copy-to-clipboard
- App layout: Import button in sidebar + dynamic ImportModal mount
- Library page: Import button in header (desktop), openImportGuide context
- Port corrected to 3027 (was 3025, conflict with CityCorners)
- CLAUDE.md: full project docs (routes, collections, env vars, phase status)
- Root package.json: dev:guides:server, updated dev:guides:app/local/full

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 21:42:26 +02:00
Till JS
6d2509c258 feat(memoro): add deployment infrastructure and migrate web services to new Hono server
- Dockerfile for audio-server (Bun + ffmpeg)
- docker-compose.macmini.yml entries for memoro-server (3015) and memoro-audio-server (3016)
- Dev commands: dev:memoro:server, dev:memoro:audio-server, dev:memoro:app, dev:memoro:full
- MEMORO_* env vars in .env.development
- web: add PUBLIC_MEMORO_SERVER_URL env var to env.ts and .env.example
- web: rewrite transcriptionService → POST /api/v1/memos (new server path)
- web: rewrite spaceService → /api/v1/spaces/* (aligned with actual Hono routes)
- server: fix callAudioServer param name audioPath (was filePath) in memos.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 20:16:54 +02:00
Till JS
0a9c38161b feat(guides): add mana guides app — step-by-step playbook app
New app at apps/guides/ with local-first architecture (Dexie.js + mana-sync).

- 5 collections: guides, sections, steps, collections, runs
- Library view: card grid with search, category & difficulty filters
- Guide detail: sections/steps overview, start-run buttons
- Run mode: scroll (all steps) + focus (one step at a time) with note support
- Collections view: learning paths with progress bars
- History view: all runs with timestamps and duration
- Guest seed: 3 demo guides (dev setup, pasta recipe, git basics)
- GuideCard with run-status indicator (○◑●⟳)
- GuideEditModal with emoji, color, difficulty, tags
- Registered in shared-branding: port 5200, teal #0d9488, guides.mana.how
- Plan doc: .claude/plans/mana-guides.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 20:12:36 +02:00
Till JS
402baf7c7f feat(monitoring): add uptime monitoring via Blackbox Exporter
- scripts/check-status.sh: parallel HTTP check aller mana.how Domains aus cloudflared-config.yml
- docker/blackbox/blackbox.yml: Blackbox Exporter Config (http_2xx, http_health Module)
- docker-compose.macmini.yml: blackbox-exporter Container (Port 9115, 32MB RAM)
- docker/prometheus/prometheus.yml: 4 Scrape-Jobs (blackbox-web, blackbox-api, blackbox-infra, blackbox-gpu)
- docker/prometheus/alerts.yml: 5 Alert-Regeln (WebAppDown, APIDown, InfraToolDown, GPUServiceDown, SlowHTTPResponse)
- docker/grafana/dashboards/uptime.json: Grafana Uptime-Dashboard mit Status-Tables und Verlauf
- package.json: check:status Script

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 17:43:25 +02:00
Till JS
d8a2b37126 chore(memoro): import legacy backend, mobile, and landing apps
Adds the original NestJS backends (backend, audio-backend), Expo mobile app,
and Astro landing page as-is from the standalone memoro repo. These are
not yet migrated to monorepo standards (migration tracked in memory/CLAUDE.md).

Also adds eslint.config.mjs ignore for apps/*/apps/audio-backend/**
and .prettierignore entries for legacy memoro dirs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 17:30:00 +02:00
Till JS
6e75718cfa feat(arcade): migrate backend from NestJS to Hono/Bun
Replace @arcade/backend (NestJS) with @arcade/server (Hono/Bun).
Same two endpoints, no auth required (public game generator):
- POST /api/games/generate — AI game generation (Gemini, Claude, GPT)
- POST /api/games/submit  — Community game submission via GitHub PR
- GET  /health            — Health check

This removes the last remaining NestJS backend from the monorepo.
NestJS is now completely gone — all servers use Hono + Bun.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 17:02:14 +02:00
Till JS
8437a4178f refactor: replace stale NestJS backend scripts with Hono server scripts
All app backends have been migrated to Hono/Bun servers — only
@arcade/backend remains on NestJS. This commit adds dev:*:local and
dev:*:server scripts for all apps, removes 15 stale :backend scripts,
25+ broken db:push/studio/seed aliases, and updates :full/:app commands
to use the new server + sync architecture.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:03:40 +02:00
Till JS
c33339b0cf rename(taktik): rebrand to Times
Rename taktik → times across the entire app: package names (@taktik →
@times), appId, localStorage keys, export filenames, type names
(TaktikSettings → TimesSettings), monorepo scripts, shared-branding,
mana-auth trustedOrigins, docker-compose, and documentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:44:18 +02:00
Till JS
72da55d3d0 feat(moodlit): restore from git history, migrate to local-first + Hono
- Restore from git history (was deleted in 079b55a79)
- Delete NestJS backend and mobile app
- Create Hono/Bun server with preset moods API
- Create local-first store (moods, sequences) with 8 preset moods
- Rewrite web app: Moods page with color gradient cards and activation,
  Sequences page with CRUD, auth via shared-auth-ui with guest mode
- Add CLAUDE.md, dev scripts, root CLAUDE.md entry
- 0 type errors on both server and web

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:03:19 +02:00