Commit graph

200 commits

Author SHA1 Message Date
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
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
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
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
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
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
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
cc55ca5578 fix(mana-core-auth): add shared-llm package to Dockerfile
The auth service now depends on @manacore/shared-llm but it was missing
from the Docker build context, causing build failures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:13:28 +01:00
Till JS
6cab9a3c24 fix(infra): remove n8n and increase health check intervals to fix port exhaustion
Mac Mini had 25k+ TIME_WAIT sockets exhausting the 16k ephemeral port range,
blocking all outgoing TCP connections. Root cause: ~50 health checks at 30s
intervals + n8n automation creating excessive short-lived connections.

- Remove n8n service and volume (no longer needed)
- Increase health check intervals: 30s → 120s (app services), 10s → 30s (infra)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:35:45 +01:00
Till JS
e2f144962c feat: add unified @manacore/shared-llm package and migrate all backends
Create a shared LLM client package that provides a unified interface
to the mana-llm service, replacing 9 individual fetch-based integrations
with consistent error handling, retry logic, and JSON extraction.

Package (@manacore/shared-llm):
- LlmModule with forRoot/forRootAsync (NestJS dynamic module)
- LlmClientService: chat, json, vision, visionJson, embed, stream
- LlmClient standalone class for non-NestJS consumers
- extractJson utility (consolidates 3 markdown-stripping implementations)
- retryFetch with exponential backoff (429, 5xx, network errors)
- 44 unit tests (json-extractor, retry, llm-client)

Migrated backends:
- mana-core-auth: raw fetch → llm.json()
- planta: raw fetch + vision → llm.visionJson()
- nutriphi: raw fetch + regex → llm.visionJson() + llm.json()
- chat: custom OllamaService (175 LOC) → llm.chatMessages()
- context: raw fetch → llm.chat() (keeps token tracking)
- traces: 2x raw fetch → llm.chat()
- manadeck: @google/genai SDK → llm.json() + llm.visionJson()
- bot-services: raw Ollama API → LlmClient standalone
- matrix-ollama-bot: raw fetch → llm.chatMessages() + llm.vision()

New credit operations:
- AI_PLANT_ANALYSIS (2 credits, planta)
- AI_GUIDE_GENERATION (5 credits, traces)
- AI_CONTEXT_GENERATION (2 credits, context)
- AI_BOT_CHAT (0.1 credits, matrix)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 22:06:30 +01:00
Till JS
7910737dd9 fix(mana-media): use prom-client directly instead of shared metrics package
mana-media uses NestJS 11 while shared-nestjs-metrics targets NestJS 10,
causing DynamicModule type incompatibility. Use prom-client directly with
a simple MetricsController to expose /metrics endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:06:09 +01:00
Till JS
e64c298cec refactor(auth,planta): optimize storage usage
mana-core-auth:
- Replace manual key generation (Date.now) with generateUserFileKey()
- Replace manual validateFileSize with maxSizeBytes in upload()
- Remove OnModuleInit — init storage directly in constructor
- Add upload hooks for structured logging
- Remove redundant getPublicUrl() fallback chain (presigned URL for 1 year)
- Add deleteAllUserAvatars() for account deletion
- Simplify getAvatarUploadUrl() using storage.getPublicUrl()

planta:
- Replace createStorageClient() with manual config by createPlantaStorage()
- Replace manual uuid + path construction with generateUserFileKey()
- Remove uuid dependency for key generation
- Add maxSizeBytes validation (20MB)
- Add cacheControl header (immutable, 1 year)
- Add upload hooks for structured logging
- Add error handling in deletePhoto()
- Add deleteAllUserPhotos() for account deletion
- Make getPhotoUrl() synchronous (was async unnecessarily)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 20:59:14 +01:00
Till JS
d9ccb5e31b feat(games): add whopixels hosting at whopxl.mana.how
Dockerfile, docker-compose service (port 5100), Caddy and cloudflared
routing for the WhoPixels game. PORT is now configurable via env var.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:57:50 +01:00
Till JS
8c2aa261e8 perf(auth): replace bcrypt with bcryptjs (pure JS, no native build tools)
- Switch from bcrypt (native C++ addon) to bcryptjs (pure JavaScript)
- Remove python3/make/g++ build tools from Dockerfile builder stage
- bcryptjs is 100% hash-compatible with bcrypt
- Smaller builder image and faster Docker builds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:46:16 +01:00
Till JS
eb859c18bc fix(auth): use SameSite=None for cross-subdomain SSO
SameSite=Lax only sends cookies on top-level navigations (link clicks),
not on programmatic fetch() requests. SSO relies on fetch() with
credentials:'include' from app subdomains to auth.mana.how, so
SameSite=None is required when COOKIE_DOMAIN is set.

Falls back to Lax for local development (no COOKIE_DOMAIN).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:55:34 +01:00
Till JS
985872330f perf(auth): optimize Dockerfile from ~740MB to ~320MB
- Use --chown on COPY instead of chown -R (eliminates duplicate layer)
- Remove corepack from production stage (not needed at runtime)
- Prune devDependencies and clean up test/docs/sourcemaps from node_modules
- Tested: container starts and passes health check

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:55:24 +01:00
Till JS
43a2226290 perf(auth): optimize Dockerfile from ~740MB to ~350MB
- Add pnpm prune --prod to remove devDependencies from node_modules
- Use --chown on COPY instead of chown -R (eliminates 1.6GB duplicate layer)
- Remove corepack from production stage (not needed at runtime)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:41:05 +01:00
Till JS
f7df8e97aa feat(auth): add audit logging, account lockout, and API key rate limiting
1. SecurityEventsService: Centralized audit logging for all auth events
   (login, register, logout, password changes, API key operations, SSO
   token exchange, etc.). Fire-and-forget pattern ensures auth flows
   are never blocked by logging failures.

2. AccountLockoutService: Locks accounts after 5 failed login attempts
   within 15 minutes. 30-minute lockout duration. Fails open on DB
   errors. Clears attempts on successful login. Email-not-verified
   does not count as a failed attempt.

3. API Key validation endpoint secured with rate limiting (10 req/min
   per IP via ThrottlerGuard) and audit logging. Key prefixes logged
   for forensics, never full keys.

New schema: auth.login_attempts table for tracking failed logins.
174 tests passing across all auth and security modules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:09:58 +01:00
Till JS
322f551b43 docs(auth): document SSO checklist for adding new apps
Adding a new app to cross-app SSO requires updating trustedOrigins,
CORS_ORIGINS, and running SSO contract tests. Documented in both
root CLAUDE.md and mana-core-auth CLAUDE.md to prevent future regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:32:35 +01:00
Till JS
bb69f78e1e fix(auth): add missing trusted origins for cross-app SSO
Several apps (mukke, photos, planta, questions, todo, traces, context,
docs, manadeck, zitare) were missing from Better Auth's trustedOrigins,
causing SSO session cookie exchange to fail for those apps. Also synced
CORS_ORIGINS in docker-compose.macmini.yml.

Added 47 SSO contract tests to prevent regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:17:34 +01:00
Till JS
97d5b13a38 feat(versioning): add semantic versioning and changesets to all apps
Assign version numbers based on app maturity: Calendar/Contacts/Todo (1.0.0),
Chat/Picture (0.3.0), 11 beta apps (0.2.0), Context/Planta/Questions (0.1.0),
Traces (0.0.1). Set up @changesets/cli for future version management.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 16:20:18 +01:00
Till JS
3b8931090f fix(auth): scope pnpm install to auth service in Dockerfile
Use --filter to only install mana-core-auth and shared-storage deps,
avoiding missing workspace package errors from root package.json.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:10:08 +01:00
Till JS
baf96cbe03 fix(auth): copy patches dir in Dockerfile to fix pnpm install
pnpm resolves patch references from root package.json even for
partial workspace installs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:09:03 +01:00
Till JS
2c21f6c2bc fix(auth): use --no-frozen-lockfile in Dockerfile
The partial workspace copy causes lockfile mismatches since not all
referenced packages are present in the Docker build context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:08:15 +01:00
Till JS
817ccfea31 fix(auth): improve email verification error detection in signIn
Better Auth may return error objects instead of throwing for unverified
emails. Now checks result.error before hasUser(), uses case-insensitive
matching, and re-throws NestJS HTTP exceptions to avoid masking them.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:05:04 +01:00
Till JS
6e1af0d889 feat(calendar): add Playwright E2E tests for web app
Add 22 E2E tests across 5 test suites covering auth, calendar views,
settings, event CRUD, and calendar management. Tests that require the
calendar backend gracefully skip when it's not running.

Also fixes: hooks.server.ts env fallbacks, ThrottlerGuard DI error,
and auth metrics service TypeScript error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 13:08:09 +01:00
Till JS
f922d2c4a1 fix(auth): return proper 403 for unverified email on login
Better Auth throws APIError("FORBIDDEN") when email is not verified,
but the signIn catch block didn't handle this case, causing a 500.
Now returns ForbiddenException with EMAIL_NOT_VERIFIED code so the
client can show the resend verification link.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 12:33:27 +01:00
Till JS
14ca0ae0b5 fix(auth): align reset-password min length to 8 characters
The ResetPasswordDto required 12 characters while registration and
change-password only required 8, causing a mismatch with frontend UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 12:22:56 +01:00
Till-JS
1d44f918c5 fix(manacore-web): add missing packages to Dockerfile
Add shared-pwa, qr-export, and wallpaper-generator packages
to the Docker build context for manacore-web.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 13:43:08 +01:00
Till-JS
20db01628a fix(auth): remove conflicting JSON body parser middleware
The manual bodyParser.json() middleware conflicts with NestJS rawBody mode.
When rawBody: true is enabled, NestJS consumes the body stream first, then
the manual parser tries to read it again causing "stream is not readable".

NestJS handles JSON parsing internally, so the manual middleware was redundant
and causing 500 errors on login requests.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 14:30:06 +01:00
Till-JS
14da5a28ef 📝 docs(auth): update organization endpoint documentation
- Add all new organization management endpoints to API table
- Add new Invitations section for invitation endpoints
- Update controller JSDoc with complete endpoint list
- Update last updated date
2026-02-16 12:57:29 +01:00
Till-JS
5fe16b5eec feat(auth): add organization management endpoints
Add missing organization features for Teams functionality:
- PUT /auth/organizations/:id - update organization
- DELETE /auth/organizations/:id - delete organization
- PATCH /auth/organizations/:orgId/members/:memberId/role - update member role
- GET /auth/organizations/:id/invitations - list org invitations
- GET /auth/invitations - list user invitations
- DELETE /auth/invitations/:id - cancel or reject invitation
2026-02-16 12:47:49 +01:00
Till-JS
b5d7524c77 💳 feat(stripe): add SEPA Direct Debit payment option
- Add sepa_debit to payment_method_types for credit purchases
- Add sepa_debit to subscription checkout sessions
- Handle payment_intent.processing webhook for SEPA status tracking
- Add blueprint article analyzing payment options (Stripe vs LSV+/FinTS)

SEPA offers lower fees (0.8% vs 1.5%+€0.25) for DACH customers.
Payments are confirmed 3-14 days after checkout (bank processing).
2026-02-16 12:05:19 +01:00
Till-JS
0e8f6f134e 📝 docs(credits): update documentation for simplified credit system
- Remove free credits and signup bonus references
- Remove B2B organization credits documentation
- Update API responses (no freeCreditsRemaining, dailyFreeCredits)
- Update environment variables (remove CREDITS_SIGNUP_BONUS, CREDITS_DAILY_FREE)
- Update JWT info to reflect EdDSA via Better Auth
- Simplify DATABASE_SCHEMA.md to B2C-only flow
2026-02-16 12:03:35 +01:00
Till-JS
d86e9031bb 🐛 fix(auth): skip body parser for Stripe webhooks
The JSON body parser was consuming the request body before NestJS
could access the rawBody needed for Stripe webhook signature
verification. Now webhooks to /api/v1/webhooks/stripe skip the
body parser middleware.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 12:01:24 +01:00
Till-JS
bfc2737ce5 ♻️ refactor(credits): simplify credit system by removing free credits and B2B
Remove free credits system (signup bonus, daily credits) and B2B organization
credits to simplify the codebase. Credits now only come from purchases or gifts.

Changes:
- Remove freeCreditsRemaining, dailyFreeCredits, lastDailyResetAt from balances
- Remove organizationBalances and creditAllocations tables from schema
- Simplify transaction types to: purchase, usage, refund, gift
- Remove B2B endpoints from credits controller
- Remove checkDailyReset, allocateCredits, deductCredits from service
- Add redeemPendingGifts method to auto-redeem gifts on registration
- Update frontend to remove free credits display
- Add database migration for the changes
- Update all related tests to match simplified system
2026-02-16 11:54:32 +01:00
Till-JS
2e660391ce 💳 feat(stripe): add ManaCore unified subscription plans
- Create Plus/Pro/Ultra subscription tiers with Stripe products & prices
- Add credit packs (100/500/1000) for one-time purchases
- Update seed script with new plan structure and Stripe IDs
- Configure webhook secret and customer portal
- Add all Stripe environment variables to .env.development

Plans:
- Free: 50 credits/month (default)
- Plus: 100 credits/month @ €4.99/mo or €49.99/yr
- Pro: 500 credits/month @ €11.99/mo or €119.99/yr
- Ultra: 2000 credits/month @ €24.99/mo or €249.99/yr

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 11:43:04 +01:00