\`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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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
- 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>
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>
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>
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>
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>
- 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>
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>
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>
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>
- 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>
- Move from apps-archived/ to apps/
- Delete NestJS backend, mobile app, legacy Python, shared-types
- Create Hono/Bun server with Groq Whisper transcription via yt-dlp
- Create local-first store (transcripts, playlists) with guest seed
- Rewrite web app: Transcribe page, Library with search/expand,
Playlists CRUD, auth via shared-auth-ui, AuthGate with guest mode
- Remove broken landing page subpages (Prettier-incompatible Astro)
- Add wisekeep to root CLAUDE.md and dev scripts
- Fix duplicate wisekeep entries in shared-branding
- 0 type errors on both server and web
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move from apps-archived/ to apps/
- Delete NestJS API, Docker files, old docs, browser extension
- Create Hono/Bun server with content extraction (Mozilla Readability)
and AI feed API reading from mana-sync's sync_changes
- Create local-first store (articles, categories) with guest seed data
- Rewrite web app: Feed page, Saved articles with URL extraction,
auth pages using shared-auth-ui, AuthGate with guest mode
- Add news to shared-branding (app icon, mana-apps registry)
- 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>
Docker:
- Dockerfile for web (sveltekit-base, port 5029) and server (Bun, port 3041)
- docker-compose.macmini.yml entries for uload-server + uload-web
- Landing page deploy script (Cloudflare Pages)
Documentation:
- Complete CLAUDE.md rewrite reflecting local-first + Hono architecture
Features:
- Bulk select/deselect all/toggle active/delete
- Link expiry date (datetime picker)
- Password-protected links
- Max clicks limit
- Badges for password/expiry/maxClicks on link items
- Advanced options collapsible section in create & edit forms
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Dockerfile: two-stage build on sveltekit-base, port 5028
- docker-compose.macmini.yml: manavoxel-web service on port 5028
- Root package.json: dev:manavoxel:web and dev:manavoxel:full scripts
- Fix Tailwind CSS import (shared-tailwind/themes.css)
- Port changed from 5195 to 5028 (consistent dev/prod)
Deploy with: ./scripts/mac-mini/build-app.sh manavoxel-web
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move from apps-archived/ to apps/
- Delete NestJS backend, PocketBase, old scripts and docs
- Create Hono/Bun redirect server (click tracking, analytics API)
- Create @manacore/uload-database shared Drizzle schema package
- Add local-first store (Dexie.js) for links, tags, folders
- Rewrite Links and Tags pages to use IndexedDB
- Simplify hooks, layouts, remove all server-side data loading
- Add dev scripts: dev:uload:web, dev:uload:server, dev:uload:local
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New calculator app with standard, scientific, programmer, unit converter,
currency, finance, date, and percentage modes. Includes 5 visual skins:
Modern, HP-35 (1972), Casio fx (1985), TI-84 (2004), and Minimal.
Local-first with IndexedDB history, keyboard support, safe math parser.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New app for professional time tracking with timer, projects, clients,
and reports. Local-first architecture with IndexedDB + mana-sync.
- Timer store with start/stop/resume, auto-save every 10s
- 6 local-store collections: clients, projects, timeEntries, tags, templates, settings
- TimerCard with live counter, project selector, billable toggle
- EntryItem with inline-expand editing, EntryList with day grouping
- EntryForm modal with quick-duration buttons (15m-4h)
- QuickStart pills from recent entries
- Projects page: card grid, color coding, budget progress, inline CRUD
- Clients page: billing rates, project rollup, inline CRUD
- Reports page: stats grid, billable breakdown, project/daily charts
- i18n: German + English
- Registered in shared-branding with icon, URLs, dev scripts
- Guest seed: 2 clients, 3 projects, 5 time entries, 4 tags
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>