The frontend expected `status.lastBackup` but the backend was returning
`status.lastRun`. This caused the backup dashboard to show "No backup available"
even when backups existed in the history.
Added:
- `lastBackup` as alias for `lastRun`
- `totalBackups` count of completed backups
- Manual backup button now works regardless of backup_enabled setting
- backup_enabled only controls scheduled/automated backups
- Manual backups only require destination to be configured
- Fixed backup_type to correctly show 'manual' vs 'scheduled'
- Increased max file size from 500MB to 10GB
- Created chunkedUploadService.js for managing chunked uploads
- Added chunked upload API endpoints (init, chunk, complete, status, abort)
- Added frontend chunked upload methods to photos.service.ts
- Files >100MB automatically use chunked uploads
- 10MB chunk size for reliable transfers
- Auto-cleanup of expired uploads after 24 hours
- Updated README with 10GB limit and nginx configuration example
This commit implements full video upload, storage, streaming, and playback functionality
for the PicPeak photo sharing platform, allowing users to upload and view videos alongside
photos in galleries.
Backend Changes:
- Added video processing dependencies (fluent-ffmpeg, @ffmpeg-installer/ffmpeg)
- Created videoProcessor.js service for video metadata extraction and thumbnail generation
- Updated photoProcessor.js to handle both images and videos
- Modified adminPhotos.js to accept video files with 500MB size limit
- Enhanced gallery.js with HTTP range request support for video streaming
- Expanded fileSecurityUtils.js with video MIME types and magic number validation
- Added database migration for video support columns (media_type, duration, codecs, dimensions)
Frontend Changes:
- Updated TypeScript types to include video metadata fields
- Created VideoPlayer.tsx component with custom controls
- Modified PhotoUpload.tsx to accept video files (.mp4, .webm, .mov, .avi)
- Updated UserPhotoUpload.tsx for guest video uploads
- Enhanced PhotoGrid.tsx with video badges and duration display
- Modified PhotoLightbox.tsx to conditionally render VideoPlayer for videos
Database Schema:
- Added media_type column ('image' | 'video')
- Added mime_type, duration, video_codec, audio_codec columns
- Added width and height columns for media dimensions
- Migrated existing photos to media_type 'image'
Features:
- Video thumbnail generation from video frames
- Streaming support with range requests for efficient playback
- Video duration display on thumbnails
- Play button indicators on video items
- Full-featured video player with playback controls
- Support for MP4, WebM, MOV, and AVI formats
This feature allows users with non-standard SMTP setups (shared hosting,
self-signed certificates) to bypass certificate validation when needed.
Changes:
- Add database migration for tls_reject_unauthorized column
- Update emailProcessor.js to pass TLS option to nodemailer
- Update adminEmail.js routes to handle the new field
- Add checkbox UI with security warning in EmailConfigPage
- Add English and German translations
Bug fixes included:
#52 - Thumbnail Generation: Added proper parsing of settings values and validation
of Sharp fit parameter to handle JSON-encoded strings correctly
#61 - Branding Settings Not Persisting: Added _parseBoolean helper for reliable
boolean parsing, added hide_powered_by option for white-label support
#55 - Categories Not Applied: Fixed category update logic to properly handle
numeric category IDs, added updated_at timestamp, improved cache invalidation
#59/#56 - Gallery Layout & Apply Theme: Set isPreviewMode=true so theme changes
immediately propagate to parent state, hidden redundant Apply button
#58 - Feedback Icons Show When Disabled: Added feedbackEnabled check to comment
and like buttons in MasonryGalleryLayout and GridGalleryLayout
#57 - Upload Limit 100MB: Increased body parser limit from 100MB to 500MB to
support larger batch uploads
#54 - Wrong Error Message: Enhanced email error handling with specific error
codes and translation keys for better user feedback
- Fix#49: Add column existence checks to migration 011_add_user_upload_settings.js
to prevent "column already exists" errors during deployment
- Fix#50: Create missing workerManager.js file that starts background services
(file watcher and expiration checker) for native installations
This commit fixes the core bugs that prevented Reference mode from functioning:
1. Missing external_relpath Error (CRITICAL FIX)
- Root cause: photoResolver prioritized event.source_mode over photo.source_origin
- Problem: Events in "reference" mode with uploaded photos would fail
because uploaded photos have source_origin='managed' but were being
treated as external photos (requiring external_relpath)
- Fix: Prioritize photo.source_origin over event.source_mode
- Result: Events can now have MIXED sources - imported external photos
AND newly uploaded managed photos coexisting correctly
- File: backend/src/services/photoResolver.js:19
2. Category Assignment Failure (CRITICAL FIX)
- Root cause: Update endpoints modified category_id column but display
used photo.type field ('individual' or 'collage')
- Problem: Category changes appeared to succeed but had no visible effect
- Fix: When category_id is 'individual' or 'collage', update the type
field instead of category_id
- Result: Category assignments now work correctly for all photos
- Files: backend/src/routes/adminPhotos.js:489-497, 605-607
3. Scroll Button Non-Functional (UX FIX)
- Root cause: Scroll indicator was purely visual (no click handler)
- Problem: Users expected to click the animated chevron to scroll
- Fix: Convert div to button with smooth scroll to grid section
- Result: Scroll button now functions as expected with proper a11y
- File: frontend/src/components/gallery/layouts/HeroGalleryLayout.tsx:165-184
Technical Details:
Mixed Source Support:
The photoResolver now correctly handles events that mix:
- External photos: source_origin='external' + external_relpath set
- Uploaded photos: source_origin='managed' + path in storage/events/active
This allows users to start with external media import and later upload
additional photos without errors.
Category/Type Distinction:
The system uses photo.type ('individual'|'collage') for display but also
has a legacy category_id column. The update logic now handles both:
- String values 'individual'/'collage' → update type field
- Numeric values → update legacy category_id field (backward compat)
Notes on Remaining Issues:
Issue #30 also mentioned:
4. Image display (cropped square) - This is by design. Thumbnails use
fit='cover' by default for consistent grid layouts. Can be changed
via app_settings.thumbnail_fit if needed.
5. Theme application - The "Apply Theme" button updates the form state
correctly. Users need to click "Save Changes" to persist to database.
This is standard form behavior, not a bug.
Testing:
- Create event in reference mode with external media
- Upload new photos to the same event → verify no external_relpath error
- Change categories on both external and uploaded photos → verify changes apply
- Use Hero gallery layout → verify scroll button works
Fixes#30
Implemented Feature Request 1 from github.com/the-luap/picpeak/issues/17:
- Added filter functionality to display only liked or favorited photos
- Integrated feedback filter directly into PhotoFilterBar component
- Implemented responsive design with proper mobile/tablet/desktop layouts
- Filter only shows when feedback is enabled for the gallery
- Added proper count display for liked and favorited photos
Improvements:
- Fixed responsive breakpoints (mobile <768px, tablet 768-1023px, desktop ≥1024px)
- Feedback filter shows inline with categories on desktop with vertical divider
- On mobile/tablet, filter appears below categories to prevent layout issues
- Added horizontal scrolling for category buttons to prevent cut-off
Code cleanup:
- Removed all debug console.log statements from production code
- Removed test route from backend gallery.js
- Cleaned up unnecessary logging in frontend components
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
- Remove all console.log/debug statements from production code
- Add NODE_ENV checks for development-only logging
- Remove test scripts (test-feedback, test-image-security, test-backup-*, test-restore)
- Remove one-time fix scripts (fix-temp-photos, fix-migration-state, mark-migration-applied)
- Remove sensitive files (.env.backup, ADMIN_CREDENTIALS.txt)
- Update package.json to remove references to deleted scripts
- Replace console statements with logger utility in backend
- Secure error boundaries to not expose stack traces in production
This makes the codebase production-ready with no debug output or test scripts.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
- Add S3/MinIO storage adapter with multipart upload support
- Implement database backup service for SQLite and PostgreSQL
- Create backup manifest generator for tracking backup contents
- Enhance backup service with S3 integration and incremental backups
- Add restore service with safety measures and rollback capability
- Create comprehensive test suite for all backup functionality
- Add admin API endpoints for backup/restore management
- Implement frontend UI with dashboard, configuration, and restore wizard
- Add roadmap section to README with implemented backup feature
This implementation provides:
- Multiple backup destinations (local, rsync, S3/MinIO)
- Intelligent change detection to minimize backup frequency
- Full database backups with compression
- Manifest-based restore with integrity validation
- Pre-restore safety backups with rollback
- Comprehensive error handling and monitoring
- User-friendly admin interface
🤖 Generated with Claude Code
Co-Authored-By: Claude <[email protected]>
- Disabled duplicate email service (emailService.js) that was creating redundant connections
- Increased connection pool size from 10 to 25 for production environment
- Extended session timeout cache from 5 to 30 minutes to reduce DB queries
- Added connection retry logic with exponential backoff for transient failures
- Fixed password validation to use retry wrapper and correct setting key
- Updated public settings and gallery middleware to handle connection failures gracefully
These changes address the "Connection terminated unexpectedly" errors in production by:
1. Reducing unnecessary database connections
2. Increasing available connection pool capacity
3. Implementing automatic retry for transient connection failures
4. Caching frequently accessed data for longer periods
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
Original: feat: enhance security logging and ensure rate limit blocks are properly tracked
- Add comprehensive logging for rate limit blocks with full request details
- IP address (with proper proxy detection), user agent, headers, timestamps
- Rate limit info (current count, limit, remaining, reset time)
- Separate tracking for auth vs general endpoints
- Enhance authentication failure logging
- JWT validation failures with detailed error info
- Admin auth attempts without token
- Failed token validation with user context
- All events include IP, path, method, user agent
- Improve Winston logger configuration for production
- Add automatic log rotation (10MB errors, 50MB combined)
- Create separate security.log for auth/rate limit events
- Ensure logs directory exists automatically
- Add structured JSON format for log aggregation
- Support container logging with LOG_TO_CONSOLE env var
- Create comprehensive documentation
- Security logging guide with examples
- Monitoring recommendations
- Configuration reference
- Add test script to verify logging functionality
All rate limit settings remain configurable via admin panel:
- Window duration, max requests, auth limits
- Skip authenticated requests option
- Public endpoints only option
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>