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,37 @@
-- +goose Up
-- Prepare staging tables for legacy helicopter dump import.
CREATE TABLE IF NOT EXISTS helicopter_old_import (
id int(11) NOT NULL,
name varchar(50) NOT NULL,
type varchar(20) DEFAULT NULL,
counter int(11) DEFAULT NULL,
engine1 varchar(50) DEFAULT NULL,
engine2 varchar(50) DEFAULT NULL,
consumption double(10,2) DEFAULT NULL,
service varchar(255) DEFAULT NULL,
nr1 tinyint(1) DEFAULT 0,
nr2 tinyint(1) DEFAULT 0,
lh tinyint(1) DEFAULT 0,
rh tinyint(1) DEFAULT 0,
mgb tinyint(1) DEFAULT 0,
igb tinyint(1) DEFAULT 0,
tgb tinyint(1) DEFAULT 0,
utc varchar(10) DEFAULT NULL,
disabled tinyint(1) DEFAULT 0,
visible tinyint(1) DEFAULT 1,
dry tinyint(1) DEFAULT 0,
docs text,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS helicopter_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_helicopter_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS helicopter_old_id_map;
DROP TABLE IF EXISTS helicopter_old_import;

View File

@@ -0,0 +1,140 @@
-- +goose Up
-- Apply legacy helicopter staging data into `helicopters`.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `helicopter_old_import`.
-- 2) Import old dump rows into `helicopter_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUIDv7-style IDs,
-- then upserts into `helicopters` with `is_active` forced to 1.
START TRANSACTION;
-- Self-heal when staging migration is marked applied but tables were dropped/reset manually.
CREATE TABLE IF NOT EXISTS helicopter_old_import (
id int(11) NOT NULL,
name varchar(50) NOT NULL,
type varchar(20) DEFAULT NULL,
counter int(11) DEFAULT NULL,
engine1 varchar(50) DEFAULT NULL,
engine2 varchar(50) DEFAULT NULL,
consumption double(10,2) DEFAULT NULL,
service varchar(255) DEFAULT NULL,
nr1 tinyint(1) DEFAULT 0,
nr2 tinyint(1) DEFAULT 0,
lh tinyint(1) DEFAULT 0,
rh tinyint(1) DEFAULT 0,
mgb tinyint(1) DEFAULT 0,
igb tinyint(1) DEFAULT 0,
tgb tinyint(1) DEFAULT 0,
utc varchar(10) DEFAULT NULL,
disabled tinyint(1) DEFAULT 0,
visible tinyint(1) DEFAULT 1,
dry tinyint(1) DEFAULT 0,
docs text,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS helicopter_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_helicopter_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
INSERT INTO helicopter_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
-- UUID layout must be 8-4-4-4-12 (32 hex chars => 16 bytes).
-- Put millisecond timestamp (48-bit) in first 8+4 chars for time ordering.
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM helicopter_old_import s
LEFT JOIN helicopter_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO helicopters (
id,
designation,
identifier,
report_sequence,
type,
counter,
engine_1,
engine_2,
consumption_lt_min,
nr1,
nr2,
lh,
rh,
mgb,
igb,
tgb,
utc_offset,
dry,
note,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
TRIM(s.name) AS designation,
TRIM(s.name) AS identifier,
0 AS report_sequence,
COALESCE(NULLIF(TRIM(s.type), ''), 'Unknown') AS type,
0 AS counter,
TRIM(COALESCE(s.engine1, '')) AS engine_1,
TRIM(COALESCE(s.engine2, '')) AS engine_2,
COALESCE(s.consumption, 0) AS consumption_lt_min,
COALESCE(s.nr1, 0) AS nr1,
COALESCE(s.nr2, 0) AS nr2,
COALESCE(s.lh, 0) AS lh,
COALESCE(s.rh, 0) AS rh,
COALESCE(s.mgb, 0) AS mgb,
COALESCE(s.igb, 0) AS igb,
COALESCE(s.tgb, 0) AS tgb,
COALESCE(CAST(NULLIF(TRIM(s.utc), '') AS SIGNED), 0) AS utc_offset,
COALESCE(s.dry, 0) AS dry,
s.docs AS note,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM helicopter_old_import s
JOIN helicopter_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
designation = VALUES(designation),
identifier = VALUES(identifier),
type = VALUES(type),
engine_1 = VALUES(engine_1),
engine_2 = VALUES(engine_2),
consumption_lt_min = VALUES(consumption_lt_min),
nr1 = VALUES(nr1),
nr2 = VALUES(nr2),
lh = VALUES(lh),
rh = VALUES(rh),
mgb = VALUES(mgb),
igb = VALUES(igb),
tgb = VALUES(tgb),
utc_offset = VALUES(utc_offset),
dry = VALUES(dry),
note = VALUES(note),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

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 @@
-- +goose Up
-- Prepare staging tables for legacy hospital dump import.
CREATE TABLE IF NOT EXISTS hospital_old_import (
id int(11) NOT NULL,
name varchar(150) DEFAULT NULL,
address varchar(255) DEFAULT NULL,
office varchar(150) DEFAULT NULL,
mobile varchar(150) DEFAULT NULL,
email varchar(150) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS hospital_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_hospital_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS hospital_old_id_map;
DROP TABLE IF EXISTS hospital_old_import;

View File

@@ -0,0 +1,69 @@
-- +goose Up
-- Apply legacy hospital staging data into `hospitals`.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `hospital_old_import`.
-- 2) Import old dump rows into `hospital_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUID-style IDs,
-- then upserts into `hospitals` with `is_active` forced to 1.
START TRANSACTION;
INSERT INTO hospital_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM hospital_old_import s
LEFT JOIN hospital_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO hospitals (
id,
hospital_name,
address,
landline_number,
mobile_number,
email,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Hospital ', s.id)), 128) AS hospital_name,
LEFT(TRIM(COALESCE(s.address, '')), 256) AS address,
LEFT(TRIM(COALESCE(s.office, '')), 20) AS landline_number,
LEFT(TRIM(COALESCE(s.mobile, '')), 20) AS mobile_number,
LEFT(TRIM(COALESCE(s.email, '')), 128) AS email,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM hospital_old_import s
JOIN hospital_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
hospital_name = VALUES(hospital_name),
address = VALUES(address),
landline_number = VALUES(landline_number),
mobile_number = VALUES(mobile_number),
email = VALUES(email),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

View File

@@ -0,0 +1,23 @@
-- +goose Up
-- Prepare staging tables for legacy ICAO dump import.
CREATE TABLE IF NOT EXISTS icao_old_import (
id int(11) NOT NULL,
code varchar(150) NOT NULL,
address varchar(255) DEFAULT NULL,
phone varchar(50) DEFAULT NULL,
mobile varchar(50) DEFAULT NULL,
email varchar(50) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS icao_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_icao_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS icao_old_id_map;
DROP TABLE IF EXISTS icao_old_import;

View File

@@ -0,0 +1,69 @@
-- +goose Up
-- Apply legacy ICAO staging data into `icaos`.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `icao_old_import`.
-- 2) Import old dump rows into `icao_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUID-style IDs,
-- then upserts into `icaos` with `is_active` forced to 1.
START TRANSACTION;
INSERT INTO icao_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM icao_old_import s
LEFT JOIN icao_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO icaos (
id,
icao_code,
address,
landline_number,
mobile_number,
email,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.code), ''), CONCAT('ICAO-', s.id)), 16) AS icao_code,
LEFT(TRIM(COALESCE(s.address, '')), 256) AS address,
LEFT(TRIM(COALESCE(s.phone, '')), 20) AS landline_number,
LEFT(TRIM(COALESCE(s.mobile, '')), 20) AS mobile_number,
LEFT(TRIM(COALESCE(s.email, '')), 128) AS email,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM icao_old_import s
JOIN icao_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
icao_code = VALUES(icao_code),
address = VALUES(address),
landline_number = VALUES(landline_number),
mobile_number = VALUES(mobile_number),
email = VALUES(email),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

View File

@@ -0,0 +1,23 @@
-- +goose Up
-- Prepare staging tables for legacy kassa dump import.
CREATE TABLE IF NOT EXISTS kassa_old_import (
id int(11) NOT NULL,
name varchar(150) DEFAULT NULL,
region varchar(255) DEFAULT NULL,
address varchar(255) DEFAULT NULL,
phone varchar(150) DEFAULT NULL,
email varchar(150) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS kassa_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_kassa_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS kassa_old_id_map;
DROP TABLE IF EXISTS kassa_old_import;

View File

@@ -0,0 +1,69 @@
-- +goose Up
-- Apply legacy kassa staging data into `health_insurance_companies`.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `kassa_old_import`.
-- 2) Import old dump rows into `kassa_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUID-style IDs,
-- then upserts into `health_insurance_companies` with `is_active` forced to 1.
START TRANSACTION;
INSERT INTO kassa_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM kassa_old_import s
LEFT JOIN kassa_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO health_insurance_companies (
id,
name,
state,
address,
mobile_number,
email,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Kassa ', s.id)), 128) AS name,
LEFT(TRIM(COALESCE(s.region, '')), 128) AS state,
LEFT(TRIM(COALESCE(s.address, '')), 256) AS address,
LEFT(TRIM(COALESCE(s.phone, '')), 20) AS mobile_number,
LEFT(TRIM(COALESCE(s.email, '')), 128) AS email,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM kassa_old_import s
JOIN kassa_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
state = VALUES(state),
address = VALUES(address),
mobile_number = VALUES(mobile_number),
email = VALUES(email),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

View File

@@ -0,0 +1,20 @@
-- +goose Up
-- Prepare staging tables for legacy nationality dump import.
CREATE TABLE IF NOT EXISTS nationality_old_import (
id int(11) NOT NULL,
name varchar(150) NOT NULL,
description varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS nationality_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_nationality_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS nationality_old_id_map;
DROP TABLE IF EXISTS nationality_old_import;

View File

@@ -0,0 +1,88 @@
-- +goose Up
-- Apply legacy nationality staging data into `nationalities`.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `nationality_old_import`.
-- 2) Import old dump rows into `nationality_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUID-style IDs,
-- then upserts into `nationalities` with `is_active` forced to 1.
START TRANSACTION;
INSERT INTO nationality_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM nationality_old_import s
LEFT JOIN nationality_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO lands (
id,
name,
land_iso_code,
is_active,
created_at,
updated_at
)
SELECT
UUID_TO_BIN(UUID()) AS id,
src.land_name AS name,
'' AS land_iso_code,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM (
SELECT DISTINCT
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Nationality ', s.id)), 128) AS land_name
FROM nationality_old_import s
) src
LEFT JOIN lands l
ON LOWER(TRIM(l.name)) = LOWER(src.land_name)
AND l.deleted_at IS NULL
WHERE l.id IS NULL;
INSERT INTO nationalities (
id,
land_id,
name,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
l.id AS land_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Nationality ', s.id)), 128) AS name,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM nationality_old_import s
JOIN nationality_old_id_map m ON m.old_id = s.id
LEFT JOIN lands l
ON LOWER(TRIM(l.name)) = LOWER(LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Nationality ', s.id)), 128))
AND l.deleted_at IS NULL
ON DUPLICATE KEY UPDATE
land_id = VALUES(land_id),
name = VALUES(name),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

View File

@@ -0,0 +1,20 @@
-- +goose Up
-- Prepare staging tables for legacy bundesland dump import.
CREATE TABLE IF NOT EXISTS bundesland_old_import (
id int(11) NOT NULL,
name varchar(150) NOT NULL,
state varchar(150) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS bundesland_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_bundesland_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS bundesland_old_id_map;
DROP TABLE IF EXISTS bundesland_old_import;

View File

@@ -0,0 +1,140 @@
-- +goose Up
-- Apply legacy bundesland staging data into `federal_states`.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `bundesland_old_import`.
-- 2) Import old dump rows into `bundesland_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUID-style IDs,
-- then upserts into `federal_states` with `is_active` forced to 1.
START TRANSACTION;
INSERT INTO bundesland_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM bundesland_old_import s
LEFT JOIN bundesland_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO lands (
id,
name,
land_iso_code,
is_active,
created_at,
updated_at
)
SELECT
UUID_TO_BIN(UUID()) AS id,
src.land_name AS name,
'' AS land_iso_code,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM (
SELECT DISTINCT
LEFT(
CASE
WHEN NULLIF(TRIM(s.state), '') IS NOT NULL THEN TRIM(s.state)
WHEN TRIM(s.name) IN (
'Vorarlberg',
'Tirol',
'Burgenland',
'Wien',
'Salzburg',
'Steiermark',
'Kärnten',
'Oberösterreich',
'Niederösterreich'
) THEN 'Österreich'
ELSE ''
END,
128
) AS land_name
FROM bundesland_old_import s
WHERE NULLIF(
CASE
WHEN NULLIF(TRIM(s.state), '') IS NOT NULL THEN TRIM(s.state)
WHEN TRIM(s.name) IN (
'Vorarlberg',
'Tirol',
'Burgenland',
'Wien',
'Salzburg',
'Steiermark',
'Kärnten',
'Oberösterreich',
'Niederösterreich'
) THEN 'Österreich'
ELSE ''
END,
''
) IS NOT NULL
) src
LEFT JOIN lands l
ON LOWER(TRIM(l.name)) = LOWER(src.land_name)
AND l.deleted_at IS NULL
WHERE l.id IS NULL;
INSERT INTO federal_states (
id,
land_id,
name,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
l.id AS land_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Federal State ', s.id)), 128) AS name,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM bundesland_old_import s
JOIN bundesland_old_id_map m ON m.old_id = s.id
LEFT JOIN lands l
ON LOWER(TRIM(l.name)) = LOWER(LEFT(
CASE
WHEN NULLIF(TRIM(s.state), '') IS NOT NULL THEN TRIM(s.state)
WHEN TRIM(s.name) IN (
'Vorarlberg',
'Tirol',
'Burgenland',
'Wien',
'Salzburg',
'Steiermark',
'Kärnten',
'Oberösterreich',
'Niederösterreich'
) THEN 'Österreich'
ELSE ''
END,
128
))
AND l.deleted_at IS NULL
ON DUPLICATE KEY UPDATE
land_id = VALUES(land_id),
name = VALUES(name),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

View File

@@ -0,0 +1,20 @@
-- +goose Up
-- Prepare staging tables for legacy OPC dump import.
CREATE TABLE IF NOT EXISTS opc_old_import (
id int(11) NOT NULL,
title varchar(150) NOT NULL,
description varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS opc_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_opc_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS opc_old_id_map;
DROP TABLE IF EXISTS opc_old_import;

View File

@@ -0,0 +1,57 @@
-- +goose Up
-- Apply legacy OPC staging data into `opcs`.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `opc_old_import`.
-- 2) Import old dump rows into `opc_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUID-style IDs,
-- then upserts into `opcs` with `is_active` forced to 1.
START TRANSACTION;
INSERT INTO opc_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM opc_old_import s
LEFT JOIN opc_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO opcs (
id,
name,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.title), ''), CONCAT('OPC ', s.id)), 64) AS name,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM opc_old_import s
JOIN opc_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

View File

@@ -0,0 +1,20 @@
-- +goose Up
-- Prepare staging tables for legacy forces dump import.
CREATE TABLE IF NOT EXISTS forces_old_import (
id int(11) NOT NULL,
name varchar(150) NOT NULL,
description varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS forces_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_forces_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS forces_old_id_map;
DROP TABLE IF EXISTS forces_old_import;

View File

@@ -0,0 +1,57 @@
-- +goose Up
-- Apply legacy forces staging data into `forces_present`.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `forces_old_import`.
-- 2) Import old dump rows into `forces_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUID-style IDs,
-- then upserts into `forces_present` with `is_active` forced to 1.
START TRANSACTION;
INSERT INTO forces_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM forces_old_import s
LEFT JOIN forces_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO forces_present (
id,
name,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Forces ', s.id)), 128) AS name,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM forces_old_import s
JOIN forces_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

View File

@@ -0,0 +1,20 @@
-- +goose Up
-- Prepare staging tables for legacy vocation dump import.
CREATE TABLE IF NOT EXISTS vocation_old_import (
id int(11) NOT NULL,
name varchar(150) NOT NULL,
description varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS vocation_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_vocation_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS vocation_old_id_map;
DROP TABLE IF EXISTS vocation_old_import;

View File

@@ -0,0 +1,57 @@
-- +goose Up
-- Apply legacy vocation staging data into `vocations`.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `vocation_old_import`.
-- 2) Import old dump rows into `vocation_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUID-style IDs,
-- then upserts into `vocations` with `is_active` forced to 1.
START TRANSACTION;
INSERT INTO vocation_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM vocation_old_import s
LEFT JOIN vocation_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO vocations (
id,
name,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Vocation ', s.id)), 64) AS name,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM vocation_old_import s
JOIN vocation_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

View File

@@ -0,0 +1,60 @@
-- +goose Up
-- Prepare staging tables for legacy medicine import:
-- - cmedikamente
-- - cmedikamente_group
-- - cmotorische_reaktion
CREATE TABLE IF NOT EXISTS medicine_group_old_import (
id int(11) NOT NULL,
name varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS medicine_group_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_medicine_group_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS motor_reaction_old_import (
id int(11) NOT NULL,
name varchar(255) DEFAULT NULL,
ball int(11) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS motor_reaction_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_motor_reaction_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS medicine_old_import (
id int(11) NOT NULL,
name varchar(255) DEFAULT NULL,
dose varchar(255) DEFAULT NULL,
weight int(11) DEFAULT NULL,
`col` int(11) DEFAULT NULL,
cmedikamente_group_id int(11) DEFAULT NULL,
motor_reaction_old_id int(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_medicine_old_import_group (cmedikamente_group_id),
KEY idx_medicine_old_import_reaction (motor_reaction_old_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS medicine_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_medicine_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS medicine_old_id_map;
DROP TABLE IF EXISTS medicine_old_import;
DROP TABLE IF EXISTS motor_reaction_old_id_map;
DROP TABLE IF EXISTS motor_reaction_old_import;
DROP TABLE IF EXISTS medicine_group_old_id_map;
DROP TABLE IF EXISTS medicine_group_old_import;

View File

@@ -0,0 +1,163 @@
-- +goose Up
-- Apply legacy medicine staging data into:
-- - medicine_groups
-- - motor_reactions
-- - medicines
--
-- Expected flow before this migration:
-- 1) Run staging migration that creates *_old_import tables.
-- 2) Load legacy dump data into:
-- - medicine_group_old_import
-- - motor_reaction_old_import
-- - medicine_old_import
START TRANSACTION;
INSERT INTO medicine_group_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM medicine_group_old_import s
LEFT JOIN medicine_group_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO motor_reaction_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM motor_reaction_old_import s
LEFT JOIN motor_reaction_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO medicine_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM medicine_old_import s
LEFT JOIN medicine_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO medicine_groups (
id,
name,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Medicine Group ', s.id)), 255) AS name,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM medicine_group_old_import s
JOIN medicine_group_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
is_active = 1,
updated_at = UTC_TIMESTAMP();
INSERT INTO motor_reactions (
id,
name,
score,
is_active,
created_at,
updated_at
)
SELECT
m.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Motor Reaction ', s.id)), 255) AS name,
s.ball AS score,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM motor_reaction_old_import s
JOIN motor_reaction_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
score = VALUES(score),
is_active = 1,
updated_at = UTC_TIMESTAMP();
INSERT INTO medicines (
id,
name,
dose,
weight,
`column`,
medicine_group_id,
motor_reaction_id,
is_active,
created_at,
updated_at
)
SELECT
med_map.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Medicine ', s.id)), 128) AS name,
LEFT(TRIM(COALESCE(s.dose, '')), 128) AS dose,
s.weight AS weight,
COALESCE(s.`col`, 0) AS `column`,
grp_map.new_id AS medicine_group_id,
react_map.new_id AS motor_reaction_id,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM medicine_old_import s
JOIN medicine_old_id_map med_map ON med_map.old_id = s.id
LEFT JOIN medicine_group_old_id_map grp_map ON grp_map.old_id = s.cmedikamente_group_id
LEFT JOIN motor_reaction_old_id_map react_map ON react_map.old_id = s.motor_reaction_old_id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
dose = VALUES(dose),
weight = VALUES(weight),
`column` = VALUES(`column`),
medicine_group_id = VALUES(medicine_group_id),
motor_reaction_id = VALUES(motor_reaction_id),
is_active = 1,
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
SELECT 1;

View File

@@ -0,0 +1,58 @@
-- +goose Up
-- Staging table set for legacy medicine dump format:
-- - cmedikamente_group
-- - cmotorische_reaktion
-- - cmedikamente
CREATE TABLE IF NOT EXISTS cmedikamente_group_old_import (
id INT(11) NOT NULL,
name VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmotorische_old_import (
id INT(11) NOT NULL,
name VARCHAR(255) DEFAULT NULL,
ball INT(11) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmedikamente_old_import (
id INT(11) NOT NULL,
name VARCHAR(255) DEFAULT NULL,
dose VARCHAR(255) DEFAULT NULL,
weight INT(11) DEFAULT NULL,
col INT(11) DEFAULT NULL,
cmedikamente_group_id INT(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_cmedikamente_old_group_id (cmedikamente_group_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmedikamente_group_old_id_map (
old_id INT(11) NOT NULL,
new_id BINARY(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_cmedikamente_group_old_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmotorische_old_id_map (
old_id INT(11) NOT NULL,
new_id BINARY(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_cmotorische_old_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmedikamente_old_id_map (
old_id INT(11) NOT NULL,
new_id BINARY(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_cmedikamente_old_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS cmedikamente_old_id_map;
DROP TABLE IF EXISTS cmotorische_old_id_map;
DROP TABLE IF EXISTS cmedikamente_group_old_id_map;
DROP TABLE IF EXISTS cmedikamente_old_import;
DROP TABLE IF EXISTS cmotorische_old_import;
DROP TABLE IF EXISTS cmedikamente_group_old_import;

View File

@@ -0,0 +1,165 @@
-- +goose Up
-- Apply legacy c* staging data into target tables:
-- - medicine_groups
-- - motor_reactions
-- - medicines
-- - medicine_motor_reactions (optional backfill via motor_reaction_id)
START TRANSACTION;
CREATE TABLE IF NOT EXISTS cmedikamente_group_old_import (
id INT(11) NOT NULL,
name VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmotorische_old_import (
id INT(11) NOT NULL,
name VARCHAR(255) DEFAULT NULL,
ball INT(11) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmedikamente_old_import (
id INT(11) NOT NULL,
name VARCHAR(255) DEFAULT NULL,
dose VARCHAR(255) DEFAULT NULL,
weight INT(11) DEFAULT NULL,
col INT(11) DEFAULT NULL,
cmedikamente_group_id INT(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_cmedikamente_old_import_group_id (cmedikamente_group_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmedikamente_group_old_id_map (
old_id INT(11) NOT NULL,
new_id BINARY(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_cmedikamente_group_old_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmotorische_old_id_map (
old_id INT(11) NOT NULL,
new_id BINARY(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_cmotorische_old_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS cmedikamente_old_id_map (
old_id INT(11) NOT NULL,
new_id BINARY(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_cmedikamente_old_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
INSERT INTO cmedikamente_group_old_id_map (old_id, new_id)
SELECT
s.id,
UNHEX(REPLACE(UUID(), '-', ''))
FROM cmedikamente_group_old_import s
LEFT JOIN cmedikamente_group_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO cmotorische_old_id_map (old_id, new_id)
SELECT
s.id,
UNHEX(REPLACE(UUID(), '-', ''))
FROM cmotorische_old_import s
LEFT JOIN cmotorische_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO cmedikamente_old_id_map (old_id, new_id)
SELECT
s.id,
UNHEX(REPLACE(UUID(), '-', ''))
FROM cmedikamente_old_import s
LEFT JOIN cmedikamente_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
INSERT INTO medicine_groups (
id,
name,
is_active,
created_at,
updated_at
)
SELECT
map.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Medicine Group ', s.id)), 255),
1,
UTC_TIMESTAMP(),
UTC_TIMESTAMP()
FROM cmedikamente_group_old_import s
JOIN cmedikamente_group_old_id_map map ON map.old_id = s.id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
is_active = 1,
updated_at = UTC_TIMESTAMP();
INSERT INTO motor_reactions (
id,
name,
score,
is_active,
created_at,
updated_at
)
SELECT
map.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Motor Reaction ', s.id)), 255),
s.ball,
1,
UTC_TIMESTAMP(),
UTC_TIMESTAMP()
FROM cmotorische_old_import s
JOIN cmotorische_old_id_map map ON map.old_id = s.id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
score = VALUES(score),
is_active = 1,
updated_at = UTC_TIMESTAMP();
INSERT INTO medicines (
id,
name,
dose,
weight,
`column`,
medicine_group_id,
is_active,
created_at,
updated_at
)
SELECT
med_map.new_id,
LEFT(COALESCE(NULLIF(TRIM(s.name), ''), CONCAT('Medicine ', s.id)), 128),
LEFT(TRIM(COALESCE(s.dose, '')), 128),
s.weight,
COALESCE(s.col, 0),
grp_map.new_id,
1,
UTC_TIMESTAMP(),
UTC_TIMESTAMP()
FROM cmedikamente_old_import s
JOIN cmedikamente_old_id_map med_map ON med_map.old_id = s.id
LEFT JOIN cmedikamente_group_old_id_map grp_map ON grp_map.old_id = s.cmedikamente_group_id
ON DUPLICATE KEY UPDATE
name = VALUES(name),
dose = VALUES(dose),
weight = VALUES(weight),
`column` = VALUES(`column`),
medicine_group_id = VALUES(medicine_group_id),
is_active = 1,
updated_at = UTC_TIMESTAMP();
-- Optional compatibility backfill: if medicines.motor_reaction_id exists, sync into join table.
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;
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
SELECT 1;

View File

@@ -0,0 +1,23 @@
-- +goose Up
INSERT INTO master_setting_values (
setting_key,
value,
is_encrypted,
created_at,
updated_at
)
VALUES (
'AUTH_LOGIN_EMAIL_OTP_ENABLED',
'false',
0,
UTC_TIMESTAMP(),
UTC_TIMESTAMP()
)
ON DUPLICATE KEY UPDATE
value = VALUES(value),
is_encrypted = 0,
updated_at = UTC_TIMESTAMP();
-- +goose Down
DELETE FROM master_setting_values
WHERE setting_key = 'AUTH_LOGIN_EMAIL_OTP_ENABLED';

View File

@@ -0,0 +1,103 @@
-- +goose Up
-- Prepare staging tables for legacy `user` dump import.
-- Source table in old DB: `user` (not `users`).
CREATE TABLE IF NOT EXISTS user_old_import (
id int(11) NOT NULL,
state tinyint(1) DEFAULT 0,
role int(2) NOT NULL,
username varchar(30) DEFAULT NULL,
password varchar(150) DEFAULT NULL,
fullname varchar(50) DEFAULT NULL,
shortName varchar(30) DEFAULT NULL,
flightNumber varchar(20) DEFAULT NULL,
license varchar(20) DEFAULT NULL,
techLicense varchar(20) DEFAULT NULL,
airport_pilot varchar(15) DEFAULT NULL,
responsible_pilot varchar(15) DEFAULT NULL,
second_pilot varchar(15) DEFAULT NULL,
double_tax_pilot varchar(15) DEFAULT NULL,
flight_instructor_pilot varchar(15) DEFAULT NULL,
night_pilot varchar(15) DEFAULT NULL,
fir_pilot varchar(15) DEFAULT NULL,
start_date varchar(15) DEFAULT NULL,
date_active varchar(15) DEFAULT NULL,
address varchar(255) DEFAULT NULL,
zipCode varchar(15) DEFAULT NULL,
street varchar(255) DEFAULT NULL,
phone varchar(50) DEFAULT NULL,
mobile varchar(50) DEFAULT NULL,
email varchar(70) DEFAULT NULL,
photo varchar(50) DEFAULT NULL,
token varchar(255) DEFAULT NULL,
hash varchar(255) DEFAULT NULL,
regDate timestamp NULL DEFAULT NULL,
lastVisit timestamp NULL DEFAULT NULL,
reportDate datetime DEFAULT NULL,
deletedAt varchar(32) DEFAULT NULL,
isDeleted tinyint(1) DEFAULT 0,
visible tinyint(1) DEFAULT 1,
lang varchar(5) DEFAULT 'de',
bases varchar(255) DEFAULT NULL,
legacy_url varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS user_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_user_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS legacy_user_role_map (
legacy_role int(2) NOT NULL,
role_code varchar(64) NOT NULL,
staff_role_label varchar(120) DEFAULT NULL,
pilot_category varchar(16) DEFAULT NULL,
is_chief_pilot tinyint(1) NOT NULL DEFAULT 0,
is_chief_physician tinyint(1) NOT NULL DEFAULT 0,
is_chief_physician_in_charge tinyint(1) NOT NULL DEFAULT 0,
is_chief_technician tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (legacy_role)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
INSERT INTO legacy_user_role_map (
legacy_role,
role_code,
staff_role_label,
pilot_category,
is_chief_pilot,
is_chief_physician,
is_chief_physician_in_charge,
is_chief_technician
)
VALUES
(1, 'pilot', NULL, 'regular', 0, 0, 0, 0),
(2, 'pilot', NULL, 'regular', 1, 0, 0, 0),
(3, 'doctor', NULL, NULL, 0, 0, 0, 0),
(4, 'doctor', NULL, NULL, 0, 1, 0, 0),
(5, 'air_rescuer', NULL, NULL, 0, 0, 0, 0),
(6, 'air_rescuer', NULL, NULL, 0, 0, 1, 0),
(7, 'admin', 'administrator', NULL, 0, 0, 0, 0),
(8, 'staff', 'billing', NULL, 0, 0, 0, 0),
(9, 'technician', NULL, NULL, 0, 0, 0, 0),
(10, 'technician', NULL, NULL, 0, 0, 0, 1),
(11, 'flight_assistant', NULL, NULL, 0, 0, 0, 0),
(12, 'staff', 'manager', NULL, 0, 0, 0, 0),
(13, 'pilot', NULL, 'freelance', 0, 0, 0, 0),
(14, 'pilot', NULL, 'dry_lease', 0, 0, 0, 0),
(15, 'staff', 'control_center', NULL, 0, 0, 0, 0)
ON DUPLICATE KEY UPDATE
role_code = VALUES(role_code),
staff_role_label = VALUES(staff_role_label),
pilot_category = VALUES(pilot_category),
is_chief_pilot = VALUES(is_chief_pilot),
is_chief_physician = VALUES(is_chief_physician),
is_chief_physician_in_charge = VALUES(is_chief_physician_in_charge),
is_chief_technician = VALUES(is_chief_technician);
-- +goose Down
DROP TABLE IF EXISTS legacy_user_role_map;
DROP TABLE IF EXISTS user_old_id_map;
DROP TABLE IF EXISTS user_old_import;

View File

@@ -0,0 +1,421 @@
-- +goose Up
-- Apply legacy user staging data into new auth/contact schema.
-- Expected flow before this migration:
-- 1) Run previous migration that creates `user_old_import` and role map.
-- 2) Import old dump rows into `user_old_import`.
-- This migration maps old integer IDs into BINARY(16) UUID-style IDs,
-- then upserts into `users`, `user_roles`, and role-specific profile tables.
START TRANSACTION;
-- 1) Reuse existing users by normalized email when possible.
INSERT INTO user_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
u.id AS new_id
FROM user_old_import s
JOIN users u
ON LOWER(TRIM(u.email)) = LOWER(TRIM(s.email))
LEFT JOIN user_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL
AND s.email IS NOT NULL
AND TRIM(s.email) <> '';
-- 2) Generate IDs for remaining legacy users.
INSERT INTO user_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM user_old_import s
LEFT JOIN user_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
-- 3) Upsert core users.
INSERT INTO users (
id,
role_id,
email,
username,
first_name,
last_name,
mobile_phone,
timezone,
is_active,
password_hash,
salt_value,
email_verified_at,
created_at,
updated_at
)
SELECT
m.new_id AS id,
r.id AS role_id,
CONCAT(
COALESCE(
NULLIF(LOWER(TRIM(SUBSTRING_INDEX(NULLIF(s.email, ''), '@', 1))), ''),
CONCAT('legacy-user-', s.id)
),
'+u', s.id,
'@mybit-innovation'
) AS email,
NULLIF(LEFT(TRIM(COALESCE(s.username, '')), 100), '') AS username,
LEFT(SUBSTRING_INDEX(TRIM(COALESCE(NULLIF(s.fullname, ''), NULLIF(s.username, ''), CONCAT('Legacy User ', s.id))), ' ', 1), 100) AS first_name,
LEFT(
COALESCE(
NULLIF(
TRIM(
SUBSTRING(
TRIM(COALESCE(NULLIF(s.fullname, ''), NULLIF(s.username, ''), CONCAT('Legacy User ', s.id))),
LENGTH(SUBSTRING_INDEX(TRIM(COALESCE(NULLIF(s.fullname, ''), NULLIF(s.username, ''), CONCAT('Legacy User ', s.id))), ' ', 1)) + 1
)
),
''
),
'-'
),
100
) AS last_name,
LEFT(TRIM(COALESCE(s.mobile, s.phone, '')), 32) AS mobile_phone,
'UTC' AS timezone,
CASE WHEN COALESCE(s.visible, 1) = 1 THEN 1 ELSE 0 END AS is_active,
NULL AS password_hash,
NULL AS salt_value,
NULL AS email_verified_at,
COALESCE(s.regDate, UTC_TIMESTAMP()) AS created_at,
COALESCE(s.lastVisit, UTC_TIMESTAMP()) AS updated_at
FROM user_old_import s
JOIN user_old_id_map m ON m.old_id = s.id
LEFT JOIN legacy_user_role_map lrm ON lrm.legacy_role = s.role
JOIN roles r ON r.code = COALESCE(lrm.role_code, 'staff')
ON DUPLICATE KEY UPDATE
role_id = VALUES(role_id),
username = VALUES(username),
first_name = VALUES(first_name),
last_name = VALUES(last_name),
mobile_phone = VALUES(mobile_phone),
timezone = VALUES(timezone),
is_active = VALUES(is_active),
password_hash = NULL,
salt_value = NULL,
email_verified_at = NULL,
updated_at = UTC_TIMESTAMP();
-- 4) Ensure user_roles relation exists for mapped role.
INSERT INTO user_roles (
id,
user_id,
role_id,
created_at,
updated_at
)
SELECT
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS id,
m.new_id AS user_id,
r.id AS role_id,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM user_old_import s
JOIN user_old_id_map m ON m.old_id = s.id
LEFT JOIN legacy_user_role_map lrm ON lrm.legacy_role = s.role
JOIN roles r ON r.code = COALESCE(lrm.role_code, 'staff')
ON DUPLICATE KEY UPDATE
updated_at = UTC_TIMESTAMP();
-- 5) Pilot profiles.
INSERT INTO pilot_profiles (
user_id,
pilot_category,
short_name,
license_no,
technician_license_no,
is_chief_pilot,
total_flight_minutes,
responsible_pilot_minutes,
second_pilot_minutes,
double_command_minutes,
flight_instructor_minutes,
night_flight_minutes,
ifr_flight_minutes,
location,
postcode,
street_line,
photo_file_id,
created_at,
updated_at
)
SELECT
m.new_id AS user_id,
COALESCE(NULLIF(lrm.pilot_category, ''), 'regular') AS pilot_category,
LEFT(TRIM(COALESCE(s.shortName, '')), 120) AS short_name,
LEFT(TRIM(COALESCE(s.license, '')), 120) AS license_no,
LEFT(TRIM(COALESCE(s.techLicense, '')), 120) AS technician_license_no,
COALESCE(lrm.is_chief_pilot, 0) AS is_chief_pilot,
CASE WHEN TRIM(COALESCE(s.airport_pilot, '')) REGEXP '^[0-9]+:[0-9]{1,2}$'
THEN CAST(SUBSTRING_INDEX(TRIM(s.airport_pilot), ':', 1) AS UNSIGNED) * 60 + CAST(SUBSTRING_INDEX(TRIM(s.airport_pilot), ':', -1) AS UNSIGNED)
ELSE 0 END AS total_flight_minutes,
CASE WHEN TRIM(COALESCE(s.responsible_pilot, '')) REGEXP '^[0-9]+:[0-9]{1,2}$'
THEN CAST(SUBSTRING_INDEX(TRIM(s.responsible_pilot), ':', 1) AS UNSIGNED) * 60 + CAST(SUBSTRING_INDEX(TRIM(s.responsible_pilot), ':', -1) AS UNSIGNED)
ELSE 0 END AS responsible_pilot_minutes,
CASE WHEN TRIM(COALESCE(s.second_pilot, '')) REGEXP '^[0-9]+:[0-9]{1,2}$'
THEN CAST(SUBSTRING_INDEX(TRIM(s.second_pilot), ':', 1) AS UNSIGNED) * 60 + CAST(SUBSTRING_INDEX(TRIM(s.second_pilot), ':', -1) AS UNSIGNED)
ELSE 0 END AS second_pilot_minutes,
CASE WHEN TRIM(COALESCE(s.double_tax_pilot, '')) REGEXP '^[0-9]+:[0-9]{1,2}$'
THEN CAST(SUBSTRING_INDEX(TRIM(s.double_tax_pilot), ':', 1) AS UNSIGNED) * 60 + CAST(SUBSTRING_INDEX(TRIM(s.double_tax_pilot), ':', -1) AS UNSIGNED)
ELSE 0 END AS double_command_minutes,
CASE WHEN TRIM(COALESCE(s.flight_instructor_pilot, '')) REGEXP '^[0-9]+:[0-9]{1,2}$'
THEN CAST(SUBSTRING_INDEX(TRIM(s.flight_instructor_pilot), ':', 1) AS UNSIGNED) * 60 + CAST(SUBSTRING_INDEX(TRIM(s.flight_instructor_pilot), ':', -1) AS UNSIGNED)
ELSE 0 END AS flight_instructor_minutes,
CASE WHEN TRIM(COALESCE(s.night_pilot, '')) REGEXP '^[0-9]+:[0-9]{1,2}$'
THEN CAST(SUBSTRING_INDEX(TRIM(s.night_pilot), ':', 1) AS UNSIGNED) * 60 + CAST(SUBSTRING_INDEX(TRIM(s.night_pilot), ':', -1) AS UNSIGNED)
ELSE 0 END AS night_flight_minutes,
CASE WHEN TRIM(COALESCE(s.fir_pilot, '')) REGEXP '^[0-9]+:[0-9]{1,2}$'
THEN CAST(SUBSTRING_INDEX(TRIM(s.fir_pilot), ':', 1) AS UNSIGNED) * 60 + CAST(SUBSTRING_INDEX(TRIM(s.fir_pilot), ':', -1) AS UNSIGNED)
ELSE 0 END AS ifr_flight_minutes,
LEFT(TRIM(COALESCE(s.address, '')), 255) AS location,
LEFT(TRIM(COALESCE(s.zipCode, '')), 32) AS postcode,
LEFT(TRIM(COALESCE(s.street, '')), 255) AS street_line,
LEFT(TRIM(COALESCE(s.photo, '')), 255) AS photo_file_id,
COALESCE(s.regDate, UTC_TIMESTAMP()) AS created_at,
COALESCE(s.lastVisit, UTC_TIMESTAMP()) AS updated_at
FROM user_old_import s
JOIN user_old_id_map m ON m.old_id = s.id
JOIN users u ON u.id = m.new_id
JOIN legacy_user_role_map lrm ON lrm.legacy_role = s.role
WHERE lrm.role_code = 'pilot'
ON DUPLICATE KEY UPDATE
pilot_category = VALUES(pilot_category),
short_name = VALUES(short_name),
license_no = VALUES(license_no),
technician_license_no = VALUES(technician_license_no),
is_chief_pilot = VALUES(is_chief_pilot),
total_flight_minutes = VALUES(total_flight_minutes),
responsible_pilot_minutes = VALUES(responsible_pilot_minutes),
second_pilot_minutes = VALUES(second_pilot_minutes),
double_command_minutes = VALUES(double_command_minutes),
flight_instructor_minutes = VALUES(flight_instructor_minutes),
night_flight_minutes = VALUES(night_flight_minutes),
ifr_flight_minutes = VALUES(ifr_flight_minutes),
location = VALUES(location),
postcode = VALUES(postcode),
street_line = VALUES(street_line),
photo_file_id = VALUES(photo_file_id),
updated_at = UTC_TIMESTAMP();
-- 6) Doctor profiles.
INSERT INTO doctor_profiles (
user_id,
short_name,
medical_license_no,
is_chief_physician,
location,
postcode,
street_line,
photo_file_id,
created_at,
updated_at
)
SELECT
m.new_id AS user_id,
LEFT(TRIM(COALESCE(s.shortName, '')), 120) AS short_name,
LEFT(TRIM(COALESCE(s.license, '')), 120) AS medical_license_no,
COALESCE(lrm.is_chief_physician, 0) AS is_chief_physician,
LEFT(TRIM(COALESCE(s.address, '')), 255) AS location,
LEFT(TRIM(COALESCE(s.zipCode, '')), 32) AS postcode,
LEFT(TRIM(COALESCE(s.street, '')), 255) AS street_line,
LEFT(TRIM(COALESCE(s.photo, '')), 255) AS photo_file_id,
COALESCE(s.regDate, UTC_TIMESTAMP()) AS created_at,
COALESCE(s.lastVisit, UTC_TIMESTAMP()) AS updated_at
FROM user_old_import s
JOIN user_old_id_map m ON m.old_id = s.id
JOIN users u ON u.id = m.new_id
JOIN legacy_user_role_map lrm ON lrm.legacy_role = s.role
WHERE lrm.role_code = 'doctor'
ON DUPLICATE KEY UPDATE
short_name = VALUES(short_name),
medical_license_no = VALUES(medical_license_no),
is_chief_physician = VALUES(is_chief_physician),
location = VALUES(location),
postcode = VALUES(postcode),
street_line = VALUES(street_line),
photo_file_id = VALUES(photo_file_id),
updated_at = UTC_TIMESTAMP();
-- 7) Air rescuer profiles.
INSERT INTO air_rescuer_profiles (
user_id,
short_name,
is_chief_physician_in_charge,
responsible_flight_rescuer,
location,
postcode,
street_line,
photo_file_id,
created_at,
updated_at
)
SELECT
m.new_id AS user_id,
LEFT(TRIM(COALESCE(s.shortName, '')), 120) AS short_name,
COALESCE(lrm.is_chief_physician_in_charge, 0) AS is_chief_physician_in_charge,
0 AS responsible_flight_rescuer,
LEFT(TRIM(COALESCE(s.address, '')), 255) AS location,
LEFT(TRIM(COALESCE(s.zipCode, '')), 32) AS postcode,
LEFT(TRIM(COALESCE(s.street, '')), 255) AS street_line,
LEFT(TRIM(COALESCE(s.photo, '')), 255) AS photo_file_id,
COALESCE(s.regDate, UTC_TIMESTAMP()) AS created_at,
COALESCE(s.lastVisit, UTC_TIMESTAMP()) AS updated_at
FROM user_old_import s
JOIN user_old_id_map m ON m.old_id = s.id
JOIN users u ON u.id = m.new_id
JOIN legacy_user_role_map lrm ON lrm.legacy_role = s.role
WHERE lrm.role_code = 'air_rescuer'
ON DUPLICATE KEY UPDATE
short_name = VALUES(short_name),
is_chief_physician_in_charge = VALUES(is_chief_physician_in_charge),
responsible_flight_rescuer = VALUES(responsible_flight_rescuer),
location = VALUES(location),
postcode = VALUES(postcode),
street_line = VALUES(street_line),
photo_file_id = VALUES(photo_file_id),
updated_at = UTC_TIMESTAMP();
-- 8) Technician profiles.
INSERT INTO technician_profiles (
user_id,
short_name,
license_no,
is_chief_technician,
location,
postcode,
street_line,
photo_file_id,
created_at,
updated_at
)
SELECT
m.new_id AS user_id,
LEFT(TRIM(COALESCE(s.shortName, '')), 120) AS short_name,
LEFT(TRIM(COALESCE(s.license, '')), 120) AS license_no,
COALESCE(lrm.is_chief_technician, 0) AS is_chief_technician,
LEFT(TRIM(COALESCE(s.address, '')), 255) AS location,
LEFT(TRIM(COALESCE(s.zipCode, '')), 32) AS postcode,
LEFT(TRIM(COALESCE(s.street, '')), 255) AS street_line,
LEFT(TRIM(COALESCE(s.photo, '')), 255) AS photo_file_id,
COALESCE(s.regDate, UTC_TIMESTAMP()) AS created_at,
COALESCE(s.lastVisit, UTC_TIMESTAMP()) AS updated_at
FROM user_old_import s
JOIN user_old_id_map m ON m.old_id = s.id
JOIN users u ON u.id = m.new_id
JOIN legacy_user_role_map lrm ON lrm.legacy_role = s.role
WHERE lrm.role_code = 'technician'
ON DUPLICATE KEY UPDATE
short_name = VALUES(short_name),
license_no = VALUES(license_no),
is_chief_technician = VALUES(is_chief_technician),
location = VALUES(location),
postcode = VALUES(postcode),
street_line = VALUES(street_line),
photo_file_id = VALUES(photo_file_id),
updated_at = UTC_TIMESTAMP();
-- 9) Flight assistant profiles.
INSERT INTO flight_assistant_profiles (
user_id,
short_name,
location,
postcode,
street_line,
photo_file_id,
created_at,
updated_at
)
SELECT
m.new_id AS user_id,
LEFT(TRIM(COALESCE(s.shortName, '')), 120) AS short_name,
LEFT(TRIM(COALESCE(s.address, '')), 255) AS location,
LEFT(TRIM(COALESCE(s.zipCode, '')), 32) AS postcode,
LEFT(TRIM(COALESCE(s.street, '')), 255) AS street_line,
LEFT(TRIM(COALESCE(s.photo, '')), 255) AS photo_file_id,
COALESCE(s.regDate, UTC_TIMESTAMP()) AS created_at,
COALESCE(s.lastVisit, UTC_TIMESTAMP()) AS updated_at
FROM user_old_import s
JOIN user_old_id_map m ON m.old_id = s.id
JOIN users u ON u.id = m.new_id
JOIN legacy_user_role_map lrm ON lrm.legacy_role = s.role
WHERE lrm.role_code = 'flight_assistant'
ON DUPLICATE KEY UPDATE
short_name = VALUES(short_name),
location = VALUES(location),
postcode = VALUES(postcode),
street_line = VALUES(street_line),
photo_file_id = VALUES(photo_file_id),
updated_at = UTC_TIMESTAMP();
-- 10) Staff profiles.
INSERT INTO staff_profiles (
user_id,
short_name,
role_label,
location,
postcode,
street_line,
photo_file_id,
created_at,
updated_at
)
SELECT
m.new_id AS user_id,
LEFT(TRIM(COALESCE(s.shortName, '')), 120) AS short_name,
LEFT(TRIM(COALESCE(lrm.staff_role_label, 'staff')), 120) AS role_label,
LEFT(TRIM(COALESCE(s.address, '')), 255) AS location,
LEFT(TRIM(COALESCE(s.zipCode, '')), 32) AS postcode,
LEFT(TRIM(COALESCE(s.street, '')), 255) AS street_line,
LEFT(TRIM(COALESCE(s.photo, '')), 255) AS photo_file_id,
COALESCE(s.regDate, UTC_TIMESTAMP()) AS created_at,
COALESCE(s.lastVisit, UTC_TIMESTAMP()) AS updated_at
FROM user_old_import s
JOIN user_old_id_map m ON m.old_id = s.id
JOIN users u ON u.id = m.new_id
JOIN legacy_user_role_map lrm ON lrm.legacy_role = s.role
WHERE lrm.role_code = 'staff'
ON DUPLICATE KEY UPDATE
short_name = VALUES(short_name),
role_label = VALUES(role_label),
location = VALUES(location),
postcode = VALUES(postcode),
street_line = VALUES(street_line),
photo_file_id = VALUES(photo_file_id),
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- Data migration is intentionally non-reversible.
-- Keep imported data and ID mapping as audit trail.
SELECT 1;

View File

@@ -0,0 +1,35 @@
-- +goose Up
-- Prepare staging tables for legacy `bases` import.
CREATE TABLE IF NOT EXISTS bases_old_import (
id int(11) NOT NULL,
name varchar(50) NOT NULL,
code varchar(10) NOT NULL,
icao varchar(255) DEFAULT NULL,
address varchar(255) DEFAULT NULL,
phone varchar(50) DEFAULT NULL,
mobile varchar(50) DEFAULT NULL,
email varchar(50) DEFAULT NULL,
rescue_emails varchar(255) DEFAULT NULL,
doctor_emails varchar(255) DEFAULT NULL,
sms_alert int(11) NOT NULL DEFAULT 1,
check_list tinyint(1) DEFAULT 0,
dry tinyint(1) DEFAULT 0,
control_center tinyint(1) DEFAULT 0,
service_transfer_list tinyint(1) DEFAULT 0,
visible tinyint(1) DEFAULT 0,
position tinyint(4) NOT NULL,
type varchar(255) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS base_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_base_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS base_old_id_map;
DROP TABLE IF EXISTS bases_old_import;

View File

@@ -0,0 +1,193 @@
-- +goose Up
-- Apply legacy base staging data into new bases schema.
START TRANSACTION;
-- 1) Reuse existing base rows by normalized (base, abbreviation) when possible.
INSERT INTO base_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
b.id AS new_id
FROM bases_old_import s
JOIN bases b
ON LOWER(TRIM(b.base)) = LOWER(TRIM(s.name))
AND LOWER(TRIM(COALESCE(b.base_abbreviation, ''))) = LOWER(TRIM(COALESCE(s.code, '')))
LEFT JOIN base_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
-- 2) Generate IDs for remaining legacy bases.
INSERT INTO base_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM bases_old_import s
LEFT JOIN base_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
-- 3) Upsert base rows.
INSERT INTO bases (
id,
base,
base_category_id,
base_abbreviation,
address,
landline_number,
mobile_number,
email,
sortkey,
sms_alert,
checklist,
dry,
control_center,
dul,
is_active,
created_at,
updated_at
)
SELECT
m.new_id AS id,
LEFT(TRIM(COALESCE(s.name, '')), 150) AS base,
bc.id AS base_category_id,
LEFT(TRIM(COALESCE(s.code, '')), 64) AS base_abbreviation,
LEFT(TRIM(COALESCE(s.address, '')), 255) AS address,
LEFT(TRIM(COALESCE(s.phone, '')), 64) AS landline_number,
LEFT(TRIM(COALESCE(s.mobile, '')), 64) AS mobile_number,
LEFT(TRIM(COALESCE(s.email, '')), 191) AS email,
COALESCE(s.position, 0) AS sortkey,
CASE WHEN COALESCE(s.sms_alert, 0) <> 0 THEN 1 ELSE 0 END AS sms_alert,
CASE WHEN COALESCE(s.check_list, 0) <> 0 THEN 1 ELSE 0 END AS checklist,
CASE WHEN COALESCE(s.dry, 0) <> 0 THEN 1 ELSE 0 END AS dry,
CASE WHEN COALESCE(s.control_center, 0) <> 0 THEN 1 ELSE 0 END AS control_center,
CASE WHEN COALESCE(s.service_transfer_list, 0) <> 0 THEN 1 ELSE 0 END AS dul,
CASE WHEN COALESCE(s.visible, 0) <> 0 THEN 1 ELSE 0 END AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM bases_old_import s
JOIN base_old_id_map m ON m.old_id = s.id
LEFT JOIN base_categories bc
ON bc.`key` = CASE WHEN LOWER(TRIM(COALESCE(s.type, ''))) = 'hems' THEN 'hems' ELSE 'regular' END
ON DUPLICATE KEY UPDATE
base = VALUES(base),
base_category_id = VALUES(base_category_id),
base_abbreviation = VALUES(base_abbreviation),
address = VALUES(address),
landline_number = VALUES(landline_number),
mobile_number = VALUES(mobile_number),
email = VALUES(email),
sortkey = VALUES(sortkey),
sms_alert = VALUES(sms_alert),
checklist = VALUES(checklist),
dry = VALUES(dry),
control_center = VALUES(control_center),
dul = VALUES(dul),
is_active = VALUES(is_active),
updated_at = UTC_TIMESTAMP();
-- 4) Build extracted legacy base-contact links from serialized fields.
DROP TEMPORARY TABLE IF EXISTS tmp_base_contact_extract;
CREATE TEMPORARY TABLE tmp_base_contact_extract (
old_base_id int(11) NOT NULL,
role_code varchar(64) NOT NULL,
legacy_user_id int(11) NOT NULL,
PRIMARY KEY (old_base_id, role_code, legacy_user_id)
) ENGINE=MEMORY;
INSERT IGNORE INTO tmp_base_contact_extract (old_base_id, role_code, legacy_user_id)
WITH RECURSIVE seq AS (
SELECT 1 AS n
UNION ALL
SELECT n + 1 FROM seq WHERE n < 128
),
src AS (
SELECT
b.id AS old_base_id,
'responsible_flight_rescuer' AS role_code,
COALESCE(b.rescue_emails, '') AS serialized
FROM bases_old_import b
UNION ALL
SELECT
b.id AS old_base_id,
'chief_physician_in_charge' AS role_code,
COALESCE(b.doctor_emails, '') AS serialized
FROM bases_old_import b
)
SELECT
src.old_base_id,
src.role_code,
CAST(
SUBSTRING_INDEX(
SUBSTRING_INDEX(
REGEXP_SUBSTR(src.serialized, 's:[0-9]+:"[0-9]+"', 1, seq.n),
'"',
2
),
'"',
-1
) AS UNSIGNED
) AS legacy_user_id
FROM src
JOIN seq
ON REGEXP_SUBSTR(src.serialized, 's:[0-9]+:"[0-9]+"', 1, seq.n) IS NOT NULL;
-- 5) Replace base_contact_roles for imported bases (targeted role codes only).
DELETE bcr
FROM base_contact_roles bcr
JOIN base_old_id_map bm ON bm.new_id = bcr.base_id
WHERE bcr.role_code IN ('responsible_flight_rescuer', 'chief_physician_in_charge');
-- 6) Insert deduplicated base_contact_roles by mapping legacy user IDs to new user IDs.
INSERT INTO base_contact_roles (
id,
base_id,
contact_id,
role_code,
created_at,
updated_at
)
SELECT
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS id,
bm.new_id AS base_id,
um.new_id AS contact_id,
e.role_code AS role_code,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM (
SELECT DISTINCT old_base_id, role_code, legacy_user_id
FROM tmp_base_contact_extract
) e
JOIN base_old_id_map bm ON bm.old_id = e.old_base_id
JOIN user_old_id_map um ON um.old_id = e.legacy_user_id
;
DROP TEMPORARY TABLE IF EXISTS tmp_base_contact_extract;
COMMIT;
-- +goose Down
-- no-op rollback

View File

@@ -0,0 +1,24 @@
-- +goose Up
-- Prepare staging tables for legacy `slings` import.
CREATE TABLE IF NOT EXISTS slings_old_import (
id int(11) NOT NULL,
cat int(11) NOT NULL,
name varchar(255) DEFAULT NULL,
type varchar(255) DEFAULT NULL,
length varchar(255) DEFAULT NULL,
weight varchar(255) DEFAULT NULL,
electric varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS slings_old_id_map (
old_id int(11) NOT NULL,
new_id binary(16) NOT NULL,
PRIMARY KEY (old_id),
UNIQUE KEY uq_slings_old_id_map_new_id (new_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- +goose Down
DROP TABLE IF EXISTS slings_old_id_map;
DROP TABLE IF EXISTS slings_old_import;

View File

@@ -0,0 +1,99 @@
-- +goose Up
-- Apply legacy sling staging data into new facilities schema.
START TRANSACTION;
-- 1) Reuse existing facilities rows by normalized (category, name, type) when possible.
INSERT INTO slings_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
f.id AS new_id
FROM slings_old_import s
JOIN facilities f
ON LOWER(TRIM(f.category)) = LOWER(TRIM(
CASE
WHEN s.cat = 1 THEN 'hems-hec-sling'
WHEN s.cat = 2 THEN 'logging-sling'
WHEN s.cat = 3 THEN 'heslo-sling'
WHEN s.cat IN (4, 6) THEN 'fuel-truck'
WHEN s.cat = 5 THEN 'hec-sling'
ELSE 'hec-sling'
END
))
AND LOWER(TRIM(f.name)) = LOWER(TRIM(COALESCE(s.name, '')))
AND LOWER(TRIM(f.type)) = LOWER(TRIM(COALESCE(s.type, '')))
LEFT JOIN slings_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
-- 2) Generate IDs for remaining legacy sling rows.
INSERT INTO slings_old_id_map (old_id, new_id)
SELECT
s.id AS old_id,
UNHEX(REPLACE(
LOWER(CONCAT(
LPAD(HEX(FLOOR(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED) / 65536)), 8, '0'),
'-',
LPAD(HEX(MOD(CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), 65536)), 4, '0'),
'-',
'7', LPAD(HEX(FLOOR(RAND() * 4096)), 3, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 16384) + 32768), 4, '0'),
'-',
LPAD(HEX(FLOOR(RAND() * 281474976710656)), 12, '0')
)),
'-', ''
)) AS new_id
FROM slings_old_import s
LEFT JOIN slings_old_id_map m ON m.old_id = s.id
WHERE m.old_id IS NULL;
-- 3) Upsert into facilities.
INSERT INTO facilities (
id,
category,
name,
type,
length,
weight,
electric,
note,
is_active,
created_at,
updated_at
)
SELECT
m.new_id AS id,
CASE
WHEN s.cat = 1 THEN 'hems-hec-sling'
WHEN s.cat = 2 THEN 'logging-sling'
WHEN s.cat = 3 THEN 'heslo-sling'
WHEN s.cat IN (4, 6) THEN 'fuel-truck'
WHEN s.cat = 5 THEN 'hec-sling'
ELSE 'hec-sling'
END AS category,
LEFT(TRIM(COALESCE(s.name, '')), 150) AS name,
LEFT(TRIM(COALESCE(s.type, '')), 100) AS type,
LEFT(TRIM(COALESCE(s.length, '')), 64) AS length,
LEFT(TRIM(COALESCE(s.weight, '')), 64) AS weight,
LEFT(TRIM(COALESCE(s.electric, '')), 255) AS electric,
NULL AS note,
1 AS is_active,
UTC_TIMESTAMP() AS created_at,
UTC_TIMESTAMP() AS updated_at
FROM slings_old_import s
JOIN slings_old_id_map m ON m.old_id = s.id
ON DUPLICATE KEY UPDATE
category = VALUES(category),
name = VALUES(name),
type = VALUES(type),
length = VALUES(length),
weight = VALUES(weight),
electric = VALUES(electric),
note = VALUES(note),
is_active = VALUES(is_active),
updated_at = UTC_TIMESTAMP();
COMMIT;
-- +goose Down
-- no-op rollback

View File

@@ -0,0 +1,17 @@
-- +goose Up
-- +goose StatementBegin
ALTER TABLE facilities
MODIFY COLUMN electric VARCHAR(255) NOT NULL DEFAULT '';
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
UPDATE facilities
SET electric = CASE
WHEN LOWER(TRIM(electric)) IN ('', '0', 'false', 'no', 'n') THEN '0'
ELSE '1'
END;
ALTER TABLE facilities
MODIFY COLUMN electric TINYINT(1) NOT NULL DEFAULT 0;
-- +goose StatementEnd

View File

@@ -0,0 +1,26 @@
-- +goose Up
-- Align duty roster schema with takeover flow.
-- A takeover creates a fresh roster row, so base/date must be a lookup index,
-- not a unique constraint.
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);
DROP INDEX idx_roster_base_date ON duty_rosters;
CREATE INDEX idx_roster_base_date
ON duty_rosters (base_id, duty_date);
-- +goose Down
DROP INDEX idx_roster_base_date ON duty_rosters;
CREATE UNIQUE INDEX idx_roster_base_date
ON duty_rosters (base_id, duty_date);
DROP INDEX idx_roster_flight_id ON duty_rosters;
ALTER TABLE duty_rosters
DROP COLUMN flight_id;

View File

@@ -0,0 +1,15 @@
-- +goose Up
-- Username uniqueness is now enforced in the backend for contact flows,
-- so keep a regular index for lookups instead of a unique constraint.
DROP INDEX IF EXISTS idx_users_username ON users;
CREATE INDEX idx_users_username
ON users (username);
-- +goose Down
DROP INDEX IF EXISTS idx_users_username ON users;
CREATE UNIQUE INDEX idx_users_username
ON users (username);
iya

View File

@@ -0,0 +1,53 @@
-- +goose Up
-- Normalize base operational shift times to use per-day ranges.
ALTER TABLE base_operational_shift_times
ADD COLUMN IF NOT EXISTS date_start DATE NULL AFTER base_id,
ADD COLUMN IF NOT EXISTS date_end DATE NULL AFTER date_start;
UPDATE base_operational_shift_times
SET date_start = COALESCE(date_start, operation_date),
date_end = COALESCE(date_end, operation_date)
WHERE deleted_at IS NULL;
ALTER TABLE base_operational_shift_times
DROP FOREIGN KEY fk_base_operational_shift_times_base;
ALTER TABLE base_operational_shift_times
DROP INDEX idx_base_operational_shift_times_base_date;
ALTER TABLE base_operational_shift_times
DROP COLUMN operation_date;
ALTER TABLE base_operational_shift_times
ADD KEY idx_base_operational_shift_times_base_date (base_id, date_start, date_end),
MODIFY COLUMN date_start DATE NULL,
MODIFY COLUMN date_end DATE NULL,
ADD CONSTRAINT fk_base_operational_shift_times_base
FOREIGN KEY (base_id) REFERENCES bases(id)
ON UPDATE CASCADE
ON DELETE CASCADE;
-- +goose Down
ALTER TABLE base_operational_shift_times
ADD COLUMN IF NOT EXISTS operation_date DATE NULL AFTER base_id;
UPDATE base_operational_shift_times
SET operation_date = COALESCE(operation_date, date_start)
WHERE deleted_at IS NULL;
ALTER TABLE base_operational_shift_times
DROP FOREIGN KEY fk_base_operational_shift_times_base;
ALTER TABLE base_operational_shift_times
DROP INDEX idx_base_operational_shift_times_base_date;
ALTER TABLE base_operational_shift_times
ADD KEY idx_base_operational_shift_times_base_date (base_id, operation_date),
DROP COLUMN date_start,
DROP COLUMN date_end,
MODIFY COLUMN operation_date DATE NOT NULL,
ADD CONSTRAINT fk_base_operational_shift_times_base
FOREIGN KEY (base_id) REFERENCES bases(id)
ON UPDATE CASCADE
ON DELETE CASCADE;

View File

@@ -0,0 +1,31 @@
-- +goose Up
ALTER TABLE bases
ADD COLUMN IF NOT EXISTS latitude DECIMAL(10,7) NOT NULL DEFAULT 0 AFTER address,
ADD COLUMN IF NOT EXISTS longitude DECIMAL(10,7) NOT NULL DEFAULT 0 AFTER latitude;
ALTER TABLE base_operational_shift_times
ADD COLUMN IF NOT EXISTS start_time_type VARCHAR(16) NOT NULL DEFAULT 'FIXED' AFTER date_end,
ADD COLUMN IF NOT EXISTS end_time_type VARCHAR(16) NOT NULL DEFAULT 'FIXED' AFTER start_time_type;
ALTER TABLE missions
ADD COLUMN IF NOT EXISTS start_time TIME NULL AFTER note,
ADD COLUMN IF NOT EXISTS end_time TIME NULL AFTER start_time;
ALTER TABLE missions
MODIFY COLUMN start_time TIME NULL,
MODIFY COLUMN end_time TIME NULL;
-- +goose Down
ALTER TABLE missions
DROP COLUMN IF EXISTS end_time,
DROP COLUMN IF EXISTS start_time;
ALTER TABLE base_operational_shift_times
DROP COLUMN IF EXISTS end_time_type,
DROP COLUMN IF EXISTS start_time_type;
ALTER TABLE bases
DROP COLUMN IF EXISTS longitude,
DROP COLUMN IF EXISTS latitude;

View File

@@ -0,0 +1,15 @@
-- +goose Up
-- Enable security-PIN confirmation for signing an EASA maintenance release
-- (Release to Service). Fresh DBs get this via the default PIN policy at seed
-- time; this backfills existing permission rows. The guard avoids overriding a
-- value an admin has already customised (updated_by set).
UPDATE permissions
SET requires_pin = 1
WHERE `key` = 'easa_release.sign'
AND (updated_by IS NULL OR LENGTH(updated_by) = 0);
-- +goose Down
UPDATE permissions
SET requires_pin = 0
WHERE `key` = 'easa_release.sign'
AND (updated_by IS NULL OR LENGTH(updated_by) = 0);