feat: implement gallery feedback system with version tracking for backups

Gallery Feedback Features:
- Add feedback system allowing ratings, likes, comments, and favorites on photos
- Implement admin controls for enabling/disabling feedback per event
- Add content moderation with word filters and spam detection
- Implement rate limiting to prevent abuse (10 requests/15min per type)
- Create comprehensive admin interface for feedback management
- Add analytics dashboard for feedback insights
- Export feedback data when archiving events

Frontend Components:
- PhotoRating: 5-star rating system with optimistic updates
- PhotoLikes: Like/unlike with animation
- PhotoComments: Threaded comments with moderation
- PhotoFavorites: Bookmark functionality
- FeedbackSettings: Admin configuration panel
- EventFeedbackPage: Complete management interface

Backend Implementation:
- Database migration 033: 4 new tables for feedback system
- RESTful API with proper authorization
- Guest identification via SHA256(IP+UserAgent)
- Automatic backup integration
- Email notification support

Backup Version Tracking:
- Migration 034: Add version columns to backup tables
- Track app version, Node.js version, and DB schema version
- Create restore_history table for tracking restore attempts
- Add version compatibility checking for safe restores
- Configurable version matching requirements

Security & Performance:
- Input validation and sanitization
- Rate limiting per feedback type
- Content moderation system
- Optimistic UI updates
- Efficient database queries with proper indexes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-22 15:08:52 +02:00
parent 2624ea6130
commit dc1419c051
28 changed files with 4312 additions and 15 deletions
+35 -3
View File
@@ -11,6 +11,7 @@ const logger = require('../utils/logger');
const { formatBoolean } = require('../utils/dbCompat');
const backupManifest = require('./backupManifest');
const S3StorageAdapter = require('./storage/s3Storage');
const packageJson = require('../../package.json');
// Backup job reference
let backupJob = null;
@@ -20,6 +21,21 @@ let isRunning = false;
// Storage paths
const getStoragePath = () => process.env.STORAGE_PATH || path.join(__dirname, '../../../storage');
/**
* Get current database schema version
*/
async function getCurrentSchemaVersion() {
try {
const result = await db('knex_migrations')
.orderBy('id', 'desc')
.first();
return result ? result.name : 'unknown';
} catch (error) {
logger.error('Failed to get schema version:', error);
return 'unknown';
}
}
/**
* Calculate file checksum using SHA256
*/
@@ -646,11 +662,17 @@ async function runBackup() {
return;
}
// Create backup run record
// Get current schema version
const schemaVersion = await getCurrentSchemaVersion();
// Create backup run record with version info
const [runId] = await db('backup_runs').insert({
started_at: startTime,
status: 'running',
backup_type: 'scheduled'
backup_type: 'scheduled',
app_version: packageJson.version,
node_version: process.version,
db_schema_version: schemaVersion
});
backupRun = { id: runId };
@@ -801,7 +823,7 @@ async function runBackup() {
// Don't fail the entire backup for manifest generation failure
}
// Update backup run record
// Update backup run record with manifest info
await db('backup_runs')
.where('id', runId)
.update({
@@ -812,6 +834,16 @@ async function runBackup() {
duration_seconds: durationSeconds,
manifest_path: manifestPath,
manifest_id: manifestPath ? path.basename(manifestPath, path.extname(manifestPath)) : null,
manifest_info: manifestSummary ? JSON.stringify({
manifest_version: manifestSummary.manifest?.version,
backup_id: manifestSummary.backup?.id,
system_info: manifestSummary.system,
file_count: manifestSummary.files?.count,
database_info: {
type: manifestSummary.database?.type,
schema_version: manifestSummary.database?.schema_version
}
}) : null,
statistics: JSON.stringify({
totalFilesChecked: files.length,
filesBackedUp: result.backedUpCount,