init push

This commit is contained in:
2026-07-16 22:16:45 +07:00
commit 8b068bdb10
1021 changed files with 332816 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
-- +goose Up
-- HEMS contacts/users module schema extension
ALTER TABLE roles
ADD COLUMN IF NOT EXISTS code VARCHAR(64) NULL,
ADD UNIQUE KEY IF NOT EXISTS uq_roles_code (code);
ALTER TABLE users
ADD COLUMN IF NOT EXISTS username VARCHAR(100) NULL,
ADD UNIQUE KEY IF NOT EXISTS uq_users_username (username),
ADD COLUMN IF NOT EXISTS is_active TINYINT(1) NOT NULL DEFAULT 1;
CREATE TABLE IF NOT EXISTS pilot_profiles (
user_id BINARY(16) NOT NULL,
pilot_category ENUM('regular','freelance','dry_lease') NOT NULL,
short_name VARCHAR(120) NULL,
license_no VARCHAR(120) NULL,
license_issued_at DATETIME NULL,
license_expired_at DATETIME NULL,
technician_license_no VARCHAR(120) NULL,
has_ifr_qualification TINYINT(1) NOT NULL DEFAULT 0,
is_chief_pilot TINYINT(1) NOT NULL DEFAULT 0,
is_dul TINYINT(1) NOT NULL DEFAULT 0,
total_flight_minutes INT NOT NULL DEFAULT 0,
responsible_pilot_minutes INT NOT NULL DEFAULT 0,
second_pilot_minutes INT NOT NULL DEFAULT 0,
double_command_minutes INT NOT NULL DEFAULT 0,
flight_instructor_minutes INT NOT NULL DEFAULT 0,
night_flight_minutes INT NOT NULL DEFAULT 0,
ifr_flight_minutes INT NOT NULL DEFAULT 0,
location VARCHAR(255) NULL,
postcode VARCHAR(32) NULL,
street_line VARCHAR(255) NULL,
weight_kg DECIMAL(8,2) NULL,
photo_file_id VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
PRIMARY KEY (user_id),
KEY idx_pilot_profiles_category (pilot_category),
KEY idx_pilot_profiles_license (license_no),
CONSTRAINT fk_pilot_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS doctor_profiles (
user_id BINARY(16) NOT NULL,
short_name VARCHAR(120) NULL,
medical_license_no VARCHAR(120) NULL,
license_issued_at DATETIME NULL,
license_expired_at DATETIME NULL,
specialization VARCHAR(120) NULL,
sub_specialization VARCHAR(120) NULL,
is_chief_physician TINYINT(1) NOT NULL DEFAULT 0,
location VARCHAR(255) NULL,
postcode VARCHAR(32) NULL,
street_line VARCHAR(255) NULL,
photo_file_id VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
PRIMARY KEY (user_id),
KEY idx_doctor_profiles_medical_license (medical_license_no),
CONSTRAINT fk_doctor_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS air_rescuer_profiles (
user_id BINARY(16) NOT NULL,
short_name VARCHAR(120) NULL,
is_chief_physician_in_charge TINYINT(1) NOT NULL DEFAULT 0,
responsible_flight_rescuer TINYINT(1) NOT NULL DEFAULT 0,
location VARCHAR(255) NULL,
postcode VARCHAR(32) NULL,
street_line VARCHAR(255) NULL,
photo_file_id VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
PRIMARY KEY (user_id),
CONSTRAINT fk_air_rescuer_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS technician_profiles (
user_id BINARY(16) NOT NULL,
short_name VARCHAR(120) NULL,
license_no VARCHAR(120) NULL,
is_chief_technician TINYINT(1) NOT NULL DEFAULT 0,
is_responsible_complaints TINYINT(1) NOT NULL DEFAULT 0,
location VARCHAR(255) NULL,
postcode VARCHAR(32) NULL,
street_line VARCHAR(255) NULL,
photo_file_id VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
PRIMARY KEY (user_id),
KEY idx_technician_profiles_license (license_no),
CONSTRAINT fk_technician_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS flight_assistant_profiles (
user_id BINARY(16) NOT NULL,
short_name VARCHAR(120) NULL,
location VARCHAR(255) NULL,
postcode VARCHAR(32) NULL,
street_line VARCHAR(255) NULL,
photo_file_id VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
PRIMARY KEY (user_id),
CONSTRAINT fk_flight_assistant_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS staff_profiles (
user_id BINARY(16) NOT NULL,
short_name VARCHAR(120) NULL,
role_label VARCHAR(120) NULL,
location VARCHAR(255) NULL,
postcode VARCHAR(32) NULL,
street_line VARCHAR(255) NULL,
photo_file_id VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
PRIMARY KEY (user_id),
CONSTRAINT fk_staff_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);
-- +goose Down
DROP TABLE IF EXISTS staff_profiles;
DROP TABLE IF EXISTS flight_assistant_profiles;
DROP TABLE IF EXISTS technician_profiles;
DROP TABLE IF EXISTS air_rescuer_profiles;
DROP TABLE IF EXISTS doctor_profiles;
DROP TABLE IF EXISTS pilot_profiles;
ALTER TABLE users
DROP COLUMN IF EXISTS is_active,
DROP INDEX IF EXISTS uq_users_username,
DROP COLUMN IF EXISTS username;
ALTER TABLE roles
DROP INDEX IF EXISTS uq_roles_code,
DROP COLUMN IF EXISTS code;

View File

@@ -0,0 +1,21 @@
-- +goose Up
ALTER TABLE air_rescuer_profiles
ADD COLUMN IF NOT EXISTS responsible_flight_rescuer TINYINT(1) NOT NULL DEFAULT 0 AFTER is_chief_physician_in_charge;
UPDATE air_rescuer_profiles arp
JOIN pilot_profiles pp ON pp.user_id = arp.user_id
SET arp.responsible_flight_rescuer = pp.responsible_flight_rescuer;
ALTER TABLE pilot_profiles
DROP COLUMN IF EXISTS responsible_flight_rescuer;
-- +goose Down
ALTER TABLE pilot_profiles
ADD COLUMN IF NOT EXISTS responsible_flight_rescuer TINYINT(1) NOT NULL DEFAULT 0 AFTER is_dul;
UPDATE pilot_profiles pp
JOIN air_rescuer_profiles arp ON arp.user_id = pp.user_id
SET pp.responsible_flight_rescuer = arp.responsible_flight_rescuer;
ALTER TABLE air_rescuer_profiles
DROP COLUMN IF EXISTS responsible_flight_rescuer;

View File

@@ -0,0 +1,66 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS file_folders (
id BINARY(16) NOT NULL,
parent_id BINARY(16) NULL,
name VARCHAR(128) NOT NULL,
name_normalized VARCHAR(128) NOT NULL,
depth SMALLINT UNSIGNED NOT NULL DEFAULT 0,
path_cache VARCHAR(2048) NULL,
name_slot CHAR(36) NOT NULL DEFAULT 'live',
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
created_by BINARY(16) NULL,
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
updated_by BINARY(16) NULL,
deleted_at DATETIME(6) NULL,
deleted_by BINARY(16) NULL,
purge_at DATETIME(6) NULL,
PRIMARY KEY (id),
CONSTRAINT fk_file_folders_parent
FOREIGN KEY (parent_id) REFERENCES file_folders(id)
ON UPDATE CASCADE
ON DELETE RESTRICT,
UNIQUE KEY uq_file_folders_parent_name_slot (parent_id, name_normalized, name_slot),
KEY idx_file_folders_parent_active (parent_id, deleted_at),
KEY idx_file_folders_deleted_at (deleted_at),
KEY idx_file_folders_purge_at (purge_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS file_files (
id BINARY(16) NOT NULL,
folder_id BINARY(16) NOT NULL,
name VARCHAR(255) NOT NULL,
name_normalized VARCHAR(255) NOT NULL,
extension VARCHAR(32) NULL,
size_bytes BIGINT UNSIGNED NOT NULL DEFAULT 0,
mime_type VARCHAR(255) NOT NULL,
bucket VARCHAR(128) NOT NULL,
object_key VARCHAR(512) NOT NULL,
object_version VARCHAR(128) NULL,
etag VARCHAR(128) NULL,
checksum_sha256 CHAR(64) NULL,
status VARCHAR(32) NOT NULL DEFAULT 'pending',
upload_error TEXT NULL,
name_slot CHAR(36) NOT NULL DEFAULT 'live',
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
created_by BINARY(16) NULL,
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
updated_by BINARY(16) NULL,
deleted_at DATETIME(6) NULL,
deleted_by BINARY(16) NULL,
trashed_at DATETIME(6) NULL,
purge_at DATETIME(6) NULL,
PRIMARY KEY (id),
CONSTRAINT fk_file_files_folder
FOREIGN KEY (folder_id) REFERENCES file_folders(id)
ON UPDATE CASCADE
ON DELETE RESTRICT,
UNIQUE KEY uq_file_files_object_key (object_key),
UNIQUE KEY uq_file_files_folder_name_slot (folder_id, name_normalized, name_slot),
KEY idx_file_files_folder_active (folder_id, deleted_at),
KEY idx_file_files_status_updated (status, updated_at),
KEY idx_file_files_purge_at (purge_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- +goose Down
DROP TABLE IF EXISTS file_files;
DROP TABLE IF EXISTS file_folders;

View File

@@ -0,0 +1,42 @@
-- +goose Up
ALTER TABLE file_files
MODIFY COLUMN status VARCHAR(32) NOT NULL DEFAULT 'uploaded',
ADD COLUMN processing_started_at DATETIME(6) NULL AFTER status,
ADD COLUMN processed_at DATETIME(6) NULL AFTER processing_started_at,
ADD COLUMN validated_at DATETIME(6) NULL AFTER processed_at,
ADD COLUMN failed_at DATETIME(6) NULL AFTER validated_at,
ADD COLUMN failure_reason TEXT NULL AFTER failed_at;
UPDATE file_files
SET status = 'validated',
processed_at = COALESCE(processed_at, updated_at),
validated_at = COALESCE(validated_at, updated_at)
WHERE status = 'pending';
UPDATE file_files
SET status = 'processing',
processing_started_at = COALESCE(processing_started_at, updated_at)
WHERE status = 'uploading';
UPDATE file_files
SET failure_reason = NULLIF(TRIM(upload_error), '')
WHERE (failure_reason IS NULL OR failure_reason = '')
AND upload_error IS NOT NULL
AND TRIM(upload_error) <> '';
-- +goose Down
UPDATE file_files
SET status = 'pending'
WHERE status IN ('uploaded', 'validated');
UPDATE file_files
SET status = 'uploading'
WHERE status = 'processing';
ALTER TABLE file_files
DROP COLUMN failure_reason,
DROP COLUMN failed_at,
DROP COLUMN validated_at,
DROP COLUMN processed_at,
DROP COLUMN processing_started_at,
MODIFY COLUMN status VARCHAR(32) NOT NULL DEFAULT 'pending';

View File

@@ -0,0 +1,33 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS file_processing_outbox_messages (
id BINARY(16) NOT NULL,
message_id VARCHAR(64) NOT NULL,
kind VARCHAR(64) NOT NULL,
job_type VARCHAR(64) NOT NULL,
body LONGBLOB NOT NULL,
attributes LONGBLOB NULL,
message_group_id VARCHAR(128) NULL,
deduplication_id VARCHAR(128) NULL,
status VARCHAR(32) NOT NULL DEFAULT 'pending',
attempts INT NOT NULL DEFAULT 0,
available_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
locked_at DATETIME(6) NULL,
locked_by VARCHAR(64) NULL,
published_at DATETIME(6) NULL,
last_error TEXT NULL,
correlation_id VARCHAR(64) NULL,
trace_id VARCHAR(64) NULL,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY (id),
UNIQUE KEY uq_file_processing_outbox_message_id (message_id),
KEY idx_file_processing_outbox_status_available (status, available_at),
KEY idx_file_processing_outbox_locked_at (locked_at),
KEY idx_file_processing_outbox_kind (kind),
KEY idx_file_processing_outbox_job_type (job_type),
KEY idx_file_processing_outbox_correlation (correlation_id),
KEY idx_file_processing_outbox_trace (trace_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- +goose Down
DROP TABLE IF EXISTS file_processing_outbox_messages;

View File

@@ -0,0 +1,22 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS file_status_realtime_events (
id BINARY(16) NOT NULL,
file_id BINARY(16) NOT NULL,
user_id BINARY(16) NOT NULL,
status VARCHAR(32) NOT NULL,
name VARCHAR(255) NOT NULL,
failure_reason TEXT NULL,
occurred_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
delivered_at DATETIME(6) NULL,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY (id),
KEY idx_file_status_realtime_events_file (file_id),
KEY idx_file_status_realtime_events_user (user_id),
KEY idx_file_status_realtime_events_status (status),
KEY idx_file_status_realtime_events_occurred (occurred_at),
KEY idx_file_status_realtime_events_delivered (delivered_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- +goose Down
DROP TABLE IF EXISTS file_status_realtime_events;

View File

@@ -0,0 +1,27 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS file_upload_intents (
id BINARY(16) NOT NULL,
name VARCHAR(255) NOT NULL,
name_normalized VARCHAR(255) NOT NULL,
extension VARCHAR(32) NULL,
size_bytes BIGINT UNSIGNED NOT NULL DEFAULT 0,
mime_type VARCHAR(255) NOT NULL,
bucket VARCHAR(128) NOT NULL,
object_key VARCHAR(512) NOT NULL,
status VARCHAR(32) NOT NULL DEFAULT 'pending',
expires_at DATETIME(6) NOT NULL,
completed_at DATETIME(6) NULL,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
created_by BINARY(16) NULL,
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
updated_by BINARY(16) NULL,
PRIMARY KEY (id),
UNIQUE KEY uq_file_upload_intents_object_key (object_key),
KEY idx_file_upload_intents_status (status),
KEY idx_file_upload_intents_expires_at (expires_at),
KEY idx_file_upload_intents_completed_at (completed_at),
KEY idx_file_upload_intents_created_by (created_by)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- +goose Down
DROP TABLE IF EXISTS file_upload_intents;

View File

@@ -0,0 +1,35 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS user_roles (
id BINARY(16) NOT NULL,
user_id BINARY(16) NOT NULL,
role_id BINARY(16) NOT NULL,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
created_by BINARY(16) NULL,
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
updated_by BINARY(16) NULL,
PRIMARY KEY (id),
UNIQUE KEY ux_user_role (user_id, role_id),
KEY idx_user_roles_user_id (user_id),
KEY idx_user_roles_role_id (role_id),
CONSTRAINT fk_user_roles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_user_roles_role FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO user_roles (id, user_id, role_id, created_at, updated_at)
SELECT
UNHEX(REPLACE(UUID(), '-', '')),
users.id,
users.role_id,
CURRENT_TIMESTAMP(6),
CURRENT_TIMESTAMP(6)
FROM users
WHERE users.role_id IS NOT NULL
AND NOT EXISTS (
SELECT 1
FROM user_roles
WHERE user_roles.user_id = users.id
AND user_roles.role_id = users.role_id
);
-- +goose Down
DROP TABLE IF EXISTS user_roles;

View File

@@ -0,0 +1,265 @@
-- +goose Up
SET @col_default_shift_start_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'default_shift_start'
);
SET @add_default_shift_start_sql := IF(
@col_default_shift_start_exists = 0,
'ALTER TABLE bases ADD COLUMN default_shift_start TIME NULL AFTER leg_time',
'SELECT 1'
);
PREPARE stmt_add_default_shift_start FROM @add_default_shift_start_sql;
EXECUTE stmt_add_default_shift_start;
DEALLOCATE PREPARE stmt_add_default_shift_start;
SET @col_default_shift_end_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'default_shift_end'
);
SET @add_default_shift_end_sql := IF(
@col_default_shift_end_exists = 0,
'ALTER TABLE bases ADD COLUMN default_shift_end TIME NULL AFTER default_shift_start',
'SELECT 1'
);
PREPARE stmt_add_default_shift_end FROM @add_default_shift_end_sql;
EXECUTE stmt_add_default_shift_end;
DEALLOCATE PREPARE stmt_add_default_shift_end;
SET @col_foto_attachment_id_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'foto_attachment_id'
);
SET @add_foto_attachment_id_sql := IF(
@col_foto_attachment_id_exists = 0,
'ALTER TABLE bases ADD COLUMN foto_attachment_id BINARY(16) NULL AFTER foto',
'SELECT 1'
);
PREPARE stmt_add_foto_attachment_id FROM @add_foto_attachment_id_sql;
EXECUTE stmt_add_foto_attachment_id;
DEALLOCATE PREPARE stmt_add_foto_attachment_id;
SET @col_deleted_at_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'deleted_at'
);
SET @add_deleted_at_sql := IF(
@col_deleted_at_exists = 0,
'ALTER TABLE bases ADD COLUMN deleted_at DATETIME(3) NULL AFTER updated_at',
'SELECT 1'
);
PREPARE stmt_add_deleted_at FROM @add_deleted_at_sql;
EXECUTE stmt_add_deleted_at;
DEALLOCATE PREPARE stmt_add_deleted_at;
SET @col_deleted_by_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'deleted_by'
);
SET @add_deleted_by_sql := IF(
@col_deleted_by_exists = 0,
'ALTER TABLE bases ADD COLUMN deleted_by BINARY(16) NULL AFTER deleted_at',
'SELECT 1'
);
PREPARE stmt_add_deleted_by FROM @add_deleted_by_sql;
EXECUTE stmt_add_deleted_by;
DEALLOCATE PREPARE stmt_add_deleted_by;
SET @idx_bases_deleted_at_exists := (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND index_name = 'idx_bases_deleted_at'
);
SET @add_idx_bases_deleted_at_sql := IF(
@idx_bases_deleted_at_exists = 0,
'ALTER TABLE bases ADD INDEX idx_bases_deleted_at (deleted_at)',
'SELECT 1'
);
PREPARE stmt_add_idx_bases_deleted_at FROM @add_idx_bases_deleted_at_sql;
EXECUTE stmt_add_idx_bases_deleted_at;
DEALLOCATE PREPARE stmt_add_idx_bases_deleted_at;
SET @idx_bases_foto_attachment_id_exists := (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND index_name = 'idx_bases_foto_attachment_id'
);
SET @add_idx_bases_foto_attachment_id_sql := IF(
@idx_bases_foto_attachment_id_exists = 0,
'ALTER TABLE bases ADD INDEX idx_bases_foto_attachment_id (foto_attachment_id)',
'SELECT 1'
);
PREPARE stmt_add_idx_bases_foto_attachment_id FROM @add_idx_bases_foto_attachment_id_sql;
EXECUTE stmt_add_idx_bases_foto_attachment_id;
DEALLOCATE PREPARE stmt_add_idx_bases_foto_attachment_id;
SET @attachments_table_exists := (
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'attachments'
);
SET @fk_bases_foto_attachment_exists := (
SELECT COUNT(*)
FROM information_schema.table_constraints
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND constraint_name = 'fk_bases_foto_attachment'
AND constraint_type = 'FOREIGN KEY'
);
SET @add_fk_bases_foto_attachment_sql := IF(
@attachments_table_exists > 0 AND @fk_bases_foto_attachment_exists = 0,
'ALTER TABLE bases ADD CONSTRAINT fk_bases_foto_attachment FOREIGN KEY (foto_attachment_id) REFERENCES attachments(id) ON UPDATE CASCADE ON DELETE SET NULL',
'SELECT 1'
);
PREPARE stmt_add_fk_bases_foto_attachment FROM @add_fk_bases_foto_attachment_sql;
EXECUTE stmt_add_fk_bases_foto_attachment;
DEALLOCATE PREPARE stmt_add_fk_bases_foto_attachment;
-- +goose Down
SET @fk_bases_foto_attachment_exists := (
SELECT COUNT(*)
FROM information_schema.table_constraints
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND constraint_name = 'fk_bases_foto_attachment'
AND constraint_type = 'FOREIGN KEY'
);
SET @drop_fk_bases_foto_attachment_sql := IF(
@fk_bases_foto_attachment_exists > 0,
'ALTER TABLE bases DROP FOREIGN KEY fk_bases_foto_attachment',
'SELECT 1'
);
PREPARE stmt_drop_fk_bases_foto_attachment FROM @drop_fk_bases_foto_attachment_sql;
EXECUTE stmt_drop_fk_bases_foto_attachment;
DEALLOCATE PREPARE stmt_drop_fk_bases_foto_attachment;
SET @idx_bases_foto_attachment_id_exists := (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND index_name = 'idx_bases_foto_attachment_id'
);
SET @drop_idx_bases_foto_attachment_id_sql := IF(
@idx_bases_foto_attachment_id_exists > 0,
'ALTER TABLE bases DROP INDEX idx_bases_foto_attachment_id',
'SELECT 1'
);
PREPARE stmt_drop_idx_bases_foto_attachment_id FROM @drop_idx_bases_foto_attachment_id_sql;
EXECUTE stmt_drop_idx_bases_foto_attachment_id;
DEALLOCATE PREPARE stmt_drop_idx_bases_foto_attachment_id;
SET @idx_bases_deleted_at_exists := (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND index_name = 'idx_bases_deleted_at'
);
SET @drop_idx_bases_deleted_at_sql := IF(
@idx_bases_deleted_at_exists > 0,
'ALTER TABLE bases DROP INDEX idx_bases_deleted_at',
'SELECT 1'
);
PREPARE stmt_drop_idx_bases_deleted_at FROM @drop_idx_bases_deleted_at_sql;
EXECUTE stmt_drop_idx_bases_deleted_at;
DEALLOCATE PREPARE stmt_drop_idx_bases_deleted_at;
SET @col_deleted_by_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'deleted_by'
);
SET @drop_deleted_by_sql := IF(
@col_deleted_by_exists > 0,
'ALTER TABLE bases DROP COLUMN deleted_by',
'SELECT 1'
);
PREPARE stmt_drop_deleted_by FROM @drop_deleted_by_sql;
EXECUTE stmt_drop_deleted_by;
DEALLOCATE PREPARE stmt_drop_deleted_by;
SET @col_deleted_at_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'deleted_at'
);
SET @drop_deleted_at_sql := IF(
@col_deleted_at_exists > 0,
'ALTER TABLE bases DROP COLUMN deleted_at',
'SELECT 1'
);
PREPARE stmt_drop_deleted_at FROM @drop_deleted_at_sql;
EXECUTE stmt_drop_deleted_at;
DEALLOCATE PREPARE stmt_drop_deleted_at;
SET @col_foto_attachment_id_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'foto_attachment_id'
);
SET @drop_foto_attachment_id_sql := IF(
@col_foto_attachment_id_exists > 0,
'ALTER TABLE bases DROP COLUMN foto_attachment_id',
'SELECT 1'
);
PREPARE stmt_drop_foto_attachment_id FROM @drop_foto_attachment_id_sql;
EXECUTE stmt_drop_foto_attachment_id;
DEALLOCATE PREPARE stmt_drop_foto_attachment_id;
SET @col_default_shift_end_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'default_shift_end'
);
SET @drop_default_shift_end_sql := IF(
@col_default_shift_end_exists > 0,
'ALTER TABLE bases DROP COLUMN default_shift_end',
'SELECT 1'
);
PREPARE stmt_drop_default_shift_end FROM @drop_default_shift_end_sql;
EXECUTE stmt_drop_default_shift_end;
DEALLOCATE PREPARE stmt_drop_default_shift_end;
SET @col_default_shift_start_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'default_shift_start'
);
SET @drop_default_shift_start_sql := IF(
@col_default_shift_start_exists > 0,
'ALTER TABLE bases DROP COLUMN default_shift_start',
'SELECT 1'
);
PREPARE stmt_drop_default_shift_start FROM @drop_default_shift_start_sql;
EXECUTE stmt_drop_default_shift_start;
DEALLOCATE PREPARE stmt_drop_default_shift_start;

View File

@@ -0,0 +1,81 @@
-- +goose Up
ALTER TABLE permissions
ADD COLUMN requires_pin TINYINT(1) NOT NULL DEFAULT 0 AFTER description;
UPDATE permissions
SET requires_pin = 1
WHERE (updated_by IS NULL OR LENGTH(updated_by) = 0)
AND `key` IN (
'user.create',
'user.update',
'user.delete',
'role.create',
'role.update',
'role.delete',
'role.permission.assign',
'role.permission.remove',
'role.permission.update',
'helicopter.create',
'helicopter.report.generate',
'helicopter.update',
'helicopter.delete',
'facility.create',
'facility.update',
'facility.delete',
'base.create',
'base.update',
'base.delete',
'hems_base.create',
'hems_base.update',
'hems_base.delete',
'bmd.create',
'bmd.update',
'bmd.delete',
'medicine.create',
'medicine.update',
'medicine.delete',
'vocation.create',
'vocation.update',
'vocation.delete',
'opc.create',
'opc.update',
'opc.delete',
'forces_present.create',
'forces_present.update',
'forces_present.delete',
'hospital.create',
'hospital.update',
'hospital.delete',
'health_insurance_companies.create',
'health_insurance_companies.update',
'health_insurance_companies.delete',
'federal_state.create',
'federal_state.update',
'federal_state.delete',
'nationality.create',
'nationality.update',
'nationality.delete',
'icao.create',
'icao.update',
'icao.delete',
'land.create',
'land.update',
'land.delete',
'master_settings.create',
'master_settings.update',
'master_settings.delete',
'file_manager.create',
'file_manager.update',
'file_manager.delete',
'hems_duty_roster.create',
'hems_duty_roster.update',
'hems_duty_roster.delete',
'air_rescuer_checklist.create',
'air_rescuer_checklist.update',
'air_rescuer_checklist.delete',
'audit.read'
);
-- +goose Down
ALTER TABLE permissions
DROP COLUMN requires_pin;

View File

@@ -0,0 +1,85 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS crews (
id BINARY(16) PRIMARY KEY,
crew_type VARCHAR(32) NOT NULL,
user_id BINARY(16) NOT NULL,
start_date DATETIME NOT NULL,
end_date DATETIME NOT NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
CONSTRAINT chk_crews_crew_type CHECK (crew_type IN ('main', 'additional')),
CONSTRAINT chk_crews_date_range CHECK (start_date <= end_date),
CONSTRAINT fk_crews_user FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE INDEX idx_crews_user_id ON crews(user_id);
CREATE INDEX idx_crews_crew_type ON crews(crew_type);
CREATE INDEX idx_crews_start_date ON crews(start_date);
CREATE INDEX idx_crews_end_date ON crews(end_date);
CREATE TABLE IF NOT EXISTS roster_crews (
id BINARY(16) PRIMARY KEY,
roster_id BINARY(16) NOT NULL,
crew_id BINARY(16) NOT NULL,
confirm_at DATETIME NULL,
role VARCHAR(32) NOT NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
CONSTRAINT chk_roster_crews_role CHECK (role IN ('Pilot', 'Copilot', 'Doctor', 'AirRescuer')),
CONSTRAINT fk_roster_crews_roster FOREIGN KEY (roster_id) REFERENCES hems_duty_rosters(id),
CONSTRAINT fk_roster_crews_crew FOREIGN KEY (crew_id) REFERENCES crews(id)
);
CREATE INDEX idx_roster_crews_roster_id ON roster_crews(roster_id);
CREATE INDEX idx_roster_crews_role ON roster_crews(role);
CREATE UNIQUE INDEX idx_roster_crews_roster_crew ON roster_crews(roster_id, crew_id);
CREATE TABLE IF NOT EXISTS duty_roster_other_persons (
id BINARY(16) PRIMARY KEY,
roster_id BINARY(16) NOT NULL,
name VARCHAR(191) NOT NULL,
mobile_phone VARCHAR(64) NULL,
email VARCHAR(191) NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
CONSTRAINT fk_duty_roster_other_persons_roster FOREIGN KEY (roster_id) REFERENCES hems_duty_rosters(id)
);
CREATE INDEX idx_duty_roster_other_persons_roster_id ON duty_roster_other_persons(roster_id);
CREATE TABLE IF NOT EXISTS duty_roster_crew_pilot_additionals (
id BINARY(16) PRIMARY KEY,
crew_id BINARY(16) NOT NULL,
flight_instructor TINYINT(1) NOT NULL DEFAULT 0,
line_checker TINYINT(1) NOT NULL DEFAULT 0,
supervisor TINYINT(1) NOT NULL DEFAULT 0,
examiner TINYINT(1) NOT NULL DEFAULT 0,
copilot TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
CONSTRAINT fk_duty_roster_crew_pilot_additionals_crew FOREIGN KEY (crew_id) REFERENCES crews(id)
);
CREATE UNIQUE INDEX idx_duty_roster_crew_pilot_additionals_crew_id ON duty_roster_crew_pilot_additionals(crew_id);
-- +goose Down
DROP TABLE IF EXISTS duty_roster_crew_pilot_additionals;
DROP TABLE IF EXISTS duty_roster_other_persons;
DROP TABLE IF EXISTS roster_crews;
DROP TABLE IF EXISTS crews;

View File

@@ -0,0 +1,25 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS attachments (
id BINARY(16) NOT NULL,
file_id BINARY(16) NOT NULL,
ref_type VARCHAR(64) NOT NULL,
ref_id VARCHAR(191) NOT NULL,
category VARCHAR(64) NULL,
sort_order INT NOT NULL DEFAULT 0,
is_primary TINYINT(1) NOT NULL DEFAULT 0,
attached_by BINARY(16) NULL,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY (id),
CONSTRAINT fk_attachments_file
FOREIGN KEY (file_id) REFERENCES file_files(id)
ON UPDATE CASCADE
ON DELETE CASCADE,
UNIQUE KEY uq_attachments_ref_file (ref_type, ref_id, file_id),
KEY idx_attachments_file_id (file_id),
KEY idx_attachments_ref_sort (ref_type, ref_id, sort_order, created_at),
KEY idx_attachments_ref_category (ref_type, ref_id, category)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- +goose Down
DROP TABLE IF EXISTS attachments;

View File

@@ -0,0 +1,7 @@
-- +goose Up
ALTER TABLE hems_duty_roster_crews
ADD COLUMN IF NOT EXISTS confirm_at DATETIME NULL AFTER email;
-- +goose Down
ALTER TABLE hems_duty_roster_crews
DROP COLUMN IF EXISTS confirm_at;

View File

@@ -0,0 +1,25 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS after_flight_inspections (
id BINARY(16) PRIMARY KEY,
flight_inspection_id BINARY(16) NOT NULL,
ac_oil_upload_liter DECIMAL(10,2) NULL,
oil_engine_nr1_checked TINYINT(1) NULL,
oil_engine_nr2_checked TINYINT(1) NULL,
hydraulic_lh_checked TINYINT(1) NULL,
hydraulic_rh_checked TINYINT(1) NULL,
oil_transmission_mgb_checked TINYINT(1) NULL,
oil_transmission_igb_checked TINYINT(1) NULL,
oil_transmission_tgb_checked TINYINT(1) NULL,
note TEXT NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
CONSTRAINT fk_after_flight_inspections_flight_inspection FOREIGN KEY (flight_inspection_id) REFERENCES flight_inspections(id),
CONSTRAINT chk_after_flight_ac_oil_upload_liter CHECK (ac_oil_upload_liter IS NULL OR ac_oil_upload_liter >= 0)
);
CREATE UNIQUE INDEX idx_after_flight_inspections_flight_inspection_id ON after_flight_inspections(flight_inspection_id);
-- +goose Down
DROP TABLE IF EXISTS after_flight_inspections;

View File

@@ -0,0 +1,27 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS before_flight_inspections (
id BINARY(16) PRIMARY KEY,
flight_inspection_id BINARY(16) NOT NULL,
oil_engine_nr1_checked TINYINT(1) NULL,
oil_engine_nr2_checked TINYINT(1) NULL,
hydraulic_lh_checked TINYINT(1) NULL,
hydraulic_rh_checked TINYINT(1) NULL,
oil_transmission_mgb_checked TINYINT(1) NULL,
oil_transmission_igb_checked TINYINT(1) NULL,
oil_transmission_tgb_checked TINYINT(1) NULL,
fuel_amount DECIMAL(10,2) NULL,
fuel_unit VARCHAR(10) NULL,
fuel_added_amount DECIMAL(10,2) NULL,
note TEXT NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
CONSTRAINT fk_before_flight_inspections_flight_inspection FOREIGN KEY (flight_inspection_id) REFERENCES flight_inspections(id),
CONSTRAINT chk_before_flight_fuel_unit CHECK (fuel_unit IS NULL OR fuel_unit IN ('LT', 'KG', 'POUND'))
);
CREATE UNIQUE INDEX idx_before_flight_inspections_flight_inspection_id ON before_flight_inspections(flight_inspection_id);
-- +goose Down
DROP TABLE IF EXISTS before_flight_inspections;

View File

@@ -0,0 +1,30 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS flight_inspections (
id BINARY(16) PRIMARY KEY,
helicopter_id BINARY(16) NOT NULL,
inspection_date DATE NOT NULL,
operation_id BINARY(16) NULL,
status ENUM('Draft', 'InProgress', 'Completed') NOT NULL DEFAULT 'Draft',
before_flight_completed_at DATETIME NULL,
before_flight_completed_by BINARY(16) NULL,
flight_prep_completed_at DATETIME NULL,
flight_prep_completed_by BINARY(16) NULL,
after_flight_completed_at DATETIME NULL,
after_flight_completed_by BINARY(16) NULL,
final_completed_at DATETIME NULL,
final_completed_by BINARY(16) NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
CONSTRAINT fk_flight_inspections_helicopter FOREIGN KEY (helicopter_id) REFERENCES helicopters(id)
);
CREATE INDEX idx_flight_inspections_helicopter_id ON flight_inspections(helicopter_id);
CREATE INDEX idx_flight_inspections_inspection_date ON flight_inspections(inspection_date);
CREATE INDEX idx_flight_inspections_status ON flight_inspections(status);
CREATE INDEX idx_flight_inspections_operation_id ON flight_inspections(operation_id);
CREATE INDEX idx_flight_inspections_helicopter_date ON flight_inspections(helicopter_id, inspection_date);
-- +goose Down
DROP TABLE IF EXISTS flight_inspections;

View File

@@ -0,0 +1,26 @@
-- +goose Up
-- Migration: Create flight_prep_checks table
-- Date: 2026-04-09
-- Description: Per-inspection execution data for flight preparation checklist items
CREATE TABLE flight_prep_checks (
id BINARY(16) PRIMARY KEY,
flight_inspection_id BINARY(16) NOT NULL,
flight_prep_item_id BINARY(16) NOT NULL,
is_done TINYINT(1) NOT NULL DEFAULT 0,
note TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16),
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16),
CONSTRAINT fk_flight_prep_checks_flight_inspection FOREIGN KEY (flight_inspection_id) REFERENCES flight_inspections(id) ON DELETE CASCADE,
CONSTRAINT fk_flight_prep_checks_flight_prep_item FOREIGN KEY (flight_prep_item_id) REFERENCES flight_prep_items(id) ON DELETE RESTRICT,
INDEX idx_flight_prep_checks_flight_inspection (flight_inspection_id),
INDEX idx_flight_prep_checks_flight_inspection_sorted (flight_inspection_id, is_done),
UNIQUE KEY uk_flight_prep_checks_inspection_item (flight_inspection_id, flight_prep_item_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- +goose Down
DROP TABLE IF EXISTS flight_prep_checks;

View File

@@ -0,0 +1,25 @@
-- +goose Up
-- Migration: Create flight_prep_items table
-- Date: 2026-04-09
-- Description: Master data table for flight preparation checklist items
CREATE TABLE flight_prep_items (
id BINARY(16) PRIMARY KEY,
title VARCHAR(255) NOT NULL,
section ENUM('FLIGHT_PREPARATION', 'WEIGHT_AND_BALANCE') NOT NULL,
sort_order INT NOT NULL DEFAULT 0 CHECK (sort_order >= 0),
is_required TINYINT(1) NOT NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16),
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16),
INDEX idx_flight_prep_items_section_active (section, is_active),
INDEX idx_flight_prep_items_sort_order (sort_order),
INDEX idx_flight_prep_items_created_at (created_at),
UNIQUE KEY uk_flight_prep_items_title_section_active (title, section, is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- +goose Down
DROP TABLE IF EXISTS flight_prep_items;

View File

@@ -0,0 +1,20 @@
-- +goose Up
-- Create opcs table for OPC (Operation Planning Center) master data
CREATE TABLE IF NOT EXISTS opcs (
id BINARY(16) NOT NULL PRIMARY KEY,
name VARCHAR(64) NOT NULL UNIQUE,
description VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
KEY idx_opcs_name (name),
KEY idx_opcs_deleted_at (deleted_at)
);
-- +goose Down
DROP TABLE IF EXISTS opcs;

View File

@@ -0,0 +1,57 @@
-- +goose Up
-- Create insurance_patient_data table
CREATE TABLE IF NOT EXISTS insurance_patient_data (
id BINARY(16) NOT NULL PRIMARY KEY,
health_insurance_companies_id BINARY(16) NULL,
federal_state_id BINARY(16) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
KEY idx_insurance_patient_data_health_insurance_companies_id (health_insurance_companies_id),
KEY idx_insurance_patient_data_federal_state_id (federal_state_id),
KEY idx_insurance_patient_data_deleted_at (deleted_at)
);
-- Create patient_data table
CREATE TABLE IF NOT EXISTS patient_data (
id BINARY(16) NOT NULL PRIMARY KEY,
family_name VARCHAR(128) NOT NULL,
first_name VARCHAR(128) NOT NULL,
opc_id BINARY(16) NULL,
birth_date DATE NULL,
gender ENUM('male','female') NOT NULL,
street VARCHAR(255) NULL,
svnr VARCHAR(64) NULL,
email VARCHAR(191) NULL,
phone VARCHAR(64) NULL,
co_insured TINYINT(1) NOT NULL DEFAULT 0,
place_id BINARY(16) NULL,
nationality_id BINARY(16) NULL,
insurance_patient_data_id BINARY(16) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
KEY idx_patient_data_opc_id (opc_id),
KEY idx_patient_data_place_id (place_id),
KEY idx_patient_data_nationality_id (nationality_id),
KEY idx_patient_data_insurance_patient_data_id (insurance_patient_data_id),
KEY idx_patient_data_deleted_at (deleted_at),
CONSTRAINT fk_patient_data_insurance_patient_data
FOREIGN KEY (insurance_patient_data_id) REFERENCES insurance_patient_data (id)
ON UPDATE CASCADE ON DELETE SET NULL
);
-- +goose Down
DROP TABLE IF EXISTS patient_data;
DROP TABLE IF EXISTS insurance_patient_data;

View File

@@ -0,0 +1,28 @@
-- +goose Up
-- Create places table
CREATE TABLE IF NOT EXISTS places (
id BINARY(16) NOT NULL PRIMARY KEY,
state VARCHAR(255) NULL,
post_code VARCHAR(32) NULL,
location VARCHAR(255) NOT NULL,
street VARCHAR(255) NULL,
no VARCHAR(50) NULL,
country_code VARCHAR(10) NULL,
country_name VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
KEY idx_places_location (location),
KEY idx_places_state (state),
KEY idx_places_post_code (post_code),
KEY idx_places_country_code (country_code),
KEY idx_places_deleted_at (deleted_at)
);
-- +goose Down
DROP TABLE IF EXISTS places;

View File

@@ -0,0 +1,26 @@
CREATE TABLE IF NOT EXISTS reserve_acs (
id BINARY(16) PRIMARY KEY,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
helicopter_id BINARY(16) NOT NULL,
inspection_id BINARY(16) NOT NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
CONSTRAINT chk_reserve_ac_status CHECK (status IN ('pending', 'approved', 'onprogress')),
CONSTRAINT fk_reserve_acs_helicopter FOREIGN KEY (helicopter_id) REFERENCES helicopters(id),
CONSTRAINT fk_reserve_acs_inspection FOREIGN KEY (inspection_id) REFERENCES flight_inspections(id)
);
CREATE INDEX idx_reserve_acs_helicopter_id ON reserve_acs(helicopter_id);
CREATE INDEX idx_reserve_acs_inspection_id ON reserve_acs(inspection_id);
CREATE INDEX idx_reserve_acs_deleted_at ON reserve_acs(deleted_at);
ALTER TABLE flight_inspections DROP FOREIGN KEY fk_flight_inspections_helicopter;
DROP INDEX idx_flight_inspections_helicopter_id ON flight_inspections;
DROP INDEX idx_flight_inspections_operation_id ON flight_inspections;
DROP INDEX idx_flight_inspections_helicopter_date ON flight_inspections;
ALTER TABLE flight_inspections DROP COLUMN helicopter_id;
ALTER TABLE flight_inspections DROP COLUMN operation_id;

View File

@@ -0,0 +1,23 @@
CREATE TABLE IF NOT EXISTS flights (
id BINARY(16) PRIMARY KEY,
mission_code VARCHAR(64) NOT NULL,
mission_type VARCHAR(32) NOT NULL,
date DATE NOT NULL,
duty_roster_id BINARY(16) NULL,
reserve_ac_id BINARY(16) NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
CONSTRAINT fk_flights_reserve_ac FOREIGN KEY (reserve_ac_id) REFERENCES reserve_acs(id),
CONSTRAINT chk_flights_mission_type CHECK (mission_type IN ('hems', 'cat', 'spo', 'nco'))
);
CREATE INDEX idx_flights_mission_code ON flights(mission_code);
CREATE INDEX idx_flights_mission_type ON flights(mission_type);
CREATE INDEX idx_flights_date ON flights(date);
CREATE INDEX idx_flights_duty_roster_id ON flights(duty_roster_id);
CREATE INDEX idx_flights_reserve_ac_id ON flights(reserve_ac_id);
CREATE INDEX idx_flights_deleted_at ON flights(deleted_at);

View File

@@ -0,0 +1,41 @@
CREATE TABLE IF NOT EXISTS helicopter_files (
id BINARY(16) PRIMARY KEY,
section VARCHAR(64) NOT NULL,
helicopter_id BINARY(16) NOT NULL,
file_attachment_id BINARY(16) NOT NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
CONSTRAINT chk_helicopter_files_section CHECK (
section IN (
'before_first_flight_inspection',
'flight_preparation_and_wb',
'after_last_flight_inspection'
)
),
CONSTRAINT fk_helicopter_files_helicopter FOREIGN KEY (helicopter_id) REFERENCES helicopters(id),
CONSTRAINT fk_helicopter_files_attachment FOREIGN KEY (file_attachment_id) REFERENCES attachments(id)
);
CREATE INDEX idx_helicopter_files_section ON helicopter_files(section);
CREATE INDEX idx_helicopter_files_helicopter_id ON helicopter_files(helicopter_id);
CREATE INDEX idx_helicopter_files_attachment_id ON helicopter_files(file_attachment_id);
CREATE TABLE IF NOT EXISTS flight_inspection_file_checklists (
id BINARY(16) PRIMARY KEY,
is_done TINYINT(1) NOT NULL DEFAULT 0,
helicopter_file_id BINARY(16) NOT NULL,
flight_inspection_id BINARY(16) NOT NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
CONSTRAINT fk_flight_inspection_file_checklists_helicopter_file FOREIGN KEY (helicopter_file_id) REFERENCES helicopter_files(id),
CONSTRAINT fk_flight_inspection_file_checklists_inspection FOREIGN KEY (flight_inspection_id) REFERENCES flight_inspections(id),
CONSTRAINT uq_flight_inspection_file_checklists_inspection_file UNIQUE (flight_inspection_id, helicopter_file_id)
);
CREATE INDEX idx_flight_inspection_file_checklists_file_id ON flight_inspection_file_checklists(helicopter_file_id);
CREATE INDEX idx_flight_inspection_file_checklists_inspection_id ON flight_inspection_file_checklists(flight_inspection_id);
CREATE INDEX idx_flight_inspection_file_checklists_inspection_sorted ON flight_inspection_file_checklists(flight_inspection_id, is_done);

View File

@@ -0,0 +1,35 @@
ALTER TABLE hems_operations
ADD COLUMN IF NOT EXISTS mission_id BINARY(16) NULL;
SET @fk_exists := (
SELECT COUNT(1)
FROM information_schema.table_constraints
WHERE table_schema = DATABASE()
AND table_name = 'hems_operations'
AND constraint_type = 'FOREIGN KEY'
AND constraint_name = 'fk_hems_operations_mission'
);
SET @fk_sql := IF(
@fk_exists = 0,
'ALTER TABLE hems_operations ADD CONSTRAINT fk_hems_operations_mission FOREIGN KEY (mission_id) REFERENCES missions(id) ON UPDATE CASCADE ON DELETE SET NULL',
'SELECT 1'
);
PREPARE stmt_fk FROM @fk_sql;
EXECUTE stmt_fk;
DEALLOCATE PREPARE stmt_fk;
SET @idx_exists := (
SELECT COUNT(1)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'hems_operations'
AND index_name = 'uidx_hems_operations_mission_id'
);
SET @idx_sql := IF(
@idx_exists = 0,
'ALTER TABLE hems_operations ADD UNIQUE INDEX uidx_hems_operations_mission_id (mission_id)',
'SELECT 1'
);
PREPARE stmt_idx FROM @idx_sql;
EXECUTE stmt_idx;
DEALLOCATE PREPARE stmt_idx;

View File

@@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS missions (
id BINARY(16) PRIMARY KEY,
flight_id BINARY(16) NOT NULL,
type VARCHAR(20) NOT NULL,
created_at DATETIME NULL,
created_by BINARY(16) NULL,
updated_at DATETIME NULL,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
CONSTRAINT fk_missions_flight FOREIGN KEY (flight_id) REFERENCES flights(id) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT chk_missions_type CHECK (type IN ('CAT', 'SPO', 'NCO', 'HEMS'))
);
CREATE UNIQUE INDEX uidx_missions_flight_id ON missions(flight_id);
CREATE INDEX idx_missions_type ON missions(type);
CREATE INDEX idx_missions_deleted_at ON missions(deleted_at);

View File

@@ -0,0 +1,2 @@
ALTER TABLE reserve_acs DROP INDEX idx_reserve_acs_inspection_id;
ALTER TABLE reserve_acs ADD UNIQUE INDEX uidx_reserve_acs_inspection_id (inspection_id);

View File

@@ -0,0 +1,17 @@
ALTER TABLE helicopter_files DROP CHECK chk_helicopter_files_section;
UPDATE helicopter_files
SET section = 'bfi'
WHERE section = 'before_first_flight_inspection';
UPDATE helicopter_files
SET section = 'fpwb'
WHERE section = 'flight_preparation_and_wb';
UPDATE helicopter_files
SET section = 'afi'
WHERE section = 'after_last_flight_inspection';
ALTER TABLE helicopter_files
ADD CONSTRAINT chk_helicopter_files_section
CHECK (section IN ('bfi', 'fpwb', 'afi'));

View File

@@ -0,0 +1 @@
DROP TABLE IF EXISTS flight_prep_items;

View File

@@ -0,0 +1,14 @@
ALTER TABLE flight_prep_checks DROP FOREIGN KEY fk_flight_prep_checks_flight_prep_item;
ALTER TABLE flight_prep_checks DROP INDEX uk_flight_prep_checks_inspection_item;
ALTER TABLE flight_prep_checks DROP COLUMN flight_prep_item_id;
ALTER TABLE flight_prep_checks DROP COLUMN is_done;
ALTER TABLE flight_prep_checks DROP COLUMN note;
ALTER TABLE flight_prep_checks DROP INDEX idx_flight_prep_checks_flight_inspection_sorted;
ALTER TABLE flight_prep_checks
ADD COLUMN notam_briefing TINYINT(1) NOT NULL DEFAULT 0 AFTER id,
ADD COLUMN weather_briefing TINYINT(1) NOT NULL DEFAULT 0 AFTER notam_briefing,
ADD COLUMN operational_flight_plan TINYINT(1) NOT NULL DEFAULT 0 AFTER weather_briefing;
ALTER TABLE flight_prep_checks
ADD UNIQUE KEY uk_flight_prep_checks_inspection (flight_inspection_id);

View File

@@ -0,0 +1,14 @@
-- +goose Up
ALTER TABLE helicopters
ADD COLUMN foto_attachment_id BINARY(16) NULL,
ADD KEY idx_helicopters_foto_attachment_id (foto_attachment_id),
ADD CONSTRAINT fk_helicopters_foto_attachment
FOREIGN KEY (foto_attachment_id) REFERENCES attachments(id)
ON UPDATE CASCADE
ON DELETE SET NULL;
-- +goose Down
ALTER TABLE helicopters
DROP FOREIGN KEY fk_helicopters_foto_attachment,
DROP KEY idx_helicopters_foto_attachment_id,
DROP COLUMN foto_attachment_id;

View File

@@ -0,0 +1,16 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS master_setting_values (
setting_key VARCHAR(120) NOT NULL PRIMARY KEY,
value TEXT NOT NULL,
is_encrypted TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
KEY idx_master_setting_values_updated_at (updated_at),
KEY idx_master_setting_values_is_encrypted (is_encrypted)
);
-- +goose Down
DROP TABLE IF EXISTS master_setting_values;

View File

@@ -0,0 +1,14 @@
-- +goose Up
ALTER TABLE users
ADD COLUMN image_attachment_id BINARY(16) NULL,
ADD KEY idx_users_image_attachment_id (image_attachment_id),
ADD CONSTRAINT fk_users_image_attachment
FOREIGN KEY (image_attachment_id) REFERENCES attachments(id)
ON UPDATE CASCADE
ON DELETE SET NULL;
-- +goose Down
ALTER TABLE users
DROP FOREIGN KEY fk_users_image_attachment,
DROP KEY idx_users_image_attachment_id,
DROP COLUMN image_attachment_id;

View File

@@ -0,0 +1,8 @@
ALTER TABLE file_files
ADD COLUMN thumbnail_mime_type VARCHAR(255) NULL AFTER etag,
ADD COLUMN thumbnail_size_bytes BIGINT UNSIGNED NULL AFTER thumbnail_mime_type,
ADD COLUMN thumbnail_bucket VARCHAR(128) NULL AFTER thumbnail_size_bytes,
ADD COLUMN thumbnail_object_key VARCHAR(512) NULL AFTER thumbnail_bucket,
ADD COLUMN thumbnail_object_version VARCHAR(128) NULL AFTER thumbnail_object_key,
ADD COLUMN thumbnail_etag VARCHAR(128) NULL AFTER thumbnail_object_version,
ADD UNIQUE KEY uq_file_files_thumbnail_object_key (thumbnail_object_key);

View File

@@ -0,0 +1,13 @@
UPDATE file_files
SET
thumbnail_mime_type = NULLIF(TRIM(thumbnail_mime_type), ''),
thumbnail_bucket = NULLIF(TRIM(thumbnail_bucket), ''),
thumbnail_object_key = NULLIF(TRIM(thumbnail_object_key), ''),
thumbnail_object_version = NULLIF(TRIM(thumbnail_object_version), ''),
thumbnail_etag = NULLIF(TRIM(thumbnail_etag), '')
WHERE
COALESCE(TRIM(thumbnail_mime_type), '') = ''
OR COALESCE(TRIM(thumbnail_bucket), '') = ''
OR COALESCE(TRIM(thumbnail_object_key), '') = ''
OR COALESCE(TRIM(thumbnail_object_version), '') = ''
OR COALESCE(TRIM(thumbnail_etag), '') = '';

View File

@@ -0,0 +1,7 @@
-- +goose Up
ALTER TABLE helicopters
ADD COLUMN aog_reason TEXT NULL AFTER air_on_ground;
-- +goose Down
ALTER TABLE helicopters
DROP COLUMN aog_reason;

View File

@@ -0,0 +1,31 @@
-- Backfill checklist rows for existing reserve AC records.
-- This fixes historical gaps where checklist rows were not inserted.
INSERT INTO flight_inspection_file_checklists (
id,
is_done,
helicopter_file_id,
flight_inspection_id,
created_at,
created_by,
updated_at,
updated_by
)
SELECT
UUID_TO_BIN(UUID()) AS id,
0 AS is_done,
hf.id AS helicopter_file_id,
ra.inspection_id AS flight_inspection_id,
UTC_TIMESTAMP(3) AS created_at,
ra.created_by AS created_by,
UTC_TIMESTAMP(3) AS updated_at,
ra.updated_by AS updated_by
FROM reserve_acs ra
JOIN helicopter_files hf
ON hf.helicopter_id = ra.helicopter_id
AND hf.section IN ('bfi', 'fpwb')
LEFT JOIN flight_inspection_file_checklists fck
ON fck.flight_inspection_id = ra.inspection_id
AND fck.helicopter_file_id = hf.id
WHERE ra.deleted_at IS NULL
AND fck.id IS NULL;

View File

@@ -0,0 +1,52 @@
-- Remove legacy aircraft_file_id from flight_inspection_file_checklists.
-- Current app writes helicopter_file_id; keeping aircraft_file_id as NOT NULL
-- causes inserts to fail with:
-- Error 1364 (HY000): Field 'aircraft_file_id' doesn't have a default value
SET @schema_name := DATABASE();
SELECT COUNT(*) INTO @has_legacy_fk
FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspection_file_checklists'
AND CONSTRAINT_TYPE = 'FOREIGN KEY'
AND CONSTRAINT_NAME = 'fk_flight_inspection_file_checklists_aircraft_file';
SET @drop_legacy_fk_sql := IF(
@has_legacy_fk > 0,
'ALTER TABLE flight_inspection_file_checklists DROP FOREIGN KEY fk_flight_inspection_file_checklists_aircraft_file',
'SELECT 1'
);
PREPARE stmt_drop_legacy_fk FROM @drop_legacy_fk_sql;
EXECUTE stmt_drop_legacy_fk;
DEALLOCATE PREPARE stmt_drop_legacy_fk;
SELECT COUNT(*) INTO @has_legacy_index
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspection_file_checklists'
AND INDEX_NAME = 'fk_flight_inspection_file_checklists_aircraft_file';
SET @drop_legacy_index_sql := IF(
@has_legacy_index > 0,
'ALTER TABLE flight_inspection_file_checklists DROP INDEX fk_flight_inspection_file_checklists_aircraft_file',
'SELECT 1'
);
PREPARE stmt_drop_legacy_index FROM @drop_legacy_index_sql;
EXECUTE stmt_drop_legacy_index;
DEALLOCATE PREPARE stmt_drop_legacy_index;
SELECT COUNT(*) INTO @has_legacy_column
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspection_file_checklists'
AND COLUMN_NAME = 'aircraft_file_id';
SET @drop_legacy_column_sql := IF(
@has_legacy_column > 0,
'ALTER TABLE flight_inspection_file_checklists DROP COLUMN aircraft_file_id',
'SELECT 1'
);
PREPARE stmt_drop_legacy_column FROM @drop_legacy_column_sql;
EXECUTE stmt_drop_legacy_column;
DEALLOCATE PREPARE stmt_drop_legacy_column;

View File

@@ -0,0 +1,9 @@
-- +goose Up
ALTER TABLE bases
ADD COLUMN sortkey INT NULL AFTER position,
ADD KEY idx_bases_sortkey (sortkey);
-- +goose Down
ALTER TABLE bases
DROP KEY idx_bases_sortkey,
DROP COLUMN sortkey;

View File

@@ -0,0 +1,15 @@
-- +goose Up
ALTER TABLE bmds
ADD COLUMN note VARCHAR(255) NULL AFTER country_name,
ADD COLUMN sortkey INT NULL AFTER country_name,
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER sortkey,
ADD KEY idx_bmds_sortkey (sortkey),
ADD KEY idx_bmds_is_active (is_active);
-- +goose Down
ALTER TABLE bmds
DROP KEY idx_bmds_sortkey,
DROP KEY idx_bmds_is_active,
DROP COLUMN sortkey,
DROP COLUMN note,
DROP COLUMN is_active;

View File

@@ -0,0 +1,51 @@
-- +goose Up
SET @bases_exists := (
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'bases'
);
SET @col_default_shift_time_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'default_shift_time'
);
SET @drop_default_shift_time_sql := IF(
@bases_exists > 0 AND @col_default_shift_time_exists > 0,
'ALTER TABLE bases DROP COLUMN default_shift_time',
'SELECT 1'
);
PREPARE stmt_drop_default_shift_time FROM @drop_default_shift_time_sql;
EXECUTE stmt_drop_default_shift_time;
DEALLOCATE PREPARE stmt_drop_default_shift_time;
-- +goose Down
SET @bases_exists := (
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'bases'
);
SET @col_default_shift_time_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'bases'
AND column_name = 'default_shift_time'
);
SET @add_default_shift_time_sql := IF(
@bases_exists > 0 AND @col_default_shift_time_exists = 0,
'ALTER TABLE bases ADD COLUMN default_shift_time VARCHAR(64) NULL AFTER default_shift_end',
'SELECT 1'
);
PREPARE stmt_add_default_shift_time FROM @add_default_shift_time_sql;
EXECUTE stmt_add_default_shift_time;
DEALLOCATE PREPARE stmt_add_default_shift_time;

View File

@@ -0,0 +1,9 @@
-- +goose Up
ALTER TABLE facilities
ADD COLUMN sortkey INT NULL AFTER type,
ADD KEY idx_facilities_sortkey (sortkey);
-- +goose Down
ALTER TABLE facilities
DROP KEY idx_facilities_sortkey,
DROP COLUMN sortkey;

View File

@@ -0,0 +1,15 @@
-- +goose Up
ALTER TABLE forces_present
ADD COLUMN note VARCHAR(255) NULL AFTER description,
ADD COLUMN sortkey INT NULL AFTER name,
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER sortkey,
ADD KEY idx_forces_present_sortkey (sortkey),
ADD KEY idx_forces_present_is_active (is_active);
-- +goose Down
ALTER TABLE forces_present
DROP KEY idx_forces_present_sortkey,
DROP KEY idx_forces_present_is_active,
DROP COLUMN sortkey,
DROP COLUMN note,
DROP COLUMN is_active;

View File

@@ -0,0 +1,13 @@
-- +goose Up
ALTER TABLE health_insurance_companies
ADD COLUMN sortkey INT NULL AFTER name,
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER sortkey,
ADD KEY idx_health_insurance_companies_sortkey (sortkey),
ADD KEY idx_health_insurance_companies_is_active (is_active);
-- +goose Down
ALTER TABLE health_insurance_companies
DROP KEY idx_health_insurance_companies_sortkey,
DROP KEY idx_health_insurance_companies_is_active,
DROP COLUMN sortkey,
DROP COLUMN is_active;

View File

@@ -0,0 +1,9 @@
-- +goose Up
ALTER TABLE helicopters
ADD COLUMN sortkey INT NULL AFTER type,
ADD KEY idx_helicopters_sortkey (sortkey);
-- +goose Down
ALTER TABLE helicopters
DROP KEY idx_helicopters_sortkey,
DROP COLUMN sortkey;

View File

@@ -0,0 +1,73 @@
-- +goose Up
ALTER TABLE hospitals
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE icaos
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE health_insurance_companies
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE federal_states
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE lands
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE nationalities
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE pilot_profiles
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE doctor_profiles
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE air_rescuer_profiles
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE technician_profiles
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE flight_assistant_profiles
ADD COLUMN IF NOT EXISTS note TEXT NULL;
ALTER TABLE staff_profiles
ADD COLUMN IF NOT EXISTS note TEXT NULL;
-- +goose Down
ALTER TABLE hospitals
DROP COLUMN IF EXISTS note;
ALTER TABLE icaos
DROP COLUMN IF EXISTS note;
ALTER TABLE health_insurance_companies
DROP COLUMN IF EXISTS note;
ALTER TABLE federal_states
DROP COLUMN IF EXISTS note;
ALTER TABLE lands
DROP COLUMN IF EXISTS note;
ALTER TABLE nationalities
DROP COLUMN IF EXISTS note;
ALTER TABLE pilot_profiles
DROP COLUMN IF EXISTS note;
ALTER TABLE doctor_profiles
DROP COLUMN IF EXISTS note;
ALTER TABLE air_rescuer_profiles
DROP COLUMN IF EXISTS note;
ALTER TABLE technician_profiles
DROP COLUMN IF EXISTS note;
ALTER TABLE flight_assistant_profiles
DROP COLUMN IF EXISTS note;
ALTER TABLE staff_profiles
DROP COLUMN IF EXISTS note;

View File

@@ -0,0 +1,80 @@
-- +goose Up
SET @table_hospitals_exists := (
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'hospitals'
);
SET @col_hospitals_is_active_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'hospitals'
AND column_name = 'is_active'
);
SET @add_hospitals_is_active_sql := IF(
@table_hospitals_exists > 0 AND @col_hospitals_is_active_exists = 0,
'ALTER TABLE hospitals ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER note',
'SELECT 1'
);
PREPARE stmt_add_hospitals_is_active FROM @add_hospitals_is_active_sql;
EXECUTE stmt_add_hospitals_is_active;
DEALLOCATE PREPARE stmt_add_hospitals_is_active;
SET @idx_hospitals_is_active_exists := (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'hospitals'
AND index_name = 'idx_hospitals_is_active'
);
SET @add_idx_hospitals_is_active_sql := IF(
@table_hospitals_exists > 0 AND @idx_hospitals_is_active_exists = 0,
'ALTER TABLE hospitals ADD INDEX idx_hospitals_is_active (is_active)',
'SELECT 1'
);
PREPARE stmt_add_idx_hospitals_is_active FROM @add_idx_hospitals_is_active_sql;
EXECUTE stmt_add_idx_hospitals_is_active;
DEALLOCATE PREPARE stmt_add_idx_hospitals_is_active;
-- +goose Down
SET @idx_hospitals_is_active_exists := (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'hospitals'
AND index_name = 'idx_hospitals_is_active'
);
SET @drop_idx_hospitals_is_active_sql := IF(
@idx_hospitals_is_active_exists > 0,
'ALTER TABLE hospitals DROP INDEX idx_hospitals_is_active',
'SELECT 1'
);
PREPARE stmt_drop_idx_hospitals_is_active FROM @drop_idx_hospitals_is_active_sql;
EXECUTE stmt_drop_idx_hospitals_is_active;
DEALLOCATE PREPARE stmt_drop_idx_hospitals_is_active;
SET @col_hospitals_is_active_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'hospitals'
AND column_name = 'is_active'
);
SET @drop_hospitals_is_active_sql := IF(
@col_hospitals_is_active_exists > 0,
'ALTER TABLE hospitals DROP COLUMN is_active',
'SELECT 1'
);
PREPARE stmt_drop_hospitals_is_active FROM @drop_hospitals_is_active_sql;
EXECUTE stmt_drop_hospitals_is_active;
DEALLOCATE PREPARE stmt_drop_hospitals_is_active;

View File

@@ -0,0 +1,13 @@
-- +goose Up
ALTER TABLE icaos
ADD COLUMN sortkey INT NULL AFTER icao_code,
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER sortkey,
ADD KEY idx_icaos_sortkey (sortkey),
ADD KEY idx_icaos_is_active (is_active);
-- +goose Down
ALTER TABLE icaos
DROP KEY idx_icaos_sortkey,
DROP KEY idx_icaos_is_active,
DROP COLUMN sortkey,
DROP COLUMN is_active;

View File

@@ -0,0 +1,17 @@
-- +goose Up
ALTER TABLE lands
ADD COLUMN IF NOT EXISTS is_active TINYINT(1) NOT NULL DEFAULT 1,
ADD KEY idx_lands_is_active (is_active);
ALTER TABLE opcs
ADD COLUMN IF NOT EXISTS is_active TINYINT(1) NOT NULL DEFAULT 1,
ADD KEY idx_opcs_is_active (is_active);
-- +goose Down
ALTER TABLE lands
DROP KEY idx_lands_is_active,
DROP COLUMN IF EXISTS is_active;
ALTER TABLE opcs
DROP KEY idx_opcs_is_active,
DROP COLUMN IF EXISTS is_active;

View File

@@ -0,0 +1,15 @@
-- +goose Up
ALTER TABLE medicines
ADD COLUMN note VARCHAR(255) NULL AFTER name,
ADD COLUMN sortkey INT NULL AFTER name,
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER sortkey,
ADD KEY idx_medicines_sortkey (sortkey),
ADD KEY idx_medicines_is_active (is_active);
-- +goose Down
ALTER TABLE medicines
DROP KEY idx_medicines_sortkey,
DROP KEY idx_medicines_is_active,
DROP COLUMN sortkey,
DROP COLUMN note,
DROP COLUMN is_active;

View File

@@ -0,0 +1,11 @@
-- +goose Up
ALTER TABLE opcs
ADD COLUMN note VARCHAR(255) NULL AFTER description,
ADD COLUMN sortkey INT NULL AFTER name,
ADD KEY idx_opcs_sortkey (sortkey);
-- +goose Down
ALTER TABLE opcs
DROP KEY idx_opcs_sortkey,
DROP COLUMN sortkey,
DROP COLUMN note;

View File

@@ -0,0 +1,43 @@
-- +goose Up
-- Remove deprecated places table and patient_data.place_id relation.
ALTER TABLE patient_data
DROP FOREIGN KEY fk_patient_data_place;
ALTER TABLE patient_data
DROP COLUMN place_id;
DROP TABLE IF EXISTS places;
-- +goose Down
-- Recreate places table and patient_data.place_id column.
CREATE TABLE IF NOT EXISTS places (
id BINARY(16) NOT NULL PRIMARY KEY,
state VARCHAR(255) NULL,
post_code VARCHAR(32) NULL,
location VARCHAR(255) NOT NULL,
street VARCHAR(255) NULL,
no VARCHAR(50) NULL,
country_code VARCHAR(10) NULL,
country_name VARCHAR(255) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
KEY idx_places_location (location),
KEY idx_places_state (state),
KEY idx_places_post_code (post_code),
KEY idx_places_country_code (country_code),
KEY idx_places_deleted_at (deleted_at)
);
ALTER TABLE patient_data
ADD COLUMN place_id BINARY(16) NULL AFTER co_insured,
ADD KEY idx_patient_data_place_id (place_id),
ADD CONSTRAINT fk_patient_data_place
FOREIGN KEY (place_id) REFERENCES places (id)
ON UPDATE CASCADE ON DELETE SET NULL;

View File

@@ -0,0 +1,9 @@
-- +goose Up
ALTER TABLE users
ADD COLUMN sortkey INT NULL AFTER timezone,
ADD KEY idx_users_sortkey (sortkey);
-- +goose Down
ALTER TABLE users
DROP KEY idx_users_sortkey,
DROP COLUMN sortkey;

View File

@@ -0,0 +1,15 @@
-- +goose Up
ALTER TABLE vocations
ADD COLUMN note VARCHAR(255) NULL AFTER description,
ADD COLUMN sortkey INT NULL AFTER name,
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER sortkey,
ADD KEY idx_vocations_sortkey (sortkey),
ADD KEY idx_vocations_is_active (is_active);
-- +goose Down
ALTER TABLE vocations
DROP KEY idx_vocations_sortkey,
DROP KEY idx_vocations_is_active,
DROP COLUMN sortkey,
DROP COLUMN note,
DROP COLUMN is_active;

View File

@@ -0,0 +1,13 @@
-- +goose Up
ALTER TABLE federal_states
ADD COLUMN IF NOT EXISTS sortkey INT NULL AFTER name,
ADD COLUMN IF NOT EXISTS is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER note,
ADD KEY idx_federal_states_sortkey (sortkey),
ADD KEY idx_federal_states_is_active (is_active);
-- +goose Down
ALTER TABLE federal_states
DROP KEY idx_federal_states_sortkey,
DROP KEY idx_federal_states_is_active,
DROP COLUMN IF EXISTS sortkey,
DROP COLUMN IF EXISTS is_active;

View File

@@ -0,0 +1,9 @@
-- +goose Up
ALTER TABLE hospitals
ADD COLUMN sortkey INT NULL AFTER hospital_name,
ADD KEY idx_hospitals_sortkey (sortkey);
-- +goose Down
ALTER TABLE hospitals
DROP KEY idx_hospitals_sortkey,
DROP COLUMN sortkey;

View File

@@ -0,0 +1,9 @@
-- +goose Up
ALTER TABLE lands
ADD COLUMN sortkey INT NULL AFTER name,
ADD KEY idx_lands_sortkey (sortkey);
-- +goose Down
ALTER TABLE lands
DROP KEY idx_lands_sortkey,
DROP COLUMN sortkey;

View File

@@ -0,0 +1,13 @@
-- +goose Up
ALTER TABLE nationalities
ADD COLUMN sortkey INT NULL AFTER name,
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER note,
ADD KEY idx_nationalities_sortkey (sortkey),
ADD KEY idx_nationalities_is_active (is_active);
-- +goose Down
ALTER TABLE nationalities
DROP KEY idx_nationalities_is_active,
DROP KEY idx_nationalities_sortkey,
DROP COLUMN is_active,
DROP COLUMN sortkey;

View File

@@ -0,0 +1,30 @@
-- +goose Up
ALTER TABLE file_files
ADD COLUMN lifecycle_status VARCHAR(32) NOT NULL DEFAULT 'temp' AFTER status,
ADD COLUMN attached_at DATETIME(6) NULL AFTER lifecycle_status,
ADD COLUMN orphaned_at DATETIME(6) NULL AFTER attached_at,
ADD COLUMN lifecycle_deleted_at DATETIME(6) NULL AFTER orphaned_at,
ADD KEY idx_file_files_lifecycle_status_orphaned (lifecycle_status, orphaned_at);
UPDATE file_files
SET lifecycle_status = CASE
WHEN deleted_at IS NOT NULL THEN 'deleted'
WHEN status = 'ready' AND name_slot = 'live' THEN 'active'
ELSE 'temp'
END,
attached_at = CASE
WHEN status = 'ready' AND name_slot = 'live' AND deleted_at IS NULL THEN COALESCE(attached_at, updated_at)
ELSE attached_at
END,
lifecycle_deleted_at = CASE
WHEN deleted_at IS NOT NULL THEN COALESCE(lifecycle_deleted_at, deleted_at)
ELSE lifecycle_deleted_at
END;
-- +goose Down
ALTER TABLE file_files
DROP KEY idx_file_files_lifecycle_status_orphaned,
DROP COLUMN lifecycle_deleted_at,
DROP COLUMN orphaned_at,
DROP COLUMN attached_at,
DROP COLUMN lifecycle_status;

View File

@@ -0,0 +1,2 @@
ALTER TABLE flights
MODIFY COLUMN mission_type VARCHAR(32) NULL;

View File

@@ -0,0 +1,31 @@
SET @has_old_rosters := (
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hems_duty_rosters'
);
SET @has_new_rosters := (
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'duty_rosters'
);
SET @sql_rosters := IF(@has_old_rosters = 1 AND @has_new_rosters = 0,
'RENAME TABLE hems_duty_rosters TO duty_rosters',
'SELECT 1'
);
PREPARE stmt_rosters FROM @sql_rosters;
EXECUTE stmt_rosters;
DEALLOCATE PREPARE stmt_rosters;
SET @has_old_crews := (
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hems_duty_roster_crews'
);
SET @has_new_crews := (
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'duty_roster_crews'
);
SET @sql_crews := IF(@has_old_crews = 1 AND @has_new_crews = 0,
'RENAME TABLE hems_duty_roster_crews TO duty_roster_crews',
'SELECT 1'
);
PREPARE stmt_crews FROM @sql_crews;
EXECUTE stmt_crews;
DEALLOCATE PREPARE stmt_crews;

View File

@@ -0,0 +1,135 @@
-- +goose Up
-- Normalize legacy HEMS duty roster artifacts into neutral duty roster naming.
-- 1) Rename legacy tables when old name exists and new name does not.
SET @has_old_rosters := (
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hems_duty_rosters'
);
SET @has_new_rosters := (
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'duty_rosters'
);
SET @sql_rename_rosters := IF(@has_old_rosters = 1 AND @has_new_rosters = 0,
'RENAME TABLE hems_duty_rosters TO duty_rosters',
'SELECT 1'
);
PREPARE stmt_rename_rosters FROM @sql_rename_rosters;
EXECUTE stmt_rename_rosters;
DEALLOCATE PREPARE stmt_rename_rosters;
SET @has_old_crews := (
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hems_duty_roster_crews'
);
SET @has_new_crews := (
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'duty_roster_crews'
);
SET @sql_rename_crews := IF(@has_old_crews = 1 AND @has_new_crews = 0,
'RENAME TABLE hems_duty_roster_crews TO duty_roster_crews',
'SELECT 1'
);
PREPARE stmt_rename_crews FROM @sql_rename_crews;
EXECUTE stmt_rename_crews;
DEALLOCATE PREPARE stmt_rename_crews;
-- 2) Rename legacy header column.
SET @has_duty_rosters := (
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'duty_rosters'
);
SET @has_hems_base_id := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'duty_rosters'
AND COLUMN_NAME = 'hems_base_id'
);
SET @has_base_id := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'duty_rosters'
AND COLUMN_NAME = 'base_id'
);
SET @sql_rename_base_col := IF(@has_duty_rosters = 1 AND @has_hems_base_id = 1 AND @has_base_id = 0,
'ALTER TABLE duty_rosters RENAME COLUMN hems_base_id TO base_id',
'SELECT 1'
);
PREPARE stmt_rename_base_col FROM @sql_rename_base_col;
EXECUTE stmt_rename_base_col;
DEALLOCATE PREPARE stmt_rename_base_col;
-- 3) Ensure confirm_at exists on normalized crews table.
SET @has_confirm_at_new_crews := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'duty_roster_crews'
AND COLUMN_NAME = 'confirm_at'
);
SET @sql_add_confirm_at_new_crews := IF(@has_new_crews = 1 AND @has_confirm_at_new_crews = 0,
'ALTER TABLE duty_roster_crews ADD COLUMN confirm_at DATETIME NULL AFTER email',
'SELECT 1'
);
PREPARE stmt_add_confirm_at_new_crews FROM @sql_add_confirm_at_new_crews;
EXECUTE stmt_add_confirm_at_new_crews;
DEALLOCATE PREPARE stmt_add_confirm_at_new_crews;
-- 4) If legacy crew table still exists, keep it compatible too.
SET @has_confirm_at_old_crews := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'hems_duty_roster_crews'
AND COLUMN_NAME = 'confirm_at'
);
SET @sql_add_confirm_at_old_crews := IF(@has_old_crews = 1 AND @has_confirm_at_old_crews = 0,
'ALTER TABLE hems_duty_roster_crews ADD COLUMN confirm_at DATETIME NULL AFTER email',
'SELECT 1'
);
PREPARE stmt_add_confirm_at_old_crews FROM @sql_add_confirm_at_old_crews;
EXECUTE stmt_add_confirm_at_old_crews;
DEALLOCATE PREPARE stmt_add_confirm_at_old_crews;
-- 5) Normalize legacy FK references to duty_rosters where needed.
SET @fk_roster_crews_ref := (
SELECT COALESCE(MAX(kcu.REFERENCED_TABLE_NAME), '')
FROM information_schema.TABLE_CONSTRAINTS tc
JOIN information_schema.KEY_COLUMN_USAGE kcu
ON tc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA
AND tc.TABLE_NAME = kcu.TABLE_NAME
AND tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
WHERE tc.CONSTRAINT_SCHEMA = DATABASE()
AND tc.TABLE_NAME = 'roster_crews'
AND tc.CONSTRAINT_TYPE = 'FOREIGN KEY'
AND tc.CONSTRAINT_NAME = 'fk_roster_crews_roster'
);
SET @sql_rewire_roster_crews_fk := IF(@has_new_rosters = 1 AND @fk_roster_crews_ref = 'hems_duty_rosters',
'ALTER TABLE roster_crews DROP FOREIGN KEY fk_roster_crews_roster, ADD CONSTRAINT fk_roster_crews_roster FOREIGN KEY (roster_id) REFERENCES duty_rosters(id)',
'SELECT 1'
);
PREPARE stmt_rewire_roster_crews_fk FROM @sql_rewire_roster_crews_fk;
EXECUTE stmt_rewire_roster_crews_fk;
DEALLOCATE PREPARE stmt_rewire_roster_crews_fk;
SET @fk_other_persons_ref := (
SELECT COALESCE(MAX(kcu.REFERENCED_TABLE_NAME), '')
FROM information_schema.TABLE_CONSTRAINTS tc
JOIN information_schema.KEY_COLUMN_USAGE kcu
ON tc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA
AND tc.TABLE_NAME = kcu.TABLE_NAME
AND tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
WHERE tc.CONSTRAINT_SCHEMA = DATABASE()
AND tc.TABLE_NAME = 'duty_roster_other_persons'
AND tc.CONSTRAINT_TYPE = 'FOREIGN KEY'
AND tc.CONSTRAINT_NAME = 'fk_duty_roster_other_persons_roster'
);
SET @sql_rewire_other_persons_fk := IF(@has_new_rosters = 1 AND @fk_other_persons_ref = 'hems_duty_rosters',
'ALTER TABLE duty_roster_other_persons DROP FOREIGN KEY fk_duty_roster_other_persons_roster, ADD CONSTRAINT fk_duty_roster_other_persons_roster FOREIGN KEY (roster_id) REFERENCES duty_rosters(id)',
'SELECT 1'
);
PREPARE stmt_rewire_other_persons_fk FROM @sql_rewire_other_persons_fk;
EXECUTE stmt_rewire_other_persons_fk;
DEALLOCATE PREPARE stmt_rewire_other_persons_fk;
-- +goose Down
-- Intentionally no-op: legacy normalization is one-way to keep schema stable.
SELECT 1;

View File

@@ -0,0 +1,2 @@
ALTER TABLE users
ADD COLUMN sso_email VARCHAR(191) NULL AFTER email;

View File

@@ -0,0 +1,116 @@
-- Cleanup legacy hems_bases table after consolidation to unified bases table.
-- Safe/idempotent behavior:
-- 1) If only hems_bases exists -> rename to bases.
-- 2) If both tables exist -> copy missing rows from hems_bases into bases as HEMS category.
-- 3) Drop hems_bases afterwards when possible.
SET @schema := DATABASE();
SET @has_hems_bases := (
SELECT COUNT(*)
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = 'hems_bases'
);
SET @has_bases := (
SELECT COUNT(*)
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = 'bases'
);
-- Ensure HEMS category exists when unified bases table is present.
SET @has_base_categories := (
SELECT COUNT(*)
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = 'base_categories'
);
SET @sql_seed_hems_category := IF(@has_bases = 1 AND @has_base_categories = 1,
'INSERT INTO base_categories (id, `key`, name, created_at, updated_at)
SELECT UUID_TO_BIN(UUID(), true), ''hems'', ''HEMS Base'', UTC_TIMESTAMP(3), UTC_TIMESTAMP(3)
WHERE NOT EXISTS (
SELECT 1 FROM base_categories WHERE `key` = ''hems''
)',
'SELECT 1'
);
PREPARE stmt FROM @sql_seed_hems_category;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- Case A: legacy only => rename directly.
SET @sql_rename_hems_bases := IF(@has_hems_bases = 1 AND @has_bases = 0,
'RENAME TABLE hems_bases TO bases',
'SELECT 1'
);
PREPARE stmt FROM @sql_rename_hems_bases;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- Re-evaluate after possible rename.
SET @has_hems_bases := (
SELECT COUNT(*)
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = 'hems_bases'
);
SET @has_bases := (
SELECT COUNT(*)
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = 'bases'
);
-- Case B: both exist => backfill rows from legacy table into unified table.
SET @sql_backfill := IF(@has_hems_bases = 1 AND @has_bases = 1,
'INSERT INTO bases (
id, base, base_category_id, base_abbreviation, address,
landline_number, mobile_number, email,
position, sms_alert, checklist, leg_time,
default_shift_time, utc, foto,
dry, control_center, dul, visible,
notes, is_active,
created_by, updated_by, created_at, updated_at
)
SELECT
hb.id,
hb.base,
bc.id,
hb.base_abbreviation,
hb.address,
hb.landline_number,
hb.mobile_number,
hb.email,
hb.position,
hb.sms_alert,
hb.checklist,
hb.leg_time,
hb.default_shift_time,
hb.utc,
hb.foto,
hb.dry,
hb.control_center,
hb.dul,
hb.visible,
hb.notes,
hb.is_active,
hb.created_by,
hb.updated_by,
hb.created_at,
hb.updated_at
FROM hems_bases hb
LEFT JOIN base_categories bc ON bc.`key` = ''hems''
LEFT JOIN bases b ON b.id = hb.id
WHERE b.id IS NULL',
'SELECT 1'
);
PREPARE stmt FROM @sql_backfill;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- Drop legacy table if still present.
SET @sql_drop_hems_bases := IF(@has_hems_bases = 1,
'DROP TABLE hems_bases',
'SELECT 1'
);
PREPARE stmt FROM @sql_drop_hems_bases;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,36 @@
-- Add canonical duty_roster permissions and map existing role grants from legacy hems_duty_roster keys.
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID(), true), 'Create Duty Roster', 'duty_roster.create', 'Create duty roster', 0, UTC_TIMESTAMP(), UTC_TIMESTAMP()
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'duty_roster.create');
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID(), true), 'Read Duty Roster', 'duty_roster.read', 'Read duty roster', 0, UTC_TIMESTAMP(), UTC_TIMESTAMP()
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'duty_roster.read');
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID(), true), 'Update Duty Roster', 'duty_roster.update', 'Update duty roster', 0, UTC_TIMESTAMP(), UTC_TIMESTAMP()
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'duty_roster.update');
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID(), true), 'Delete Duty Roster', 'duty_roster.delete', 'Delete duty roster', 0, UTC_TIMESTAMP(), UTC_TIMESTAMP()
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'duty_roster.delete');
INSERT INTO role_permissions (id, role_id, permission_id, created_at, updated_at)
SELECT
UUID_TO_BIN(UUID(), true),
rp.role_id,
p_new.id,
UTC_TIMESTAMP(),
UTC_TIMESTAMP()
FROM role_permissions rp
JOIN permissions p_old ON p_old.id = rp.permission_id
JOIN permissions p_new ON p_new.`key` = CONCAT('duty_roster.', SUBSTRING_INDEX(p_old.`key`, '.', -1))
LEFT JOIN role_permissions rp_existing ON rp_existing.role_id = rp.role_id AND rp_existing.permission_id = p_new.id
WHERE p_old.`key` IN (
'hems_duty_roster.create',
'hems_duty_roster.read',
'hems_duty_roster.update',
'hems_duty_roster.delete'
)
AND rp_existing.id IS NULL;

View File

@@ -0,0 +1,59 @@
-- Purge legacy hems_duty_roster.* permissions.
-- Safe flow:
-- 1) Ensure canonical duty_roster.* permissions exist.
-- 2) Grant canonical permission to any role that still has legacy permission.
-- 3) Remove legacy role_permissions rows.
-- 4) Remove legacy permission rows.
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID(), true), 'Create Duty Roster', 'duty_roster.create', 'Create duty roster', 0, UTC_TIMESTAMP(), UTC_TIMESTAMP()
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'duty_roster.create');
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID(), true), 'Read Duty Roster', 'duty_roster.read', 'Read duty roster', 0, UTC_TIMESTAMP(), UTC_TIMESTAMP()
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'duty_roster.read');
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID(), true), 'Update Duty Roster', 'duty_roster.update', 'Update duty roster', 0, UTC_TIMESTAMP(), UTC_TIMESTAMP()
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'duty_roster.update');
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID(), true), 'Delete Duty Roster', 'duty_roster.delete', 'Delete duty roster', 0, UTC_TIMESTAMP(), UTC_TIMESTAMP()
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'duty_roster.delete');
INSERT INTO role_permissions (id, role_id, permission_id, created_at, updated_at)
SELECT
UUID_TO_BIN(UUID(), true),
rp.role_id,
p_new.id,
UTC_TIMESTAMP(),
UTC_TIMESTAMP()
FROM role_permissions rp
JOIN permissions p_old ON p_old.id = rp.permission_id
JOIN permissions p_new ON p_new.`key` = CONCAT('duty_roster.', SUBSTRING_INDEX(p_old.`key`, '.', -1))
LEFT JOIN role_permissions rp_existing ON rp_existing.role_id = rp.role_id AND rp_existing.permission_id = p_new.id
WHERE p_old.`key` IN (
'hems_duty_roster.create',
'hems_duty_roster.read',
'hems_duty_roster.update',
'hems_duty_roster.delete'
)
AND rp_existing.id IS NULL;
DELETE rp
FROM role_permissions rp
JOIN permissions p ON p.id = rp.permission_id
WHERE p.`key` IN (
'hems_duty_roster.create',
'hems_duty_roster.read',
'hems_duty_roster.update',
'hems_duty_roster.delete'
);
DELETE FROM permissions
WHERE `key` IN (
'hems_duty_roster.create',
'hems_duty_roster.read',
'hems_duty_roster.update',
'hems_duty_roster.delete'
);

View File

@@ -0,0 +1,9 @@
-- Allow multiple duty roster headers on the same base and duty date.
-- Previous schema enforced unique(base_id, duty_date) via idx_roster_base_date.
ALTER TABLE duty_rosters
DROP INDEX idx_roster_base_date;
CREATE INDEX idx_roster_base_date
ON duty_rosters (base_id, duty_date);

View File

@@ -0,0 +1,169 @@
-- +goose Up
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'federal_states' AND COLUMN_NAME = 'description'
),
'ALTER TABLE federal_states DROP COLUMN description',
'SELECT 1'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'federal_states' AND COLUMN_NAME = 'note'
),
'ALTER TABLE federal_states DROP COLUMN note',
'SELECT 1'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lands' AND COLUMN_NAME = 'description'
),
'ALTER TABLE lands DROP COLUMN description',
'SELECT 1'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lands' AND COLUMN_NAME = 'note'
),
'ALTER TABLE lands DROP COLUMN note',
'SELECT 1'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'nationalities' AND COLUMN_NAME = 'description'
),
'ALTER TABLE nationalities DROP COLUMN description',
'SELECT 1'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'nationalities' AND COLUMN_NAME = 'note'
),
'ALTER TABLE nationalities DROP COLUMN note',
'SELECT 1'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- +goose Down
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'federal_states' AND COLUMN_NAME = 'description'
),
'SELECT 1',
'ALTER TABLE federal_states ADD COLUMN description VARCHAR(256) NULL AFTER sortkey'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'federal_states' AND COLUMN_NAME = 'note'
),
'SELECT 1',
'ALTER TABLE federal_states ADD COLUMN note TEXT NULL AFTER description'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lands' AND COLUMN_NAME = 'description'
),
'SELECT 1',
'ALTER TABLE lands ADD COLUMN description VARCHAR(256) NULL AFTER sortkey'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'lands' AND COLUMN_NAME = 'note'
),
'SELECT 1',
'ALTER TABLE lands ADD COLUMN note TEXT NULL AFTER description'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'nationalities' AND COLUMN_NAME = 'description'
),
'SELECT 1',
'ALTER TABLE nationalities ADD COLUMN description VARCHAR(256) NULL AFTER sortkey'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @sql := (
SELECT IF(
EXISTS (
SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'nationalities' AND COLUMN_NAME = 'note'
),
'SELECT 1',
'ALTER TABLE nationalities ADD COLUMN note TEXT NULL AFTER description'
)
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,265 @@
-- +goose Up
INSERT INTO lands (id, name, land_iso_code, sortkey, is_active, created_at, updated_at)
SELECT UUID_TO_BIN(UUID()), src.name, src.iso_code, src.sortkey, 1, NOW(3), NOW(3)
FROM (
SELECT 'AC' AS iso_code, 'Ascension' AS name, 1 AS sortkey
UNION ALL SELECT 'AD', 'Andorra', 2
UNION ALL SELECT 'AE', 'Vereinigte Arabische Emirate', 3
UNION ALL SELECT 'AF', 'Afghanistan', 4
UNION ALL SELECT 'AG', 'Antigua und Barbuda', 5
UNION ALL SELECT 'AI', 'Anguilla', 6
UNION ALL SELECT 'AL', 'Albanien', 7
UNION ALL SELECT 'AM', 'Armenien', 8
UNION ALL SELECT 'AN', 'Niederländische Antillen', 9
UNION ALL SELECT 'AO', 'Angola', 10
UNION ALL SELECT 'AQ', 'Antarktis', 11
UNION ALL SELECT 'AR', 'Argentinien', 12
UNION ALL SELECT 'AS', 'Amerikanisch Samoa', 13
UNION ALL SELECT 'AT', 'Österreich', 14
UNION ALL SELECT 'AU', 'Australien', 15
UNION ALL SELECT 'AW', 'Aruba', 16
UNION ALL SELECT 'AX', 'Aland', 17
UNION ALL SELECT 'AZ', 'Aserbaidschan', 18
UNION ALL SELECT 'BA', 'Bosnien-Herzegowina', 19
UNION ALL SELECT 'BB', 'Barbados', 20
UNION ALL SELECT 'BD', 'Bangladesch', 21
UNION ALL SELECT 'BE', 'Belgien', 22
UNION ALL SELECT 'BF', 'Burkina Faso', 23
UNION ALL SELECT 'BG', 'Bulgarien', 24
UNION ALL SELECT 'BH', 'Bahrain', 25
UNION ALL SELECT 'BJ', 'Benin', 26
UNION ALL SELECT 'BL', 'Burundi', 27
UNION ALL SELECT 'BM', 'Bermuda', 28
UNION ALL SELECT 'BN', 'Brunei Darussalam', 29
UNION ALL SELECT 'BO', 'Bolivien', 30
UNION ALL SELECT 'BR', 'Brasilien', 31
UNION ALL SELECT 'BS', 'Bahamas', 32
UNION ALL SELECT 'BT', 'Bhutan', 33
UNION ALL SELECT 'BV', 'Bouvetinseln', 34
UNION ALL SELECT 'BW', 'Botsuana', 35
UNION ALL SELECT 'BY', 'Belarus', 36
UNION ALL SELECT 'BZ', 'Belize ', 37
UNION ALL SELECT 'CA', 'Kanada', 38
UNION ALL SELECT 'CC', 'Kokosinseln', 39
UNION ALL SELECT 'CD', 'Demokratische Republik Kongo', 40
UNION ALL SELECT 'CF', 'Zentralafrikanische Republik', 41
UNION ALL SELECT 'CG', 'Kongo', 42
UNION ALL SELECT 'CH', 'Schweiz', 43
UNION ALL SELECT 'CI', 'Elfenbeinküste', 44
UNION ALL SELECT 'CK', 'Cookinseln', 45
UNION ALL SELECT 'CL', 'Chile', 46
UNION ALL SELECT 'CM', 'Kamerun', 47
UNION ALL SELECT 'CO', 'Kolumbien', 48
UNION ALL SELECT 'CR', 'Costa Rica', 49
UNION ALL SELECT 'CU', 'Kuba', 50
UNION ALL SELECT 'CV', 'Kap Verde', 51
UNION ALL SELECT 'CX', 'Weihnachtsinsel', 52
UNION ALL SELECT 'CY', 'Zypern', 53
UNION ALL SELECT 'CZ', 'Tschechische Republik', 54
UNION ALL SELECT 'DB', 'Dubai', 55
UNION ALL SELECT 'DE', 'Deutschland', 56
UNION ALL SELECT 'DJ', 'Dschibuti', 57
UNION ALL SELECT 'DK', 'Dänemark', 58
UNION ALL SELECT 'DM', 'Dominica', 59
UNION ALL SELECT 'DO', 'Dominikanische Republik', 60
UNION ALL SELECT 'DZ', 'Algerien', 61
UNION ALL SELECT 'EC', 'Ecuador', 62
UNION ALL SELECT 'EE', 'Estland', 63
UNION ALL SELECT 'EG', 'Ägypten', 64
UNION ALL SELECT 'EH', 'Western Sahara', 65
UNION ALL SELECT 'ER', 'Eritrea', 66
UNION ALL SELECT 'ES', 'Spanien', 67
UNION ALL SELECT 'ET', 'Äthiopien', 68
UNION ALL SELECT 'FI', 'Finnland', 69
UNION ALL SELECT 'FJ', 'Fidschi', 70
UNION ALL SELECT 'FK', 'Falklandinseln', 71
UNION ALL SELECT 'FM', 'Mikronesien', 72
UNION ALL SELECT 'FO', 'Färöer', 73
UNION ALL SELECT 'FR', 'Frankreich', 74
UNION ALL SELECT 'GA', 'Gabun', 75
UNION ALL SELECT 'GB', 'Vereinigtes Königreich', 76
UNION ALL SELECT 'GD', 'Grenada', 77
UNION ALL SELECT 'GE', 'Georgien', 78
UNION ALL SELECT 'GF', 'Französische Guyana', 79
UNION ALL SELECT 'GG', 'Guernsey', 80
UNION ALL SELECT 'GH', 'Ghana', 81
UNION ALL SELECT 'GI', 'Gibraltar', 82
UNION ALL SELECT 'GL', 'Grönland', 83
UNION ALL SELECT 'GM', 'Gambia', 84
UNION ALL SELECT 'GN', 'Guinea', 85
UNION ALL SELECT 'GP', 'Guadeloupe', 86
UNION ALL SELECT 'GQ', 'Äquatorialguinea', 87
UNION ALL SELECT 'GR', 'Griechenland', 88
UNION ALL SELECT 'GS', 'South Georgia and the South Sandwich Islands', 89
UNION ALL SELECT 'GT', 'Guatemala', 90
UNION ALL SELECT 'GU', 'Guam', 91
UNION ALL SELECT 'GW', 'Guinea-Bissau', 92
UNION ALL SELECT 'GY', 'Guyana', 93
UNION ALL SELECT 'HK', 'Hong Kong', 94
UNION ALL SELECT 'HM', 'Heard Island and McDonald Islands', 95
UNION ALL SELECT 'HN', 'Honduras', 96
UNION ALL SELECT 'HR', 'Kroatien', 97
UNION ALL SELECT 'HT', 'Haiti', 98
UNION ALL SELECT 'HU', 'Ungarn', 99
UNION ALL SELECT 'ID', 'Indonesien', 100
UNION ALL SELECT 'IE', 'Irland', 101
UNION ALL SELECT 'IL', 'Israel', 102
UNION ALL SELECT 'IM', 'Isle of Man', 103
UNION ALL SELECT 'IN', 'Indien', 104
UNION ALL SELECT 'IO', 'Br.Territ./Ind.Ozean', 105
UNION ALL SELECT 'IQ', 'Irak', 106
UNION ALL SELECT 'IR', 'Iran', 107
UNION ALL SELECT 'IS', 'Island', 108
UNION ALL SELECT 'IT', 'Italien', 109
UNION ALL SELECT 'JE', 'Jersey', 110
UNION ALL SELECT 'JM', 'Jamaika', 111
UNION ALL SELECT 'JO', 'Jordanien', 112
UNION ALL SELECT 'JP', 'Japan', 113
UNION ALL SELECT 'KE', 'Kenien', 114
UNION ALL SELECT 'KG', 'Kirgisistan', 115
UNION ALL SELECT 'KH', 'Kambodscha', 116
UNION ALL SELECT 'KI', 'Kiribati', 117
UNION ALL SELECT 'KM', 'Komoren', 118
UNION ALL SELECT 'KN', 'St. Kittis und Nevis', 119
UNION ALL SELECT 'KO', 'Kosovo', 120
UNION ALL SELECT 'KP', 'Korea, Demo. VR', 121
UNION ALL SELECT 'KR', 'Korea', 122
UNION ALL SELECT 'KW', 'Kuwait', 123
UNION ALL SELECT 'KY', 'Kaimaninseln', 124
UNION ALL SELECT 'KZ', 'Kasachstan', 125
UNION ALL SELECT 'LA', 'Laos', 126
UNION ALL SELECT 'LB', 'Libanon', 127
UNION ALL SELECT 'LC', 'Sankt Lucia', 128
UNION ALL SELECT 'LI', 'Liechtenstein', 129
UNION ALL SELECT 'LK', 'Sri Lanka', 130
UNION ALL SELECT 'LR', 'Liberia', 131
UNION ALL SELECT 'LS', 'Lesotho', 132
UNION ALL SELECT 'LT', 'Litauen', 133
UNION ALL SELECT 'LU', 'Luxemburg', 134
UNION ALL SELECT 'LV', 'Lettland', 135
UNION ALL SELECT 'LY', 'Lybien', 136
UNION ALL SELECT 'MA', 'Marokko', 137
UNION ALL SELECT 'MC', 'Monaco', 138
UNION ALL SELECT 'MD', 'Moldova', 139
UNION ALL SELECT 'ME', 'Montenegro', 140
UNION ALL SELECT 'MG', 'Madagaskar', 141
UNION ALL SELECT 'MH', 'Marshallinseln', 142
UNION ALL SELECT 'MK', 'Mazedonien', 143
UNION ALL SELECT 'ML', 'Mali', 144
UNION ALL SELECT 'MM', 'Myanmar', 145
UNION ALL SELECT 'MN', 'Mongolei', 146
UNION ALL SELECT 'MO', 'Macau', 147
UNION ALL SELECT 'MP', 'Marianen', 148
UNION ALL SELECT 'MQ', 'Martinique', 149
UNION ALL SELECT 'MR', 'Mauretanien', 150
UNION ALL SELECT 'MS', 'Montserrat', 151
UNION ALL SELECT 'MT', 'Malta', 152
UNION ALL SELECT 'MU', 'Mauritius', 153
UNION ALL SELECT 'MV', 'Malediven', 154
UNION ALL SELECT 'MW', 'Malawi', 155
UNION ALL SELECT 'MX', 'Mexiko', 156
UNION ALL SELECT 'MY', 'Malaysia', 157
UNION ALL SELECT 'MZ', 'Mosambik', 158
UNION ALL SELECT 'NA', 'Namibia', 159
UNION ALL SELECT 'NC', 'Neukaledonien', 160
UNION ALL SELECT 'NE', 'Niger', 161
UNION ALL SELECT 'NF', 'Norfolkins', 162
UNION ALL SELECT 'NG', 'Nigeria', 163
UNION ALL SELECT 'NI', 'Nicaragua', 164
UNION ALL SELECT 'NL', 'Niederlande', 165
UNION ALL SELECT 'NO', 'Norwegen', 166
UNION ALL SELECT 'NP', 'Nepal', 167
UNION ALL SELECT 'NR', 'Nauru', 168
UNION ALL SELECT 'NU', 'Niue', 169
UNION ALL SELECT 'NZ', 'Neuseeland', 170
UNION ALL SELECT 'O', 'unbekannt', 171
UNION ALL SELECT 'OM', 'Oman', 172
UNION ALL SELECT 'PA', 'Panama', 173
UNION ALL SELECT 'PE', 'Peru', 174
UNION ALL SELECT 'PF', 'Französchisch Polynesien', 175
UNION ALL SELECT 'PG', 'Papua Neuguinea', 176
UNION ALL SELECT 'PH', 'Philippinen', 177
UNION ALL SELECT 'PK', 'Pakistan', 178
UNION ALL SELECT 'PL', 'Polen', 179
UNION ALL SELECT 'PM', 'St Pierre und Miquelon', 180
UNION ALL SELECT 'PN', 'Pitkern', 181
UNION ALL SELECT 'PR', 'Puerto Rico', 182
UNION ALL SELECT 'PS', 'Palestina', 183
UNION ALL SELECT 'PT', 'Portugal', 184
UNION ALL SELECT 'PW', 'Palau', 185
UNION ALL SELECT 'PY', 'Paraguay', 186
UNION ALL SELECT 'Q', 'Katar', 187
UNION ALL SELECT 'RE', 'Reunion', 188
UNION ALL SELECT 'RM', 'San Marino', 189
UNION ALL SELECT 'RO', 'Rumänien', 190
UNION ALL SELECT 'RS', 'Serbien', 191
UNION ALL SELECT 'RU', 'Russische Föderation', 192
UNION ALL SELECT 'RW', 'Ruanda', 193
UNION ALL SELECT 'SA', 'Saudi Arabien', 194
UNION ALL SELECT 'SB', 'Salomonen', 195
UNION ALL SELECT 'SC', 'Seychellen', 196
UNION ALL SELECT 'SD', 'Sudan', 197
UNION ALL SELECT 'SE', 'Schweden', 198
UNION ALL SELECT 'SG', 'Singapur', 199
UNION ALL SELECT 'SH', 'Sankt Helena', 200
UNION ALL SELECT 'SI', 'Slowenien', 201
UNION ALL SELECT 'SJ', 'Svalbard', 202
UNION ALL SELECT 'SK', 'Slowakei', 203
UNION ALL SELECT 'SL', 'Sierra Leone', 204
UNION ALL SELECT 'SN', 'Senegal', 205
UNION ALL SELECT 'SO', 'Somalia', 206
UNION ALL SELECT 'SR', 'Suriname', 207
UNION ALL SELECT 'ST', 'Sao Tome und Pricipe', 208
UNION ALL SELECT 'SV', 'El Salvador', 209
UNION ALL SELECT 'SY', 'Syrien', 210
UNION ALL SELECT 'SZ', 'Swasiland', 211
UNION ALL SELECT 'TA', 'Tristan da Cunha', 212
UNION ALL SELECT 'TC', 'Turks und Caicosinseln', 213
UNION ALL SELECT 'TD', 'Tschad', 214
UNION ALL SELECT 'TF', 'French Southern and Antarctic Lands', 215
UNION ALL SELECT 'TG', 'Togo', 216
UNION ALL SELECT 'TH', 'Thailand', 217
UNION ALL SELECT 'TI', 'Timor Leste', 218
UNION ALL SELECT 'TJ', 'Tadschikistan', 219
UNION ALL SELECT 'TK', 'Tokelau', 220
UNION ALL SELECT 'TL', 'Ost-Timor', 221
UNION ALL SELECT 'TM', 'Turkmenistan', 222
UNION ALL SELECT 'TN', 'Tunesien', 223
UNION ALL SELECT 'TO', 'Tonga', 224
UNION ALL SELECT 'TP', 'Osttimor', 225
UNION ALL SELECT 'TR', 'Türkei', 226
UNION ALL SELECT 'TT', 'Trinidad und Tobago', 227
UNION ALL SELECT 'TV', 'Tuvalu', 228
UNION ALL SELECT 'TW', 'Taiwan', 229
UNION ALL SELECT 'TZ', 'Tansania', 230
UNION ALL SELECT 'UA', 'Ukraine', 231
UNION ALL SELECT 'UG', 'Uganda', 232
UNION ALL SELECT 'UK', 'Großbritannien', 233
UNION ALL SELECT 'UM', 'Baker Island', 234
UNION ALL SELECT 'US', 'Vereinigte Staaten (USA)', 235
UNION ALL SELECT 'UY', 'Uruguay', 236
UNION ALL SELECT 'UZ', 'Usbekistan', 237
UNION ALL SELECT 'V', 'Vatikanstadt', 238
UNION ALL SELECT 'VC', 'St. Vincent udn Grenadinen', 239
UNION ALL SELECT 'VE', 'Venezuela', 240
UNION ALL SELECT 'VG', 'Jungferninseln', 241
UNION ALL SELECT 'VI', 'US Jungferninseln', 242
UNION ALL SELECT 'VN', 'Vietnam', 243
UNION ALL SELECT 'VR', 'China', 244
UNION ALL SELECT 'VU', 'Vanuatu', 245
UNION ALL SELECT 'WF', 'Wallis und Futuna', 246
UNION ALL SELECT 'WS', 'Samoa', 247
UNION ALL SELECT 'X', 'Staatenlos', 248
UNION ALL SELECT 'YE', 'Jemen', 249
UNION ALL SELECT 'YT', 'Mayotte', 250
UNION ALL SELECT 'YU', 'ehem. Jugoslawien', 251
UNION ALL SELECT 'ZA', 'Südafrika', 252
UNION ALL SELECT 'ZM', 'Sambia', 253
UNION ALL SELECT 'ZW', 'Simbabwe', 254
) AS src
LEFT JOIN lands l ON l.land_iso_code = src.iso_code AND l.deleted_at IS NULL
WHERE l.id IS NULL;
-- +goose Down
-- Intentionally no-op to avoid deleting existing production reference data.
SELECT 1;

View File

@@ -0,0 +1,23 @@
CREATE TABLE IF NOT EXISTS user_microsoft_oauth_tokens (
id BINARY(16) NOT NULL,
user_id BINARY(16) NOT NULL,
provider VARCHAR(32) NOT NULL,
tenant_id VARCHAR(128) NOT NULL,
microsoft_object_id VARCHAR(191) NOT NULL,
microsoft_subject VARCHAR(191) NOT NULL,
refresh_token_encrypted BLOB NOT NULL,
access_token_encrypted BLOB NULL,
id_token_encrypted BLOB NULL,
scope TEXT NULL,
token_type VARCHAR(32) NULL,
access_token_expires_at DATETIME(3) NULL,
refresh_token_rotated_at DATETIME(3) NULL,
created_at DATETIME(3) NULL,
created_by BINARY(16) NULL,
updated_at DATETIME(3) NULL,
updated_by BINARY(16) NULL,
PRIMARY KEY (id),
UNIQUE KEY ux_user_ms_oauth_user_provider (user_id, provider),
KEY idx_user_ms_oauth_tenant_id (tenant_id),
CONSTRAINT fk_user_ms_oauth_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);

View File

@@ -0,0 +1,22 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS base_contact_roles (
id BINARY(16) NOT NULL,
base_id BINARY(16) NOT NULL,
contact_id BINARY(16) NOT NULL,
role_code VARCHAR(64) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
PRIMARY KEY (id),
UNIQUE KEY uq_base_contact_roles_base_contact_role (base_id, contact_id, role_code),
KEY idx_base_contact_roles_base_id (base_id),
KEY idx_base_contact_roles_contact_id (contact_id),
KEY idx_base_contact_roles_role_code (role_code),
CONSTRAINT fk_base_contact_roles_base FOREIGN KEY (base_id) REFERENCES bases(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_base_contact_roles_contact FOREIGN KEY (contact_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT chk_base_contact_roles_role_code CHECK (role_code IN ('responsible_flight_rescuer', 'chief_physician_in_charge'))
);
-- +goose Down
DROP TABLE IF EXISTS base_contact_roles;

View File

@@ -0,0 +1,8 @@
ALTER TABLE helicopter_files
ADD COLUMN position INT NOT NULL DEFAULT 1 AFTER section,
ADD KEY idx_helicopter_files_position (position);
UPDATE helicopter_files
SET position = 1
WHERE position IS NULL OR position <= 0;

View File

@@ -0,0 +1,124 @@
-- Drop legacy completion metadata columns from flight_inspections.
-- Completion is derived from stage tables (before/prep/after) instead.
SET @schema_name := DATABASE();
-- before_flight_completed_at
SELECT COUNT(*) INTO @has_before_completed_at
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspections'
AND COLUMN_NAME = 'before_flight_completed_at';
SET @drop_before_completed_at_sql := IF(
@has_before_completed_at > 0,
'ALTER TABLE flight_inspections DROP COLUMN before_flight_completed_at',
'SELECT 1'
);
PREPARE stmt_drop_before_completed_at FROM @drop_before_completed_at_sql;
EXECUTE stmt_drop_before_completed_at;
DEALLOCATE PREPARE stmt_drop_before_completed_at;
-- before_flight_completed_by
SELECT COUNT(*) INTO @has_before_completed_by
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspections'
AND COLUMN_NAME = 'before_flight_completed_by';
SET @drop_before_completed_by_sql := IF(
@has_before_completed_by > 0,
'ALTER TABLE flight_inspections DROP COLUMN before_flight_completed_by',
'SELECT 1'
);
PREPARE stmt_drop_before_completed_by FROM @drop_before_completed_by_sql;
EXECUTE stmt_drop_before_completed_by;
DEALLOCATE PREPARE stmt_drop_before_completed_by;
-- flight_prep_completed_at
SELECT COUNT(*) INTO @has_prep_completed_at
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspections'
AND COLUMN_NAME = 'flight_prep_completed_at';
SET @drop_prep_completed_at_sql := IF(
@has_prep_completed_at > 0,
'ALTER TABLE flight_inspections DROP COLUMN flight_prep_completed_at',
'SELECT 1'
);
PREPARE stmt_drop_prep_completed_at FROM @drop_prep_completed_at_sql;
EXECUTE stmt_drop_prep_completed_at;
DEALLOCATE PREPARE stmt_drop_prep_completed_at;
-- flight_prep_completed_by
SELECT COUNT(*) INTO @has_prep_completed_by
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspections'
AND COLUMN_NAME = 'flight_prep_completed_by';
SET @drop_prep_completed_by_sql := IF(
@has_prep_completed_by > 0,
'ALTER TABLE flight_inspections DROP COLUMN flight_prep_completed_by',
'SELECT 1'
);
PREPARE stmt_drop_prep_completed_by FROM @drop_prep_completed_by_sql;
EXECUTE stmt_drop_prep_completed_by;
DEALLOCATE PREPARE stmt_drop_prep_completed_by;
-- after_flight_completed_at
SELECT COUNT(*) INTO @has_after_completed_at
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspections'
AND COLUMN_NAME = 'after_flight_completed_at';
SET @drop_after_completed_at_sql := IF(
@has_after_completed_at > 0,
'ALTER TABLE flight_inspections DROP COLUMN after_flight_completed_at',
'SELECT 1'
);
PREPARE stmt_drop_after_completed_at FROM @drop_after_completed_at_sql;
EXECUTE stmt_drop_after_completed_at;
DEALLOCATE PREPARE stmt_drop_after_completed_at;
-- after_flight_completed_by
SELECT COUNT(*) INTO @has_after_completed_by
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspections'
AND COLUMN_NAME = 'after_flight_completed_by';
SET @drop_after_completed_by_sql := IF(
@has_after_completed_by > 0,
'ALTER TABLE flight_inspections DROP COLUMN after_flight_completed_by',
'SELECT 1'
);
PREPARE stmt_drop_after_completed_by FROM @drop_after_completed_by_sql;
EXECUTE stmt_drop_after_completed_by;
DEALLOCATE PREPARE stmt_drop_after_completed_by;
-- final_completed_at
SELECT COUNT(*) INTO @has_final_completed_at
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspections'
AND COLUMN_NAME = 'final_completed_at';
SET @drop_final_completed_at_sql := IF(
@has_final_completed_at > 0,
'ALTER TABLE flight_inspections DROP COLUMN final_completed_at',
'SELECT 1'
);
PREPARE stmt_drop_final_completed_at FROM @drop_final_completed_at_sql;
EXECUTE stmt_drop_final_completed_at;
DEALLOCATE PREPARE stmt_drop_final_completed_at;
-- final_completed_by
SELECT COUNT(*) INTO @has_final_completed_by
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'flight_inspections'
AND COLUMN_NAME = 'final_completed_by';
SET @drop_final_completed_by_sql := IF(
@has_final_completed_by > 0,
'ALTER TABLE flight_inspections DROP COLUMN final_completed_by',
'SELECT 1'
);
PREPARE stmt_drop_final_completed_by FROM @drop_final_completed_by_sql;
EXECUTE stmt_drop_final_completed_by;
DEALLOCATE PREPARE stmt_drop_final_completed_by;

View File

@@ -0,0 +1,119 @@
-- +goose Up
-- Remove deprecated nationality module storage.
SET @drop_fk_nationality := (
SELECT IF(
EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'patient_data'
AND COLUMN_NAME = 'nationality_id'
AND REFERENCED_TABLE_NAME IS NOT NULL
),
(
SELECT CONCAT('ALTER TABLE patient_data DROP FOREIGN KEY ', CONSTRAINT_NAME)
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'patient_data'
AND COLUMN_NAME = 'nationality_id'
AND REFERENCED_TABLE_NAME IS NOT NULL
LIMIT 1
),
'SELECT 1'
)
);
PREPARE stmt_drop_fk_nationality FROM @drop_fk_nationality;
EXECUTE stmt_drop_fk_nationality;
DEALLOCATE PREPARE stmt_drop_fk_nationality;
SET @drop_idx_nationality := (
SELECT IF(
EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'patient_data'
AND INDEX_NAME = 'idx_patient_data_nationality_id'
),
'ALTER TABLE patient_data DROP INDEX idx_patient_data_nationality_id',
'SELECT 1'
)
);
PREPARE stmt_drop_idx_nationality FROM @drop_idx_nationality;
EXECUTE stmt_drop_idx_nationality;
DEALLOCATE PREPARE stmt_drop_idx_nationality;
SET @drop_col_nationality := (
SELECT IF(
EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'patient_data'
AND COLUMN_NAME = 'nationality_id'
),
'ALTER TABLE patient_data DROP COLUMN nationality_id',
'SELECT 1'
)
);
PREPARE stmt_drop_col_nationality FROM @drop_col_nationality;
EXECUTE stmt_drop_col_nationality;
DEALLOCATE PREPARE stmt_drop_col_nationality;
DROP TABLE IF EXISTS nationalities;
-- +goose Down
-- Recreate minimal nationality storage.
CREATE TABLE IF NOT EXISTS nationalities (
id BINARY(16) NOT NULL PRIMARY KEY,
land_id BINARY(16) NULL,
name VARCHAR(128) NOT NULL,
sortkey INT NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
KEY idx_nationalities_land_id (land_id),
KEY idx_nationalities_sortkey (sortkey),
KEY idx_nationalities_is_active (is_active),
KEY idx_nationalities_deleted_at (deleted_at)
);
SET @add_col_nationality := (
SELECT IF(
EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'patient_data'
AND COLUMN_NAME = 'nationality_id'
),
'SELECT 1',
'ALTER TABLE patient_data ADD COLUMN nationality_id BINARY(16) NULL AFTER co_insured'
)
);
PREPARE stmt_add_col_nationality FROM @add_col_nationality;
EXECUTE stmt_add_col_nationality;
DEALLOCATE PREPARE stmt_add_col_nationality;
SET @add_idx_nationality := (
SELECT IF(
EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'patient_data'
AND INDEX_NAME = 'idx_patient_data_nationality_id'
),
'SELECT 1',
'ALTER TABLE patient_data ADD KEY idx_patient_data_nationality_id (nationality_id)'
)
);
PREPARE stmt_add_idx_nationality FROM @add_idx_nationality;
EXECUTE stmt_add_idx_nationality;
DEALLOCATE PREPARE stmt_add_idx_nationality;

View File

@@ -0,0 +1,17 @@
-- +goose Up
ALTER TABLE icaos
ADD COLUMN land_id BINARY(16) NULL AFTER federal_state_id,
ADD KEY idx_icaos_land_id (land_id);
ALTER TABLE health_insurance_companies
ADD COLUMN land_id BINARY(16) NULL AFTER sortkey,
ADD KEY idx_health_insurance_companies_land_id (land_id);
-- +goose Down
ALTER TABLE icaos
DROP KEY idx_icaos_land_id,
DROP COLUMN land_id;
ALTER TABLE health_insurance_companies
DROP KEY idx_health_insurance_companies_land_id,
DROP COLUMN land_id;

View File

@@ -0,0 +1,48 @@
-- +goose Up
-- Remove BMD module artifacts: role-permission links, permissions, and table.
DELETE rp
FROM role_permissions rp
INNER JOIN permissions p ON p.id = rp.permission_id
WHERE p.`key` IN ('bmd.create', 'bmd.read', 'bmd.update', 'bmd.delete');
DELETE FROM permissions
WHERE `key` IN ('bmd.create', 'bmd.read', 'bmd.update', 'bmd.delete');
DROP TABLE IF EXISTS bmds;
-- +goose Down
-- Recreate BMD table and baseline permissions (without restoring historical data/links).
CREATE TABLE IF NOT EXISTS bmds (
id BINARY(16) PRIMARY KEY,
country_name VARCHAR(128) NOT NULL,
note VARCHAR(255) NULL,
sortkey INT NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
eu_accession_code SMALLINT NOT NULL,
created_at DATETIME(3) NULL,
created_by BINARY(16) NULL,
updated_at DATETIME(3) NULL,
updated_by BINARY(16) NULL,
deleted_at DATETIME(3) NULL,
deleted_by BINARY(16) NULL,
KEY idx_bmds_sortkey (sortkey),
KEY idx_bmds_is_active (is_active)
);
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID()), 'Create BMD', 'bmd.create', 'Create BMD', 1, UTC_TIMESTAMP(3), UTC_TIMESTAMP(3)
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'bmd.create');
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID()), 'Read BMD', 'bmd.read', 'Read BMD', 0, UTC_TIMESTAMP(3), UTC_TIMESTAMP(3)
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'bmd.read');
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID()), 'Update BMD', 'bmd.update', 'Update BMD', 1, UTC_TIMESTAMP(3), UTC_TIMESTAMP(3)
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'bmd.update');
INSERT INTO permissions (id, name, `key`, description, requires_pin, created_at, updated_at)
SELECT UUID_TO_BIN(UUID()), 'Delete BMD', 'bmd.delete', 'Delete BMD', 1, UTC_TIMESTAMP(3), UTC_TIMESTAMP(3)
WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE `key` = 'bmd.delete');

View File

@@ -0,0 +1,55 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS medicine_groups (
id BINARY(16) NOT NULL,
name VARCHAR(255) NOT NULL,
sortkey INT NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
created_by BINARY(16) NULL,
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
updated_by BINARY(16) NULL,
deleted_at DATETIME(6) NULL,
deleted_by BINARY(16) NULL,
PRIMARY KEY (id),
KEY idx_medicine_groups_is_active (is_active),
KEY idx_medicine_groups_sortkey (sortkey)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS motor_reactions (
id BINARY(16) NOT NULL,
name VARCHAR(255) NOT NULL,
score BIGINT NULL,
sortkey INT NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
created_by BINARY(16) NULL,
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
updated_by BINARY(16) NULL,
deleted_at DATETIME(6) NULL,
deleted_by BINARY(16) NULL,
PRIMARY KEY (id),
KEY idx_motor_reactions_is_active (is_active),
KEY idx_motor_reactions_sortkey (sortkey)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE medicines
ADD COLUMN weight BIGINT NULL AFTER dose,
ADD COLUMN medicine_group_id BINARY(16) NULL AFTER `column`,
ADD COLUMN motor_reaction_id BINARY(16) NULL AFTER medicine_group_id,
ADD KEY idx_medicines_medicine_group_id (medicine_group_id),
ADD KEY idx_medicines_motor_reaction_id (motor_reaction_id),
ADD CONSTRAINT fk_medicines_medicine_group FOREIGN KEY (medicine_group_id) REFERENCES medicine_groups(id) ON UPDATE CASCADE ON DELETE SET NULL,
ADD CONSTRAINT fk_medicines_motor_reaction FOREIGN KEY (motor_reaction_id) REFERENCES motor_reactions(id) ON UPDATE CASCADE ON DELETE SET NULL;
-- +goose Down
ALTER TABLE medicines
DROP FOREIGN KEY fk_medicines_medicine_group,
DROP FOREIGN KEY fk_medicines_motor_reaction,
DROP KEY idx_medicines_medicine_group_id,
DROP KEY idx_medicines_motor_reaction_id,
DROP COLUMN medicine_group_id,
DROP COLUMN motor_reaction_id,
DROP COLUMN weight;
DROP TABLE IF EXISTS motor_reactions;
DROP TABLE IF EXISTS medicine_groups;

View File

@@ -0,0 +1,17 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS medicine_motor_reactions (
medicine_id BINARY(16) NOT NULL,
motor_reaction_id BINARY(16) NOT NULL,
PRIMARY KEY (medicine_id, motor_reaction_id),
KEY idx_mmr_motor_reaction_id (motor_reaction_id),
CONSTRAINT fk_mmr_medicine FOREIGN KEY (medicine_id) REFERENCES medicines(id) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT fk_mmr_motor_reaction FOREIGN KEY (motor_reaction_id) REFERENCES motor_reactions(id) ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT IGNORE INTO medicine_motor_reactions (medicine_id, motor_reaction_id)
SELECT id, motor_reaction_id
FROM medicines
WHERE motor_reaction_id IS NOT NULL;
-- +goose Down
DROP TABLE IF EXISTS medicine_motor_reactions;

View File

@@ -0,0 +1,24 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS user_email_login_otps (
id BINARY(16) NOT NULL,
user_id BINARY(16) NOT NULL,
otp_hash BINARY(32) NOT NULL,
expires_at DATETIME(6) NOT NULL,
used_at DATETIME(6) NULL,
attempt_count INT NOT NULL DEFAULT 0,
max_attempts INT NOT NULL DEFAULT 5,
resend_count INT NOT NULL DEFAULT 1,
last_sent_at DATETIME(6) NOT NULL,
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
created_by BINARY(16) NULL,
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
updated_by BINARY(16) NULL,
PRIMARY KEY (id),
KEY idx_user_email_login_otps_user_id (user_id),
KEY idx_user_email_login_otps_expires_at (expires_at),
KEY idx_user_email_login_otps_used_at (used_at),
CONSTRAINT fk_user_email_login_otps_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- +goose Down
DROP TABLE IF EXISTS user_email_login_otps;

View File

@@ -0,0 +1,3 @@
ALTER TABLE users
MODIFY COLUMN role_id BINARY(16) NULL;

View File

@@ -0,0 +1,22 @@
-- +goose Up
ALTER TABLE lands
ADD UNIQUE KEY uq_lands_land_iso_code (land_iso_code);
-- +goose Down
SET @idx_exists := (
SELECT COUNT(1)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'lands'
AND index_name = 'uq_lands_land_iso_code'
);
SET @drop_sql := IF(
@idx_exists > 0,
'ALTER TABLE lands DROP INDEX uq_lands_land_iso_code',
'SELECT 1'
);
PREPARE stmt FROM @drop_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,4 @@
ALTER TABLE bases
DROP COLUMN IF EXISTS note,
DROP COLUMN IF EXISTS position,
DROP COLUMN IF EXISTS visible;

View File

@@ -0,0 +1,13 @@
-- +goose Up
ALTER TABLE medicine_groups
DROP COLUMN sortkey;
ALTER TABLE motor_reactions
DROP COLUMN sortkey;
-- +goose Down
ALTER TABLE medicine_groups
ADD COLUMN sortkey INT NULL AFTER name;
ALTER TABLE motor_reactions
ADD COLUMN sortkey INT NULL AFTER score;

View File

@@ -0,0 +1,23 @@
-- +goose Up
-- +goose StatementBegin
ALTER TABLE opcs
DROP COLUMN description;
ALTER TABLE forces_present
DROP COLUMN description;
ALTER TABLE vocations
DROP COLUMN description;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
ALTER TABLE opcs
ADD COLUMN description VARCHAR(255) NULL AFTER note;
ALTER TABLE forces_present
ADD COLUMN description VARCHAR(255) NULL AFTER note;
ALTER TABLE vocations
ADD COLUMN description VARCHAR(255) NULL AFTER note;
-- +goose StatementEnd

View File

@@ -0,0 +1,21 @@
-- +goose Up
-- +goose StatementBegin
ALTER TABLE medicine_groups
DROP INDEX idx_medicine_groups_is_active,
DROP COLUMN is_active;
ALTER TABLE motor_reactions
DROP INDEX idx_motor_reactions_is_active,
DROP COLUMN is_active;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
ALTER TABLE medicine_groups
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER name,
ADD KEY idx_medicine_groups_is_active (is_active);
ALTER TABLE motor_reactions
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER score,
ADD KEY idx_motor_reactions_is_active (is_active);
-- +goose StatementEnd

View File

@@ -0,0 +1,14 @@
-- +goose Up
ALTER TABLE duls
ADD COLUMN IF NOT EXISTS date DATE NULL AFTER name;
UPDATE duls
SET date = COALESCE(date, DATE(created_at), CURRENT_DATE())
WHERE date IS NULL;
ALTER TABLE duls
MODIFY COLUMN date DATE NOT NULL;
-- +goose Down
ALTER TABLE duls
DROP COLUMN IF EXISTS date;

View File

@@ -0,0 +1,22 @@
-- +goose Up
CREATE TABLE IF NOT EXISTS duls (
id BINARY(16) NOT NULL,
no BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(128) NOT NULL,
date DATE NOT NULL,
info TEXT NULL,
base_id BINARY(16) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by BINARY(16) NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by BINARY(16) NULL,
deleted_at DATETIME NULL,
deleted_by BINARY(16) NULL,
PRIMARY KEY (id),
UNIQUE KEY uq_duls_no (no),
KEY idx_duls_base_id (base_id),
CONSTRAINT fk_duls_base FOREIGN KEY (base_id) REFERENCES bases(id) ON UPDATE CASCADE ON DELETE RESTRICT
);
-- +goose Down
DROP TABLE IF EXISTS duls;

View File

@@ -0,0 +1,35 @@
-- +goose Up
SET @schema_name := DATABASE();
SELECT COUNT(*) INTO @has_notes
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'reserve_acs'
AND COLUMN_NAME = 'notes';
SET @add_notes_sql := IF(
@has_notes = 0,
'ALTER TABLE reserve_acs ADD COLUMN notes TEXT NULL AFTER base_id',
'SELECT 1'
);
PREPARE stmt_add_notes FROM @add_notes_sql;
EXECUTE stmt_add_notes;
DEALLOCATE PREPARE stmt_add_notes;
-- +goose Down
SET @schema_name := DATABASE();
SELECT COUNT(*) INTO @has_notes
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'reserve_acs'
AND COLUMN_NAME = 'notes';
SET @drop_notes_sql := IF(
@has_notes = 1,
'ALTER TABLE reserve_acs DROP COLUMN notes',
'SELECT 1'
);
PREPARE stmt_drop_notes FROM @drop_notes_sql;
EXECUTE stmt_drop_notes;
DEALLOCATE PREPARE stmt_drop_notes;

View File

@@ -0,0 +1,114 @@
-- +goose Up
-- Align schema for single-request takeover create flow.
-- Only apply additive changes when columns/constraints are missing.
SET @schema_name := DATABASE();
-- reserve_acs.base_id
SELECT COUNT(*) INTO @reserve_acs_has_base_id
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'reserve_acs'
AND COLUMN_NAME = 'base_id';
SET @add_reserve_acs_base_id_sql := IF(
@reserve_acs_has_base_id = 0,
'ALTER TABLE reserve_acs ADD COLUMN base_id BINARY(16) NULL AFTER status',
'SELECT 1'
);
PREPARE stmt_add_reserve_acs_base_id FROM @add_reserve_acs_base_id_sql;
EXECUTE stmt_add_reserve_acs_base_id;
DEALLOCATE PREPARE stmt_add_reserve_acs_base_id;
-- Index reserve_acs.base_id
SELECT COUNT(*) INTO @reserve_acs_has_base_id_idx
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'reserve_acs'
AND INDEX_NAME = 'idx_reserve_acs_base_id';
SET @add_reserve_acs_base_id_idx_sql := IF(
@reserve_acs_has_base_id_idx = 0,
'CREATE INDEX idx_reserve_acs_base_id ON reserve_acs(base_id)',
'SELECT 1'
);
PREPARE stmt_add_reserve_acs_base_id_idx FROM @add_reserve_acs_base_id_idx_sql;
EXECUTE stmt_add_reserve_acs_base_id_idx;
DEALLOCATE PREPARE stmt_add_reserve_acs_base_id_idx;
-- FK reserve_acs.base_id -> bases.id
SELECT COUNT(*) INTO @reserve_acs_has_base_fk
FROM information_schema.TABLE_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = @schema_name
AND TABLE_NAME = 'reserve_acs'
AND CONSTRAINT_NAME = 'fk_reserve_acs_base'
AND CONSTRAINT_TYPE = 'FOREIGN KEY';
SET @add_reserve_acs_base_fk_sql := IF(
@reserve_acs_has_base_fk = 0,
'ALTER TABLE reserve_acs ADD CONSTRAINT fk_reserve_acs_base FOREIGN KEY (base_id) REFERENCES bases(id)',
'SELECT 1'
);
PREPARE stmt_add_reserve_acs_base_fk FROM @add_reserve_acs_base_fk_sql;
EXECUTE stmt_add_reserve_acs_base_fk;
DEALLOCATE PREPARE stmt_add_reserve_acs_base_fk;
-- Optional backfill reserve_acs.base_id from linked flight -> duty_roster.
-- Safe to run repeatedly.
UPDATE reserve_acs ra
JOIN flights f ON f.reserve_ac_id = ra.id AND f.deleted_at IS NULL
JOIN duty_rosters dr ON dr.id = f.duty_roster_id AND dr.deleted_at IS NULL
SET ra.base_id = dr.base_id
WHERE ra.base_id IS NULL
AND ra.deleted_at IS NULL;
-- +goose Down
-- Keep data; only drop FK/index/column if present.
SET @schema_name := DATABASE();
SELECT COUNT(*) INTO @reserve_acs_has_base_fk
FROM information_schema.TABLE_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = @schema_name
AND TABLE_NAME = 'reserve_acs'
AND CONSTRAINT_NAME = 'fk_reserve_acs_base'
AND CONSTRAINT_TYPE = 'FOREIGN KEY';
SET @drop_reserve_acs_base_fk_sql := IF(
@reserve_acs_has_base_fk = 1,
'ALTER TABLE reserve_acs DROP FOREIGN KEY fk_reserve_acs_base',
'SELECT 1'
);
PREPARE stmt_drop_reserve_acs_base_fk FROM @drop_reserve_acs_base_fk_sql;
EXECUTE stmt_drop_reserve_acs_base_fk;
DEALLOCATE PREPARE stmt_drop_reserve_acs_base_fk;
SELECT COUNT(*) INTO @reserve_acs_has_base_id_idx
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'reserve_acs'
AND INDEX_NAME = 'idx_reserve_acs_base_id';
SET @drop_reserve_acs_base_id_idx_sql := IF(
@reserve_acs_has_base_id_idx = 1,
'DROP INDEX idx_reserve_acs_base_id ON reserve_acs',
'SELECT 1'
);
PREPARE stmt_drop_reserve_acs_base_id_idx FROM @drop_reserve_acs_base_id_idx_sql;
EXECUTE stmt_drop_reserve_acs_base_id_idx;
DEALLOCATE PREPARE stmt_drop_reserve_acs_base_id_idx;
SELECT COUNT(*) INTO @reserve_acs_has_base_id
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @schema_name
AND TABLE_NAME = 'reserve_acs'
AND COLUMN_NAME = 'base_id';
SET @drop_reserve_acs_base_id_sql := IF(
@reserve_acs_has_base_id = 1,
'ALTER TABLE reserve_acs DROP COLUMN base_id',
'SELECT 1'
);
PREPARE stmt_drop_reserve_acs_base_id FROM @drop_reserve_acs_base_id_sql;
EXECUTE stmt_drop_reserve_acs_base_id;
DEALLOCATE PREPARE stmt_drop_reserve_acs_base_id;

View File

@@ -0,0 +1,26 @@
-- Add optional name field to ICAO table.
SET @has_table := (
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'icaos'
);
SET @has_column := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'icaos'
AND column_name = 'name'
);
SET @sql := IF(
@has_table > 0 AND @has_column = 0,
'ALTER TABLE icaos ADD COLUMN name VARCHAR(128) NULL AFTER icao_code',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,18 @@
CREATE TABLE IF NOT EXISTS fleet_status_service_logs (
id BINARY(16) PRIMARY KEY,
fleet_status_id BINARY(16) NOT NULL,
helicopter_id BINARY(16) NOT NULL,
inspection_type VARCHAR(16) NOT NULL,
type VARCHAR(255) NOT NULL,
due VARCHAR(255) NULL,
ext VARCHAR(255) NULL,
serviced_at DATETIME(3) NOT NULL,
created_at DATETIME(3) NULL,
created_by BINARY(16) NULL,
INDEX idx_fleet_status_service_logs_fleet_status_id (fleet_status_id),
INDEX idx_fleet_status_service_logs_helicopter_id (helicopter_id),
INDEX idx_fleet_status_service_logs_serviced_at (serviced_at),
CONSTRAINT chk_fleet_status_service_logs_inspection_type CHECK (inspection_type IN ('A/F','ENG1','ENG2','MAIN1','MAIN2')),
CONSTRAINT fk_fleet_status_service_logs_fleet_status FOREIGN KEY (fleet_status_id) REFERENCES fleet_statuses(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_fleet_status_service_logs_helicopter FOREIGN KEY (helicopter_id) REFERENCES helicopters(id)
);

View File

@@ -0,0 +1,35 @@
CREATE TABLE IF NOT EXISTS fleet_statuses (
id BINARY(16) PRIMARY KEY,
helicopter_id BINARY(16) NOT NULL,
created_at DATETIME(3) NULL,
created_by BINARY(16) NULL,
updated_at DATETIME(3) NULL,
updated_by BINARY(16) NULL,
deleted_at DATETIME(3) NULL,
deleted_by BINARY(16) NULL,
INDEX idx_fleet_statuses_helicopter_id (helicopter_id),
INDEX idx_fleet_statuses_deleted_at (deleted_at),
CONSTRAINT fk_fleet_statuses_helicopter FOREIGN KEY (helicopter_id) REFERENCES helicopters(id)
);
CREATE TABLE IF NOT EXISTS maintenance_schedules (
id BINARY(16) PRIMARY KEY,
fleet_status_id BINARY(16) NOT NULL,
inspection_type VARCHAR(16) NOT NULL,
type VARCHAR(255) NOT NULL,
due VARCHAR(255) NULL,
ext VARCHAR(255) NULL,
INDEX idx_maintenance_schedules_fleet_status_id (fleet_status_id),
CONSTRAINT chk_maintenance_schedules_inspection_type CHECK (inspection_type IN ('A/F','ENG1','ENG2','MAIN1','MAIN2')),
CONSTRAINT fk_maintenance_schedules_fleet_status FOREIGN KEY (fleet_status_id) REFERENCES fleet_statuses(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS fleet_status_files (
id BINARY(16) PRIMARY KEY,
fleet_status_id BINARY(16) NOT NULL,
file_attachment_id BINARY(16) NOT NULL,
INDEX idx_fleet_status_files_fleet_status_id (fleet_status_id),
INDEX idx_fleet_status_files_attachment_id (file_attachment_id),
CONSTRAINT fk_fleet_status_files_fleet_status FOREIGN KEY (fleet_status_id) REFERENCES fleet_statuses(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_fleet_status_files_attachment FOREIGN KEY (file_attachment_id) REFERENCES attachments(id)
);

View File

@@ -0,0 +1,11 @@
-- +goose Up
ALTER TABLE motor_reactions
MODIFY COLUMN score BIGINT NULL;
-- +goose Down
UPDATE motor_reactions
SET score = 0
WHERE score IS NULL;
ALTER TABLE motor_reactions
MODIFY COLUMN score BIGINT NOT NULL;

View File

@@ -0,0 +1,26 @@
-- Rename hospital table to no_icao_codes
-- This keeps existing data and constraints while moving to the new table name.
SET @has_hospitals := (
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'hospitals'
);
SET @has_no_icao_codes := (
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'no_icao_codes'
);
SET @rename_sql := IF(
@has_hospitals > 0 AND @has_no_icao_codes = 0,
'RENAME TABLE hospitals TO no_icao_codes',
'SELECT 1'
);
PREPARE stmt FROM @rename_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,25 @@
-- Rename OPC table to hems_opcs.
SET @has_opcs := (
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'opcs'
);
SET @has_hems_opcs := (
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name = 'hems_opcs'
);
SET @rename_sql := IF(
@has_opcs > 0 AND @has_hems_opcs = 0,
'RENAME TABLE opcs TO hems_opcs',
'SELECT 1'
);
PREPARE stmt FROM @rename_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,10 @@
ALTER TABLE duty_rosters
ADD COLUMN flight_id BINARY(16) NULL AFTER id;
CREATE UNIQUE INDEX idx_roster_flight_id
ON duty_rosters (flight_id);
-- Keep base/date as a non-unique lookup index so existing roster views still work.
DROP INDEX idx_roster_base_date ON duty_rosters;
CREATE INDEX idx_roster_base_date
ON duty_rosters (base_id, duty_date);

View File

@@ -0,0 +1,18 @@
-- Keep fleet status service log schema aligned with service timestamp usage.
SET @has_status_col := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'fleet_status_service_logs'
AND column_name = 'serviced_at'
);
SET @sql := IF(
@has_status_col = 0,
'ALTER TABLE fleet_status_service_logs ADD COLUMN serviced_at DATETIME(3) NOT NULL AFTER ext',
'SELECT 1'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,69 @@
-- Add explicit service state to fleet statuses.
SET @has_status := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'fleet_statuses'
AND column_name = 'status'
);
SET @has_serviced_at := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'fleet_statuses'
AND column_name = 'serviced_at'
);
SET @sql1 := IF(
@has_status = 0,
'ALTER TABLE fleet_statuses ADD COLUMN status VARCHAR(16) NOT NULL DEFAULT ''active'' AFTER helicopter_id',
'SELECT 1'
);
PREPARE stmt1 FROM @sql1;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
SET @sql2 := IF(
@has_serviced_at = 0,
'ALTER TABLE fleet_statuses ADD COLUMN serviced_at DATETIME(3) NULL AFTER status',
'SELECT 1'
);
PREPARE stmt2 FROM @sql2;
EXECUTE stmt2;
DEALLOCATE PREPARE stmt2;
SET @idx_status := (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'fleet_statuses'
AND index_name = 'idx_fleet_statuses_status'
);
SET @sql3 := IF(
@idx_status = 0,
'ALTER TABLE fleet_statuses ADD INDEX idx_fleet_statuses_status (status)',
'SELECT 1'
);
PREPARE stmt3 FROM @sql3;
EXECUTE stmt3;
DEALLOCATE PREPARE stmt3;
SET @idx_serviced := (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'fleet_statuses'
AND index_name = 'idx_fleet_statuses_serviced_at'
);
SET @sql4 := IF(
@idx_serviced = 0,
'ALTER TABLE fleet_statuses ADD INDEX idx_fleet_statuses_serviced_at (serviced_at)',
'SELECT 1'
);
PREPARE stmt4 FROM @sql4;
EXECUTE stmt4;
DEALLOCATE PREPARE stmt4;

View File

@@ -0,0 +1,6 @@
ALTER TABLE flights
ADD COLUMN status VARCHAR(20) NOT NULL DEFAULT 'draft' AFTER id;
UPDATE flights
SET status = 'draft'
WHERE status IS NULL OR status = '';

View File

@@ -0,0 +1,12 @@
ALTER TABLE flights
ADD COLUMN takeover_ac_id BINARY(16) NULL AFTER reserve_ac_id,
ADD INDEX idx_flights_takeover_ac_id (takeover_ac_id);
ALTER TABLE duty_roster_crews
ADD COLUMN takeover_ac_id BINARY(16) NULL AFTER confirm_at,
ADD INDEX idx_duty_roster_crews_takeover_ac_id (takeover_ac_id);
ALTER TABLE duty_roster_other_persons
ADD COLUMN takeover_ac_id BINARY(16) NULL AFTER email,
ADD INDEX idx_duty_roster_other_persons_takeover_ac_id (takeover_ac_id);

Some files were not shown because too many files have changed in this diff Show More