mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
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>
177 lines
9.5 KiB
Markdown
177 lines
9.5 KiB
Markdown
# CLAUDE.md
|
|
|
|
Guidance for Claude Code when working in this repo.
|
|
|
|
## Monorepo Overview
|
|
|
|
pnpm workspace monorepo with two consolidated tops:
|
|
|
|
- **`apps/mana/apps/web`** — unified SvelteKit frontend serving 27+ product modules under `mana.how`. One build, one IndexedDB, one auth session, one deployment.
|
|
- **`apps/api`** (`@mana/api`) — unified Hono/Bun backend API server. Consolidates per-module compute servers; routes registered under `/api/v1/{module}/*`.
|
|
|
|
Per-product directories under `apps/{product}/` still exist for landing pages, mobile apps, and product-specific packages, but the active web frontend and API both live in the two consolidated apps above.
|
|
|
|
- **Package Manager:** pnpm 9.15.0
|
|
- **Build System:** Turborepo
|
|
- **Node:** 20+
|
|
- **Primary doc:** [`apps/mana/CLAUDE.md`](apps/mana/CLAUDE.md) — module structure, data layer, encryption, routing.
|
|
|
|
### Repo layout
|
|
|
|
```
|
|
apps/
|
|
├── mana/ # Unified frontend (SvelteKit web + Expo mobile + Astro landing)
|
|
├── api/ # Unified backend API (Hono/Bun) — @mana/api
|
|
├── {product}/ # Per-product landing pages, mobile apps, packages
|
|
│ # Standalone (own container, not unified): manavoxel
|
|
games/ # arcade, voxelava, whopixels, worldream
|
|
services/ # Backend services (Hono/Bun, Go, Python) — see list below
|
|
packages/ # Shared workspace packages (@mana/*)
|
|
docs/ # Long-form docs (deployment, hardware, postmortems, etc.)
|
|
.claude/guidelines/ # Coding conventions — read before changing code
|
|
```
|
|
|
|
### Active services (`services/`)
|
|
|
|
`mana-auth` (3001), `mana-sync` (3050), `mana-credits`, `mana-user`, `mana-subscriptions`, `mana-analytics`, `mana-search` (3021), `mana-crawler`, `mana-api-gateway`, `mana-notify`, `mana-media`, `mana-llm`, `mana-image-gen`, `mana-video-gen`, `mana-stt`, `mana-tts`, `mana-voice-bot`, `mana-events`, `mana-landing-builder`. Each non-trivial service has its own `CLAUDE.md`.
|
|
|
|
## Coding Guidelines
|
|
|
|
Always consult before changing code:
|
|
|
|
| Document | Purpose |
|
|
|----------|---------|
|
|
| [`.claude/GUIDELINES.md`](.claude/GUIDELINES.md) | Overview |
|
|
| [`.claude/guidelines/code-style.md`](.claude/guidelines/code-style.md) | Formatting, naming, linting |
|
|
| [`.claude/guidelines/sveltekit-web.md`](.claude/guidelines/sveltekit-web.md) | Svelte 5 runes, stores |
|
|
| [`.claude/guidelines/expo-mobile.md`](.claude/guidelines/expo-mobile.md) | React Native, NativeWind |
|
|
| [`.claude/guidelines/hono-server.md`](.claude/guidelines/hono-server.md) | Hono/Bun servers |
|
|
| [`.claude/guidelines/database.md`](.claude/guidelines/database.md) | Drizzle ORM, pgSchema |
|
|
| [`.claude/guidelines/authentication.md`](.claude/guidelines/authentication.md) | Mana Auth integration |
|
|
| [`.claude/guidelines/error-handling.md`](.claude/guidelines/error-handling.md) | Result types, error codes |
|
|
| [`.claude/guidelines/testing.md`](.claude/guidelines/testing.md) | Vitest, mock factories |
|
|
| [`.claude/guidelines/design-ux.md`](.claude/guidelines/design-ux.md) | UI patterns, a11y |
|
|
|
|
## Development Quick Start
|
|
|
|
See [`docs/LOCAL_DEVELOPMENT.md`](docs/LOCAL_DEVELOPMENT.md) for the full setup.
|
|
|
|
```bash
|
|
pnpm docker:up # PostgreSQL, Redis, MinIO
|
|
pnpm setup:env # Generate per-app .env files from .env.development
|
|
pnpm setup:db # Create databases + push schemas
|
|
|
|
# Start the unified Mana app (most common)
|
|
pnpm run mana:dev
|
|
|
|
# Project-specific full stack (auth + backend + web with auto DB setup)
|
|
pnpm dev:chat:full
|
|
pnpm dev:todo:full
|
|
pnpm dev:picture:full
|
|
# … one per project
|
|
|
|
# Service-only
|
|
pnpm dev:auth # mana-auth (3001)
|
|
pnpm dev:sync # mana-sync Go server (3050)
|
|
```
|
|
|
|
Quality:
|
|
|
|
```bash
|
|
pnpm run build
|
|
pnpm run type-check
|
|
pnpm run format
|
|
```
|
|
|
|
## Key Architecture Notes
|
|
|
|
These are the patterns that span the repo. Service-/app-specific details live in their own CLAUDE.md.
|
|
|
|
### Local-first data layer
|
|
|
|
The unified Mana app uses **one IndexedDB** (`mana`) with all 120+ collections. Module stores write directly to Dexie tables; hooks in `database.ts` track changes into `_pendingChanges` tagged by `appId`. The unified sync engine (`sync.ts`) groups by `appId` and pushes to `mana-sync` (Go, port 3050), which persists field-level LWW into PostgreSQL with RLS.
|
|
|
|
Full architecture, sprint history, threat model:
|
|
- [`apps/mana/apps/web/src/lib/data/DATA_LAYER_AUDIT.md`](apps/mana/apps/web/src/lib/data/DATA_LAYER_AUDIT.md)
|
|
- [`apps/mana/CLAUDE.md`](apps/mana/CLAUDE.md)
|
|
|
|
### At-rest encryption
|
|
|
|
Sensitive user content in 27 tables is AES-GCM-256 encrypted before hitting IndexedDB. Master key lives in `mana-auth`, KEK-wrapped (`MANA_AUTH_KEK` env, must be set in prod). Optional zero-knowledge mode via Settings → Sicherheit.
|
|
|
|
When touching sensitive fields:
|
|
1. Add the table to `apps/mana/apps/web/src/lib/data/crypto/registry.ts` with the field allowlist
|
|
2. `await encryptRecord(tableName, record)` before writes
|
|
3. `await decryptRecords(tableName, visible)` after Dexie reads, before the type converter
|
|
|
|
Default new user-typed fields to **encrypt**; default new IDs/timestamps/sort-keys to **plaintext**.
|
|
|
|
### Authentication
|
|
|
|
All servers use `@mana/shared-hono` with `authMiddleware()`. Tokens are EdDSA JWTs issued by `mana-auth` with claims `{sub, email, role, sid, tier, exp, iss, aud}`. Cross-app SSO works across `*.mana.how`. See [`.claude/guidelines/authentication.md`](.claude/guidelines/authentication.md) and `services/mana-auth/`.
|
|
|
|
**Adding an app to SSO** requires updating *all three*:
|
|
1. `trustedOrigins` in `services/mana-auth/src/auth/better-auth.config.ts`
|
|
2. `CORS_ORIGINS` for mana-auth in `docker-compose.macmini.yml`
|
|
3. Run `pnpm test -- src/auth/sso-config.spec.ts` from `services/mana-auth/`
|
|
|
|
### Access tiers
|
|
|
|
`guest < public < beta < alpha < founder`. Apps gate themselves via `requiredTier` in `packages/shared-branding/src/mana-apps.ts`; the JWT carries a `tier` claim; `AuthGate` enforces it client-side. Admin API at `PUT /api/v1/admin/users/:id/tier`.
|
|
|
|
### Database (PostgreSQL)
|
|
|
|
Two databases: **`mana_platform`** (all services + app server-side data, schema-isolated via `pgSchema`) and **`mana_sync`** (sync engine, write-heavy). Always use `pgSchema('name').table(...)`, never plain `pgTable()`. Adding a new schema: see [`.claude/guidelines/database.md`](.claude/guidelines/database.md).
|
|
|
|
### Object storage
|
|
|
|
MinIO (Docker, S3-compatible) in both local and prod. Console: http://localhost:9001 (`minioadmin`/`minioadmin`). Use `@mana/shared-storage` helpers. Pre-configured per-project buckets (`picture-storage`, `chat-storage`, `cards-storage`, …).
|
|
|
|
### Turborepo: avoid recursive turbo calls
|
|
|
|
**CRITICAL**: Parent workspace packages (e.g. `apps/chat/package.json`) must NEVER define `type-check`, `build`, or `lint` scripts that call `turbo run <task>`. Root turbo already orchestrates those — defining them in children causes infinite recursion (10+ minute hangs, thousands of duplicate tasks). Only `dev` is OK to delegate to turbo from a parent package, since it's persistent and typically scoped.
|
|
|
|
## Shared Packages (`packages/`)
|
|
|
|
| Package | Purpose |
|
|
|---------|---------|
|
|
| `@mana/shared-auth` | Client-side auth for web/mobile |
|
|
| `@mana/shared-hono` | Hono middleware (auth, health, errors) |
|
|
| `@mana/shared-storage` | S3/MinIO helpers |
|
|
| `@mana/shared-branding` | App registry, tiers, branding |
|
|
| `@mana/shared-types` | Common TS types |
|
|
| `@mana/shared-utils` | Utility functions |
|
|
| `@mana/shared-ui` | React Native UI components |
|
|
| `@mana/shared-theme` | Theme config |
|
|
| `@mana/shared-i18n` | i18n |
|
|
| `@mana/local-store` | Local-first store primitives — used by unified Mana, manavoxel, arcade, and shared-uload/-stores/-links |
|
|
|
|
## Adding Dependencies
|
|
|
|
```bash
|
|
pnpm add -D <pkg> -w # Workspace root (dev tools)
|
|
pnpm add <pkg> --filter @mana/web # A specific app
|
|
pnpm add <pkg> --filter @mana/shared-utils # A shared package
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
Single source of truth: **`.env.development`** (committed). After editing, run `pnpm setup:env` to regenerate per-app `.env` files with the right prefixes (`EXPO_PUBLIC_*` for mobile, `PUBLIC_*` for SvelteKit, no prefix for Hono/Bun servers). Mapping logic in `scripts/generate-env.mjs`. Full guide: [`docs/ENVIRONMENT_VARIABLES.md`](docs/ENVIRONMENT_VARIABLES.md).
|
|
|
|
## Server Access
|
|
|
|
- **Production (Mac Mini):** `ssh mana-server` (Cloudflare Tunnel). See [`docs/MAC_MINI_SERVER.md`](docs/MAC_MINI_SERVER.md). Useful: `./scripts/mac-mini/status.sh`, `./scripts/mac-mini/deploy.sh`, `./scripts/mac-mini/build-app.sh <app>`.
|
|
- **GPU server (Windows, RTX 3090):** `ssh mana-gpu` (192.168.178.11, LAN only). Hosts STT/TTS/image-gen/video-gen/Ollama. See [`docs/WINDOWS_GPU_SERVER_SETUP.md`](docs/WINDOWS_GPU_SERVER_SETUP.md).
|
|
|
|
## Reference Docs
|
|
|
|
| Path | When you need it |
|
|
|------|------------------|
|
|
| [`apps/mana/CLAUDE.md`](apps/mana/CLAUDE.md) | **Default** — module pattern, routing, encryption usage |
|
|
| [`apps/mana/apps/web/src/lib/data/DATA_LAYER_AUDIT.md`](apps/mana/apps/web/src/lib/data/DATA_LAYER_AUDIT.md) | Sync engine deep-dive, encryption rollout, threat model |
|
|
| [`docs/LOCAL_DEVELOPMENT.md`](docs/LOCAL_DEVELOPMENT.md) | First-time setup, `dev:*:full` commands |
|
|
| [`docs/ENVIRONMENT_VARIABLES.md`](docs/ENVIRONMENT_VARIABLES.md) | All env vars |
|
|
| [`docs/DATABASE_MIGRATIONS.md`](docs/DATABASE_MIGRATIONS.md) | Migration workflow + rollback |
|
|
| [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) | Production deployment |
|
|
| [`docs/PORT_SCHEMA.md`](docs/PORT_SCHEMA.md) | Which service runs on which port |
|
|
| Service-specific `CLAUDE.md` files | Service internals |
|