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>
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>
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>
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>
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>
- 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
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
- 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).
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>
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
Drizzle ORM requires explicit null values for optional fields instead of
leaving them undefined. Added explicit null for organizationId,
idempotencyKey, portionNumber, and creditTransactionId.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Drizzle ORM throws "UNDEFINED_VALUE" error when inserting undefined values.
Convert dto.sourceAppId to null using nullish coalescing operator.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add matrix-onboarding-bot service that guides users through profile setup
- Extend mana-core-auth GlobalSettings with displayName, interests, onboardingCompleted fields
- Implement state machine for onboarding flow (NAME → INTERESTS → LANGUAGE → SUMMARY)
- Support commands: !start, !profile, !edit, !skip, !help
- Add German and English localization
- Integrate with mana-core-auth Settings API for profile persistence
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
NestJS matches routes in declaration order. The dynamic :code route was
matching before me/created and me/received, treating 'me' as a gift code.
Moved specific routes before the dynamic parameter route.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add recentEmojis field to GlobalSettings in shared-theme
- Create userSettings store for Matrix app with JWT token management
- Exchange session cookie for JWT after SSO login
- Update MessageInput to use userSettings instead of localStorage
- Add recentEmojis support to mana-core-auth settings API
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove duplicate route prefix in GiftsController (was /api/v1/api/v1/gifts)
- Fix JwtAuthGuard to use JWT_ISSUER as fallback when BASE_URL is not set
- Add comprehensive GIFT_CODES.md documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add gift code creation, redemption, and refund endpoints
- Add Stripe payment link generation for credits
- Add gifts database schema
- Enhance credits controller with new operations
Add backend endpoints for user profile management:
- GET /auth/profile - retrieve user profile data
- POST /auth/profile - update name and profile image
- POST /auth/change-password - change password (requires current)
- DELETE /auth/account - soft-delete account (requires password)
Security features:
- Password verification before sensitive actions
- Soft-delete preserves data for retention
- Security events logged for audit trail
- Rate limiting on sensitive endpoints
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add account deletion confirmation email
- Extend data export with sessions, security events, transactions
- Add DSGVO info banner with privacy policy link
- Add data retention periods section
- Add cookie info (no tracking cookies)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add admin modules with GET/DELETE /api/v1/admin/user-data/:userId
- Photos: albums, favorites, tags counting and deletion
- Clock: alarms, timers, world clocks, presets counting and deletion
- Storage: files, folders, shares, tags counting and deletion
- Update UserDataService to include photos, clock, storage backends
- Add ADMIN_SERVICE_KEY env var to all backends in docker-compose
- Build storage-backend locally instead of using GHCR image
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add /api/v1/me/data endpoints for users to view, export, and delete
their own data without admin privileges (GDPR compliance).
Backend:
- New MeModule with MeController and MeService
- GET /api/v1/me/data - view own data summary
- GET /api/v1/me/data/export - download as JSON
- DELETE /api/v1/me/data - delete all own data
Frontend:
- New /settings/my-data page with full data overview
- Export button for JSON download
- DeleteConfirmationModal with email verification
- Link from settings page to my-data
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add api_keys schema in mana-core-auth with SHA-256 hashing
- Create NestJS module with CRUD endpoints and validation
- Add external auth module to STT/TTS for sk_live_ key validation
- Create web UI page at /api-keys for key management
- Support rate limiting per key with configurable limits
- Cache validation results for 5 minutes to reduce auth service load
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive admin dashboard to view and manage user data across all projects:
Backend:
- Add admin endpoints to Chat, Todo, Contacts, Calendar, Picture, Zitare, Presi
- Each backend exposes GET/DELETE /api/v1/admin/user-data/:userId
- Service-to-service auth via X-Service-Key header
Aggregation (mana-core-auth):
- GET /api/v1/admin/users - Paginated user list with search
- GET /api/v1/admin/users/:userId/data - Aggregated data from all backends
- DELETE /api/v1/admin/users/:userId/data - GDPR deletion across all projects
Frontend (ManaCore web):
- New User Data tab in admin navigation
- User search page at /admin/user-data
- User detail page with ProjectDataCard components
- GDPR deletion dialog with email confirmation
Presi:
- Migrate user_id from UUID to TEXT for Better Auth compatibility
- Add SQL migration script
When users log into Matrix via OIDC (Sign in with Mana Core), their
Matrix user ID is now automatically linked to their Mana account.
This enables automatic bot authentication without requiring a
separate !login command.
- Add autoLinkOnOidcLogin() method to MatrixSessionService
- Hook into OIDC userinfo endpoint to create links automatically
- Calculate Matrix user ID from email using Synapse's template
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Better Auth signs JWTs with issuer=BASE_URL (https://auth.mana.how) for OIDC
compatibility, but validation was using jwt.issuer config which defaults to
'manacore'. This caused "unexpected iss claim value" errors.
Fixed in:
- better-auth.service.ts validateToken()
- jwt-auth.guard.ts
- optional-auth.guard.ts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The refresh endpoint was using manual jwt.sign with RSA keys, but the
server doesn't have JWT_PRIVATE_KEY configured. Changed to use Better
Auth's signJWT method which uses the JWKS/EdDSA keys from the database.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Same issue as sessionToToken - the signIn method was returning the
session cookie token as refreshToken, but the /api/v1/auth/refresh
endpoint expects the actual refreshToken field from the sessions table.
Now signIn:
- Fetches the session from database after Better Auth creates it
- Uses existing refreshToken if available
- Generates and stores a new refreshToken if missing
- Returns the actual refreshToken that works with token refresh
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The get-session endpoint needs to be accessible at /api/auth/get-session
(without the /api/v1 prefix) for SSO to work.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The SSO flow in client apps calls /api/auth/get-session with cookies
to check if the user has a valid session. This endpoint was missing
from the NestJS passthrough controller.
Now the endpoint forwards the request with cookies to Better Auth's
native handler and returns the session data.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The sessionToToken method was incorrectly returning the session cookie
token instead of the actual refreshToken from the database. This caused
"No refresh token available" errors when users logged in via SSO
(cross-domain cookie) because the /api/v1/auth/refresh endpoint expects
the refreshToken field from the sessions table, not the cookie token.
Now the method:
- Fetches the session from database by cookie token
- Uses existing refreshToken if available
- Generates and stores a new refreshToken if missing
- Returns the actual refreshToken that works with token refresh
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Activate Redis session storage in both bots for cross-bot SSO
- Update SessionHelper to async methods for Redis-backed SessionService
- Fix async/await issues in todo-bot and calendar-bot matrix.service.ts
- Remove unused imports from calendar-api and todo-api services
- Add CALENDAR_BACKEND_URL and MANA_CORE_SERVICE_KEY to .env.development
Note: SessionService methods are now async (Redis-backed). Other bots
need their matrix.service.ts updated to await these async calls.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Single Sign-On (SSO) support across all mana.how subdomains:
- Add trySSO() method to @manacore/shared-auth that exchanges session
cookies for JWT tokens
- Add /api/v1/auth/session-to-token endpoint to mana-core-auth service
- Update all 15 web apps to try SSO during auth initialization
SSO Flow:
1. User logs in on any app (e.g., calendar.mana.how)
2. Session cookie is set with Domain=.mana.how
3. When visiting another app (e.g., todo.mana.how), it checks for
local tokens first
4. If no local tokens, tries SSO via session cookie
5. Session cookie is exchanged for JWT tokens via new endpoint
6. User is automatically authenticated
Apps updated: calendar, chat, clock, contacts, manacore, manadeck,
nutriphi, picture, planta, presi, questions, skilltree, storage,
todo, zitare
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Document cross-domain SSO with COOKIE_DOMAIN configuration
- Add production test credentials for automated testing
- Explain cookie-based SSO flow across *.mana.how subdomains
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Configure Better Auth with crossSubDomainCookies for .mana.how domain
- Add COOKIE_DOMAIN environment variable (production: .mana.how)
- Sync trustedOrigins with all production subdomains
- Users now login once and are authenticated across all apps
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix LoggerService mock in better-auth.service.spec.ts
- Fix name assertion in auth.controller.spec.ts (empty string fallback)
- Fix createRemoteJWKSet mock in jwt-auth.guard.spec.ts
- Add Grafana dashboard for Auth Service monitoring
- Add 10 auth-specific Prometheus alert rules
- Update production readiness plan to 100% complete
All 199 unit tests passing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Build matrix-mana-bot only for linux/amd64 (arm64 fails due to QEMU)
- Move pnpm overrides for cpu-features and ssh2 to root package.json
- These native deps cause illegal instruction errors under QEMU emulation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
OIDC providers like Synapse expect the JWT issuer claim to match the
discovery document's issuer URL. Changed JWT plugin config from
JWT_ISSUER to BASE_URL to ensure consistency.
Also adds:
- @manacore/credit-operations package with operation definitions
- @manacore/shared-credit-ui package with React Native and Svelte components
- CreditInterceptor and @UseCredits decorator in nestjs-integration
- Credit system integration in chat backend