Validator now checks 52 Dockerfiles (web + backend + service).
Fixed 10 missing COPYs across backends, services, and nestjs-base.
Generator also supports backend/service Dockerfiles with markers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
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>
Migrate matrix-project-doc-bot from raw fetch to @manacore/shared-llm
and remove the unused openai npm package. The bot was already using
mana-llm and mana-stt (not OpenAI directly), but the code still had
raw fetch calls and the openai package installed.
Changes:
- generation.service.ts: raw fetch → llm.chat() via LlmClientService
- app.module.ts: add LlmModule.forRootAsync()
- Remove openai dependency (was unused in code)
- Update CLAUDE.md: document actual AI stack (mana-llm + mana-stt)
- Update TECH_STACK_INDEPENDENCE.md: mark Prio 1-3 as completed
- Prio 1: Picture App → mana-image-gen ✅
- Prio 2: Project Doc Bot → Ollama + mana-stt ✅
- Prio 3: All LLM calls via mana-llm ✅
- Self-hosted percentage: 75% → ~80%
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>
Replace pnpm deploy with direct workspace copy approach since pnpm
deploy doesn't work well with workspace:* dependencies in partial copies.
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>
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>
The pnpm-lock.yaml references patches (react-native-reanimated) which
must be present for pnpm install --frozen-lockfile to succeed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The production domain is mana.how, not manacore.app. Updated all
references across shared-branding APP_URLS, app configs, landing pages,
docs, help content, calendar iCal UIDs, and deploy scripts.
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>
- 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>
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>
- 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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
Restructure standalone traces app into monorepo pattern with mobile + backend + shared types.
Add NestJS backend with Drizzle ORM schema for locations, cities, places, POIs, and AI guides.
Add mobile sync layer, cities tab, and guide generation UI. Fix pre-existing type errors across
mobile codebase, matrix-mana-bot (sendDirectMessage), llm-playground, and all web auth stores
(signUp call signature).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Same fix as planta-bot - I18nService injection was failing because
the service couldn't be resolved in the BotModule context despite
I18nModule having global: true.
Co-Authored-By: Claude Opus 4.5 <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>
Also restore @Global() decorator to I18nModule while keeping
global: true in DynamicModule config for consistency with other
modules like CreditModule.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add configurable morning summaries that aggregate data from multiple sources:
- Weather forecast via Open-Meteo API (free, no API key needed)
- Today's calendar events
- Today's tasks + overdue tasks
- Birthdays from contacts
- Plants needing water from Planta
New commands:
- !morning / !morgen - Get summary now
- !morning-on/off - Enable/disable automatic delivery
- !morning-time HH:MM - Set delivery time
- !morning-location [city] - Set weather location
- !morning-timezone [zone] - Set timezone
- !morning-format [kompakt|ausfuehrlich] - Set format
- !morning-settings - Show current settings
New shared services in @manacore/bot-services:
- WeatherService - Open-Meteo integration with geocoding
- ContactsApiService - Birthday fetching
- PlantaApiService - Watering schedule
- MorningSummaryService - Aggregates all sources
- MorningPreferencesService - User preferences storage
Includes scheduler for automatic daily delivery at user-configured time.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use node:20-slim like other bots
- Copy and build shared packages (bot-services, matrix-bot-common)
- Use pnpm instead of npm
- Add non-root user for security
- Fix healthcheck port to 4022
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add handleImageMessage() to BaseMatrixService for image support
- Implement photo upload and Gemini Vision analysis in PlantaService
- Add image handler in MatrixService that downloads, uploads, and analyzes
- Format analysis results with health status, care tips, and confidence
- Update CLAUDE.md documentation with new feature
- Fix type mismatch in onboarding-bot (fullName → displayName)
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