- 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>
The root package.json postinstall script runs scripts/generate-env.mjs
which doesn't exist in the Docker build context. Using --ignore-scripts
skips this postinstall step since env generation isn't needed in Docker.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
mana-media Dockerfile has a pre-existing bug with pnpm symlinks
that needs to be fixed separately.
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.
Photos doesn't use credits, so ManaCoreModule is not needed.
Use shared-nestjs-auth directly instead.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Dockerfile for photos-backend (port 3039)
- Add Dockerfile for photos-web (port 5019)
- Add docker-entrypoint.sh for database migrations
- Add health endpoint for photos-web
- Add photos services to docker-compose.macmini.yml
- Update CORS_ORIGINS for mana-auth and mana-media
- Update CLAUDE.md with production URLs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
storage-web and manacore-web both use shared-stores but it wasn't declared
as a dependency in their package.json files.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
shared-stores is used for navigation stores, shared-types is needed by
shared-auth at build time.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The vite config package exports from dist/ and needs to be built before
the web app can be built.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
Storage-backend build was failing on ARM64 due to QEMU emulation
"Illegal instruction" crash when building native dependencies.
Same approach used for matrix-mana-bot and matrix-tts-bot.
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
- todo: Make task-content button fill full height for better click target
- matrix: Fix TypeScript errors by using Boolean() for template expressions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Simplify navigation by removing unused sidebar mode from both apps:
Todo App:
- Remove isSidebarMode state, handlers, and localStorage persistence
- Remove sidebar-related CSS classes and styles
- Simplify TodoToolbar to pure wrapper component
Contacts App:
- Remove isSidebarMode state, handlers, and localStorage persistence
- Remove sidebar-related CSS from ContactsToolbar and ContactAlphabetView
- Always show view-mode-pill (no longer conditional on sidebar mode)
This removes ~250 lines of unused code across 5 files.
Simplify the bottom bars by removing the unused sidebar mode:
- Remove isSidebarMode prop from all components
- Remove sidebar-related CSS classes and styles
- Simplify CalendarToolbar to pure wrapper component
- Remove localStorage persistence for sidebar mode
This removes ~230 lines of unused code across 8 files.
- 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>
- Add showTasksInCalendar setting (default: false) to hide task blocks
- Auto-scroll time-grid views to 12:00 on initial load for better UX
- Tasks can be re-enabled via settings toggle
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>
- user-settings.svelte.ts: use getAuthUrl() for settings API
- contacts.ts: use getAuthUrl() for tags API client
- feedback.ts: use getAuthUrl() for feedback service
This fixes Mixed Content errors where the app was trying to reach
internal Docker URLs (http://mana-auth:3001) instead of production
URLs (https://auth.mana.how).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes contacts-web using localhost URLs instead of production URLs.
SvelteKit bakes environment variables at build time, so we need to
inject runtime URLs via hooks.server.ts for Docker deployments.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This utility function was used by contacts-web skeletons but wasn't
exported from the main shared-ui package entry point.
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>
The package was incorrectly exporting src/index.ts which causes runtime
errors when used with plain Node.js. Changed to export from dist/.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>