Replace all mock data with real backend integration

- Add database tables for email configs, settings, and activity logs
- Create backend endpoints for dashboard stats, analytics, archives, email config, and settings
- Create frontend service layer (admin, archive, email, settings services)
- Update AdminDashboard to use real statistics and activity data
- Update AnalyticsPage to fetch real analytics from backend
- Update ArchivesPage with pagination and real archive operations
- Update EmailConfigPage to manage real SMTP config and templates
- Remove all mock data and replace with API calls throughout admin interface

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-06 22:46:24 +02:00
parent 3470120a0d
commit 932e5e137c
15 changed files with 1998 additions and 356 deletions
+74 -1
View File
@@ -95,6 +95,79 @@ async function initializeDatabase() {
table.datetime('last_login');
});
}
// Email configuration table
const hasEmailConfigTable = await db.schema.hasTable('email_configs');
if (!hasEmailConfigTable) {
await db.schema.createTable('email_configs', (table) => {
table.increments('id').primary();
table.string('smtp_host').notNullable();
table.integer('smtp_port').notNullable();
table.boolean('smtp_secure').defaultTo(false);
table.string('smtp_user');
table.string('smtp_pass');
table.string('from_email').notNullable();
table.string('from_name');
table.datetime('updated_at').defaultTo(db.fn.now());
});
}
// Email templates table
const hasEmailTemplatesTable = await db.schema.hasTable('email_templates');
if (!hasEmailTemplatesTable) {
await db.schema.createTable('email_templates', (table) => {
table.increments('id').primary();
table.string('template_key').unique().notNullable(); // 'gallery_created', 'expiration_warning', etc.
table.string('subject').notNullable();
table.text('body_html').notNullable();
table.text('body_text');
table.json('variables'); // Available template variables
table.datetime('updated_at').defaultTo(db.fn.now());
});
}
// App settings table
const hasAppSettingsTable = await db.schema.hasTable('app_settings');
if (!hasAppSettingsTable) {
await db.schema.createTable('app_settings', (table) => {
table.increments('id').primary();
table.string('setting_key').unique().notNullable();
table.json('setting_value');
table.string('setting_type'); // 'branding', 'theme', 'general'
table.datetime('updated_at').defaultTo(db.fn.now());
});
}
// Activity logs table
const hasActivityLogsTable = await db.schema.hasTable('activity_logs');
if (!hasActivityLogsTable) {
await db.schema.createTable('activity_logs', (table) => {
table.increments('id').primary();
table.string('activity_type').notNullable(); // 'event_created', 'photos_uploaded', etc.
table.string('actor_type'); // 'admin', 'system', 'guest'
table.integer('actor_id');
table.string('actor_name');
table.json('metadata'); // Additional data about the activity
table.integer('event_id').references('id').inTable('events');
table.datetime('created_at').defaultTo(db.fn.now());
});
}
}
module.exports = { db, initializeDatabase };
// Helper function to log activities
async function logActivity(activityType, metadata = {}, eventId = null, actor = null) {
try {
await db('activity_logs').insert({
activity_type: activityType,
actor_type: actor?.type || 'system',
actor_id: actor?.id || null,
actor_name: actor?.name || null,
metadata: JSON.stringify(metadata),
event_id: eventId
});
} catch (error) {
console.error('Failed to log activity:', error);
}
}
module.exports = { db, initializeDatabase, logActivity };