Files
zibo-dashboard/docs/employee-profile-install.md
T
2026-05-14 16:10:10 +03:00

247 lines
11 KiB
Markdown

# 1. Database migration
```mysql
ALTER TABLE employees
ADD COLUMN address varchar(500) DEFAULT NULL AFTER last_name,
ADD COLUMN phone varchar(255) DEFAULT NULL AFTER address,
ADD COLUMN email varchar(255) DEFAULT NULL AFTER phone,
ADD COLUMN job_role_id int(10) UNSIGNED DEFAULT NULL AFTER department_id;
-- Replace ENUM status with plain VARCHAR for easier maintenance.
ALTER TABLE employees
MODIFY status varchar(255) NOT NULL DEFAULT 'active';
CREATE TABLE IF NOT EXISTS job_roles (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
description text DEFAULT NULL,
sort_order int(10) UNSIGNED NOT NULL DEFAULT 999,
is_active tinyint(1) NOT NULL DEFAULT 1,
created_at timestamp NULL DEFAULT current_timestamp(),
updated_at timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY (id),
UNIQUE KEY uniq_job_roles_name (name),
KEY idx_job_roles_active (is_active),
KEY idx_job_roles_sort_order (sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE employees
ADD KEY idx_employees_job_role_id (job_role_id);
ALTER TABLE employees
ADD CONSTRAINT fk_employees_job_role
FOREIGN KEY (job_role_id) REFERENCES job_roles (id)
ON DELETE SET NULL
ON UPDATE CASCADE;
-- 1) Seed job_roles with every distinct non-empty value of employees.position.
INSERT IGNORE INTO job_roles (name, is_active, sort_order, created_at, updated_at)
SELECT DISTINCT TRIM(position), 1, 999, NOW(), NOW()
FROM employees
WHERE position IS NOT NULL AND TRIM(position) <> '';
-- 2) Backfill employees.job_role_id by matching position text to job_roles.name.
UPDATE employees e
JOIN job_roles jr ON jr.name = TRIM(e.position)
SET e.job_role_id = jr.id
WHERE e.position IS NOT NULL AND TRIM(e.position) <> '';
-- 3) Drop the legacy column.
ALTER TABLE employees DROP COLUMN position;
CREATE TABLE IF NOT EXISTS training_topics (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
description text DEFAULT NULL,
default_frequency_months int(10) UNSIGNED DEFAULT NULL,
default_reminder_days int(10) UNSIGNED NOT NULL DEFAULT 30,
sort_order int(10) UNSIGNED NOT NULL DEFAULT 999,
is_active tinyint(1) NOT NULL DEFAULT 1,
is_mandatory tinyint(1) NOT NULL DEFAULT 0,
created_at timestamp NULL DEFAULT current_timestamp(),
updated_at timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY (id),
UNIQUE KEY uniq_training_topics_name (name),
KEY idx_training_topics_active (is_active),
KEY idx_training_topics_mandatory (is_mandatory),
KEY idx_training_topics_sort_order (sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS employee_documents (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
employee_id int(10) UNSIGNED NOT NULL,
category varchar(255) NOT NULL DEFAULT 'other',
original_name varchar(500) NOT NULL,
stored_name varchar(500) NOT NULL,
mime_type varchar(255) DEFAULT NULL,
size int(10) UNSIGNED DEFAULT NULL,
notes text DEFAULT NULL,
uploaded_by int(10) UNSIGNED DEFAULT NULL,
created_at timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (id),
KEY idx_employee_documents_employee (employee_id),
KEY idx_employee_documents_category (category),
KEY idx_employee_documents_uploaded_by (uploaded_by),
CONSTRAINT fk_employee_documents_employee
FOREIGN KEY (employee_id) REFERENCES employees (id)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_employee_documents_uploaded_by
FOREIGN KEY (uploaded_by) REFERENCES auth_users (id)
ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS employee_ppe (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
employee_id int(10) UNSIGNED NOT NULL,
item_name varchar(255) NOT NULL,
delivery_date date DEFAULT NULL,
delivered_by varchar(255) DEFAULT NULL,
notes text DEFAULT NULL,
created_by int(10) UNSIGNED DEFAULT NULL,
created_at timestamp NULL DEFAULT current_timestamp(),
updated_at timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY (id),
KEY idx_employee_ppe_employee (employee_id),
KEY idx_employee_ppe_delivery_date (delivery_date),
CONSTRAINT fk_employee_ppe_employee
FOREIGN KEY (employee_id) REFERENCES employees (id)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_employee_ppe_created_by
FOREIGN KEY (created_by) REFERENCES auth_users (id)
ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS employee_trainings (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
employee_id int(10) UNSIGNED NOT NULL,
training_topic_id int(10) UNSIGNED NOT NULL,
completed_date date NOT NULL,
delivered_by varchar(255) DEFAULT NULL,
description text DEFAULT NULL,
training_type varchar(255) NOT NULL DEFAULT 'initial',
update_frequency_months int(10) UNSIGNED DEFAULT NULL,
reminder_days int(10) UNSIGNED DEFAULT NULL,
next_due_date date DEFAULT NULL,
created_by int(10) UNSIGNED DEFAULT NULL,
created_at timestamp NULL DEFAULT current_timestamp(),
updated_at timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY (id),
KEY idx_employee_trainings_employee (employee_id),
KEY idx_employee_trainings_topic (training_topic_id),
KEY idx_employee_trainings_next_due (next_due_date),
KEY idx_employee_trainings_employee_topic (employee_id, training_topic_id),
KEY idx_employee_trainings_created_by (created_by),
CONSTRAINT fk_employee_trainings_employee
FOREIGN KEY (employee_id) REFERENCES employees (id)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_employee_trainings_topic
FOREIGN KEY (training_topic_id) REFERENCES training_topics (id)
ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT fk_employee_trainings_created_by
FOREIGN KEY (created_by) REFERENCES auth_users (id)
ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS employee_training_attachments (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
training_id int(10) UNSIGNED NOT NULL,
original_name varchar(500) NOT NULL,
stored_name varchar(500) NOT NULL,
mime_type varchar(255) DEFAULT NULL,
size int(10) UNSIGNED DEFAULT NULL,
uploaded_by int(10) UNSIGNED DEFAULT NULL,
created_at timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (id),
KEY idx_employee_training_attachments_training (training_id),
KEY idx_employee_training_attachments_uploaded_by (uploaded_by),
CONSTRAINT fk_employee_training_attachments_training
FOREIGN KEY (training_id) REFERENCES employee_trainings (id)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_employee_training_attachments_uploaded_by
FOREIGN KEY (uploaded_by) REFERENCES auth_users (id)
ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS employee_training_log (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
employee_id int(10) UNSIGNED DEFAULT NULL,
training_id int(10) UNSIGNED DEFAULT NULL,
action varchar(255) NOT NULL,
field varchar(255) DEFAULT NULL,
old_value text DEFAULT NULL,
new_value text DEFAULT NULL,
changed_by int(10) UNSIGNED DEFAULT NULL,
changed_at timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (id),
KEY idx_employee_training_log_employee (employee_id),
KEY idx_employee_training_log_training (training_id),
KEY idx_employee_training_log_changed_at (changed_at),
CONSTRAINT fk_employee_training_log_employee
FOREIGN KEY (employee_id) REFERENCES employees (id)
ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT fk_employee_training_log_training
FOREIGN KEY (training_id) REFERENCES employee_trainings (id)
ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT fk_employee_training_log_changed_by
FOREIGN KEY (changed_by) REFERENCES auth_users (id)
ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO auth_roles (name, display_name, description, removable, created_at, updated_at) VALUES
('employee', 'Employee', 'Read-only access to own employee profile.', 1, NOW(), NOW()),
('employee-hr', 'HR Manager', 'Can manage employee profiles, documents, PPE and training records.', 1, NOW(), NOW()),
('manager', 'Manager', 'Same permissions as HR Manager.', 1, NOW(), NOW())
ON DUPLICATE KEY UPDATE
display_name = VALUES(display_name),
description = VALUES(description),
updated_at = NOW();
CREATE TABLE IF NOT EXISTS training_reminder_log (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
training_id int(10) UNSIGNED DEFAULT NULL,
employee_id int(10) UNSIGNED DEFAULT NULL,
training_topic_id int(10) UNSIGNED DEFAULT NULL,
addressee_email varchar(255) NOT NULL,
next_due_date date DEFAULT NULL,
status_at_send varchar(255) NOT NULL,
sent_at timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (id),
KEY idx_training_reminder_log_dedup (training_id, addressee_email, next_due_date),
KEY idx_training_reminder_log_dedup_missing (employee_id, training_topic_id, addressee_email),
KEY idx_training_reminder_log_sent_at (sent_at),
CONSTRAINT fk_training_reminder_log_training
FOREIGN KEY (training_id) REFERENCES employee_trainings (id)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_training_reminder_log_employee
FOREIGN KEY (employee_id) REFERENCES employees (id)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_training_reminder_log_topic
FOREIGN KEY (training_topic_id) REFERENCES training_topics (id)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```
# 2. Upload storage folder
Create the storage directory with the correct permissions for the web server:
```bash
mkdir -p /var/www/zibo-dashboard/public/userarea/files/employees
chown -R www-data:www-data /var/www/zibo-dashboard/public/userarea/files
chmod -R 775 /var/www/zibo-dashboard/public/userarea/files
```
Uploaded files will be organized as:
```
files/employees/{employee_id}/documents/ # File Repository (HR)
files/employees/{employee_id}/trainings/ # Training certificates
```
# 3. Cron for automated emails
```cron
0 7 * * * /usr/bin/php /var/www/zibo-dashboard/public/userarea/cron/send_training_reminders.php \
>> /var/www/zibo-dashboard/storage/logs/training_reminders.log 2>&1
```