- Add BUILD_TIME and BUILD_HASH exports to all version.ts files
- Add getBuildDefines() to all vite.config.ts for compile-time injection
- Add buildTime prop to shared LoginPage component
- Display formatted date/time next to version number (e.g. "v1.0.0 · 21.03.2026 10:30")
- Add app.d.ts type declarations for __BUILD_TIME__ and __BUILD_HASH__
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Dockerfile pruning step deleted all 'docs' directories in node_modules,
including googleapis/build/src/apis/docs/ which is the Google Docs API
sub-module. This caused 'Cannot find module ./docs' crash loop on startup.
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>
Tests (109 total, all passing):
- Backend (Jest, 83 tests): file, folder, trash, search, share, tag services
- Web (Vitest, 26 tests): API client coverage for all endpoints
- Mock factories for File, Folder, Share, Tag entities
File Preview Modal:
- Image preview for image/* MIME types, file info display
- Action buttons: download, rename, share, favorite, delete
- Full ARIA accessibility, responsive, escape/click-outside close
- Integrated in /files, /files/[folderId], /favorites, /search pages
Dockerfiles:
- Fix incorrect port 3019 → 3016 in backend Dockerfile and web build arg
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3-step onboarding using shared-app-onboarding package (same as calendar):
1. Sort order: first name vs last name
2. Import: Google, vCard/CSV, or skip — navigates to import page on completion
3. Tips: self-contact card, quick input, focus mode, tags
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add meta description, Open Graph tags, theme-color, preconnect/dns-prefetch to app.html
- Add per-page meta descriptions (files, favorites, search, trash, shared, settings)
- Add ARIA attributes to all loading states (role="status", aria-live="polite")
- Add aria-label, aria-expanded, aria-haspopup to all menu buttons (FileCard, FolderCard, FileRow, FolderRow)
- Add role="menu" and role="menuitem" to all dropdown menus
- Add semantic table roles to FileList (role="table", role="columnheader", role="rowgroup")
- Add aria-label and progressbar ARIA to UploadZone
- Add role="img" with aria-label to emoji icons in trash
- Add aria-label to icon-only delete button in shared page
- Add aria-hidden to decorative SVGs and spinners
- Use type="search" with aria-label on search input
- Remove console.log statements from files, favorites, and search pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the marketing landing page at / with an immediate redirect:
authenticated users go to /library, others go to /login. This matches
the behavior of other apps like calendar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces individual QuickInputBar, DateStrip, DateStripFab, CalendarToolbar, and ViewsBar
with a single UnifiedBar component. Layers stack via flexbox, child positioning overridden
to relative. Overlay menu allows toggling layer visibility. View switcher integrated into
toolbar layer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The RecurrenceSelector was already built but only available in the full
EventForm. Now it's integrated into the QuickEventOverlay so users can
set recurring events directly when creating via grid click.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every user now gets their own contact card (like iOS "My Card") automatically
created on first API call, pre-filled with their email. The self-contact is
shown prominently at the top of the list with an "Ich/Me" badge, can be fully
edited, but cannot be deleted.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Document all supported audio formats in mukke CLAUDE.md with browser
compatibility matrix and notes on formats needing transcoding
- Add utils.test.ts for shared-storage: MIME type mappings, audio
extension validation, and AUDIO_EXTENSIONS completeness checks (19 tests)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Expand accepted audio formats beyond MP3/WAV/OGG to include FLAC, AAC,
M4A, AIFF, OPUS, WMA, WebM, ALAC, APE, WavPack, DSF, and DFF.
The HTML5 Audio player already handles whatever the browser supports.
Changes:
- BeatUploader: accept audio/* instead of hardcoded format list
- shared-storage: add MIME type mappings for all common audio formats
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The click-to-create handler was using SNAP_INTERVAL_MINUTES (15) as the
initial event duration. Now uses DEFAULT_EVENT_DURATION_MINUTES (60) to
match the configured default. Drag behavior still uses snap interval.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uses the shared ContextMenu component from @manacore/shared-ui to provide
quick actions (play, edit metadata, open in editor, toggle favorite, delete)
on right-click in the song list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace thin progress bar with animated step dots
- Add checkmark icon and stronger highlight for selected options
- Remove redundant step emoji (duplicate of header)
- Hide "Zurück" button on first step instead of just opacity:0
- Remove timezone step (auto-detect is always correct, 4 options too limited)
- Replace unsupported "day" view with "agenda" in view options
- Wire onComplete to actually apply weekStart and defaultView to settingsStore
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace vitest run with echo (no test files exist)
- Update Current State section: 25 → 128 test files,
reflect actual CI/CD and pre-commit setup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add format:check step (prettier --check, hard fail)
- Make lint step a hard fail (remove || echo fallback)
- Add test step (soft fail for now — coverage is thin)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add docker/Dockerfile.nestjs-base with all shared packages pre-built
- Convert 6 backend Dockerfiles (chat, todo, calendar, clock, contacts,
mukke) to inherit from nestjs-base:local
- Fix bugs: duplicate shared-nestjs-setup builds (mukke), unnecessary
shared-error-tracking rebuild in production stage (chat, clock)
- CD pipeline builds base image before services when backends deploy
- Net reduction: 317 lines removed, 112 added (-205 lines)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use direct image name lookup (<service>:local) instead of
docker compose images --format which isn't supported.
Fallback via running container inspection.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Calendar Sharing:
- Add shares store with full lifecycle (share, accept/decline, remove, permissions)
- Add missing API methods (getInvitations, getSharedWithMe)
- Create /settings/sharing page with:
- Pending invitations section with accept/decline
- "Shared with me" section
- Per-calendar share management (expandable list, add/remove shares)
- Share modal with email, permission selection
- Add link from main settings page
Error Boundaries:
- Create ServiceStatusBanner component for graceful degradation
- Integrate into main calendar page for Todo and Birthday services
- Shows warning when service unavailable with retry button
- Uses existing serviceAvailable flags from stores
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pnpm install fails without the patches/ directory since pnpm-lock.yaml
references patch files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace manual validateFileSize() with maxSizeBytes in upload()
- Add upload hooks for structured logging
- Add deleteFiles() for bulk deletion via deleteMany()
- Add deleteAllUserFiles() for account deletion via deleteByPrefix()
- Remove unused validateFileSize import
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>
SongService:
- Use deleteMany() for batch deletion of audio + cover (was sequential)
- Add maxSizeBytes validation on cover art (10MB) and tag writing (500MB)
- Add cacheControl header on cover art uploads (immutable, 1 year)
- Add upload hooks for structured logging
- Use 'songs' subfolder for audio, 'covers' for cover art (was flat)
- Add deleteAllUserFiles() for account deletion via deleteByPrefix()
- Log storage errors instead of silently swallowing
BeatService:
- Add upload:error hook for structured logging
- Use 'beats' subfolder for organized key structure
- Log storage deletion errors instead of swallowing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 4 tests: getReminders (success + error), createReminder with body
validation, deleteReminder endpoint
- All 120 tests passing across 13 test files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DuplicatesService.mergeContacts() now deletes S3 photos of merged
contacts before removing them from the DB. Photos that were adopted
by the primary contact (via mergeContactData) are preserved.
- Import PhotoModule in DuplicatesModule
- Inject PhotoService into DuplicatesService
- Add photo cleanup loop before DB deletion
- Update test mock
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>