Add full time-off lifecycle: create/edit/delete with shift conflict detection, auto-removal from conflicting shifts with admin notification, shift restoration on admin delete, and hard block on assigning volunteers with approved time off to shifts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
149 lines
7.6 KiB
Go
149 lines
7.6 KiB
Go
package db
|
|
|
|
var statements = []string{
|
|
`CREATE TABLE IF NOT EXISTS volunteers (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
email VARCHAR(255) NOT NULL UNIQUE,
|
|
password VARCHAR(255) NOT NULL DEFAULT '',
|
|
role VARCHAR(50) NOT NULL DEFAULT 'volunteer' COMMENT 'admin or volunteer',
|
|
active TINYINT NOT NULL DEFAULT 1,
|
|
is_trainee TINYINT NOT NULL DEFAULT 0,
|
|
phone VARCHAR(20) NULL,
|
|
operational_roles TEXT NOT NULL,
|
|
notification_preference VARCHAR(50) NOT NULL DEFAULT 'email',
|
|
admin_notes TEXT NULL,
|
|
last_login DATETIME NULL,
|
|
invite_token VARCHAR(255) NULL,
|
|
invite_expires_at DATETIME NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
// Additive column migrations for existing deployments (duplicates ignored at runtime)
|
|
`ALTER TABLE volunteers ADD COLUMN is_trainee TINYINT NOT NULL DEFAULT 0`,
|
|
`ALTER TABLE volunteers ADD COLUMN phone VARCHAR(20) NULL`,
|
|
`ALTER TABLE volunteers ADD COLUMN operational_roles TEXT NOT NULL`,
|
|
`ALTER TABLE volunteers ADD COLUMN notification_preference VARCHAR(50) NOT NULL DEFAULT 'email'`,
|
|
`ALTER TABLE volunteers ADD COLUMN admin_notes TEXT NULL`,
|
|
`ALTER TABLE volunteers ADD COLUMN last_login DATETIME NULL`,
|
|
`ALTER TABLE volunteers ADD COLUMN invite_token VARCHAR(255) NULL`,
|
|
`ALTER TABLE volunteers ADD COLUMN invite_expires_at DATETIME NULL`,
|
|
`CREATE TABLE IF NOT EXISTS schedules (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
volunteer_id INT NOT NULL,
|
|
title VARCHAR(255) NOT NULL,
|
|
starts_at DATETIME NOT NULL,
|
|
ends_at DATETIME NOT NULL,
|
|
notes TEXT,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (volunteer_id) REFERENCES volunteers(id) ON DELETE CASCADE,
|
|
INDEX idx_volunteer_id (volunteer_id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
`CREATE TABLE IF NOT EXISTS time_off_requests (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
volunteer_id INT NOT NULL,
|
|
starts_at DATETIME NOT NULL,
|
|
ends_at DATETIME NOT NULL,
|
|
reason TEXT,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'pending' COMMENT 'pending, approved, rejected',
|
|
reviewed_by INT,
|
|
reviewed_at DATETIME,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (volunteer_id) REFERENCES volunteers(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (reviewed_by) REFERENCES volunteers(id) ON DELETE SET NULL,
|
|
INDEX idx_volunteer_id (volunteer_id),
|
|
INDEX idx_status (status)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
`CREATE TABLE IF NOT EXISTS checkins (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
volunteer_id INT NOT NULL,
|
|
schedule_id INT,
|
|
checked_in_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
checked_out_at TIMESTAMP NULL,
|
|
notes TEXT,
|
|
FOREIGN KEY (volunteer_id) REFERENCES volunteers(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (schedule_id) REFERENCES schedules(id) ON DELETE SET NULL,
|
|
INDEX idx_volunteer_id (volunteer_id),
|
|
INDEX idx_schedule_id (schedule_id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
`CREATE TABLE IF NOT EXISTS notifications (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
volunteer_id INT NOT NULL,
|
|
message TEXT NOT NULL,
|
|
is_read TINYINT NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (volunteer_id) REFERENCES volunteers(id) ON DELETE CASCADE,
|
|
INDEX idx_volunteer_id (volunteer_id),
|
|
INDEX idx_is_read (is_read)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
`CREATE TABLE IF NOT EXISTS shift_templates (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
day_of_week TINYINT NOT NULL COMMENT '0=Sunday 1=Monday ... 6=Saturday (matches Go time.Weekday)',
|
|
start_time TIME NOT NULL,
|
|
end_time TIME NOT NULL,
|
|
min_capacity INT NOT NULL DEFAULT 1,
|
|
max_capacity INT NOT NULL DEFAULT 1,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
`CREATE TABLE IF NOT EXISTS shift_template_roles (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
template_id INT NOT NULL,
|
|
role_name VARCHAR(255) NOT NULL,
|
|
count INT NOT NULL DEFAULT 1,
|
|
FOREIGN KEY (template_id) REFERENCES shift_templates(id) ON DELETE CASCADE,
|
|
INDEX idx_template_id (template_id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
`CREATE TABLE IF NOT EXISTS shift_template_volunteers (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
template_id INT NOT NULL,
|
|
volunteer_id INT NOT NULL,
|
|
UNIQUE KEY uq_template_volunteer (template_id, volunteer_id),
|
|
FOREIGN KEY (template_id) REFERENCES shift_templates(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (volunteer_id) REFERENCES volunteers(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
`CREATE TABLE IF NOT EXISTS shift_instances (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
template_id INT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
date DATE NOT NULL,
|
|
start_time TIME NOT NULL,
|
|
end_time TIME NOT NULL,
|
|
min_capacity INT NOT NULL DEFAULT 1,
|
|
max_capacity INT NOT NULL DEFAULT 1,
|
|
status VARCHAR(20) NOT NULL DEFAULT 'draft' COMMENT 'draft or published',
|
|
year INT NOT NULL,
|
|
month INT NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (template_id) REFERENCES shift_templates(id) ON DELETE SET NULL,
|
|
INDEX idx_year_month (year, month),
|
|
INDEX idx_status (status)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
`CREATE TABLE IF NOT EXISTS shift_instance_volunteers (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
instance_id INT NOT NULL,
|
|
volunteer_id INT NOT NULL,
|
|
confirmed TINYINT NOT NULL DEFAULT 0,
|
|
confirmed_at DATETIME NULL,
|
|
UNIQUE KEY uq_instance_volunteer (instance_id, volunteer_id),
|
|
FOREIGN KEY (instance_id) REFERENCES shift_instances(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (volunteer_id) REFERENCES volunteers(id) ON DELETE CASCADE,
|
|
INDEX idx_instance_id (instance_id),
|
|
INDEX idx_volunteer_id (volunteer_id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
`CREATE TABLE IF NOT EXISTS time_off_removed_shifts (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
time_off_id INT NOT NULL,
|
|
instance_id INT NOT NULL,
|
|
volunteer_id INT NOT NULL,
|
|
FOREIGN KEY (time_off_id) REFERENCES time_off_requests(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (instance_id) REFERENCES shift_instances(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (volunteer_id) REFERENCES volunteers(id) ON DELETE CASCADE,
|
|
INDEX idx_time_off_id (time_off_id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`,
|
|
}
|