Commit 63bd524e authored by Administrator's avatar Administrator

Update 2 files via Son of Anton

parent 47f482ca
Pipeline #16 canceled with stage
-- ============================================================================
-- AL-ARCADE HR PLATFORM v3.0 — "THE GRIND"
-- COMPLETE DATABASE SCHEMA
-- MySQL 8.0+ · InnoDB · utf8mb4_unicode_ci
-- ============================================================================
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
SET SQL_MODE = 'STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
CREATE DATABASE IF NOT EXISTS `al_arcade_hr`
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE `al_arcade_hr`;
-- TABLE 1: file_uploads
CREATE TABLE IF NOT EXISTS `file_uploads` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`original_name` VARCHAR(255) NOT NULL,
`stored_name` VARCHAR(255) NOT NULL,
`mime_type` VARCHAR(100) NOT NULL,
`size_bytes` BIGINT UNSIGNED NOT NULL,
`storage_path` VARCHAR(500) NOT NULL,
`uploaded_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 2: system_settings
CREATE TABLE IF NOT EXISTS `system_settings` (
`key` VARCHAR(100) NOT NULL,
`value` TEXT NOT NULL,
`value_type` ENUM('string','integer','decimal','boolean','json') NOT NULL,
`group` VARCHAR(50) NOT NULL,
`updated_by_id` BIGINT UNSIGNED NULL,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`key`),
INDEX `idx_system_settings_group` (`group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 3: users
CREATE TABLE IF NOT EXISTS `users` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(30) NOT NULL,
`password_hash` VARCHAR(255) NOT NULL,
`role` ENUM('super_admin','admin','project_leader','contractor') NOT NULL,
`full_name_en` VARCHAR(200) NOT NULL,
`full_name_ar` VARCHAR(200) NOT NULL,
`national_id` VARCHAR(14) NOT NULL,
`date_of_birth` DATE NOT NULL,
`phone_primary` VARCHAR(15) NOT NULL,
`phone_secondary` VARCHAR(15) NULL DEFAULT NULL,
`address` TEXT NOT NULL,
`profile_photo_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`emergency_contact_name` VARCHAR(200) NOT NULL,
`emergency_contact_phone` VARCHAR(15) NOT NULL,
`emergency_contact_relationship` ENUM('parent','sibling','spouse','friend','other') NOT NULL,
`bank_name` VARCHAR(100) NOT NULL,
`bank_account_number` VARCHAR(50) NOT NULL,
`bank_account_holder` VARCHAR(200) NOT NULL,
`tax_registration_number` VARCHAR(50) NULL DEFAULT NULL,
`contractor_type` ENUM('full_timer','intern') NULL DEFAULT NULL,
`status` ENUM('onboarding','active','on_pip','suspended','terminated') NOT NULL DEFAULT 'onboarding',
`activation_date` DATE NULL DEFAULT NULL,
`assigned_pl_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`base_salary` DECIMAL(12,2) NULL DEFAULT NULL,
`actual_salary` DECIMAL(12,2) NULL DEFAULT NULL,
`actual_salary_set_at` DATETIME NULL DEFAULT NULL,
`contract_start_date` DATE NULL DEFAULT NULL,
`contract_end_date` DATE NULL DEFAULT NULL,
`force_password_change` TINYINT(1) NOT NULL DEFAULT 0,
`temp_password_hash` VARCHAR(255) NULL DEFAULT NULL,
`temp_password_expires_at` DATETIME NULL DEFAULT NULL,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`last_login_at` DATETIME NULL DEFAULT NULL,
`theme_preference` ENUM('light','dark','system') NOT NULL DEFAULT 'system',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_users_username` (`username`),
UNIQUE INDEX `idx_users_national_id` (`national_id`),
UNIQUE INDEX `idx_users_phone_primary` (`phone_primary`),
INDEX `idx_users_role` (`role`),
INDEX `idx_users_status` (`status`),
INDEX `idx_users_contractor_type` (`contractor_type`),
INDEX `idx_users_assigned_pl` (`assigned_pl_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Backfill FKs
ALTER TABLE `file_uploads`
ADD CONSTRAINT `fk_file_uploads_uploaded_by` FOREIGN KEY (`uploaded_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE `system_settings`
ADD CONSTRAINT `fk_system_settings_updated_by` FOREIGN KEY (`updated_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE `users`
ADD CONSTRAINT `fk_users_profile_photo` FOREIGN KEY (`profile_photo_id`) REFERENCES `file_uploads` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT `fk_users_assigned_pl` FOREIGN KEY (`assigned_pl_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- TABLE 4: sessions
CREATE TABLE IF NOT EXISTS `sessions` (
`id` VARCHAR(128) NOT NULL,
`user_id` BIGINT UNSIGNED NOT NULL,
`ip_address` VARCHAR(45) NOT NULL,
`user_agent` TEXT NOT NULL,
`payload` TEXT NULL DEFAULT NULL,
`last_activity_at` DATETIME NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_sessions_user` (`user_id`),
INDEX `idx_sessions_last_activity` (`last_activity_at`),
CONSTRAINT `fk_sessions_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 5: login_attempts
CREATE TABLE IF NOT EXISTS `login_attempts` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(30) NOT NULL,
`ip_address` VARCHAR(45) NOT NULL,
`user_agent` TEXT NULL DEFAULT NULL,
`success` TINYINT(1) NOT NULL,
`failure_reason` VARCHAR(100) NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_login_attempts_username` (`username`, `created_at`),
INDEX `idx_login_attempts_ip` (`ip_address`, `created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 6: api_keys
CREATE TABLE IF NOT EXISTS `api_keys` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`key_hash` VARCHAR(255) NOT NULL,
`key_prefix` VARCHAR(8) NOT NULL,
`scope` ENUM('read_only','read_write','admin') NOT NULL,
`rate_limit_per_hour` INT UNSIGNED NOT NULL DEFAULT 1000,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`last_used_at` DATETIME NULL DEFAULT NULL,
`revoked_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_api_keys_hash` (`key_hash`),
CONSTRAINT `fk_api_keys_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 7: invites
CREATE TABLE IF NOT EXISTS `invites` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`code` VARCHAR(8) NOT NULL,
`token` VARCHAR(128) NOT NULL,
`contractor_type` ENUM('full_timer','intern') NOT NULL,
`assigned_pl_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`custom_welcome_note` TEXT NULL DEFAULT NULL,
`status` ENUM('active','used','expired','revoked') NOT NULL DEFAULT 'active',
`expires_at` DATETIME NOT NULL,
`used_at` DATETIME NULL DEFAULT NULL,
`used_by_user_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_invites_code` (`code`),
UNIQUE INDEX `idx_invites_token` (`token`),
INDEX `idx_invites_status` (`status`),
CONSTRAINT `fk_invites_assigned_pl` FOREIGN KEY (`assigned_pl_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_invites_used_by` FOREIGN KEY (`used_by_user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_invites_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 8: user_schedule_days
CREATE TABLE IF NOT EXISTS `user_schedule_days` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`day_of_week` TINYINT UNSIGNED NOT NULL,
`work_mode` ENUM('in_office','remote','off') NOT NULL,
`effective_from` DATE NOT NULL,
`effective_to` DATE NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `idx_schedule_user_effective` (`user_id`, `effective_from`, `effective_to`),
CONSTRAINT `fk_schedule_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 9: salary_history
CREATE TABLE IF NOT EXISTS `salary_history` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`old_actual_salary` DECIMAL(12,2) NULL DEFAULT NULL,
`new_actual_salary` DECIMAL(12,2) NOT NULL,
`old_base_salary` DECIMAL(12,2) NULL DEFAULT NULL,
`new_base_salary` DECIMAL(12,2) NULL DEFAULT NULL,
`reason` TEXT NULL DEFAULT NULL,
`changed_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_salary_history_user` (`user_id`, `created_at`),
CONSTRAINT `fk_salary_history_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_salary_history_changed_by` FOREIGN KEY (`changed_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 10: schedule_change_requests
CREATE TABLE IF NOT EXISTS `schedule_change_requests` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`proposed_schedule_json` JSON NOT NULL,
`current_schedule_json` JSON NOT NULL,
`current_base_salary` DECIMAL(12,2) NOT NULL,
`proposed_base_salary` DECIMAL(12,2) NOT NULL,
`effective_date` DATE NOT NULL,
`reason` TEXT NOT NULL,
`status` ENUM('pending','approved','rejected') NOT NULL DEFAULT 'pending',
`reviewed_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`review_reason` TEXT NULL DEFAULT NULL,
`reviewed_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_schedule_change_user` (`user_id`),
INDEX `idx_schedule_change_status` (`status`),
CONSTRAINT `fk_schedule_change_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_schedule_change_reviewed_by` FOREIGN KEY (`reviewed_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 11: contractor_private_notes
CREATE TABLE IF NOT EXISTS `contractor_private_notes` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`author_id` BIGINT UNSIGNED NOT NULL,
`content` TEXT NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_private_notes_contractor` (`contractor_id`),
CONSTRAINT `fk_private_notes_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_private_notes_author` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 12: contractor_status_history
CREATE TABLE IF NOT EXISTS `contractor_status_history` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`from_status` VARCHAR(20) NULL DEFAULT NULL,
`to_status` VARCHAR(20) NOT NULL,
`reason` TEXT NULL DEFAULT NULL,
`changed_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_status_history_user` (`user_id`, `created_at`),
CONSTRAINT `fk_status_history_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_status_history_changed_by` FOREIGN KEY (`changed_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 13: boards
CREATE TABLE IF NOT EXISTS `boards` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200) NOT NULL,
`description` TEXT NULL DEFAULT NULL,
`board_key` VARCHAR(10) NOT NULL,
`allow_contractor_card_creation` TINYINT(1) NOT NULL DEFAULT 1,
`auto_archive_done_days` INT UNSIGNED NOT NULL DEFAULT 30,
`deadline_excludes_holidays` TINYINT(1) NOT NULL DEFAULT 0,
`card_sequence` INT UNSIGNED NOT NULL DEFAULT 0,
`is_archived` TINYINT(1) NOT NULL DEFAULT 0,
`archived_at` DATETIME NULL DEFAULT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_boards_key` (`board_key`),
INDEX `idx_boards_archived` (`is_archived`),
CONSTRAINT `fk_boards_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 14: board_members
CREATE TABLE IF NOT EXISTS `board_members` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`board_id` BIGINT UNSIGNED NOT NULL,
`user_id` BIGINT UNSIGNED NOT NULL,
`role_on_board` ENUM('project_leader','member') NOT NULL DEFAULT 'member',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_board_members_unique` (`board_id`, `user_id`),
CONSTRAINT `fk_board_members_board` FOREIGN KEY (`board_id`) REFERENCES `boards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_board_members_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 15: board_columns
CREATE TABLE IF NOT EXISTS `board_columns` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`board_id` BIGINT UNSIGNED NOT NULL,
`name` VARCHAR(50) NOT NULL,
`slug` VARCHAR(50) NOT NULL,
`icon` VARCHAR(10) NULL DEFAULT NULL,
`position` INT UNSIGNED NOT NULL,
`is_system` TINYINT(1) NOT NULL DEFAULT 0,
`wip_limit_per_user` INT UNSIGNED NULL DEFAULT NULL,
`wip_limit_total` INT UNSIGNED NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_board_columns_board_pos` (`board_id`, `position`),
CONSTRAINT `fk_board_columns_board` FOREIGN KEY (`board_id`) REFERENCES `boards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 16: labels
CREATE TABLE IF NOT EXISTS `labels` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`text` VARCHAR(20) NOT NULL,
`bg_color` VARCHAR(7) NOT NULL,
`text_color` VARCHAR(7) NOT NULL,
`scope` ENUM('organization','board') NOT NULL,
`board_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_labels_scope_board` (`scope`, `board_id`),
CONSTRAINT `fk_labels_board` FOREIGN KEY (`board_id`) REFERENCES `boards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_labels_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 17: cards
CREATE TABLE IF NOT EXISTS `cards` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`board_id` BIGINT UNSIGNED NOT NULL,
`column_id` BIGINT UNSIGNED NOT NULL,
`card_number` INT UNSIGNED NOT NULL,
`card_key` VARCHAR(20) NOT NULL,
`title` VARCHAR(200) NOT NULL,
`description` TEXT NULL DEFAULT NULL,
`priority` ENUM('critical','high','medium','low','none') NOT NULL DEFAULT 'none',
`estimated_hours` DECIMAL(5,2) NULL DEFAULT NULL,
`bounty_amount` DECIMAL(12,2) NULL DEFAULT NULL,
`bounty_split_json` JSON NULL,
`deadline` DATETIME NULL DEFAULT NULL,
`frozen_reason` TEXT NULL DEFAULT NULL,
`cover_image_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`position_in_column` INT UNSIGNED NOT NULL DEFAULT 0,
`first_doing_at` DATETIME NULL DEFAULT NULL,
`done_at` DATETIME NULL DEFAULT NULL,
`total_frozen_seconds` INT UNSIGNED NOT NULL DEFAULT 0,
`frozen_started_at` DATETIME NULL DEFAULT NULL,
`is_archived` TINYINT(1) NOT NULL DEFAULT 0,
`archived_at` DATETIME NULL DEFAULT NULL,
`version` INT UNSIGNED NOT NULL DEFAULT 1,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_cards_key` (`card_key`),
INDEX `idx_cards_board_column` (`board_id`, `column_id`, `position_in_column`),
INDEX `idx_cards_deadline` (`deadline`),
INDEX `idx_cards_archived` (`is_archived`),
FULLTEXT INDEX `idx_cards_search` (`title`, `description`),
CONSTRAINT `fk_cards_board` FOREIGN KEY (`board_id`) REFERENCES `boards` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_cards_column` FOREIGN KEY (`column_id`) REFERENCES `board_columns` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_cards_cover_image` FOREIGN KEY (`cover_image_id`) REFERENCES `file_uploads` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_cards_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 18: card_assignments
CREATE TABLE IF NOT EXISTS `card_assignments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`card_id` BIGINT UNSIGNED NOT NULL,
`user_id` BIGINT UNSIGNED NOT NULL,
`assigned_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_card_assign_unique` (`card_id`, `user_id`),
INDEX `idx_card_assign_user` (`user_id`),
CONSTRAINT `fk_card_assign_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_assign_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_assign_by` FOREIGN KEY (`assigned_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 19: card_watchers
CREATE TABLE IF NOT EXISTS `card_watchers` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`card_id` BIGINT UNSIGNED NOT NULL,
`user_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_card_watcher_unique` (`card_id`, `user_id`),
CONSTRAINT `fk_card_watcher_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_watcher_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 20: card_labels
CREATE TABLE IF NOT EXISTS `card_labels` (
`card_id` BIGINT UNSIGNED NOT NULL,
`label_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`card_id`, `label_id`),
CONSTRAINT `fk_card_labels_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_labels_label` FOREIGN KEY (`label_id`) REFERENCES `labels` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 21: card_checklists
CREATE TABLE IF NOT EXISTS `card_checklists` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`card_id` BIGINT UNSIGNED NOT NULL,
`name` VARCHAR(100) NOT NULL,
`position` INT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_card_checklists_card` (`card_id`, `position`),
CONSTRAINT `fk_card_checklists_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 22: card_checklist_items
CREATE TABLE IF NOT EXISTS `card_checklist_items` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`checklist_id` BIGINT UNSIGNED NOT NULL,
`text` VARCHAR(500) NOT NULL,
`is_checked` TINYINT(1) NOT NULL DEFAULT 0,
`checked_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`checked_at` DATETIME NULL DEFAULT NULL,
`position` INT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_checklist_items_checklist` (`checklist_id`, `position`),
CONSTRAINT `fk_checklist_items_checklist` FOREIGN KEY (`checklist_id`) REFERENCES `card_checklists` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_checklist_items_checked` FOREIGN KEY (`checked_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 23: card_dependencies
CREATE TABLE IF NOT EXISTS `card_dependencies` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`card_id` BIGINT UNSIGNED NOT NULL,
`depends_on_card_id` BIGINT UNSIGNED NOT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_card_dep_unique` (`card_id`, `depends_on_card_id`),
CONSTRAINT `fk_card_dep_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_dep_depends_on` FOREIGN KEY (`depends_on_card_id`) REFERENCES `cards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_dep_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 24: card_comments
CREATE TABLE IF NOT EXISTS `card_comments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`card_id` BIGINT UNSIGNED NOT NULL,
`author_id` BIGINT UNSIGNED NOT NULL,
`content` TEXT NOT NULL,
`original_content` TEXT NULL DEFAULT NULL,
`edited_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_card_comments_card` (`card_id`, `created_at`),
CONSTRAINT `fk_card_comments_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_comments_author` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 25: card_activity_log
CREATE TABLE IF NOT EXISTS `card_activity_log` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`card_id` BIGINT UNSIGNED NOT NULL,
`user_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`action` VARCHAR(50) NOT NULL,
`details_json` JSON NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_card_activity_card` (`card_id`, `created_at`),
CONSTRAINT `fk_card_activity_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_activity_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 26: card_attachments
CREATE TABLE IF NOT EXISTS `card_attachments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`card_id` BIGINT UNSIGNED NOT NULL,
`file_id` BIGINT UNSIGNED NOT NULL,
`uploaded_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_card_attachments_card` (`card_id`),
CONSTRAINT `fk_card_attach_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_attach_file` FOREIGN KEY (`file_id`) REFERENCES `file_uploads` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_card_attach_user` FOREIGN KEY (`uploaded_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 27: daily_reports
CREATE TABLE IF NOT EXISTS `daily_reports` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`report_date` DATE NOT NULL,
`status` ENUM('draft','submitted','late','approved','approved_auto','flagged_vague','flagged_inconsistent','revision_requested','amended','unreported') NOT NULL DEFAULT 'draft',
`blockers` TEXT NULL DEFAULT NULL,
`additional_notes` TEXT NULL DEFAULT NULL,
`mood` ENUM('frustrated','neutral','good','on_fire') NULL DEFAULT NULL,
`total_hours` DECIMAL(5,2) NULL DEFAULT NULL,
`submitted_at` DATETIME NULL DEFAULT NULL,
`reviewed_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`reviewed_at` DATETIME NULL DEFAULT NULL,
`review_note` TEXT NULL DEFAULT NULL,
`is_on_time` TINYINT(1) NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_reports_user_date` (`user_id`, `report_date`),
INDEX `idx_reports_status` (`status`),
INDEX `idx_reports_date` (`report_date`),
CONSTRAINT `fk_reports_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_reports_reviewed_by` FOREIGN KEY (`reviewed_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 28: report_task_entries
CREATE TABLE IF NOT EXISTS `report_task_entries` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`report_id` BIGINT UNSIGNED NOT NULL,
`card_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`work_description` TEXT NOT NULL,
`time_spent_minutes` INT UNSIGNED NOT NULL,
`task_status` ENUM('in_progress','completed','blocked') NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_report_tasks_report` (`report_id`),
CONSTRAINT `fk_report_tasks_report` FOREIGN KEY (`report_id`) REFERENCES `daily_reports` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_report_tasks_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 29: report_amendments
CREATE TABLE IF NOT EXISTS `report_amendments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`original_report_id` BIGINT UNSIGNED NOT NULL,
`reason` TEXT NOT NULL,
`amended_content_json` JSON NOT NULL,
`status` ENUM('pending','approved','rejected') NOT NULL DEFAULT 'pending',
`reviewed_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`review_note` TEXT NULL DEFAULT NULL,
`reviewed_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_report_amendments_report` (`original_report_id`),
CONSTRAINT `fk_amendments_report` FOREIGN KEY (`original_report_id`) REFERENCES `daily_reports` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_amendments_reviewed_by` FOREIGN KEY (`reviewed_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 30: deductions
CREATE TABLE IF NOT EXISTS `deductions` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`initiated_by_id` BIGINT UNSIGNED NOT NULL,
`category` ENUM('A','B','C','D') NOT NULL,
`sub_category` VARCHAR(5) NOT NULL,
`related_card_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`related_report_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`violation_date` DATE NOT NULL,
`description` TEXT NOT NULL,
`calculated_amount` DECIMAL(12,2) NOT NULL,
`final_amount` DECIMAL(12,2) NULL DEFAULT NULL,
`status` ENUM('draft_pending_admin','pending_acknowledgment','acknowledged','pending_response','accepted','disputed','under_review','applied','applied_no_response','reduced','dismissed') NOT NULL,
`acknowledged_at` DATETIME NULL DEFAULT NULL,
`response_deadline` DATETIME NULL DEFAULT NULL,
`reviewed_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`review_decision` ENUM('upheld','reduced','dismissed') NULL DEFAULT NULL,
`review_note` TEXT NULL DEFAULT NULL,
`reviewed_at` DATETIME NULL DEFAULT NULL,
`applied_at` DATETIME NULL DEFAULT NULL,
`payroll_month` VARCHAR(7) NULL DEFAULT NULL,
`is_auto_triggered` TINYINT(1) NOT NULL DEFAULT 0,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `idx_deductions_contractor` (`contractor_id`, `created_at`),
INDEX `idx_deductions_status` (`status`),
INDEX `idx_deductions_payroll_month` (`payroll_month`),
INDEX `idx_deductions_category` (`category`, `sub_category`),
CONSTRAINT `fk_deductions_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_deductions_initiated_by` FOREIGN KEY (`initiated_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_deductions_card` FOREIGN KEY (`related_card_id`) REFERENCES `cards` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_deductions_report` FOREIGN KEY (`related_report_id`) REFERENCES `daily_reports` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_deductions_reviewed_by` FOREIGN KEY (`reviewed_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 31: deduction_responses
CREATE TABLE IF NOT EXISTS `deduction_responses` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`deduction_id` BIGINT UNSIGNED NOT NULL,
`response_type` ENUM('accept','dispute') NOT NULL,
`explanation` TEXT NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_deduction_responses_deduction` (`deduction_id`),
CONSTRAINT `fk_deduction_responses_deduction` FOREIGN KEY (`deduction_id`) REFERENCES `deductions` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 32: deduction_evidence
CREATE TABLE IF NOT EXISTS `deduction_evidence` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`deduction_id` BIGINT UNSIGNED NOT NULL,
`file_id` BIGINT UNSIGNED NOT NULL,
`uploaded_by_id` BIGINT UNSIGNED NOT NULL,
`evidence_type` ENUM('initiator','contractor_dispute') NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_deduction_evidence_deduction` (`deduction_id`),
CONSTRAINT `fk_ded_evidence_deduction` FOREIGN KEY (`deduction_id`) REFERENCES `deductions` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_ded_evidence_file` FOREIGN KEY (`file_id`) REFERENCES `file_uploads` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_ded_evidence_user` FOREIGN KEY (`uploaded_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 33: bounty_payouts
CREATE TABLE IF NOT EXISTS `bounty_payouts` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`card_id` BIGINT UNSIGNED NOT NULL,
`recipient_id` BIGINT UNSIGNED NOT NULL,
`amount` DECIMAL(12,2) NOT NULL,
`total_bounty` DECIMAL(12,2) NOT NULL,
`split_percentage` DECIMAL(5,2) NOT NULL,
`payroll_month` VARCHAR(7) NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_bounty_payouts_recipient` (`recipient_id`, `payroll_month`),
INDEX `idx_bounty_payouts_card` (`card_id`),
CONSTRAINT `fk_bounty_payouts_card` FOREIGN KEY (`card_id`) REFERENCES `cards` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_bounty_payouts_recipient` FOREIGN KEY (`recipient_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 34: manual_adjustments
CREATE TABLE IF NOT EXISTS `manual_adjustments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`type` ENUM('positive','negative') NOT NULL,
`amount` DECIMAL(12,2) NOT NULL,
`category` ENUM('advance','reimbursement','bonus','correction','loan','other') NOT NULL,
`description` TEXT NOT NULL,
`effective_month` VARCHAR(7) NOT NULL,
`status` ENUM('pending_approval','approved','rejected') NOT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`reviewed_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`reviewed_at` DATETIME NULL DEFAULT NULL,
`review_note` TEXT NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `idx_adjustments_contractor` (`contractor_id`, `effective_month`),
INDEX `idx_adjustments_status` (`status`),
CONSTRAINT `fk_adjustments_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_adjustments_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_adjustments_reviewed_by` FOREIGN KEY (`reviewed_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 35: payroll_records
CREATE TABLE IF NOT EXISTS `payroll_records` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`month` VARCHAR(7) NOT NULL,
`actual_salary` DECIMAL(12,2) NOT NULL,
`total_bounties` DECIMAL(12,2) NOT NULL DEFAULT 0.00,
`total_positive_adjustments` DECIMAL(12,2) NOT NULL DEFAULT 0.00,
`total_deductions_a` DECIMAL(12,2) NOT NULL DEFAULT 0.00,
`total_deductions_b` DECIMAL(12,2) NOT NULL DEFAULT 0.00,
`total_deductions_c` DECIMAL(12,2) NOT NULL DEFAULT 0.00,
`total_deductions_d` DECIMAL(12,2) NOT NULL DEFAULT 0.00,
`total_negative_adjustments` DECIMAL(12,2) NOT NULL DEFAULT 0.00,
`net_payable` DECIMAL(12,2) NOT NULL,
`status` ENUM('pending_calculation','calculated','under_review','submitted','approved','rejected','processing','paid') NOT NULL,
`calculated_at` DATETIME NULL DEFAULT NULL,
`reviewed_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`submitted_at` DATETIME NULL DEFAULT NULL,
`approved_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`approved_at` DATETIME NULL DEFAULT NULL,
`rejected_note` TEXT NULL DEFAULT NULL,
`paid_at` DATETIME NULL DEFAULT NULL,
`notes` TEXT NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_payroll_contractor_month` (`contractor_id`, `month`),
INDEX `idx_payroll_status` (`status`),
INDEX `idx_payroll_month` (`month`),
CONSTRAINT `fk_payroll_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_payroll_reviewed_by` FOREIGN KEY (`reviewed_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_payroll_approved_by` FOREIGN KEY (`approved_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 36: evaluation_cycles
CREATE TABLE IF NOT EXISTS `evaluation_cycles` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`month` VARCHAR(7) NOT NULL,
`status` ENUM('open','technical_phase','professional_phase','compiling','completed') NOT NULL,
`opened_at` DATETIME NOT NULL,
`tech_deadline` DATETIME NOT NULL,
`prof_deadline` DATETIME NOT NULL,
`completed_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_eval_cycles_month` (`month`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 37: evaluations
CREATE TABLE IF NOT EXISTS `evaluations` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`cycle_id` BIGINT UNSIGNED NOT NULL,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`type` ENUM('technical','professional') NOT NULL,
`evaluator_id` BIGINT UNSIGNED NOT NULL,
`total_score` DECIMAL(3,2) NULL DEFAULT NULL,
`submitted_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_eval_unique` (`cycle_id`, `contractor_id`, `type`),
CONSTRAINT `fk_evaluations_cycle` FOREIGN KEY (`cycle_id`) REFERENCES `evaluation_cycles` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_evaluations_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_evaluations_evaluator` FOREIGN KEY (`evaluator_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 38: evaluation_criterion_scores
CREATE TABLE IF NOT EXISTS `evaluation_criterion_scores` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`evaluation_id` BIGINT UNSIGNED NOT NULL,
`criterion_key` VARCHAR(50) NOT NULL,
`auto_value` DECIMAL(3,2) NULL DEFAULT NULL,
`manual_value` DECIMAL(3,2) NULL DEFAULT NULL,
`final_value` DECIMAL(3,2) NOT NULL,
`weight` DECIMAL(3,2) NOT NULL,
`justification` TEXT NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_eval_scores_evaluation` (`evaluation_id`),
CONSTRAINT `fk_eval_scores_evaluation` FOREIGN KEY (`evaluation_id`) REFERENCES `evaluations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 39: compiled_evaluations
CREATE TABLE IF NOT EXISTS `compiled_evaluations` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`cycle_id` BIGINT UNSIGNED NOT NULL,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`technical_score` DECIMAL(3,2) NULL DEFAULT NULL,
`professional_score` DECIMAL(3,2) NULL DEFAULT NULL,
`overall_score` DECIMAL(3,2) NOT NULL,
`rating` ENUM('exceptional','strong','adequate','below_expectations','unacceptable') NOT NULL,
`system_metrics_json` JSON NOT NULL,
`acknowledged_at` DATETIME NULL DEFAULT NULL,
`contractor_response` TEXT NULL DEFAULT NULL,
`responded_at` DATETIME NULL DEFAULT NULL,
`compiled_at` DATETIME NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_compiled_eval_unique` (`cycle_id`, `contractor_id`),
CONSTRAINT `fk_compiled_eval_cycle` FOREIGN KEY (`cycle_id`) REFERENCES `evaluation_cycles` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_compiled_eval_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 40: pips
CREATE TABLE IF NOT EXISTS `pips` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`duration_days` INT UNSIGNED NOT NULL,
`start_date` DATE NOT NULL,
`end_date` DATE NOT NULL,
`specific_issues` JSON NOT NULL,
`check_in_frequency` ENUM('weekly','biweekly') NOT NULL,
`check_in_day` TINYINT UNSIGNED NOT NULL,
`success_criteria` TEXT NOT NULL,
`consequence_of_failure` TEXT NOT NULL,
`status` ENUM('created','acknowledged','active','passed','failed') NOT NULL,
`acknowledged_at` DATETIME NULL DEFAULT NULL,
`result_decided_at` DATETIME NULL DEFAULT NULL,
`result_decided_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `idx_pips_contractor` (`contractor_id`),
INDEX `idx_pips_status` (`status`),
CONSTRAINT `fk_pips_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_pips_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_pips_result_decided` FOREIGN KEY (`result_decided_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 41: pip_targets
CREATE TABLE IF NOT EXISTS `pip_targets` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`pip_id` BIGINT UNSIGNED NOT NULL,
`description` TEXT NOT NULL,
`target_metric` TEXT NOT NULL,
`position` INT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_pip_targets_pip` (`pip_id`, `position`),
CONSTRAINT `fk_pip_targets_pip` FOREIGN KEY (`pip_id`) REFERENCES `pips` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 42: pip_checkins
CREATE TABLE IF NOT EXISTS `pip_checkins` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`pip_id` BIGINT UNSIGNED NOT NULL,
`scheduled_date` DATE NOT NULL,
`logged_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`attendees_json` JSON NULL,
`observations` TEXT NULL DEFAULT NULL,
`progress_notes` TEXT NULL DEFAULT NULL,
`logged_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_pip_checkins_pip` (`pip_id`, `scheduled_date`),
CONSTRAINT `fk_pip_checkins_pip` FOREIGN KEY (`pip_id`) REFERENCES `pips` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_pip_checkins_logged` FOREIGN KEY (`logged_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 43: competency_areas
CREATE TABLE IF NOT EXISTS `competency_areas` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200) NOT NULL,
`position` INT UNSIGNED NOT NULL,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 44: competency_assessments
CREATE TABLE IF NOT EXISTS `competency_assessments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`competency_area_id` BIGINT UNSIGNED NOT NULL,
`assessor_type` ENUM('self','project_leader') NOT NULL,
`assessor_id` BIGINT UNSIGNED NOT NULL,
`level` TINYINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_competency_contractor` (`contractor_id`, `competency_area_id`, `assessor_type`),
CONSTRAINT `fk_comp_assess_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_comp_assess_area` FOREIGN KEY (`competency_area_id`) REFERENCES `competency_areas` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_comp_assess_assessor` FOREIGN KEY (`assessor_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 45: learning_goals
CREATE TABLE IF NOT EXISTS `learning_goals` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`competency_area_id` BIGINT UNSIGNED NOT NULL,
`title` VARCHAR(100) NOT NULL,
`description` TEXT NOT NULL,
`assessment_method` ENUM('pl_assessment','live_demonstration','deliverable_review','quiz_test') NOT NULL,
`pass_fail_criteria` TEXT NOT NULL,
`deadline` DATE NOT NULL,
`status` ENUM('active','overdue','passed','failed','extended') NOT NULL DEFAULT 'active',
`is_auto_generated` TINYINT(1) NOT NULL DEFAULT 0,
`extension_count` TINYINT UNSIGNED NOT NULL DEFAULT 0,
`extension_reason` TEXT NULL DEFAULT NULL,
`assessed_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`assessment_notes` TEXT NULL DEFAULT NULL,
`assessed_at` DATETIME NULL DEFAULT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `idx_learning_goals_contractor` (`contractor_id`, `status`),
INDEX `idx_learning_goals_deadline` (`deadline`),
CONSTRAINT `fk_learn_goals_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_learn_goals_area` FOREIGN KEY (`competency_area_id`) REFERENCES `competency_areas` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_learn_goals_assessed` FOREIGN KEY (`assessed_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_learn_goals_created` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 46: conversations
CREATE TABLE IF NOT EXISTS `conversations` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`type` ENUM('dm','group') NOT NULL,
`title` VARCHAR(200) NULL DEFAULT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`last_message_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `fk_conversations_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 47: conversation_participants
CREATE TABLE IF NOT EXISTS `conversation_participants` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`conversation_id` BIGINT UNSIGNED NOT NULL,
`user_id` BIGINT UNSIGNED NOT NULL,
`last_read_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_conv_participant` (`conversation_id`, `user_id`),
INDEX `idx_conv_participant_user` (`user_id`),
CONSTRAINT `fk_conv_part_conversation` FOREIGN KEY (`conversation_id`) REFERENCES `conversations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_conv_part_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 48: messages
CREATE TABLE IF NOT EXISTS `messages` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`conversation_id` BIGINT UNSIGNED NOT NULL,
`sender_id` BIGINT UNSIGNED NOT NULL,
`content` TEXT NOT NULL,
`deleted_at` DATETIME NULL DEFAULT NULL,
`deleted_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_messages_conversation` (`conversation_id`, `created_at`),
CONSTRAINT `fk_messages_conversation` FOREIGN KEY (`conversation_id`) REFERENCES `conversations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_messages_sender` FOREIGN KEY (`sender_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_messages_deleted_by` FOREIGN KEY (`deleted_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 49: message_attachments
CREATE TABLE IF NOT EXISTS `message_attachments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`message_id` BIGINT UNSIGNED NOT NULL,
`file_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_msg_attachments_message` (`message_id`),
CONSTRAINT `fk_msg_attach_message` FOREIGN KEY (`message_id`) REFERENCES `messages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_msg_attach_file` FOREIGN KEY (`file_id`) REFERENCES `file_uploads` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 50: notifications
CREATE TABLE IF NOT EXISTS `notifications` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`tier` ENUM('blocking','important','informational') NOT NULL,
`title` VARCHAR(200) NOT NULL,
`content` TEXT NOT NULL,
`link_url` VARCHAR(500) NULL DEFAULT NULL,
`link_entity_type` VARCHAR(50) NULL DEFAULT NULL,
`link_entity_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`is_read` TINYINT(1) NOT NULL DEFAULT 0,
`read_at` DATETIME NULL DEFAULT NULL,
`is_acknowledged` TINYINT(1) NOT NULL DEFAULT 0,
`acknowledged_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_notif_user_unread` (`user_id`, `is_read`, `created_at`),
INDEX `idx_notif_user_blocking` (`user_id`, `tier`, `is_acknowledged`),
CONSTRAINT `fk_notifications_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 51: meetings
CREATE TABLE IF NOT EXISTS `meetings` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`title` VARCHAR(200) NOT NULL,
`description` TEXT NULL DEFAULT NULL,
`meeting_date` DATE NOT NULL,
`start_time` TIME NOT NULL,
`end_time` TIME NOT NULL,
`location` VARCHAR(500) NULL DEFAULT NULL,
`recurrence` ENUM('none','weekly','biweekly','monthly') NOT NULL DEFAULT 'none',
`related_entity_type` VARCHAR(50) NULL DEFAULT NULL,
`related_entity_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`status` ENUM('scheduled','completed','cancelled') NOT NULL DEFAULT 'scheduled',
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_meetings_date` (`meeting_date`),
INDEX `idx_meetings_status` (`status`),
CONSTRAINT `fk_meetings_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 52: meeting_invitees
CREATE TABLE IF NOT EXISTS `meeting_invitees` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`meeting_id` BIGINT UNSIGNED NOT NULL,
`user_id` BIGINT UNSIGNED NOT NULL,
`attended` TINYINT(1) NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_meeting_invitees_unique` (`meeting_id`, `user_id`),
CONSTRAINT `fk_meeting_invitees_meeting` FOREIGN KEY (`meeting_id`) REFERENCES `meetings` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_meeting_invitees_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 53: meeting_notes
CREATE TABLE IF NOT EXISTS `meeting_notes` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`meeting_id` BIGINT UNSIGNED NOT NULL,
`logged_by_id` BIGINT UNSIGNED NOT NULL,
`summary` TEXT NOT NULL,
`action_items` TEXT NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_meeting_notes_meeting` (`meeting_id`),
CONSTRAINT `fk_meeting_notes_meeting` FOREIGN KEY (`meeting_id`) REFERENCES `meetings` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_meeting_notes_logged` FOREIGN KEY (`logged_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 54: contracts
CREATE TABLE IF NOT EXISTS `contracts` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`contract_text` LONGTEXT NOT NULL,
`contractor_type_at_signing` VARCHAR(20) NOT NULL,
`schedule_at_signing_json` JSON NOT NULL,
`base_salary_at_signing` DECIMAL(12,2) NOT NULL,
`signed_name` VARCHAR(200) NOT NULL,
`signed_at` DATETIME NOT NULL,
`signer_ip` VARCHAR(45) NOT NULL,
`signer_user_agent` TEXT NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_contracts_contractor` (`contractor_id`),
CONSTRAINT `fk_contracts_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 55: contract_clause_acknowledgments
CREATE TABLE IF NOT EXISTS `contract_clause_acknowledgments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contract_id` BIGINT UNSIGNED NOT NULL,
`clause_key` VARCHAR(50) NOT NULL,
`acknowledged_at` DATETIME NOT NULL,
PRIMARY KEY (`id`),
INDEX `idx_clause_ack_contract` (`contract_id`),
CONSTRAINT `fk_clause_ack_contract` FOREIGN KEY (`contract_id`) REFERENCES `contracts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 56: policies
CREATE TABLE IF NOT EXISTS `policies` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200) NOT NULL,
`requires_acknowledgment` TINYINT(1) NOT NULL DEFAULT 1,
`is_archived` TINYINT(1) NOT NULL DEFAULT 0,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 57: policy_versions
CREATE TABLE IF NOT EXISTS `policy_versions` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`policy_id` BIGINT UNSIGNED NOT NULL,
`version_number` INT UNSIGNED NOT NULL,
`content` LONGTEXT NOT NULL,
`published_at` DATETIME NOT NULL,
`published_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_policy_versions_policy` (`policy_id`, `version_number`),
CONSTRAINT `fk_policy_ver_policy` FOREIGN KEY (`policy_id`) REFERENCES `policies` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_policy_ver_published` FOREIGN KEY (`published_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 58: policy_acknowledgments
CREATE TABLE IF NOT EXISTS `policy_acknowledgments` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`policy_version_id` BIGINT UNSIGNED NOT NULL,
`user_id` BIGINT UNSIGNED NOT NULL,
`acknowledged_at` DATETIME NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_policy_ack_unique` (`policy_version_id`, `user_id`),
CONSTRAINT `fk_policy_ack_version` FOREIGN KEY (`policy_version_id`) REFERENCES `policy_versions` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `fk_policy_ack_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 59: notices
CREATE TABLE IF NOT EXISTS `notices` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`title` VARCHAR(200) NOT NULL,
`content` TEXT NOT NULL,
`type` ENUM('general_announcement','official_warning','policy_update','custom') NOT NULL,
`is_blocking` TINYINT(1) NOT NULL,
`target_type` ENUM('all_users','all_contractors','specific_users','by_board','by_role') NOT NULL,
`target_filter_json` JSON NULL,
`priority` ENUM('normal','high') NOT NULL DEFAULT 'normal',
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_notices_type` (`type`),
CONSTRAINT `fk_notices_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 60: notice_recipients
CREATE TABLE IF NOT EXISTS `notice_recipients` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`notice_id` BIGINT UNSIGNED NOT NULL,
`user_id` BIGINT UNSIGNED NOT NULL,
`acknowledged_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_notice_recipients_unique` (`notice_id`, `user_id`),
CONSTRAINT `fk_notice_recip_notice` FOREIGN KEY (`notice_id`) REFERENCES `notices` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_notice_recip_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 61: holidays
CREATE TABLE IF NOT EXISTS `holidays` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200) NOT NULL,
`start_date` DATE NOT NULL,
`end_date` DATE NOT NULL,
`is_recurring` TINYINT(1) NOT NULL DEFAULT 0,
`notes` TEXT NULL DEFAULT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_holidays_dates` (`start_date`, `end_date`),
CONSTRAINT `fk_holidays_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 62: unavailability_records
CREATE TABLE IF NOT EXISTS `unavailability_records` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`start_date` DATE NOT NULL,
`end_date` DATE NOT NULL,
`reason_category` ENUM('personal','medical','religious','emergency','other') NOT NULL,
`notes` TEXT NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_unavailability_user` (`user_id`, `start_date`, `end_date`),
CONSTRAINT `fk_unavailability_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 63: onboarding_checklists
CREATE TABLE IF NOT EXISTS `onboarding_checklists` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`contractor_id` BIGINT UNSIGNED NOT NULL,
`is_complete` TINYINT(1) NOT NULL DEFAULT 0,
`completed_at` DATETIME NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_onboarding_contractor` (`contractor_id`),
CONSTRAINT `fk_onboarding_contractor` FOREIGN KEY (`contractor_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 64: onboarding_checklist_items
CREATE TABLE IF NOT EXISTS `onboarding_checklist_items` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`checklist_id` BIGINT UNSIGNED NOT NULL,
`item_key` VARCHAR(50) NOT NULL,
`is_complete` TINYINT(1) NOT NULL DEFAULT 0,
`completed_by_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`completed_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `idx_onboard_items_checklist` (`checklist_id`),
CONSTRAINT `fk_onboard_items_checklist` FOREIGN KEY (`checklist_id`) REFERENCES `onboarding_checklists` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_onboard_items_completed` FOREIGN KEY (`completed_by_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 65: card_templates
CREATE TABLE IF NOT EXISTS `card_templates` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200) NOT NULL,
`scope` ENUM('organization','board') NOT NULL,
`board_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`title_template` VARCHAR(200) NOT NULL,
`description_template` TEXT NULL DEFAULT NULL,
`priority` ENUM('critical','high','medium','low','none') NULL DEFAULT NULL,
`estimated_hours` DECIMAL(5,2) NULL DEFAULT NULL,
`labels_json` JSON NULL,
`checklists_json` JSON NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_card_templates_scope` (`scope`, `board_id`),
CONSTRAINT `fk_card_templates_board` FOREIGN KEY (`board_id`) REFERENCES `boards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_card_templates_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 66: board_templates
CREATE TABLE IF NOT EXISTS `board_templates` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200) NOT NULL,
`description` TEXT NULL DEFAULT NULL,
`settings_json` JSON NOT NULL,
`columns_json` JSON NOT NULL,
`labels_json` JSON NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `fk_board_templates_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 67: deduction_presets
CREATE TABLE IF NOT EXISTS `deduction_presets` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200) NOT NULL,
`category` ENUM('A','B','C','D') NOT NULL,
`sub_category` VARCHAR(5) NOT NULL,
`default_description` TEXT NOT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `fk_deduction_presets_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 68: recurring_card_definitions
CREATE TABLE IF NOT EXISTS `recurring_card_definitions` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`board_id` BIGINT UNSIGNED NOT NULL,
`card_template_json` JSON NOT NULL,
`frequency` ENUM('daily','weekly','biweekly','monthly','custom') NOT NULL,
`frequency_days` INT UNSIGNED NULL DEFAULT NULL,
`day_of_week` TINYINT UNSIGNED NULL DEFAULT NULL,
`day_of_month` TINYINT UNSIGNED NULL DEFAULT NULL,
`assignees_json` JSON NULL,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`last_created_at` DATETIME NULL DEFAULT NULL,
`next_creation_at` DATETIME NULL DEFAULT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_recurring_cards_board` (`board_id`),
INDEX `idx_recurring_cards_active` (`is_active`, `next_creation_at`),
CONSTRAINT `fk_recurring_cards_board` FOREIGN KEY (`board_id`) REFERENCES `boards` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_recurring_cards_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 69: audit_trail (NO FOREIGN KEYS — IMMUTABLE)
CREATE TABLE IF NOT EXISTS `audit_trail` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`username` VARCHAR(30) NULL DEFAULT NULL,
`user_role` VARCHAR(20) NULL DEFAULT NULL,
`action` VARCHAR(50) NOT NULL,
`entity_type` VARCHAR(50) NOT NULL,
`entity_id` BIGINT UNSIGNED NULL DEFAULT NULL,
`module` VARCHAR(50) NOT NULL,
`endpoint` VARCHAR(200) NULL DEFAULT NULL,
`before_json` JSON NULL,
`after_json` JSON NULL,
`ip_address` VARCHAR(45) NULL DEFAULT NULL,
`user_agent` TEXT NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_audit_user` (`user_id`, `created_at`),
INDEX `idx_audit_entity` (`entity_type`, `entity_id`),
INDEX `idx_audit_action` (`action`, `created_at`),
INDEX `idx_audit_date` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 70: webhooks
CREATE TABLE IF NOT EXISTS `webhooks` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`url` VARCHAR(500) NOT NULL,
`secret` VARCHAR(255) NOT NULL,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`subscribed_events_json` JSON NOT NULL,
`created_by_id` BIGINT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `fk_webhooks_created_by` FOREIGN KEY (`created_by_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 71: webhook_deliveries
CREATE TABLE IF NOT EXISTS `webhook_deliveries` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`webhook_id` BIGINT UNSIGNED NOT NULL,
`event` VARCHAR(50) NOT NULL,
`payload_json` JSON NOT NULL,
`attempt_number` TINYINT UNSIGNED NOT NULL,
`response_code` INT UNSIGNED NULL DEFAULT NULL,
`response_body` TEXT NULL DEFAULT NULL,
`status` ENUM('pending','success','failed') NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_webhook_del_webhook` (`webhook_id`, `created_at`),
INDEX `idx_webhook_del_status` (`status`),
CONSTRAINT `fk_webhook_del_webhook` FOREIGN KEY (`webhook_id`) REFERENCES `webhooks` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 72: background_jobs
CREATE TABLE IF NOT EXISTS `background_jobs` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`job_key` VARCHAR(100) NOT NULL,
`last_run_at` DATETIME NULL DEFAULT NULL,
`next_run_at` DATETIME NULL DEFAULT NULL,
`last_status` ENUM('success','failed','running') NULL DEFAULT NULL,
`last_error` TEXT NULL DEFAULT NULL,
`is_enabled` TINYINT(1) NOT NULL DEFAULT 1,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE INDEX `idx_background_jobs_key` (`job_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- TABLE 73: saved_filters
CREATE TABLE IF NOT EXISTS `saved_filters` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`context` VARCHAR(50) NOT NULL,
`name` VARCHAR(100) NOT NULL,
`filter_json` JSON NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_saved_filters_user` (`user_id`, `context`),
CONSTRAINT `fk_saved_filters_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
SET FOREIGN_KEY_CHECKS = 1;
-- Verification
SELECT
COUNT(*) AS `total_tables`,
CASE WHEN COUNT(*) = 73 THEN '✅ ALL 73 TABLES CREATED' ELSE CONCAT('❌ EXPECTED 73, GOT ', COUNT(*)) END AS `status`
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'al_arcade_hr'
AND TABLE_TYPE = 'BASE TABLE';
\ No newline at end of file
......@@ -2,57 +2,150 @@
set -e
echo "=== AL-ARCADE HR Platform v3.0 — Starting ==="
echo "Timestamp: $(date)"
echo ""
# ─── Read Environment ───
DB_HOST="${DB_HOST:-srv-captain--mysql-db}"
DB_PORT="${DB_PORT:-3306}"
DB_NAME="${DB_NAME:-al_arcade_hr}"
DB_USER="${DB_USER:-root}"
DB_PASS="${DB_PASS:-Alarcade123#}"
DB_NAME="${DB_NAME:-al_arcade_hr}"
# Wait for MySQL
echo "Configuration:"
echo " DB_HOST: ${DB_HOST}"
echo " DB_PORT: ${DB_PORT}"
echo " DB_NAME: ${DB_NAME}"
echo " DB_USER: ${DB_USER}"
echo " DB_PASS: [REDACTED]"
echo ""
# ─── Debug: DNS Resolution ───
echo "Attempting DNS resolution for ${DB_HOST}..."
if getent hosts "${DB_HOST}" > /dev/null 2>&1; then
RESOLVED_IP=$(getent hosts "${DB_HOST}" | awk '{ print $1 }')
echo " ✅ ${DB_HOST} resolves to ${RESOLVED_IP}"
else
echo " ❌ CANNOT RESOLVE ${DB_HOST}"
echo ""
echo " This means either:"
echo " 1. You haven't created a MySQL app named 'mysql-db' on CapRover"
echo " 2. Your MySQL app has a different name (check CapRover dashboard)"
echo " 3. The apps aren't on the same Docker network"
echo ""
echo " To fix on CapRover:"
echo " - Go to Apps → One-Click Apps → MySQL"
echo " - Name it 'mysql-db' (creates hostname 'srv-captain--mysql-db')"
echo " - OR set DB_HOST env var on your app to the correct hostname"
echo ""
echo " Available Docker networks this container can see:"
cat /etc/hosts 2>/dev/null || true
echo ""
echo " Proceeding anyway (MySQL might come up later)..."
fi
echo ""
# ─── Wait for MySQL ───
echo "Waiting for MySQL at ${DB_HOST}:${DB_PORT}..."
MAX_TRIES=30
COUNT=0
while ! mysqladmin ping -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USER" -p"$DB_PASS" --silent 2>/dev/null; do
COUNT=$((COUNT + 1))
if [ $COUNT -ge $MAX_TRIES ]; then
echo "ERROR: MySQL not available after ${MAX_TRIES} attempts. Starting anyway..."
MAX_ATTEMPTS=60
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
ATTEMPT=$((ATTEMPT + 1))
if mysqladmin ping -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" --silent 2>/dev/null; then
echo "✅ MySQL is ready! (attempt ${ATTEMPT}/${MAX_ATTEMPTS})"
break
fi
echo " MySQL not ready... (attempt $COUNT/$MAX_TRIES)"
# Every 10 attempts, try a raw TCP connection test for better debugging
if [ $((ATTEMPT % 10)) -eq 0 ]; then
echo " MySQL not ready... (attempt ${ATTEMPT}/${MAX_ATTEMPTS})"
echo " TCP test: $(timeout 2 bash -c "echo > /dev/tcp/${DB_HOST}/${DB_PORT}" 2>&1 && echo 'port open' || echo 'port closed/unreachable')"
else
echo " MySQL not ready... (attempt ${ATTEMPT}/${MAX_ATTEMPTS})"
fi
sleep 2
done
echo "MySQL is up."
# Create database if it doesn't exist
echo "Ensuring database exists..."
mysql -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USER" -p"$DB_PASS" -e "CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 2>/dev/null || true
if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then
echo ""
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ ❌ FATAL: Could not connect to MySQL after ${MAX_ATTEMPTS} attempts ║"
echo "║ ║"
echo "║ Host: ${DB_HOST}:${DB_PORT} "
echo "║ User: ${DB_USER} "
echo "║ ║"
echo "║ CHECKLIST: ║"
echo "║ 1. Is MySQL running? Check CapRover dashboard. ║"
echo "║ 2. Is the app name correct? Should be 'mysql-db' ║"
echo "║ for hostname 'srv-captain--mysql-db' ║"
echo "║ 3. Are credentials correct? Check env vars. ║"
echo "║ 4. Try: CapRover → App → Edit Default Nginx Config ║"
echo "║ to check networking. ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
echo "Starting Apache anyway (app will show DB errors)..."
exec "$@"
exit 0
fi
# ─── Create Database if not exists ───
echo ""
echo "Ensuring database '${DB_NAME}' exists..."
mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" -e "CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 2>/dev/null
echo "✅ Database ensured."
# ─── Run Schema if tables don't exist ───
TABLE_COUNT=$(mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" -N -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='${DB_NAME}' AND TABLE_TYPE='BASE TABLE';" 2>/dev/null)
echo "Current table count: ${TABLE_COUNT}"
# Check table count
TABLE_COUNT=$(mysql -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USER" -p"$DB_PASS" -N -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = '${DB_NAME}';" 2>/dev/null || echo "0")
if [ "${TABLE_COUNT}" -lt "70" ] 2>/dev/null; then
echo "Running schema migration (expected 73 tables, found ${TABLE_COUNT})..."
if [ "$TABLE_COUNT" -lt "70" ]; then
echo "Database has $TABLE_COUNT tables (need 73). Running schema..."
if [ -f /var/www/html/database/schema.sql ]; then
mysql -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USER" -p"$DB_PASS" < /var/www/html/database/schema.sql 2>&1 && echo "✅ Schema deployed." || echo "⚠️ Schema may already exist."
if [ -f "/var/www/html/database/schema.sql" ]; then
mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" "${DB_NAME}" < /var/www/html/database/schema.sql 2>&1
echo "✅ Schema applied."
else
echo "❌ schema.sql not found!"
echo "⚠️ No schema.sql found at /var/www/html/database/schema.sql"
echo " Skipping schema creation."
fi
# Run seed data
if [ -f "/var/www/html/database/seed.sql" ]; then
echo "Running seed data..."
if [ -f /var/www/html/database/seed.sql ]; then
mysql -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < /var/www/html/database/seed.sql 2>&1 && echo "✅ Seed data applied." || echo "⚠️ Seed data may already exist."
mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" "${DB_NAME}" < /var/www/html/database/seed.sql 2>&1
echo "✅ Seed data applied."
fi
else
echo "✅ Schema already exists (${TABLE_COUNT} tables). Skipping migration."
fi
# ─── Create Super Admin ───
SA_EXISTS=$(mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" -N -e "SELECT COUNT(*) FROM \`${DB_NAME}\`.users WHERE role='super_admin';" 2>/dev/null || echo "0")
echo "Creating super admin..."
php /var/www/html/cli/create-superadmin.php 2>&1 || echo "⚠️ Super admin may already exist."
if [ "${SA_EXISTS}" = "0" ]; then
echo "Creating Super Admin..."
if [ -f "/var/www/html/cli/create-superadmin.php" ]; then
php /var/www/html/cli/create-superadmin.php
fi
else
echo "Database has $TABLE_COUNT tables. Schema OK. Skipping."
echo "✅ Super Admin already exists. Skipping."
fi
# Fix permissions
# ─── Fix Permissions ───
echo "Setting permissions..."
chown -R www-data:www-data /var/www/html/storage 2>/dev/null || true
chmod -R 775 /var/www/html/storage 2>/dev/null || true
echo "=== AL-ARCADE HR v3.0 Ready. Launching Apache ==="
echo ""
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ ✅ AL-ARCADE HR Platform v3.0 — Ready! ║"
echo "║ Starting Apache... ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
# ─── Start Apache ───
exec "$@"
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment