feat: comprehensive UI/UX and feature improvements
- Dark mode: CSS custom properties (global.css) + toggle button, persisted in localStorage - i18n: German/English language switcher (lang/de.php, lang/en.php, includes/I18n.php) - Mobile-responsive admin layout: hamburger menu, sidebar overlay (global.js + global.css) - Shared admin navigation include (includes/admin_nav.php) used across all admin pages - Toast notifications system globally available via global.js - Voucher templates/profiles: CRUD UI at admin/templates.php with voucher_templates DB table - Bulk voucher creation: create 1-20 vouchers at once with multi-print layout on index.php - Configurable voucher defaults: expire time, device limit, max limit in admin settings - Template quick-select on voucher form: auto-fills max_uses and expire_minutes - Password reset flow: forgot_password.php + reset_password.php with token-based reset - Audit log UI: admin/audit_log.php with filter, pagination, audit_log DB table - Audit logging on login, user create/edit/delete, site create/edit/delete - Admin pages updated: index, vouchers, users, sites all use admin_nav.php + dark mode + i18n - Voucher admin: live search input added alongside existing status filter + pagination - Users admin: password-reset-link button per user row (when SMTP enabled) - Login page: i18n, dark mode, language switcher, forgot password link https://claude.ai/code/session_01YN6Bcm1VSi8mpDeyKpyrdJ
This commit is contained in:
parent
bf3e55a967
commit
a1021a0f84
20 changed files with 5281 additions and 5471 deletions
256
database.sql
256
database.sql
|
|
@ -1,118 +1,138 @@
|
|||
-- UniFi Voucher Management System - Datenbankstruktur
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `settings` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`setting_key` VARCHAR(100) UNIQUE NOT NULL,
|
||||
`setting_value` TEXT,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sites` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`site_id` VARCHAR(100) NOT NULL,
|
||||
`unifi_controller_url` VARCHAR(255) NOT NULL,
|
||||
`unifi_username` VARCHAR(100) NOT NULL,
|
||||
`unifi_password` VARCHAR(255) NOT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`public_access` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`email` VARCHAR(255) UNIQUE NOT NULL,
|
||||
`name` VARCHAR(255),
|
||||
`password_hash` VARCHAR(255),
|
||||
`is_admin` TINYINT(1) DEFAULT 0,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`microsoft_id` VARCHAR(255) UNIQUE,
|
||||
`last_login` TIMESTAMP NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_email` (`email`),
|
||||
INDEX `idx_microsoft` (`microsoft_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `user_site_access` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`user_id` INT NOT NULL,
|
||||
`site_id` INT NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`site_id`) REFERENCES `sites`(`id`) ON DELETE CASCADE,
|
||||
UNIQUE KEY `unique_user_site` (`user_id`, `site_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `vouchers` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`site_id` INT NOT NULL,
|
||||
`user_id` INT,
|
||||
`voucher_code` VARCHAR(50) NOT NULL,
|
||||
`voucher_name` VARCHAR(255) NOT NULL,
|
||||
`max_uses` INT NOT NULL,
|
||||
`expire_minutes` INT NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`unifi_voucher_id` VARCHAR(100),
|
||||
`status` ENUM('valid', 'used', 'expired') DEFAULT 'valid',
|
||||
`used_count` INT DEFAULT 0,
|
||||
`expires_at` TIMESTAMP NULL,
|
||||
`synced_from_unifi` TINYINT(1) DEFAULT 0,
|
||||
`last_sync` TIMESTAMP NULL,
|
||||
FOREIGN KEY (`site_id`) REFERENCES `sites`(`id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL,
|
||||
INDEX `idx_site` (`site_id`),
|
||||
INDEX `idx_created` (`created_at`),
|
||||
INDEX `idx_unifi_id` (`unifi_voucher_id`),
|
||||
INDEX `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Migration für bestehende Tabellen (falls bereits vorhanden):
|
||||
-- ALTER TABLE vouchers ADD COLUMN `status` ENUM('valid', 'used', 'expired') DEFAULT 'valid';
|
||||
-- ALTER TABLE vouchers ADD COLUMN `used_count` INT DEFAULT 0;
|
||||
-- ALTER TABLE vouchers ADD COLUMN `expires_at` TIMESTAMP NULL;
|
||||
-- ALTER TABLE vouchers ADD COLUMN `synced_from_unifi` TINYINT(1) DEFAULT 0;
|
||||
-- ALTER TABLE vouchers ADD COLUMN `last_sync` TIMESTAMP NULL;
|
||||
-- ALTER TABLE vouchers ADD INDEX `idx_unifi_id` (`unifi_voucher_id`);
|
||||
-- ALTER TABLE vouchers ADD INDEX `idx_status` (`status`);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sessions` (
|
||||
`id` VARCHAR(128) PRIMARY KEY,
|
||||
`user_id` INT NOT NULL,
|
||||
`data` TEXT,
|
||||
`expires_at` TIMESTAMP NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,
|
||||
INDEX `idx_expires` (`expires_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `login_attempts` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`ip_address` VARCHAR(45) NOT NULL,
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
`attempted_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_ip` (`ip_address`),
|
||||
INDEX `idx_email` (`email`),
|
||||
INDEX `idx_attempted` (`attempted_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `audit_log` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`user_id` INT,
|
||||
`action` VARCHAR(100) NOT NULL,
|
||||
`entity_type` VARCHAR(50),
|
||||
`entity_id` VARCHAR(100),
|
||||
`details` TEXT,
|
||||
`ip_address` VARCHAR(45),
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL,
|
||||
INDEX `idx_user` (`user_id`),
|
||||
INDEX `idx_action` (`action`),
|
||||
INDEX `idx_created` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Migration für bestehende Installationen:
|
||||
-- Neue Tabellen werden automatisch erstellt (CREATE TABLE IF NOT EXISTS)
|
||||
-- UniFi Voucher Management System - Datenbankstruktur
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `settings` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`setting_key` VARCHAR(100) UNIQUE NOT NULL,
|
||||
`setting_value` TEXT,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sites` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`site_id` VARCHAR(100) NOT NULL,
|
||||
`unifi_controller_url` VARCHAR(255) NOT NULL,
|
||||
`unifi_username` VARCHAR(100) NOT NULL,
|
||||
`unifi_password` VARCHAR(255) NOT NULL,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`public_access` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_active` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`email` VARCHAR(255) UNIQUE NOT NULL,
|
||||
`name` VARCHAR(255),
|
||||
`password_hash` VARCHAR(255),
|
||||
`is_admin` TINYINT(1) DEFAULT 0,
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`microsoft_id` VARCHAR(255) UNIQUE,
|
||||
`last_login` TIMESTAMP NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_email` (`email`),
|
||||
INDEX `idx_microsoft` (`microsoft_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `user_site_access` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`user_id` INT NOT NULL,
|
||||
`site_id` INT NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`site_id`) REFERENCES `sites`(`id`) ON DELETE CASCADE,
|
||||
UNIQUE KEY `unique_user_site` (`user_id`, `site_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `voucher_templates` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`max_uses` INT NOT NULL DEFAULT 1,
|
||||
`expire_minutes` INT NOT NULL DEFAULT 480,
|
||||
`description` VARCHAR(500),
|
||||
`is_active` TINYINT(1) DEFAULT 1,
|
||||
`created_by` INT,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `vouchers` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`site_id` INT NOT NULL,
|
||||
`user_id` INT,
|
||||
`voucher_code` VARCHAR(50) NOT NULL,
|
||||
`voucher_name` VARCHAR(255) NOT NULL,
|
||||
`max_uses` INT NOT NULL,
|
||||
`expire_minutes` INT NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`unifi_voucher_id` VARCHAR(100),
|
||||
`status` ENUM('valid', 'used', 'expired') DEFAULT 'valid',
|
||||
`used_count` INT DEFAULT 0,
|
||||
`expires_at` TIMESTAMP NULL,
|
||||
`synced_from_unifi` TINYINT(1) DEFAULT 0,
|
||||
`last_sync` TIMESTAMP NULL,
|
||||
FOREIGN KEY (`site_id`) REFERENCES `sites`(`id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL,
|
||||
INDEX `idx_site` (`site_id`),
|
||||
INDEX `idx_created` (`created_at`),
|
||||
INDEX `idx_unifi_id` (`unifi_voucher_id`),
|
||||
INDEX `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sessions` (
|
||||
`id` VARCHAR(128) PRIMARY KEY,
|
||||
`user_id` INT NOT NULL,
|
||||
`data` TEXT,
|
||||
`expires_at` TIMESTAMP NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,
|
||||
INDEX `idx_expires` (`expires_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `login_attempts` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`ip_address` VARCHAR(45) NOT NULL,
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
`attempted_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX `idx_ip` (`ip_address`),
|
||||
INDEX `idx_email` (`email`),
|
||||
INDEX `idx_attempted` (`attempted_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `audit_log` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`user_id` INT,
|
||||
`action` VARCHAR(100) NOT NULL,
|
||||
`entity_type` VARCHAR(50),
|
||||
`entity_id` VARCHAR(100),
|
||||
`details` TEXT,
|
||||
`ip_address` VARCHAR(45),
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL,
|
||||
INDEX `idx_user` (`user_id`),
|
||||
INDEX `idx_action` (`action`),
|
||||
INDEX `idx_created` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `password_reset_tokens` (
|
||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`user_id` INT NOT NULL,
|
||||
`token` VARCHAR(128) NOT NULL,
|
||||
`expires_at` TIMESTAMP NOT NULL,
|
||||
`used` TINYINT(1) DEFAULT 0,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,
|
||||
UNIQUE KEY `unique_token` (`token`),
|
||||
INDEX `idx_expires` (`expires_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Migrations für bestehende Installationen:
|
||||
-- ALTER TABLE vouchers ADD COLUMN IF NOT EXISTS `status` ENUM('valid', 'used', 'expired') DEFAULT 'valid';
|
||||
-- ALTER TABLE vouchers ADD COLUMN IF NOT EXISTS `used_count` INT DEFAULT 0;
|
||||
-- ALTER TABLE vouchers ADD COLUMN IF NOT EXISTS `expires_at` TIMESTAMP NULL;
|
||||
-- ALTER TABLE vouchers ADD COLUMN IF NOT EXISTS `synced_from_unifi` TINYINT(1) DEFAULT 0;
|
||||
-- ALTER TABLE vouchers ADD COLUMN IF NOT EXISTS `last_sync` TIMESTAMP NULL;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue