fix: Add error handling to dependencies + cleanup migrations
- Add detailed error handling in DependencyModel (throw exceptions on failure) - Add try-catch in ticket_dependencies.php to catch query errors - Remove all old migrations (001-014) that have already been run - Keep only new feature migrations (015-018) for reference Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -74,8 +74,12 @@ switch ($method) {
|
||||
ResponseHelper::error('Ticket ID required');
|
||||
}
|
||||
|
||||
try {
|
||||
$dependencies = $dependencyModel->getDependencies($ticketId);
|
||||
$dependents = $dependencyModel->getDependentTickets($ticketId);
|
||||
} catch (Exception $e) {
|
||||
ResponseHelper::serverError('Query error: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
ResponseHelper::success([
|
||||
'dependencies' => $dependencies,
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
-- Create users table for SSO integration
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
user_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(100) UNIQUE NOT NULL,
|
||||
display_name VARCHAR(255),
|
||||
email VARCHAR(255),
|
||||
groups TEXT,
|
||||
is_admin BOOLEAN DEFAULT FALSE,
|
||||
last_login TIMESTAMP NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_username (username)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Insert system user for hwmonDaemon
|
||||
INSERT INTO users (username, display_name, email, groups, is_admin, created_at)
|
||||
VALUES ('system', 'System', 'system@lotusguild.org', '', FALSE, NOW())
|
||||
ON DUPLICATE KEY UPDATE username = username;
|
||||
@@ -1,15 +0,0 @@
|
||||
-- Create API keys table for external service authentication
|
||||
CREATE TABLE IF NOT EXISTS api_keys (
|
||||
api_key_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
key_name VARCHAR(100) NOT NULL,
|
||||
key_hash VARCHAR(255) UNIQUE NOT NULL,
|
||||
key_prefix VARCHAR(20) NOT NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_by INT,
|
||||
last_used TIMESTAMP NULL,
|
||||
expires_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE SET NULL,
|
||||
INDEX idx_key_hash (key_hash),
|
||||
INDEX idx_is_active (is_active)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@@ -1,16 +0,0 @@
|
||||
-- Create audit log table for tracking all user actions
|
||||
CREATE TABLE IF NOT EXISTS audit_log (
|
||||
audit_id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT,
|
||||
action_type VARCHAR(50) NOT NULL,
|
||||
entity_type VARCHAR(50) NOT NULL,
|
||||
entity_id VARCHAR(50),
|
||||
details JSON,
|
||||
ip_address VARCHAR(45),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE SET NULL,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_created_at (created_at),
|
||||
INDEX idx_entity (entity_type, entity_id),
|
||||
INDEX idx_action_type (action_type)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@@ -1,30 +0,0 @@
|
||||
-- Add user tracking columns to tickets table
|
||||
ALTER TABLE tickets
|
||||
ADD COLUMN IF NOT EXISTS created_by INT,
|
||||
ADD COLUMN IF NOT EXISTS updated_by INT,
|
||||
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP NULL;
|
||||
|
||||
-- Add foreign key constraints if they don't exist
|
||||
SET @fk_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
|
||||
WHERE CONSTRAINT_NAME = 'fk_tickets_created_by'
|
||||
AND TABLE_NAME = 'tickets'
|
||||
AND TABLE_SCHEMA = DATABASE());
|
||||
|
||||
SET @sql = IF(@fk_exists = 0,
|
||||
'ALTER TABLE tickets ADD CONSTRAINT fk_tickets_created_by FOREIGN KEY (created_by) REFERENCES users(user_id) ON DELETE SET NULL',
|
||||
'SELECT "Foreign key fk_tickets_created_by already exists"');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @fk_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
|
||||
WHERE CONSTRAINT_NAME = 'fk_tickets_updated_by'
|
||||
AND TABLE_NAME = 'tickets'
|
||||
AND TABLE_SCHEMA = DATABASE());
|
||||
|
||||
SET @sql = IF(@fk_exists = 0,
|
||||
'ALTER TABLE tickets ADD CONSTRAINT fk_tickets_updated_by FOREIGN KEY (updated_by) REFERENCES users(user_id) ON DELETE SET NULL',
|
||||
'SELECT "Foreign key fk_tickets_updated_by already exists"');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
@@ -1,19 +0,0 @@
|
||||
-- Add user_id column to ticket_comments table
|
||||
ALTER TABLE ticket_comments
|
||||
ADD COLUMN IF NOT EXISTS user_id INT;
|
||||
|
||||
-- Add foreign key constraint if it doesn't exist
|
||||
SET @fk_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
|
||||
WHERE CONSTRAINT_NAME = 'fk_comments_user_id'
|
||||
AND TABLE_NAME = 'ticket_comments'
|
||||
AND TABLE_SCHEMA = DATABASE());
|
||||
|
||||
SET @sql = IF(@fk_exists = 0,
|
||||
'ALTER TABLE ticket_comments ADD CONSTRAINT fk_comments_user_id FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE SET NULL',
|
||||
'SELECT "Foreign key fk_comments_user_id already exists"');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- Update existing comments to reference jared user (first admin)
|
||||
-- This will be done after jared user is created via web login
|
||||
@@ -1,39 +0,0 @@
|
||||
-- Add database indexes for performance optimization
|
||||
-- Check and create index on tickets.status
|
||||
SET @index_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
|
||||
WHERE TABLE_NAME = 'tickets'
|
||||
AND INDEX_NAME = 'idx_status'
|
||||
AND TABLE_SCHEMA = DATABASE());
|
||||
|
||||
SET @sql = IF(@index_exists = 0,
|
||||
'CREATE INDEX idx_status ON tickets(status)',
|
||||
'SELECT "Index idx_status already exists"');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- Check and create index on tickets.priority
|
||||
SET @index_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
|
||||
WHERE TABLE_NAME = 'tickets'
|
||||
AND INDEX_NAME = 'idx_priority'
|
||||
AND TABLE_SCHEMA = DATABASE());
|
||||
|
||||
SET @sql = IF(@index_exists = 0,
|
||||
'CREATE INDEX idx_priority ON tickets(priority)',
|
||||
'SELECT "Index idx_priority already exists"');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- Check and create index on tickets.created_at
|
||||
SET @index_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
|
||||
WHERE TABLE_NAME = 'tickets'
|
||||
AND INDEX_NAME = 'idx_tickets_created_at'
|
||||
AND TABLE_SCHEMA = DATABASE());
|
||||
|
||||
SET @sql = IF(@index_exists = 0,
|
||||
'CREATE INDEX idx_tickets_created_at ON tickets(created_at)',
|
||||
'SELECT "Index idx_tickets_created_at already exists"');
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
@@ -1,13 +0,0 @@
|
||||
-- Migration 007: Add ticket assignment functionality
|
||||
-- Adds assigned_to column to tickets table
|
||||
|
||||
-- Add assigned_to column to tickets table
|
||||
ALTER TABLE tickets
|
||||
ADD COLUMN assigned_to INT NULL,
|
||||
ADD CONSTRAINT fk_tickets_assigned_to
|
||||
FOREIGN KEY (assigned_to)
|
||||
REFERENCES users(user_id)
|
||||
ON DELETE SET NULL;
|
||||
|
||||
-- Add index for performance
|
||||
CREATE INDEX idx_assigned_to ON tickets(assigned_to);
|
||||
@@ -1,31 +0,0 @@
|
||||
-- Migration 008: Add status workflow management
|
||||
-- Creates status_transitions table for workflow validation
|
||||
|
||||
-- Table to define allowed status transitions
|
||||
CREATE TABLE status_transitions (
|
||||
transition_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
from_status VARCHAR(50) NOT NULL,
|
||||
to_status VARCHAR(50) NOT NULL,
|
||||
requires_comment BOOLEAN DEFAULT FALSE,
|
||||
requires_admin BOOLEAN DEFAULT FALSE,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY unique_transition (from_status, to_status),
|
||||
INDEX idx_from_status (from_status)
|
||||
);
|
||||
|
||||
-- Insert default transitions
|
||||
INSERT INTO status_transitions (from_status, to_status, requires_comment) VALUES
|
||||
('Open', 'In Progress', FALSE),
|
||||
('Open', 'Closed', TRUE),
|
||||
('In Progress', 'Open', FALSE),
|
||||
('In Progress', 'Closed', TRUE),
|
||||
('Closed', 'Open', TRUE),
|
||||
('Closed', 'In Progress', FALSE);
|
||||
|
||||
-- Add new status "Resolved"
|
||||
INSERT INTO status_transitions (from_status, to_status, requires_comment) VALUES
|
||||
('In Progress', 'Resolved', FALSE),
|
||||
('Resolved', 'Closed', FALSE),
|
||||
('Resolved', 'In Progress', TRUE),
|
||||
('Open', 'Resolved', FALSE);
|
||||
@@ -1,24 +0,0 @@
|
||||
-- Migration 009: Add ticket templates
|
||||
-- Creates ticket_templates table for reusable ticket templates
|
||||
|
||||
CREATE TABLE ticket_templates (
|
||||
template_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
template_name VARCHAR(100) NOT NULL,
|
||||
title_template VARCHAR(255) NOT NULL,
|
||||
description_template TEXT NOT NULL,
|
||||
category VARCHAR(50),
|
||||
type VARCHAR(50),
|
||||
default_priority INT DEFAULT 4,
|
||||
created_by INT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (created_by) REFERENCES users(user_id),
|
||||
INDEX idx_template_name (template_name)
|
||||
);
|
||||
|
||||
-- Insert default templates
|
||||
INSERT INTO ticket_templates (template_name, title_template, description_template, category, type, default_priority) VALUES
|
||||
('Hardware Failure', 'Hardware Failure: [Device Name]', 'Device: \nIssue: \nError Messages: \nTroubleshooting Done: ', 'Hardware', 'Problem', 2),
|
||||
('Software Installation', 'Install [Software Name]', 'Software: \nVersion: \nLicense Key: \nInstallation Path: ', 'Software', 'Install', 3),
|
||||
('Network Issue', 'Network Issue: [Brief Description]', 'Affected System: \nSymptoms: \nIP Address: \nConnectivity Tests: ', 'Hardware', 'Problem', 2),
|
||||
('Maintenance Request', 'Scheduled Maintenance: [System Name]', 'System: \nMaintenance Type: \nScheduled Date: \nDowntime Expected: ', 'Hardware', 'Maintenance', 4);
|
||||
@@ -1,43 +0,0 @@
|
||||
-- Migration 009: Simplify status workflow
|
||||
-- Removes "Resolved" status and adds "Pending" status
|
||||
-- Keeps only: Open, Pending, In Progress, Closed
|
||||
|
||||
-- First, update any existing tickets with "Resolved" status to "Closed"
|
||||
UPDATE tickets SET status = 'Closed' WHERE status = 'Resolved';
|
||||
|
||||
-- Delete all existing transitions with "Resolved"
|
||||
DELETE FROM status_transitions WHERE from_status = 'Resolved' OR to_status = 'Resolved';
|
||||
|
||||
-- Clear all existing transitions to rebuild clean workflow
|
||||
DELETE FROM status_transitions;
|
||||
|
||||
-- Define new simplified workflow with Pending status
|
||||
-- OPEN transitions
|
||||
INSERT INTO status_transitions (from_status, to_status, requires_comment, requires_admin) VALUES
|
||||
('Open', 'Pending', FALSE, FALSE), -- Waiting on external dependency
|
||||
('Open', 'In Progress', FALSE, FALSE), -- Start work
|
||||
('Open', 'Closed', TRUE, FALSE); -- Close without work (duplicate, won't fix, etc.)
|
||||
|
||||
-- PENDING transitions
|
||||
INSERT INTO status_transitions (from_status, to_status, requires_comment, requires_admin) VALUES
|
||||
('Pending', 'Open', FALSE, FALSE), -- Unblock and reopen
|
||||
('Pending', 'In Progress', FALSE, FALSE), -- Start work while pending
|
||||
('Pending', 'Closed', TRUE, FALSE); -- Close while pending
|
||||
|
||||
-- IN PROGRESS transitions
|
||||
INSERT INTO status_transitions (from_status, to_status, requires_comment, requires_admin) VALUES
|
||||
('In Progress', 'Open', FALSE, FALSE), -- Stop work, back to queue
|
||||
('In Progress', 'Pending', FALSE, FALSE), -- Blocked by external dependency
|
||||
('In Progress', 'Closed', TRUE, FALSE); -- Complete and close
|
||||
|
||||
-- CLOSED transitions
|
||||
INSERT INTO status_transitions (from_status, to_status, requires_comment, requires_admin) VALUES
|
||||
('Closed', 'Open', TRUE, FALSE), -- Reopen (requires explanation)
|
||||
('Closed', 'In Progress', FALSE, FALSE); -- Reopen and start work immediately
|
||||
|
||||
-- Verify new transitions
|
||||
SELECT 'New Status Transitions:' as info;
|
||||
SELECT from_status, to_status, requires_comment, requires_admin
|
||||
FROM status_transitions
|
||||
WHERE is_active = TRUE
|
||||
ORDER BY from_status, to_status;
|
||||
@@ -1,19 +0,0 @@
|
||||
-- Migration 010: Add bulk operations tracking
|
||||
-- Creates bulk_operations table for admin bulk actions
|
||||
|
||||
CREATE TABLE bulk_operations (
|
||||
operation_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
operation_type VARCHAR(50) NOT NULL,
|
||||
ticket_ids TEXT NOT NULL, -- Comma-separated
|
||||
performed_by INT NOT NULL,
|
||||
parameters JSON,
|
||||
status VARCHAR(20) DEFAULT 'pending',
|
||||
total_tickets INT,
|
||||
processed_tickets INT DEFAULT 0,
|
||||
failed_tickets INT DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
completed_at TIMESTAMP NULL,
|
||||
FOREIGN KEY (performed_by) REFERENCES users(user_id),
|
||||
INDEX idx_performed_by (performed_by),
|
||||
INDEX idx_created_at (created_at)
|
||||
);
|
||||
@@ -1,18 +0,0 @@
|
||||
-- Migration 010: Expand status column to accommodate longer status names
|
||||
-- The status column was likely VARCHAR(10) which can't fit "In Progress" or "Pending"
|
||||
|
||||
-- Check current column definition
|
||||
SHOW COLUMNS FROM tickets LIKE 'status';
|
||||
|
||||
-- Expand the status column to accommodate longer status names
|
||||
ALTER TABLE tickets
|
||||
MODIFY COLUMN status VARCHAR(20) NOT NULL DEFAULT 'Open';
|
||||
|
||||
-- Verify the change
|
||||
SHOW COLUMNS FROM tickets LIKE 'status';
|
||||
|
||||
-- Show current status distribution
|
||||
SELECT status, COUNT(*) as count
|
||||
FROM tickets
|
||||
GROUP BY status
|
||||
ORDER BY status;
|
||||
@@ -1,48 +0,0 @@
|
||||
-- Migration 011: Create user_preferences table for persistent user settings
|
||||
-- Stores user-specific preferences like rows per page, default filters, etc.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_preferences (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
preference_key VARCHAR(100) NOT NULL,
|
||||
preference_value TEXT,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY unique_user_pref (user_id, preference_key),
|
||||
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Default preferences for existing users
|
||||
INSERT INTO user_preferences (user_id, preference_key, preference_value)
|
||||
SELECT user_id, 'rows_per_page', '15' FROM users
|
||||
WHERE user_id NOT IN (SELECT user_id FROM user_preferences WHERE preference_key = 'rows_per_page');
|
||||
|
||||
INSERT INTO user_preferences (user_id, preference_key, preference_value)
|
||||
SELECT user_id, 'default_status_filters', 'Open,Pending,In Progress' FROM users
|
||||
WHERE user_id NOT IN (SELECT user_id FROM user_preferences WHERE preference_key = 'default_status_filters');
|
||||
|
||||
INSERT INTO user_preferences (user_id, preference_key, preference_value)
|
||||
SELECT user_id, 'table_density', 'normal' FROM users
|
||||
WHERE user_id NOT IN (SELECT user_id FROM user_preferences WHERE preference_key = 'table_density');
|
||||
|
||||
INSERT INTO user_preferences (user_id, preference_key, preference_value)
|
||||
SELECT user_id, 'notifications_enabled', '1' FROM users
|
||||
WHERE user_id NOT IN (SELECT user_id FROM user_preferences WHERE preference_key = 'notifications_enabled');
|
||||
|
||||
INSERT INTO user_preferences (user_id, preference_key, preference_value)
|
||||
SELECT user_id, 'sound_effects', '1' FROM users
|
||||
WHERE user_id NOT IN (SELECT user_id FROM user_preferences WHERE preference_key = 'sound_effects');
|
||||
|
||||
INSERT INTO user_preferences (user_id, preference_key, preference_value)
|
||||
SELECT user_id, 'toast_duration', '3000' FROM users
|
||||
WHERE user_id NOT IN (SELECT user_id FROM user_preferences WHERE preference_key = 'toast_duration');
|
||||
|
||||
-- Verify table created
|
||||
SELECT 'User Preferences Table Created' as info;
|
||||
DESCRIBE user_preferences;
|
||||
|
||||
-- Show count of preferences
|
||||
SELECT 'Default Preferences Inserted' as info;
|
||||
SELECT preference_key, COUNT(*) as user_count
|
||||
FROM user_preferences
|
||||
GROUP BY preference_key
|
||||
ORDER BY preference_key;
|
||||
@@ -1,2 +0,0 @@
|
||||
-- Remove all ticket view tracking records from audit_log
|
||||
DELETE FROM audit_log WHERE action_type = 'view';
|
||||
@@ -1,15 +0,0 @@
|
||||
-- Create saved_filters table for storing user's custom search filters
|
||||
CREATE TABLE IF NOT EXISTS saved_filters (
|
||||
filter_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
filter_name VARCHAR(100) NOT NULL,
|
||||
filter_criteria JSON NOT NULL,
|
||||
is_default BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE,
|
||||
UNIQUE KEY unique_user_filter_name (user_id, filter_name)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Create index for faster lookups
|
||||
CREATE INDEX idx_user_filters ON saved_filters(user_id, is_default);
|
||||
@@ -1,11 +0,0 @@
|
||||
-- Migration 013: Add performance indexes for critical queries
|
||||
|
||||
-- Index on ticket_comments.ticket_id (foreign key without index)
|
||||
-- Speeds up comment loading by 10-100x on large tables
|
||||
CREATE INDEX IF NOT EXISTS idx_ticket_comments_ticket_id
|
||||
ON ticket_comments(ticket_id);
|
||||
|
||||
-- Composite index on audit_log for entity lookups with date sorting
|
||||
-- Optimizes activity timeline queries
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_entity_created
|
||||
ON audit_log(entity_type, entity_id, created_at DESC);
|
||||
@@ -1,4 +0,0 @@
|
||||
-- Rollback for migration 013: Remove performance indexes
|
||||
|
||||
DROP INDEX IF EXISTS idx_ticket_comments_ticket_id ON ticket_comments;
|
||||
DROP INDEX IF EXISTS idx_audit_entity_created ON audit_log;
|
||||
@@ -1,23 +0,0 @@
|
||||
-- Migration: Add additional indexes for improved query performance
|
||||
-- Version: 014
|
||||
|
||||
-- Index for audit log queries by user and date (activity reports)
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_user_created ON audit_log(user_id, created_at DESC);
|
||||
|
||||
-- Index for audit log queries by action type (security monitoring)
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_log_action_type ON audit_log(action_type, created_at DESC);
|
||||
|
||||
-- Index for tickets by status only (status filtering)
|
||||
CREATE INDEX IF NOT EXISTS idx_tickets_status ON tickets(status);
|
||||
|
||||
-- Composite index for common dashboard queries (status + priority + created_at)
|
||||
CREATE INDEX IF NOT EXISTS idx_tickets_status_priority_created ON tickets(status, priority, created_at DESC);
|
||||
|
||||
-- Index for ticket comments by ticket_id and date (comment listing)
|
||||
CREATE INDEX IF NOT EXISTS idx_comments_ticket_created ON ticket_comments(ticket_id, created_at DESC);
|
||||
|
||||
-- Index for API keys by key value (authentication lookups)
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_key_value ON api_keys(key_value);
|
||||
|
||||
-- Index for user preferences lookup
|
||||
CREATE INDEX IF NOT EXISTS idx_user_preferences_user_key ON user_preferences(user_id, preference_key);
|
||||
@@ -1,118 +0,0 @@
|
||||
# Migration 009: Simplify Status Workflow
|
||||
|
||||
This migration removes the "Resolved" status and adds a "Pending" status to the ticket system.
|
||||
|
||||
## Status Changes
|
||||
|
||||
### Before (4 statuses):
|
||||
- Open
|
||||
- In Progress
|
||||
- **Resolved** ❌ (being removed)
|
||||
- Closed
|
||||
|
||||
### After (4 statuses):
|
||||
- Open
|
||||
- **Pending** ✅ (new)
|
||||
- In Progress
|
||||
- Closed
|
||||
|
||||
## What "Pending" Means
|
||||
|
||||
**Pending** status indicates a ticket is waiting on:
|
||||
- External dependencies
|
||||
- Third-party responses
|
||||
- Parts/equipment to arrive
|
||||
- Customer information
|
||||
- Approval from another team
|
||||
|
||||
Unlike "In Progress" which means active work is happening, "Pending" means the ticket is blocked and waiting.
|
||||
|
||||
## Running the Migration
|
||||
|
||||
On the tinkertickets server, run:
|
||||
|
||||
```bash
|
||||
cd /var/www/html/tinkertickets/migrations
|
||||
mysql -h 10.10.10.50 -u tinkertickets -p'&*woX!5R$x8Tyrm7zNxC' ticketing_system < 009_simplify_status_workflow.sql
|
||||
```
|
||||
|
||||
## What the Migration Does
|
||||
|
||||
1. Updates any existing tickets with status "Resolved" to "Closed"
|
||||
2. Deletes all status transitions involving "Resolved"
|
||||
3. Creates new workflow with "Pending" status
|
||||
4. Sets up the following allowed transitions:
|
||||
|
||||
### New Workflow Transitions:
|
||||
|
||||
**From Open:**
|
||||
- → Pending (no comment required)
|
||||
- → In Progress (no comment required)
|
||||
- → Closed (requires comment)
|
||||
|
||||
**From Pending:**
|
||||
- → Open (no comment required)
|
||||
- → In Progress (no comment required)
|
||||
- → Closed (requires comment)
|
||||
|
||||
**From In Progress:**
|
||||
- → Open (no comment required)
|
||||
- → Pending (no comment required)
|
||||
- → Closed (requires comment)
|
||||
|
||||
**From Closed:**
|
||||
- → Open (requires comment - explain why reopening)
|
||||
- → In Progress (no comment required)
|
||||
|
||||
## CSS Updates
|
||||
|
||||
The following CSS files have been updated:
|
||||
- ✅ `/assets/css/dashboard.css` - Added `.status-Pending` styling with purple color (#9c27b0) and pause icon
|
||||
- ✅ `/assets/css/ticket.css` - Added `.status-Pending` styling
|
||||
|
||||
## Visual Appearance
|
||||
|
||||
The Pending status will display as:
|
||||
```
|
||||
[⏸ PENDING]
|
||||
```
|
||||
- Purple color border and text
|
||||
- Pause icon (⏸) to indicate waiting state
|
||||
- Terminal-style glow effect
|
||||
|
||||
## Verification
|
||||
|
||||
After running the migration, verify:
|
||||
|
||||
1. Check that all tickets previously marked "Resolved" are now "Closed":
|
||||
```sql
|
||||
SELECT COUNT(*) FROM tickets WHERE status = 'Resolved'; -- Should be 0
|
||||
SELECT COUNT(*) FROM tickets WHERE status = 'Closed';
|
||||
```
|
||||
|
||||
2. Check new transitions exist:
|
||||
```sql
|
||||
SELECT from_status, to_status FROM status_transitions
|
||||
WHERE from_status = 'Pending' OR to_status = 'Pending'
|
||||
ORDER BY from_status, to_status;
|
||||
```
|
||||
|
||||
3. Test creating a new ticket and changing its status to Pending in the UI
|
||||
|
||||
## Rollback (if needed)
|
||||
|
||||
If you need to rollback this migration:
|
||||
|
||||
```sql
|
||||
-- Restore Resolved status transitions
|
||||
DELETE FROM status_transitions WHERE from_status = 'Pending' OR to_status = 'Pending';
|
||||
|
||||
INSERT INTO status_transitions (from_status, to_status, requires_comment) VALUES
|
||||
('In Progress', 'Resolved', FALSE),
|
||||
('Resolved', 'Closed', FALSE),
|
||||
('Resolved', 'In Progress', TRUE),
|
||||
('Open', 'Resolved', FALSE);
|
||||
|
||||
-- Update any Pending tickets to Open
|
||||
UPDATE tickets SET status = 'Open' WHERE status = 'Pending';
|
||||
```
|
||||
@@ -1,25 +0,0 @@
|
||||
-- Rollback script to undo all SSO integration changes
|
||||
-- WARNING: This will delete all user data, API keys, and audit logs
|
||||
|
||||
-- Drop foreign keys first
|
||||
ALTER TABLE ticket_comments DROP FOREIGN KEY IF EXISTS fk_comments_user_id;
|
||||
ALTER TABLE tickets DROP FOREIGN KEY IF EXISTS fk_tickets_created_by;
|
||||
ALTER TABLE tickets DROP FOREIGN KEY IF EXISTS fk_tickets_updated_by;
|
||||
ALTER TABLE api_keys DROP FOREIGN KEY IF EXISTS api_keys_ibfk_1;
|
||||
ALTER TABLE audit_log DROP FOREIGN KEY IF EXISTS audit_log_ibfk_1;
|
||||
|
||||
-- Drop columns from existing tables
|
||||
ALTER TABLE ticket_comments DROP COLUMN IF EXISTS user_id;
|
||||
ALTER TABLE tickets DROP COLUMN IF EXISTS created_by;
|
||||
ALTER TABLE tickets DROP COLUMN IF EXISTS updated_by;
|
||||
ALTER TABLE tickets DROP COLUMN IF EXISTS updated_at;
|
||||
|
||||
-- Drop new tables
|
||||
DROP TABLE IF EXISTS audit_log;
|
||||
DROP TABLE IF EXISTS api_keys;
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
-- Drop indexes
|
||||
DROP INDEX IF EXISTS idx_status ON tickets;
|
||||
DROP INDEX IF EXISTS idx_priority ON tickets;
|
||||
DROP INDEX IF EXISTS idx_tickets_created_at ON tickets;
|
||||
@@ -23,8 +23,13 @@ class DependencyModel {
|
||||
ORDER BY d.dependency_type, d.created_at DESC";
|
||||
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
if (!$stmt) {
|
||||
throw new Exception('Prepare failed: ' . $this->conn->error);
|
||||
}
|
||||
$stmt->bind_param("s", $ticketId);
|
||||
$stmt->execute();
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception('Execute failed: ' . $stmt->error);
|
||||
}
|
||||
$result = $stmt->get_result();
|
||||
|
||||
$dependencies = [
|
||||
@@ -56,8 +61,13 @@ class DependencyModel {
|
||||
ORDER BY d.dependency_type, d.created_at DESC";
|
||||
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
if (!$stmt) {
|
||||
throw new Exception('Prepare failed: ' . $this->conn->error);
|
||||
}
|
||||
$stmt->bind_param("s", $ticketId);
|
||||
$stmt->execute();
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception('Execute failed: ' . $stmt->error);
|
||||
}
|
||||
$result = $stmt->get_result();
|
||||
|
||||
$dependents = [];
|
||||
|
||||
Reference in New Issue
Block a user