Switch from adapter-netlify to adapter-node for self-hosted Docker deployment.
Add missing Button and Card UI components, remove Netlify config files,
and add picture-backend + picture-web services to docker-compose and
Cloudflare tunnel routing (picture.mana.how).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create ReminderSelector component with two modes:
- Draft mode (new events): configure reminders before save with preset
dropdown, push/email toggles, add/remove multiple reminders
- Saved mode (existing events): view reminders with status (pending/sent/
failed), add via preset dropdown, delete individual reminders
- Integrate into EventForm: default reminder pre-configured from settings,
drafts passed to parent via onSave callback for creation after event save
- Integrate into EventDetailModal: load and display reminders for existing
events, add/remove reminders directly via API, auto-refresh on change
- German UI labels for all reminder presets (Zum Zeitpunkt, 5/10/15/30 Min.,
1/2 Stunden, 1/2 Tage, 1 Woche vorher)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bug fix:
- ContactService.delete() now cleans up S3 photo before DB deletion
(previously left orphaned files in storage)
- ContactModule imports PhotoModule for dependency injection
PhotoService improvements:
- Use maxSizeBytes in upload() instead of manual validateFileSize()
- Use getPublicUrl()/result.url instead of manual URL construction
via getStorageConfig() + BUCKETS concatenation
- Add cacheControl header for immutable photo assets (1 year)
- Add upload hooks for structured logging via Logger
- Add deletePhotoByUrl() for contact deletion cleanup
- Add deleteAllUserPhotos() for account deletion via deleteByPrefix()
- Store photos in 'photos' subfolder for cleaner key structure
- Remove unused getStorageConfig/BUCKETS imports
Test fix:
- Add PhotoService mock to ContactService spec
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>
Cover all features added in recent commits: hooks, metrics,
Prometheus collector, presigned multipart, move, copy,
deleteByPrefix, getMetadata, stream size validation, CDN URLs.
Update bucket table to match current state.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sends a message to a Matrix room when a deploy fails, including
the failing services, commit, deployer, and a link to the logs.
Requires two GitHub Actions secrets:
- DEPLOY_NOTIFY_ROOM_ID: Matrix room ID
- DEPLOY_NOTIFY_BOT_TOKEN: Matrix bot access token
Skips silently if secrets are not configured.
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>
Replace 697 lines of inline drag/drop/resize/create/keyboard handlers
in WeekView.svelte with existing composables:
- useEventDragDrop: event drag & resize (was ~220 LOC inline)
- useTaskDragDrop: task drag & resize (was ~180 LOC inline)
- useSidebarDrop: sidebar task drop (was ~70 LOC inline)
- useDragToCreate: new composable for click-drag event creation (was ~105 LOC)
- useCalendarKeyboard: Escape key cancel (was ~50 LOC inline)
Also adds getResizePreviewTime() to useEventDragDrop return value
so WeekView doesn't need access to internal resize state.
WeekView.svelte: 1600 → 903 lines (-44%)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add pnpm prune --prod and remove .ts/.map/test/docs files from
node_modules in the builder stage for chat, todo, calendar, clock,
and contacts backends. Same approach as mana-core-auth optimization.
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>
Upload hooks:
- StorageHooks class with fire-and-forget event emitter pattern
- Events: upload, upload:error, delete, delete:error, download
- All StorageClient operations now emit appropriate events
- Unsubscribe functions for cleanup
Metrics:
- StorageMetricsCollector interface (decoupled from prom-client)
- InMemoryMetrics for testing and local dev
- attachMetrics() wires hooks to any collector automatically
- Backends can create a Prometheus collector via MetricsService
Presigned multipart upload (browser direct-upload):
- createMultipartUpload() initiates and returns uploadId
- getMultipartUploadUrls() generates presigned PUT URLs per part
- completeMultipartUpload() finalizes with part ETags
- abortMultipartUpload() for cleanup on abandoned uploads
90 tests passing across 5 test files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- shared-vite-config: getBuildDefines() injects __BUILD_HASH__ and
__BUILD_TIME__ as compile-time constants via Vite define
- shared-ui: DevBuildBadge component shows git hash + build timestamp
in a small fixed badge at bottom-right (click to expand)
- Integrated into mukke-web for deployment verification
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove archived LIGHTWRITE and NUTRIPHI from BUCKETS
- Add missing PLANTA and PROJECTDOC buckets (were in Docker init but not in code)
- Add maxSizeBytes option to upload() and uploadMultipart() for size enforcement
- Add deleteMany() with automatic batching (1000 keys per S3 request)
- Add factories for createPlantaStorage() and createProjectDocStorage()
- Update tests (62 passing)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The signIn() method only called the custom /api/v1/auth/login endpoint
which returns JWT tokens but doesn't set a session cookie. Without the
cookie, cross-subdomain SSO (trySSO) can never find an active session.
Now also calls Better Auth's native /api/auth/sign-in/email with
credentials:'include' after successful login, which sets the session
cookie with Domain=.mana.how for cross-subdomain SSO.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Wire RecurrenceEditDialog into EventDetailModal and QuickEventOverlay
so deleting recurring events shows "this/all/future" options
- Add external calendars section to CalendarSidebar with visibility
toggle and sync error indicator
- Update COMPLEXITY_AUDIT.md to mark sync and recurrence as implemented
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>
- Fix exists() to only catch 404/NotFound, rethrow real errors
- Add downloadStream() for memory-efficient large file downloads
- Add uploadMultipart() using @aws-sdk/lib-storage for large files
- Add automatic pagination to list() via continuation tokens
- Add CDN URL support (cdnUrl in BucketConfig, getCdnUrl() method)
- Reduce factory boilerplate with generic createStorage() function
- Add MinIO lifecycle rules for tmp/ prefixes (chat 90d, calendar 30d, picture 7d)
- Add vitest setup with 56 tests covering client, factory, and utils
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CalDAV/iCal Sync:
- Add sync API client (lib/api/sync.ts) for all external calendar endpoints
- Add external calendars store with connect, disconnect, sync operations
- Add /settings/sync page with provider selection (Google, CalDAV, iCal URL, Apple),
credentials form, CalDAV discovery, sync status display, and manual sync trigger
- Add link to sync settings from main settings page
Recurring Events:
- Add RecurrenceSelector component with preset selection (daily, weekly, monthly,
yearly, weekdays) and custom configuration (interval, weekday picker, end date)
- Integrate RecurrenceSelector into EventForm between date fields and location
- Expand recurring events into individual occurrences in events store using
generateOccurrences() from @calendar/shared
- Add recurrence-aware delete: single occurrence (exception), all occurrences,
or series update via dedicated store methods
- Add RecurrenceEditDialog component for "this/all/this and future" selection
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>
Mukke was missing from the automated deployment pipeline, so changes
to the web app were not being deployed to the Mac Mini server.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add explicit uid: deploy-tracking to datasource provisioning
- Add instant: true to all Prometheus stat/gauge panel queries
- Pushgateway gauges need instant queries, not range queries
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove unnecessary complexity from the calendar web app:
- Remove tag groups system entirely (store, API client, route, components)
Tags are now a flat alphabetically-sorted list instead of grouped hierarchy
- Remove unused legacy composables (useDragDrop, useResize) that were never
imported by any component — useEventDragDrop already consolidates both
- Simplify TagStripModal from 1,452 to ~350 LOC by removing group CRUD,
drag-drop between groups, and group hierarchy rendering
- Add complexity audit report documenting remaining issues
Total: -2,170 LOC across 13 files
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>
- Remove set -euo pipefail from sourced library (breaks caller error handling)
- Replace declare -A associative arrays with string-based lookups
- macOS ships Bash 3.2 which doesn't support declare -A
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
getBaseUrl() always overrides baseUrl with window.__PUBLIC_BACKEND_URL__,
which breaks cross-app API clients (e.g. calendar→todo, calendar→contacts)
by routing all requests to the host app's backend.
Added useRuntimeUrl: false option to skip the runtime override when
the client already resolves its own base URL.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instrument the CD pipeline to record per-deploy and per-service metrics
(build time, image size, startup time, health status) into PostgreSQL and
push gauges to Pushgateway. Adds a Grafana dashboard with 13 panels covering
deploy frequency, build performance, service health, and history.
New files:
- scripts/mac-mini/init-deploy-tracking.sql (idempotent DDL)
- scripts/deploy-metrics.sh (bash library for CI)
- docker/grafana/provisioning/datasources/deploy-tracking.yml
- docker/grafana/dashboards/deploy-tracking.json
Modified:
- docker/prometheus/prometheus.yml (pushgateway scrape job)
- .github/workflows/cd-macmini.yml (build/health instrumentation)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Songs in library are now clickable to play (with full queue support)
- Active song highlighted with primary color and play/pause overlay on cover
- Player store: error state, audio error listener, auto-skip on failure
- MiniPlayer: error toast bar with dismiss button
- Library store: filter non-image paths from cover URL loading
- Cover images: onerror fallback to icon when S3 file is missing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pnpm install fails without the patches directory since the lockfile
references react-native-reanimated patch.
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>
74 commits covering cross-app SSO fix, audit logging service,
account lockout, API key rate limiting, GlitchTip integration
for all 15 backends, and production readiness audits for all 20 apps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add 7 database indexes on all query paths (userId, deckId, order, themeId)
- Add timestamps with timezone for all tables
- Enable Swagger/OpenAPI documentation at /api/docs
- Add ApiTags and ApiBearerAuth to all controllers
- Add ParseUUIDPipe on all ID parameters
- Harden DTO validation: string length limits, @IsIn for enums,
@IsUrl for URLs, @ArrayMaxSize for arrays, @Min(0) for order fields
- Update audit to reflect improvements
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 10 test files covering all 5 services and 5 controllers
- Add global ThrottlerGuard (100 req/min) via APP_GUARD
- Add SvelteKit +error.svelte error boundary
- Add Jest config and test dependencies
- Update audit to reflect improvements
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>
- 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>
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>