Files
JobcardSystem/database/schema.sql
T

205 lines
8.5 KiB
SQL
Raw Normal View History

2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS roles (
2026-09-01 18:54:47 +02:00
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(80) NOT NULL UNIQUE,
description VARCHAR(255) NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS permissions (
2026-09-01 18:54:47 +02:00
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(120) NOT NULL UNIQUE,
description VARCHAR(255) NULL
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS role_permissions (
2026-09-01 18:54:47 +02:00
role_id BIGINT UNSIGNED NOT NULL,
permission_id BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS users (
2026-09-01 18:54:47 +02:00
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
role_id BIGINT UNSIGNED NOT NULL,
email VARCHAR(190) NOT NULL UNIQUE,
name VARCHAR(120) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
last_login_at TIMESTAMP NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (role_id) REFERENCES roles(id)
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS clients (
2026-09-01 18:54:47 +02:00
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(190) NOT NULL,
registration_number VARCHAR(120) NULL,
status ENUM('active', 'inactive') NOT NULL DEFAULT 'active',
support_email VARCHAR(190) NULL,
support_phone VARCHAR(60) NULL,
preferred_contact_method VARCHAR(40) NULL,
physical_address TEXT NULL,
postal_address TEXT NULL,
general_notes TEXT NULL,
created_by BIGINT UNSIGNED NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX clients_name_idx (name),
INDEX clients_status_idx (status),
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS client_contacts (
2026-09-01 18:54:47 +02:00
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
client_id BIGINT UNSIGNED NOT NULL,
name VARCHAR(120) NOT NULL,
email VARCHAR(190) NULL,
phone VARCHAR(60) NULL,
is_primary BOOLEAN NOT NULL DEFAULT FALSE,
primary_client_id BIGINT UNSIGNED AS (IF(is_primary, client_id, NULL)) STORED,
2026-09-01 18:54:47 +02:00
notes TEXT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE,
INDEX contacts_client_idx (client_id),
UNIQUE KEY one_primary_contact (primary_client_id)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS jobcard_sequences (
sequence_year SMALLINT UNSIGNED PRIMARY KEY,
next_sequence INT UNSIGNED NOT NULL
2026-09-01 18:54:47 +02:00
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS sla_agreements (
2026-09-01 18:54:47 +02:00
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
client_id BIGINT UNSIGNED NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
agreement_type VARCHAR(120) NULL,
allocated_hours DECIMAL(10,2) NOT NULL DEFAULT 0,
period_type ENUM('monthly', 'annual', 'custom') NOT NULL DEFAULT 'monthly',
start_date DATE NULL,
end_date DATE NULL,
rollover_enabled BOOLEAN NOT NULL DEFAULT FALSE,
notes TEXT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE,
UNIQUE KEY sla_client_unique (client_id)
2026-09-01 18:54:47 +02:00
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS jobcards (
2026-09-01 18:54:47 +02:00
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
reference_no VARCHAR(40) NOT NULL UNIQUE,
client_id BIGINT UNSIGNED NOT NULL,
created_by BIGINT UNSIGNED NULL,
priority VARCHAR(40) NOT NULL DEFAULT 'normal',
status VARCHAR(60) NOT NULL DEFAULT 'new',
work_requested TEXT NOT NULL,
technician_notes TEXT NULL,
internal_notes TEXT NULL,
completed_at DATETIME NULL,
closed_at DATETIME NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (client_id) REFERENCES clients(id),
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
INDEX jobcards_client_idx (client_id),
INDEX jobcards_status_idx (status),
INDEX jobcards_created_idx (created_at)
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS jobcard_assignments (
2026-09-01 18:54:47 +02:00
jobcard_id BIGINT UNSIGNED NOT NULL,
user_id BIGINT UNSIGNED NOT NULL,
assigned_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
assigned_by BIGINT UNSIGNED NULL,
PRIMARY KEY (jobcard_id, user_id),
FOREIGN KEY (jobcard_id) REFERENCES jobcards(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (assigned_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS jobcard_status_history (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
jobcard_id BIGINT UNSIGNED NOT NULL,
from_status VARCHAR(60) NOT NULL,
to_status VARCHAR(60) NOT NULL,
changed_by BIGINT UNSIGNED NULL,
changed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (jobcard_id) REFERENCES jobcards(id) ON DELETE CASCADE,
FOREIGN KEY (changed_by) REFERENCES users(id) ON DELETE SET NULL,
INDEX status_history_jobcard_idx (jobcard_id, changed_at)
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS time_entries (
2026-09-01 18:54:47 +02:00
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
jobcard_id BIGINT UNSIGNED NOT NULL,
technician_id BIGINT UNSIGNED NOT NULL,
work_date DATE NOT NULL,
start_time TIME NULL,
end_time TIME NULL,
hours DECIMAL(10,2) NOT NULL,
notes TEXT NULL,
counts_toward_sla BOOLEAN NOT NULL DEFAULT TRUE,
created_by BIGINT UNSIGNED NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (jobcard_id) REFERENCES jobcards(id) ON DELETE CASCADE,
FOREIGN KEY (technician_id) REFERENCES users(id),
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
INDEX time_jobcard_idx (jobcard_id),
INDEX time_date_idx (work_date)
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
CREATE TABLE IF NOT EXISTS audit_events (
2026-09-01 18:54:47 +02:00
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT UNSIGNED NULL,
action VARCHAR(120) NOT NULL,
entity_type VARCHAR(80) NOT NULL,
entity_id BIGINT UNSIGNED NULL,
metadata JSON NULL,
ip_address VARCHAR(45) NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX audit_entity_idx (entity_type, entity_id),
INDEX audit_created_idx (created_at),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB;
2026-09-01 19:26:10 +02:00
INSERT IGNORE INTO roles (name, description) VALUES
2026-09-01 18:54:47 +02:00
('Administrator', 'Full system access'),
('Accounts', 'Client, jobcard and reporting access'),
('Technician', 'Assigned support work access');
2026-09-01 19:26:10 +02:00
INSERT IGNORE INTO permissions (name, description) VALUES
2026-09-01 18:54:47 +02:00
('dashboard.view', 'View the operational dashboard'),
('clients.view', 'View client records'),
('clients.manage', 'Create and edit client records'),
('jobcards.view', 'View jobcards'),
('jobcards.manage', 'Create and update jobcards'),
('jobcards.assign', 'Assign technicians to jobcards'),
('jobcards.internal_notes', 'View and edit internal jobcard notes'),
('time_entries.record', 'Record technician time entries'),
('sla.view', 'View client SLA agreements and usage'),
('sla.manage', 'Configure client SLA agreements'),
2026-09-01 18:54:47 +02:00
('reports.view', 'View reports'),
('reports.export', 'Export reports'),
('users.manage', 'Manage users'),
('roles.manage', 'Manage roles and permissions'),
('audit.view', 'View audit events'),
('credentials.view', 'View protected credentials');
2026-09-01 19:26:10 +02:00
INSERT IGNORE INTO role_permissions (role_id, permission_id)
2026-09-01 18:54:47 +02:00
SELECT r.id, p.id FROM roles r CROSS JOIN permissions p WHERE r.name = 'Administrator';
2026-09-01 19:26:10 +02:00
INSERT IGNORE INTO role_permissions (role_id, permission_id)
2026-09-01 18:54:47 +02:00
SELECT r.id, p.id FROM roles r JOIN permissions p ON p.name IN
('dashboard.view','clients.view','jobcards.view','reports.view','reports.export','sla.view')
2026-09-01 18:54:47 +02:00
WHERE r.name = 'Accounts';
2026-09-01 19:26:10 +02:00
INSERT IGNORE INTO role_permissions (role_id, permission_id)
2026-09-01 18:54:47 +02:00
SELECT r.id, p.id FROM roles r JOIN permissions p ON p.name IN
('dashboard.view','clients.view','jobcards.view','jobcards.manage','time_entries.record')
2026-09-01 18:54:47 +02:00
WHERE r.name = 'Technician';