The config_file override replaced the entire default PostgreSQL config
including listen_addresses, breaking inter-container communication.
Use inline -c flags instead which only override specific parameters.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add LocalImageGenService that routes to the self-hosted FLUX.2 klein
model on the Mac Mini, eliminating Replicate API dependency for basic
image generation.
Changes:
- LocalImageGenService: wraps mana-image-gen HTTP API (/generate)
with health checking, timeout handling, and GenerationResult compat
- GenerateService: routes to local or Replicate based on model config
(replicateId starting with "local/" → LocalImageGenService)
- Local models always use sync mode (no webhooks needed, ~0.8s)
- Seed: add "FLUX.2 Klein (Lokal)" model with sortOrder -1 (shown first)
- costPerGeneration: 0 (free, runs locally)
- estimatedTimeSeconds: 1
- docker-compose: add IMAGE_GEN_SERVICE_URL env var for picture backend
Replicate remains available for premium models (Seedream, Nano Banana).
Local FLUX.2 klein becomes the default free option.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All backend containers were sending error reports to glitchtip.mana.how
(via Cloudflare tunnel), creating ~6000 unnecessary external TCP connections
contributing to port exhaustion. Now routes directly to glitchtip:8020
within the Docker network.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Add Google Gemini as a fallback provider that activates automatically
when Ollama is overloaded or unavailable, ensuring LLM requests always
succeed even under load.
New provider (src/providers/google.py):
- Full LLMProvider implementation using google-genai SDK
- Chat completions (streaming + non-streaming)
- Vision/multimodal support (base64 images)
- Embeddings via text-embedding-004
- Model mapping: Ollama models → Gemini equivalents
(gemma3:4b → gemini-2.0-flash, llava:7b → gemini-2.0-flash, etc.)
Auto-fallback routing (src/providers/router.py):
- Concurrent request tracking for Ollama (OLLAMA_MAX_CONCURRENT=3)
- When Ollama concurrent > max: route to Google automatically
- When Ollama fails: retry on Google with model mapping
- Health check caching (5s TTL) to avoid hammering Ollama
- Non-Ollama providers (openrouter, groq, together) are never fallback-routed
- Fallback info included in /health endpoint response
New config (src/config.py):
- GOOGLE_API_KEY: enables Google provider
- GOOGLE_DEFAULT_MODEL: default gemini-2.0-flash
- AUTO_FALLBACK_ENABLED: toggle fallback (default: true)
- OLLAMA_MAX_CONCURRENT: concurrent request threshold (default: 3)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New service that generates static Astro landing pages for organizations
and deploys them to Cloudflare Pages at {slug}.mana.how.
Components:
- Landing Builder Service (NestJS, port 3030) with Astro template
- Admin UI in Manacore web dashboard at /organizations/[id]/landing
- TeamSection + ContactSection for shared-landing-ui
- Two org themes (classic dark, warm light)
- LandingPageConfig types in shared-types
- Docker + CI/CD integration for Mac Mini deployment
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend: GET /locations/lookup?q= endpoint that searches via mana-search, extracts content from top results, auto-detects address and category, returns pre-filled data with source links.
Frontend: /add page now has a two-step flow:
1. Search step: user enters a place name, backend scrapes the web
2. Edit step: form pre-filled with found data (name, description, address, category), user can review/edit before submitting. Shows source links.
Also fixed all API paths to use /api/v1/ prefix via centralized api() helper.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The LLM playground is a SvelteKit web app (frontend), not a backend
microservice. Moving it to apps/ follows the monorepo convention where
all user-facing apps live under apps/.
- Moved services/llm-playground/ → apps/playground/apps/web/
- Renamed package from @mana-llm/playground to @playground/web
- Updated Dockerfile paths for new location
- Updated docker-compose.macmini.yml build context
- Removed unused concurrently dependency
- Added parent package.json
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
New project with three apps:
- Landing (Astro): static site with SVG illustrations, location data
- Backend (NestJS, port 3025): CRUD API for locations + favorites, Drizzle ORM, auth via mana-core-auth
- Web (SvelteKit, port 5196): Tailwind 4, PillNav, auth (login/register/SSO), Leaflet map, favorites with optimistic updates, theme/settings
Infrastructure: DB init SQL, setup-databases.sh, generate-env.mjs, root package.json scripts, Dockerfiles, docker-compose.macmini.yml (backend:3025, web:5022), Cloudflare wrangler.toml.
Branding: registered in shared-branding (AppId, APP_BRANDING, APP_ICONS, MANA_APPS, CitycornersLogo).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Set crossOrigin='anonymous' on audio element for Web Audio API
compatibility with cross-origin sources. Add MINIO_API_CORS_ALLOW_ORIGIN
to allow browser requests from all web apps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add build context to storage-web in docker-compose (was pulling from
GHCR, now builds locally like other services)
- Add storage-backend and storage-web to CD change detection and deploy
- Fix mukke health check URLs (were using wrong ports 3035/5015)
- Remove hardcoded port from Dockerfile (use PORT env var from compose)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The GlitchTip Docker image doesn't include wget or curl, causing 692+
consecutive health check failures. Switch to python3 urllib which is
available in the image.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The NestJS app uses a global /api/v1 prefix, but the health check was
hitting /health causing 5600+ consecutive failures and unhealthy status.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exclude /health from global prefix so healthchecks hit /health instead of
/api/v1/health. Update Dockerfile EXPOSE and healthcheck to use port 3040
matching docker-compose config.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
- Add deleteByPrefix(prefix) for bulk user data deletion (account cleanup)
- Add copy(sourceKey, destKey) via CopyObjectCommand for file duplication
- Add getMetadata(key) via HeadObjectCommand for content-type/size/metadata
- Add FileMetadata type for structured metadata responses
- Add minio-init container to docker-compose.macmini.yml with bucket creation,
public access policies, and lifecycle rules (matching dev compose)
- 96 tests passing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
calendar.mana.how and contacts.mana.how need to call todo-api.mana.how
for cross-app task integration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stale GHCR image didn't include cross-app URL injection for todo/contacts
backends, causing all task/birthday requests to hit calendar-api instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace GHCR images with local Docker builds for consistency.
All 13 deployed backends now use the same build pattern:
build: context: . / dockerfile: apps/*/apps/backend/Dockerfile
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add import './instrument' to 15 remaining backend main.ts files
- Add GLITCHTIP_DSN to 10 additional backends in docker-compose.macmini.yml
- Total: 13/13 deployed backends have DSNs configured
- Total: 18/18 backends have instrument.ts + import
Backends with live error tracking after next rebuild:
chat, todo, calendar, clock, contacts, storage, presi, nutriphi,
skilltree, photos, zitare, mukke, planta
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
GlitchTip is publicly accessible like other monitoring tools (Grafana, Umami).
No login restriction needed for internal dev tooling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sentry SDK v9 rejects UUID-formatted keys with hyphens. Use the compact
hex format returned by GlitchTip's get_dsn() method.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Combines LightWrite (beat/lyrics editor) and Mukke (iOS music player) into
a single web-based music workspace app. Archives the old Mukke mobile app.
- Rename: @lightwrite/* → @mukke/*, all branding, configs, Dockerfiles
- New DB schemas: songs, playlists, playlist_songs + songId FK on projects
- New backend modules: SongModule, PlaylistModule, LibraryModule
- New web: app shell with sidebar, library (songs/albums/artists/genres),
web player (queue/shuffle/repeat/MediaSession), playlists, search,
upload, dashboard, album/artist/genre detail pages
- Auth: add forgot-password + reset-password pages, extend auth store
- Tests: 40 backend unit tests (song, playlist, library services)
- Config: env generation, MinIO bucket, docker-compose prod, cloudflare
- Docs: update CLAUDE.md, auth guidelines with SvelteKit checklist
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Backend/Web Dockerfiles: use PORT env var in healthcheck (was hardcoded)
- Web Dockerfile: align default port to 5012 (matching docker-compose)
- docker-compose.macmini.yml: add ENCRYPTION_KEY env var for calendar-backend
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update Dockerfile HEALTHCHECK to use /api/v1/health
- Update docker-compose.macmini.yml health check endpoint
- Increase start_period to 30s
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Dockerfile and docker-entrypoint.sh for planta-backend
- Add planta-backend service to docker-compose.macmini.yml (port 3022)
- Add matrix-planta-bot service to docker-compose.macmini.yml (port 4022)
- Configure dependencies: mana-auth, minio, redis, synapse, planta-backend
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When services run in Docker with internal endpoints (e.g., http://minio:9000),
presigned URLs are inaccessible from browsers. This adds S3_PUBLIC_ENDPOINT
support to generate presigned URLs using a publicly accessible endpoint
(e.g., https://minio.mana.how) while keeping internal operations on the
Docker network.
Changes:
- Add publicEndpoint to StorageConfig type
- Create separate S3Client for presigned URL generation
- Add S3_PUBLIC_ENDPOINT to factory configuration
- Configure lightwrite-backend with public MinIO endpoint
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add lightwrite, zitare, questions, planta, manadeck, picture to
mana-core-auth CORS_ORIGINS to allow auth requests from these apps.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace DaisyUI classes with the custom glassmorphic theme:
- Use bg-white/80 dark:bg-black/80 with backdrop-blur
- Use border-black/10 dark:border-white/10 for borders
- Use text-foreground and text-muted-foreground for text
- Add gradient avatars matching rest of app
- Fix tab styling with proper active states
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add STT_API_KEY to matrix-mana-bot and matrix-clock-bot
- Fix STT_URL port (3020/3021 → 3026) for consistency
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add STT bot container config on port 4021
- Uses mana-stt service via host.docker.internal:3026
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 REDIS_HOST, REDIS_PASSWORD for session storage
- Add MANA_CORE_AUTH_URL, MANA_CORE_SERVICE_KEY for Matrix-SSO-Link
- Add redis dependency to depends_on
- Use local image build instead of GHCR
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Download and configure Kerstin Piper voice (63MB, local)
- Update piper_service.py to support multiple voice models
- Set de_kerstin as default voice for TTS bot
- Update help text with new voice options
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Switch from GHCR image to local build
- Add MANA_CORE_AUTH_URL, MANA_CORE_SERVICE_KEY for SSO-Link
- Add Redis config for session storage
- Add dependencies on mana-auth and redis
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Connect stats-bot to VictoriaMetrics for infrastructure
monitoring commands (!system, !services, !traffic, !db, !growth)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>