- Remove credit display from responses (credits still charged)
- Remove "Synchronisiert" text (sync still works)
- Use sendMessage instead of sendReply to avoid quoting user ID
- Simplify status output
- Use cleaner formatting with dots instead of pipes
- 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 6-language support: original, de, en, it, fr, es
- Add quote metadata: source, year, tags, imageUrl, authorBio, verified
- Add originalLanguage field to preserve original quote language (la, el, zh, sa, etc.)
- Update all 50 quotes with full translations and metadata
- Add new utility functions: getQuoteText, getQuotesByTag, getAllTags,
getQuotesByAuthor, getVerifiedQuotes, getQuotesByYearRange,
getQuotesByOriginalLanguage
- Update matrix-zitare-bot to use new multilingual schema
- Remove local JSON storage from matrix-todo-bot and matrix-calendar-bot
- Delete TodoService, CalendarService and their modules
- Add requireLogin() helper that prompts users to authenticate
- All bot commands now require login before any operation
- Data is always synced with respective backends (todo-backend, calendar-backend)
- Update CLAUDE.md documentation for both bots
BREAKING CHANGE: Bots no longer work without authentication
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>
- Disable api-gateway and skilltree-web (no working images/Dockerfiles)
- Fix mana-search Dockerfile healthcheck port and endpoint
- Update health-check.sh to skip disabled services
- Fix search service health endpoint (/api/v1/health)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
pnpm creates symlinks in node_modules that point to ../../node_modules/.pnpm/
These symlinks break when only the service node_modules are copied.
Using pnpm deploy creates a standalone version with all dependencies
copied (no symlinks), which works correctly in Docker.
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>
Keep same directory structure in production stage so pnpm symlinks
resolve correctly. Copy the .pnpm store and app's node_modules
separately.
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>
Source .env file before starting uvicorn to enable API key auth
and other environment-based configuration.
Removes hardcoded PORT values in favor of .env configuration.
Add auth.py module to both STT and TTS services with:
- API key validation via X-API-Key header
- Rate limiting with sliding window (requests per minute)
- Internal API key option for unlimited access
- Environment variable configuration
All protected endpoints now require authentication.
Public endpoints (/health, /docs) remain accessible.
- Add Photos NestJS backend (port 3019) with albums, favorites, tags
- Add Photos SvelteKit web app (port 5189) with gallery, upload, filters
- Extend mana-media with EXIF extraction service using exifr
- Add cross-app photo listing endpoint to mana-media
- Add photo stats endpoint to mana-media
- Add photos to setup-databases.sh
Backend features:
- Albums CRUD with cover image and items management
- Favorites toggle with status check
- Tags CRUD with photo-tag associations
- Photo proxy to mana-media with local data enrichment
Web features:
- Photo grid with infinite scroll
- Photo detail modal with EXIF display
- Album grid and detail views
- Upload dropzone with progress tracking
- Filter bar (app, date range, location, sort)
- i18n support (de/en)
- Svelte 5 runes mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Disable vLLM by default (has issues on macOS CPU)
- Use Mistral API for Voxtral transcription (cloud-based)
- Keep Whisper-MLX for local transcription
- Update README with architecture diagram
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Reduce max-model-len to 4096 for CPU compatibility
- Add max-num-batched-tokens matching the context size
- Add enforce-eager for stable CPU inference
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add vllm_service.py as proxy to vLLM server for Voxtral 3B/4B
- Add voxtral_api_service.py for Mistral API fallback
- Update main.py with /transcribe/voxtral endpoint using vLLM
- Add /transcribe/auto endpoint with automatic fallback chain
- Create setup-vllm.sh and start-vllm-voxtral.sh scripts
- Add launchd plist files for Mac Mini deployment
- Add install-services.sh for automated service installation
Architecture:
- vLLM server runs Voxtral models on port 8100
- mana-stt proxies to vLLM with Mistral API fallback
- Fallback chain: vLLM -> Mistral API
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
- Use --ignore-scripts to skip postinstall builds during install
- Remove unnecessary shared-builder stage
- Fix health check URL to /api/v1/health
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
pnpm hoists dependencies to root node_modules, so we don't need to copy
service-level node_modules that don't exist.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Matrix user IDs like @user:matrix.org are not UUIDs, so the schema
needs to accept text strings for the userId field in media_references.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- heute command now shows both today's tasks AND inbox tasks
- All commands work without ! prefix (e.g., 'heute' instead of '!heute')
- Updated all help text and messages to show German commands
- Added direct command recognition for: neu, heute, erledigt, löschen, etc.
- Commands still work with ! prefix for backwards compatibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Implement mana-media service with PostgreSQL/Drizzle ORM persistence
- Add content-addressable storage (SHA-256) for automatic deduplication
- Add Matrix MXC URL import endpoint to copy images from Matrix
- Create @manacore/media-client package for service consumption
- Integrate mana-media into NutriPhi bot for persistent image storage
- Update pnpm-workspace.yaml to include nested service packages
- Add mana-media to docker-compose with port 3015
Images sent to NutriPhi bot are now stored in mana-media after analysis,
providing persistent storage with deduplication across all apps.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
Images are now automatically analyzed when sent to the bot, removing
the need for the !analyze command after sending a photo.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All 19 Matrix bots now use SessionModule.forRoot({ storageMode: 'redis' })
to share user sessions across all bots via Redis. Users only need to
login once with any bot to be authenticated with all bots.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add I18nService with per-user language preferences (de/en)
- Add !language/!sprache command to all 4 bots (todo, calendar, contacts, clock)
- Add fallback behavior: messages without commands create tasks/events/contacts/timers
- Improve clock bot duration parsing to accept bare numbers as minutes (e.g. "25" = 25min)
- Add support for more duration formats: "25 minuten", "1 stunde", etc.
Language preferences stored in SessionService, default configurable via BOT_DEFAULT_LANGUAGE env var.
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>
EventSourceResponse from sse-starlette adds its own 'data:' prefix,
so we should yield dicts with a 'data' key instead of pre-formatted
SSE strings. This was causing 'data: data:' double prefixes and
backticks appearing in chat messages.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add PlaygroundLogo to shared-branding package
- Add playground to APP_BRANDING, APP_ICONS, and APP_URLS
- Replace custom login/register pages with shared-auth-ui components
- Update authStore with resendVerificationEmail and improved signUp
- Add Caddy reverse proxy entry for playground.mana.how
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>
The tsconfig was missing include/exclude which caused the build to
output to dist/src/main.js instead of dist/main.js.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
node:20-slim doesn't include wget or curl, which is required
for the HEALTHCHECK commands in the Dockerfiles.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add root-level pnpm override to replace @matrix-org/matrix-sdk-crypto-nodejs
with empty-npm-package. This disables E2EE support but allows matrix bots
to run without native module compilation issues.
The bots don't need E2EE since Matrix Synapse handles encryption at
the server level for our use case.
Also removes the explicit pnpm add commands from Dockerfiles since the
override handles the module replacement.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add loginWithLoginToken function to exchange Matrix SSO loginToken for credentials.
The app layout now detects the loginToken URL parameter and completes the SSO flow.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The @matrix-org/matrix-sdk-crypto-nodejs package needs a rebuild step
after install to properly select the platform-specific prebuilt binary.
Without this, the module fails to find the correct binding at runtime.
Adds `pnpm rebuild @matrix-org/matrix-sdk-crypto-nodejs || true` after
both the dev and prod install steps in all matrix bot Dockerfiles.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The root package.json has postinstall hooks (generate-env, build:packages,
husky) that fail in Docker context. --ignore-scripts prevents these from
running while still allowing the build to complete.
Using node:20-slim (glibc) should handle matrix-sdk crypto modules via
prebuilt binaries without needing install scripts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>