Commit graph

405 commits

Author SHA1 Message Date
Till JS
92557ee835 feat(infra): add load testing + finalize CI/CD for Go and Hono services
Load testing:
- k6 test suite for mana-sync (HTTP sync, WebSocket stress, mixed)
- 3 scenarios: mixed workload, WebSocket-only, sync throughput
- Custom metrics: push/pull latency, WS connect time, conflict count

CI/CD:
- Add 6 missing services to ci.yml: mana-sync, mana-notify,
  mana-api-gateway, mana-crawler, mana-media, mana-credits
- Add same services to cd-macmini.yml for auto-deploy
- Add mana-sync + mana-media to docker-validate.yml
- Go services trigger on shared-go/ changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 18:22:33 +01:00
Till JS
09ccf32091 fix(mana-auth): fix schema import paths (.schema → .ts)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 18:17:57 +01:00
Till JS
73181ab91d refactor(mana-media): migrate from NestJS to Hono/Bun
Replace NestJS framework with Hono + Bun, eliminating the last
NestJS service from the stack. All business logic preserved:
- CAS upload with SHA-256 dedup
- BullMQ image processing (Sharp thumbnails/variants)
- Matrix MXC URL import
- EXIF extraction
- File streaming/transforms
- Prometheus metrics

23 NestJS files → 12 Hono files. Zero NestJS in the monorepo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 18:12:42 +01:00
Till JS
7dd8fa869f test(mana-sync): add E2E sync flow test script
Bash-based integration test that verifies the full sync cycle:
1. Health check
2. Client A pushes insert
3. Client B pulls and sees the change
4. Client B pushes update (field-level)
5. Client A pulls and sees the update
6. Client A pushes delete
7. Unauthorized request rejected (401)

Requires running mana-sync + mana-auth. Run with:
  ./services/mana-sync/test/e2e-sync-flow.sh [TOKEN]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 17:56:47 +01:00
Till JS
22fe8077b6 fix(docker): add shared-go COPY to all Go service Dockerfiles
All 4 Go services using shared-go now:
1. COPY packages/shared-go/ to /shared-go/ in builder
2. go mod edit -replace before go mod download (dep caching)
3. go mod edit -replace before go build (source rebuild)

Docker builds verified locally for mana-search and mana-notify.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:34:40 +01:00
Till JS
bf4d9cb9aa refactor(go-services): integrate shared-go into crawler + gateway, fix Dockerfiles
- mana-crawler: config → envutil, handler → httputil.WriteJSON
- mana-api-gateway: config → envutil, handlers → httputil.WriteJSON
- Fix Dockerfile COPY paths (remove stale -go suffix in all 4 services)
- All services now use packages/shared-go via replace directive

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:25:30 +01:00
Till JS
d3d11e661d feat(apps): create Hono compute servers for Traces, Planta, NutriPhi
Add lightweight Hono + Bun servers for server-only compute endpoints.
CRUD is handled by mana-sync, these handle AI + file upload only.

Traces: AI guide generation, location sync (Port 3026)
Planta: Photo upload (S3), AI plant analysis (Port 3022)
NutriPhi: AI meal analysis (photo+text), recommendations (Port 3023)

Each uses @manacore/shared-hono for auth/health/errors. ~100-200 LOC.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:16:57 +01:00
Till JS
8ccf8ff818 chore: misc fixes, new services, lockfile cleanup
Assorted changes from recent sessions:
- .gitignore: add mana-sync binary, Forgejo data
- chat/web: add isSidebarMode to navigation store
- clock/web: fix alarm page markup
- contacts/mukke/presi/questions: add svelte.config.js aliases
- context/web: add missing dependency
- manacore/landing: update pricing page
- manacore/web + todo/web: update mana dashboard pages
- planta/web: fix dashboard layout
- pnpm-lock.yaml: cleanup after backend removals
- docs/APP_GAP_ANALYSIS.md: new gap analysis doc
- services/mana-analytics: add Dockerfile
- services/mana-subscriptions: new Go subscription service

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 10:27:35 +01:00
Till JS
7e931b1c6d refactor(services): rename Go services, remove -go suffix
mana-search-go → mana-search
mana-notify-go → mana-notify
mana-crawler-go → mana-crawler
mana-api-gateway-go → mana-api-gateway

Legacy NestJS versions are deleted, suffix no longer needed.
Updated all references in docker-compose, CLAUDE.md, package.json,
Forgejo workflows, and service package.json files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 10:18:40 +01:00
Till JS
5b673282f9 feat(infra): delete mana-core-auth (NestJS), replace with mana-auth (Hono+Bun)
Remove the entire NestJS-based mana-core-auth service (~36,000 lines
including tests, config, and package files). The new mana-auth service
(Hono + Bun, ~1,900 LOC) is the complete replacement on the same port.

Deleted:
- services/mana-core-auth/ — 169 files, 36,123 lines
  (NestJS 10, Express, class-validator, all NestJS infrastructure)

Updated:
- docker-compose.macmini.yml: mana-auth now builds from services/mana-auth
  with Bun healthcheck, simplified env vars (no Redis, no DuckDB needed)
- CLAUDE.md: mana-core-auth → mana-auth in services list
- Overview plan: marked Phase 4+5 as DONE, updated next steps

The ManaCore auth ecosystem is now:
- mana-auth (3001) — Auth, JWT, SSO, OIDC, Guilds, API Keys, GDPR
- mana-credits (3061) — Credits, Gifts, Guild Pools, Stripe
- mana-user (3062) — Settings, Tags, Storage
- mana-subscriptions (3063) — Plans, Billing, Invoices
- mana-analytics (3064) — Feedback, Voting

Total: ~6,600 LOC across 5 Hono+Bun services
Replaces: ~20,000 LOC in 1 NestJS service (67% reduction)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 03:04:01 +01:00
Till JS
4318948980 feat(mana-auth): add guilds, api-keys, me, security, auth routes
Complete the mana-auth Hono service with all remaining endpoints
from mana-core-auth.

Added:
- routes/auth.ts: Full auth flow (register, login, logout, validate,
  password reset, profile, change-password, account deletion,
  security events) with lockout + security event logging
- routes/guilds.ts: Guild CRUD, member management, invitations
  (delegates to Better Auth org plugin + mana-credits for pools)
- routes/api-keys.ts: API key generation, listing, revocation,
  validation (sk_live_* format, SHA-256 hashed)
- routes/me.ts: GDPR data export/delete (Articles 17 & 20)
- services/security.ts: SecurityEventsService (fire-and-forget audit)
  + AccountLockoutService (5 failures/15min → 30min lockout)
- services/api-keys.ts: Key generation, validation, scope checks

Updated:
- index.ts: Wire all routes with proper middleware (JWT, service auth)

Service now has ~1,900 LOC covering all functionality from the
original ~11,500 LOC NestJS mana-core-auth (83% reduction).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 02:57:22 +01:00
Till JS
61ee1ae269 feat(services): create mana-auth (Hono + Bun) — Phase 5 auth rewrite
Rewrite the central authentication service from NestJS to Hono + Bun.
Uses Better Auth's native fetch-based handler — no Express conversion.

Key architecture changes:
- Better Auth handler mounted directly on Hono (app.all('/api/auth/*'))
- No NestJS DI, modules, guards, decorators — plain TypeScript
- JWT validation via jose (same as extracted services)
- Email via nodemailer (simplified, German templates)
- ~1,400 LOC vs ~11,500 LOC in NestJS (88% reduction)

Service structure:
- auth/better-auth.config.ts — copied from mana-core-auth (framework-agnostic)
- auth/stores.ts — in-memory stores for email redirect URLs
- email/send.ts — nodemailer email functions
- middleware/ — JWT auth, service auth, error handler (shared pattern)
- db/schema/ — copied from mana-core-auth (Drizzle, framework-agnostic)

Port: 3001 (same as mana-core-auth — drop-in replacement)
Database: mana_auth (same DB, same schemas)

Better Auth plugins: Organization, JWT (EdDSA), OIDC Provider,
Two-Factor (TOTP), Magic Link

Note: This is the initial version. Guilds, API keys, Me (GDPR),
security (lockout/audit), and admin endpoints will be added
incrementally. The old mana-core-auth remains until fully replaced.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 02:43:44 +01:00
Till JS
4ff3ceb01a harden(mana-sync): fix WebSocket auth, add validation, tests, and docs
Critical security and correctness fixes for the sync server:

Security:
- Fix WebSocket JWT validation — was completely broken (hardcoded
  "pending-auth"). Now validates JWT via JWKS, rejects invalid tokens,
  enforces 10-second auth deadline, sends auth-ok confirmation.
- Add 10 MB request body size limit (prevents OOM attacks)
- Validate op field (must be insert/update/delete)
- Validate table and id fields (must be non-empty)
- Abort sync on RecordChange failure (was silently continuing)

Correctness:
- Fix silent JSON unmarshal errors in store (now returns error)
- Copy client set before iterating in NotifyUser (prevents race)
- Add write timeout on WebSocket notifications

Testing (19 tests, 0 -> 100% for unit-testable code):
- auth: token extraction, validator init, missing auth handling
- config: defaults, env override, invalid port
- sync: op validation, changeset validation, response format,
  field change round-trip, body size constant

Documentation:
- Add CLAUDE.md with architecture, sync protocol, LWW explanation,
  API endpoints, configuration, security notes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 02:41:56 +01:00
Till JS
d0848ea1b3 test(go-services): add unit tests for mana-search-go and mana-notify-go
mana-search-go (42 tests):
- search: BuildCacheKey, scoreResult, normalizeResults, CacheOptions
- extract: cleanText, countWords, formatTime, BuildCacheKey
- handlers: validation for search/extract/bulk endpoints

mana-notify-go (38 tests):
- handler: validateSendRequest, parseTime, nilIfEmpty, jsonOrNil
- channel: webhook Send with httptest, IsExpoPushToken
- auth: ValidateServiceKey middleware, GetUser context
- template: RenderDirect with variables, conditionals, errors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 02:33:59 +01:00
Till JS
753c685ef7 feat(services): create mana-analytics, remove feedback/analytics/ai from auth
Extract feedback, analytics, and AI modules from mana-core-auth into
standalone mana-analytics service (Hono + Bun, Port 3064).

New service (services/mana-analytics/):
- User feedback CRUD with voting
- AI-powered feedback title generation via mana-llm
- Simplified from DuckDB analytics to pure PostgreSQL
- ~550 LOC

Removed from mana-core-auth:
- feedback/ module (6 files)
- analytics/ module (4 files)
- ai/ module (3 files)
- db/schema/feedback.schema.ts

mana-core-auth now contains ONLY pure auth:
- Better Auth (JWT, Sessions, 2FA, Passkeys, OIDC, Magic Links)
- Organizations/Guilds (membership management)
- API Keys, Security, Me (GDPR), Health, Metrics
- Ready for Phase 5: Hono rewrite

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 02:29:24 +01:00
Till JS
e7a8567e61 feat(services): create mana-subscriptions, remove from mana-core-auth
Extract subscription billing into standalone mana-subscriptions service
(Hono + Bun, Port 3063). Also removes Stripe module from mana-core-auth
since subscription webhooks are the last consumer.

New service (services/mana-subscriptions/):
- Plans CRUD, subscription management, Stripe Checkout + Portal
- Invoice tracking, webhook handlers for sub/invoice events
- Internal API for plan limits (consumed by guilds service)
- ~990 LOC (vs ~1,700 in NestJS incl. Stripe module)

Removed from mana-core-auth:
- subscriptions/ module (6 files)
- stripe/ module (4 files) — no longer needed in auth
- db/schema/subscriptions.schema.ts
- guilds.service.ts: replaced direct DB plan limit query with
  HTTP call to mana-subscriptions internal API

mana-core-auth now contains only:
- Auth (Better Auth, JWT, Sessions, 2FA, Passkeys, OIDC)
- Organizations/Guilds (membership only, no credits/plans)
- API Keys, Security, Me (GDPR), Health, Metrics
- Feedback + Analytics (next extraction target)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 02:11:42 +01:00
Till JS
ef19018e71 feat(infra): add mana-sync and mana-notify-go to docker-compose
- mana-sync on port 3051 (Go sync server for local-first apps)
- mana-notify-go on port 3040 (Go notification service)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:35:05 +01:00
Till JS
313779f439 fix(crawler): skip TLS verification for outgoing crawl requests
Required for Docker Desktop Mac (TLS proxy) and sites with
self-signed/expired certificates. Crawlers routinely need this.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:31:03 +01:00
Till JS
585cdc1753 feat(mana-notify): rewrite notification service from NestJS to Go
Replaces the NestJS mana-notify service with a Go implementation.
Features: 4 notification channels (email/SMTP, Expo push, Matrix,
webhook), goroutine worker pool with retry/backoff (replaces BullMQ),
Go template engine (replaces Handlebars), PostgreSQL with auto-migrations
(5 tables), user preferences with quiet hours, idempotency via
externalId, batch sending, scheduled delivery, JWT + service key auth.

22 API endpoints, 1:1 compatible. Binary: 21 MB.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:28:19 +01:00
Till JS
d0ef6676b5 fix(crawler): set SSL_CERT_FILE for HTTPS in Alpine container
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:24:56 +01:00
Till JS
feeebfb7c4 feat(infra): add mana-credits to docker-compose, fix port to 3061
Port 3060 was already taken by api-gateway. Updated mana-credits to 3061.

Changes:
- docker-compose.macmini.yml: Add mana-credits service with health check,
  traefik labels for credits.mana.how, depends on postgres
- docker-compose.macmini.yml: Add MANA_CREDITS_URL to mana-auth env
- Update all port references from 3060 to 3061 (config, Dockerfile, CLAUDE.md)
- Update better-auth.service.ts fallback URLs to 3061
- Update .env.development MANA_CREDITS_URL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:21:54 +01:00
Till JS
c07987138e refactor(auth): remove credits, gifts, and credit-webhooks from mana-core-auth
Remove ~4,200 lines of credit-related code now handled by mana-credits:

Deleted modules:
- credits/ (service, controller, DTOs, specs, guild-pool) — 2,590 LOC
- gifts/ (service, controller, DTOs) — 1,001 LOC
- db/schema/credits.schema.ts, gifts.schema.ts, guilds.schema.ts — 419 LOC

Updated modules:
- app.module.ts: Remove CreditsModule, GiftsModule imports
- stripe.module.ts: Remove CreditsModule dependency (keep for subscriptions)
- stripe-webhook.controller.ts: Remove credit event handlers, keep only
  subscription/invoice events
- guilds.module.ts: Remove CreditsModule dependency
- guilds.service.ts: Replace GuildPoolService with HTTP calls to mana-credits
- better-auth.service.ts: Remove GiftCodeService injection, clean up
  unused imports (Inject, forwardRef, Optional)
- db/schema/index.ts: Remove credit/gift/guild schema exports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:19:42 +01:00
Till JS
3e2558a63a fix(crawler): use background context for crawl jobs (outlive HTTP request)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:15:36 +01:00
Till JS
b0009c200b refactor(credits): route credit calls to mana-credits service
Update consumers to call the new standalone mana-credits service instead
of the credit endpoints embedded in mana-core-auth.

Changes:
- CreditClientService: Add getCreditsUrl() reading MANA_CREDITS_URL
  (falls back to MANA_CORE_AUTH_URL for backward compatibility).
  All credit calls now use /api/v1/internal/* endpoints.
- BetterAuthService: Replace direct DB inserts for credit balance and
  guild pool init with HTTP calls to mana-credits internal API.
  Replace local gift redemption with HTTP call.
- .env.development: Add MANA_CREDITS_URL=http://localhost:3060
- CLAUDE.md: Add mana-credits to services list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:13:21 +01:00
Till JS
64f7f768eb feat(infra): add Go web crawler (mana-crawler-go)
Goroutine-based crawler replacing NestJS mana-crawler:
- goquery for HTML parsing (title, content, links, metadata)
- robots.txt checker with 24h cache
- Worker pool with configurable concurrency + rate limiting
- PostgreSQL for job/result storage
- Same API surface: POST/GET/DELETE /api/v1/crawl

11 MB binary, ~15 MB Docker image vs ~200 MB NestJS.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:10:45 +01:00
Till JS
28bbd7bbb0 fix(mana-search): Go best practices hardening
- Fix response body leak in SearXNG HealthCheck (defer resp.Body.Close)
- Handle ignored errors in HTTP request creation
- Add panic recovery in BulkExtract goroutines
- Add request body size limit (1 MB) via http.MaxBytesReader
- Add MaxHeaderBytes to HTTP server
- Sort engine list for deterministic responses
- Fix variable shadowing (r → res in loop)
- Run as non-root user in Docker container
- Log shutdown errors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:09:31 +01:00
Till JS
15deaf4e0a feat(services): create mana-credits service (Hono + Bun)
Extract the credit system from mana-core-auth into a standalone service.
Uses Hono framework on Bun runtime instead of NestJS.

Service includes:
- Personal credit balance with optimistic locking
- Immutable transaction ledger
- Stripe payment integration (PaymentIntents, Checkout Sessions)
- Guild shared pools with per-member spending limits
- Gift code system (simple, personalized, split, first_come, riddle)
- Service-to-service internal API (X-Service-Key auth)
- JWT validation via JWKS from mana-core-auth (jose library)

Architecture:
- 27 files, ~2.2k LOC (vs ~4.1k in NestJS)
- Drizzle ORM schemas adapted for standalone DB (no FK to auth tables)
- Zod validation instead of class-validator
- Manual service instantiation instead of NestJS DI
- Hono middleware for JWT + service key auth

Port: 3060
Database: mana_credits (separate from mana_auth)

Next steps: Update CreditClientService URL, update mana-core-auth
registration hooks, configure Docker + Cloudflare Tunnel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:08:43 +01:00
Till JS
4b0f5a29fd feat(mana-search): rewrite search service from NestJS to Go
Replaces the NestJS mana-search service with a Go implementation for
lower resource usage and faster startup. All 7 API endpoints are 1:1
compatible (search, extract, bulk extract, engines, health, metrics,
cache clear). Uses go-readability for content extraction and
html-to-markdown for Markdown conversion. Redis cache with graceful
degradation, Prometheus metrics, and structured JSON logging.

Binary: 22 MB vs ~200+ MB node_modules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:58:40 +01:00
Till JS
16e0d99c5a feat(gpu-server): complete GPU server setup with AI services, monitoring, and public access
- Set up 5 AI services on Windows GPU server (RTX 3090):
  - mana-llm (Port 3025): OpenAI-compatible LLM gateway via Ollama
  - mana-stt (Port 3020): WhisperX with word timestamps + speaker diarization
  - mana-tts (Port 3022): Kokoro (EN) + Edge TTS (DE) + Piper (local DE)
  - mana-image-gen (Port 3023): FLUX.2 klein 4B image generation
  - Ollama (Port 11434): gemma3:4b/12b, qwen2.5-coder:14b, nomic-embed-text

- Add @manacore/shared-gpu TypeScript client package with SttClient, TtsClient, ImageClient
- Add CUDA-compatible whisper_service using faster-whisper for Windows
- Configure public access via Cloudflare Tunnel (gpu-llm/stt/tts/img.mana.how)
- Add Loki log aggregator (Docker on Mac Mini) + log shipper on GPU server
- Add GPU scrape targets to Prometheus/VictoriaMetrics config
- Add Grafana Loki datasource for GPU service logs
- Add health check with auto-restart, log rotation, and log shipping
- Document complete setup: Always-On config, troubleshooting, architecture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:35:30 +01:00
Till JS
819568c3df feat(infra): consolidate 21 Matrix bots into Go binary + add Go API gateway
Replace 21 separate NestJS Matrix bot processes (~2.1 GB RAM, ~4.2 GB Docker images)
with a single Go binary using plugin architecture (8.6 MB binary, ~30 MB RAM).

New services:
- services/mana-matrix-bot/ — Go Matrix bot with 21 plugins (mautrix-go, Redis sessions)
- services/mana-api-gateway-go/ — Go API gateway (rate limiting, API keys, credit billing)

Deleted:
- 21 services/matrix-*-bot/ directories
- packages/bot-services/ and packages/matrix-bot-common/
- Legacy deploy scripts and CI build jobs

Updated:
- docker-compose.macmini.yml: new Go services, legacy bots removed
- CI/CD: change detection + build jobs for Go services
- Root package.json: new dev:matrix, build:matrix, test:matrix scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:03:00 +01:00
Till JS
3a133555b8 fix(auth): add GuildPoolService mock to credits unit tests
Fix credits.service.spec and credits.controller.spec which failed
because CreditsService now depends on GuildPoolService. Add mock
provider and update useCredits → useCreditsWithSource references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:21:37 +01:00
Till JS
bac0a8212a docs(auth): document Gilden endpoints and architecture in CLAUDE.md
Add guild management endpoints, credit pool endpoints, credit source
routing, and subscription limit documentation to the service CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:55:32 +01:00
Till JS
8f56feb115 feat(auth): session management UI and improved account lockout feedback
Session management:
- GET /auth/sessions and DELETE /auth/sessions/:id endpoints
- listSessions() and revokeSession() in shared-auth client
- SessionManager component: active sessions list with device info,
  "Aktuell" badge, revoke individual or all other sessions
- Integrated in ManaCore settings page

Account lockout UX:
- Dedicated amber lockout banner (distinct from generic rate-limit)
- "Konto vorübergehend gesperrt" with MM:SS countdown
- "Passwort zurücksetzen" link as alternative action
- formatCountdown helper for clean time display

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:55:32 +01:00
Till JS
2624e5a6b7 feat(pricing): migrate to Mana Quelle S-XXL subscription tiers with new Stripe products
Replace old 3-tier model (Plus/Pro/Ultra) with 5 size-based tiers (S/M/L/XL/XXL).
New naming: "Mana Quelle" for subscriptions, "Mana Trank" for one-time purchases.
Create new Stripe products and prices, archive old ones, update all UI and seed data.

Subscription tiers: S (500 Mana, 4.99€), M (1000, 9.99€), L (2000, 19.99€),
XL (4000, 39.99€), XXL (10000, 99.99€). Yearly: 20% discount.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:54:58 +01:00
Till JS
17df7b32f5 feat(auth): add Gilden (guilds) shared Mana pool system
Replace removed B2B org credit system with consumer-friendly shared
Mana pools. Members spend directly from a guild pool managed by the
Gildenmeister (owner). Supports funding from personal balance,
per-member spending limits, and credit source routing.

New endpoints: /gilden/* (guild CRUD) and /credits/guild/* (pool ops).
POST /credits/use now accepts optional creditSource for guild routing.
Delete broken b2b-journey E2E tests that tested phantom endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:38:19 +01:00
Till JS
63376c1313 fix(mana-sync): correct JWKS URL to /api/auth/jwks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:38:00 +01:00
Till JS
c6b1f83f8b test(auth): add tests for audit log, magic links, and security events
Unit tests (12 new):
- Security events controller: endpoint returns events, guard config
- Audit log service: DB query, ordering, limit, empty results
- Magic link passthrough: route exists, delegates to Better Auth

E2E tests (5 new):
- Magic link routes are routable (send + verify)
- Security events endpoint auth + response shape

Total auth tests: 47 unit + ~35 E2E = 82+

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:29:24 +01:00
Till JS
cc50c0c2ab feat(auth): add password strength indicator and magic links
Password strength (zxcvbn-ts):
- PasswordStrength component with 4-segment color bar and German feedback
- Lazy-loaded with 150ms debounce to avoid SSR/bundle issues
- Integrated into RegisterPage and ChangePassword components

Magic Links (passwordless email):
- Better Auth magicLink plugin (10-minute expiry)
- sendMagicLinkEmail() in email service (German template)
- Passthrough route for /magic-link/* endpoints
- sendMagicLink() in shared-auth client
- "Login-Link per E-Mail senden" button on all 20 login pages
- All 21 auth stores have sendMagicLink() method

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:23:09 +01:00
Till JS
2e4bb9bad7 feat(local-first): add local-first architecture with Dexie.js, Go sync server, and Todo pilot
Implement the foundational local-first data layer for ManaCore apps:

- New @manacore/local-store package (Dexie.js IndexedDB, sync engine, Svelte 5 reactive queries)
- New mana-sync Go service (sync protocol, WebSocket push, field-level LWW conflict resolution)
- Todo app migrated as pilot: stores read/write IndexedDB, guest mode with onboarding seed data
- PillNavigation: prominent login pill for unauthenticated users
- SyncIndicator component showing local/syncing/offline status
- GuestWelcomeModal on first visit for Todo app
- Removed demo-mode auth_required checks from Todo components (all writes are now local)
- CSP fix for local development (localhost:3001, localhost:3050)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:17:58 +01:00
Till JS
4ddff8485b fix(tags): transaction on sync, scroll indicator, backend tests (37 tests)
- Wrap TagLinksService.sync() in db.transaction() to prevent race conditions
- Add CSS mask-image fade edges on TagStrip for scroll affordance
- Add 37 unit tests for tag controllers:
  - TagsController: 12 tests (CRUD, defaults, conflict, not-found)
  - TagGroupsController: 10 tests (CRUD, reorder, cascading)
  - TagLinksController: 15 tests (link/unlink, bulk, sync, query)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:00:12 +01:00
Till JS
0dfd603892 feat(auth): rate limit feedback, audit log UI, and E2E tests
Rate-limiting feedback:
- LoginPage detects 429/account-locked errors and shows countdown timer
- Submit button disabled during cooldown period

Audit log:
- GET /auth/security-events endpoint (JWT-protected) in auth controller
- getSecurityEvents() in BetterAuthService + shared-auth client
- AuditLog component with event type labels, relative dates, UA parsing
- Integrated in ManaCore settings page

E2E tests (passkey-2fa.e2e-spec.ts):
- Passkey registration/authentication flow tests
- Auth guard enforcement (protected vs public endpoints)
- 2FA passthrough route existence tests
- Edge cases (cross-user access, missing fields, token shape)

CSRF note: Already covered by Better Auth (SameSite + HttpOnly +
Trusted Origins). Token refresh already has 4-retry + offline detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:58:56 +01:00
Till JS
11ab265d55 fix(tags): add FK constraint, token validation, input validation
- Add proper FK constraint on tags.groupId -> tag_groups.id (onDelete: set null)
- Validate auth token is non-empty before API requests in TagsClient
- Add @IsNotEmpty/@MinLength(1) on tag and tag group name DTOs
- Add @MaxLength on all query params in tag-links DTOs
- Add GetTagsForEntityDto for validated query params on tags-for-entity endpoint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:49:21 +01:00
Till JS
0c479b3e88 feat(tags): implement cross-app tag system with groups and entity links
Backend (mana-core-auth):
- Add tag_groups table (name, color, icon, sortOrder per user)
- Add tag_links table (tagId + appId + entityId + entityType, cross-app)
- Extend tags table with groupId and sortOrder fields
- Tag Groups API: CRUD + reorder at /tag-groups
- Tag Links API: link/unlink/bulk/sync/query at /tag-links
- Tags API: updated DTOs for groupId/sortOrder

Frontend client (@manacore/shared-tags):
- Add TagGroup, TagLink types and response types
- Add tag group methods: getGroups, createGroup, updateGroup, deleteGroup, reorderGroups
- Add tag link methods: linkTag, bulkLinkTags, unlinkTag, getTagsForEntity, syncEntityTags

Shared UI (@manacore/shared-ui):
- Add TagStrip component with glass-pill styling, tag filtering, management link
- Consistent look across all apps (replaces 3 app-specific implementations)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:43:34 +01:00
Till JS
e0e9ede885 test(auth): add passkey and 2FA controller tests (35 tests)
PasskeyService tests (21):
- Registration/authentication flows with challenge management
- DB operations (store, update counter, delete, rename)
- Error cases (expired challenge, duplicate credential, deleted user)
- Challenge TTL expiry and single-use consumption

Controller tests (14):
- All 7 passkey endpoints (register, authenticate, list, delete, rename)
- Security event logging on sensitive operations
- Guard configuration (protected vs public endpoints)
- 2FA redirect passthrough in signIn flow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:35:06 +01:00
Till JS
f5a9edcfb6 feat(auth): add TOTP two-factor authentication across all apps
Uses Better Auth's built-in twoFactor plugin for TOTP + backup codes:

Backend (mana-core-auth):
- twoFactor plugin in better-auth.config.ts (issuer: ManaCore)
- twoFactorEnabled field on users table, backupCodes as encrypted text
- 2FA redirect detection in signIn flow
- Passthrough controller forwards /two-factor/* to Better Auth
- Security event types for 2FA operations

Client (shared-auth):
- enableTwoFactor, disableTwoFactor, verifyTwoFactor, verifyBackupCode,
  generateBackupCodes methods with session-to-token exchange

UI (shared-auth-ui):
- LoginPage: 2FA code input view after password login, backup code toggle
- TwoFactorSetup: settings component with enable/disable/QR code/backup codes

App integration:
- All 19 auth stores have verifyTwoFactor() and verifyBackupCode()
- All 19 login pages pass onVerifyTwoFactor and onVerifyBackupCode callbacks
- ManaCore settings page has TwoFactorSetup component

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 19:55:09 +01:00
Till JS
3091da914e feat(auth): add WebAuthn/Passkey support across all apps
Implements passwordless authentication via passkeys using @simplewebauthn:

Backend (mana-core-auth):
- New passkeys table in auth schema (credentialId, publicKey, counter, etc.)
- PasskeyService with registration/authentication flows and challenge storage
- 7 new API endpoints (register, authenticate, list, delete, rename)
- createSessionAndTokens helper for non-password auth flows
- Security event types for passkey operations

Client (shared-auth):
- signInWithPasskey() and registerPasskey() with dynamic @simplewebauthn/browser imports
- isPasskeyAvailable() browser capability check
- Passkey management methods (list, delete, rename)

UI (shared-auth-ui):
- Passkey button on LoginPage with key icon, shown when browser supports WebAuthn
- Divider between passkey and email/password form

App integration:
- All 19 web app auth stores have isPasskeyAvailable() and signInWithPasskey()
- All 19 web app login pages pass passkeyAvailable and onSignInWithPasskey props
- rpID=mana.how in production enables cross-app passkey usage (SSO-compatible)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 10:30:03 +01:00
Till JS
1052469397 feat(infra): extend Dockerfile validator to backends and services
Validator now checks 52 Dockerfiles (web + backend + service).
Fixed 10 missing COPYs across backends, services, and nestjs-base.
Generator also supports backend/service Dockerfiles with markers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 08:57:10 +01:00
Till JS
8356ac634a test(auth): add unit tests for local JWKS cache
15 tests covering: happy path, caching with TTL, empty DB, connection
failures, key rotation, and cache clearing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:36:22 +01:00
Till JS
5b5849eaa4 perf(auth): cache JWKS locally instead of HTTP self-call
Replace createRemoteJWKSet (HTTP to localhost) with local DB-backed
JWKS cache. Keys are read from auth.jwks table and cached in memory
with 5-minute TTL. Eliminates HTTP roundtrip per token validation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:26:16 +01:00
Till JS
46925dec90 fix(project-doc-bot): restore shared-llm dependency in package.json
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 12:40:58 +01:00