1
CREATE TABLE IF NOT EXISTS sync_changes (
2
change_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
3
tenant_id CHAR(36) NOT NULL,
4
entity_type VARCHAR(40) NOT NULL,
5
entity_id CHAR(36) NOT NULL,
6
operation VARCHAR(20) NOT NULL,
7
row_version INT NOT NULL,
8
data_json LONGTEXT NOT NULL,
9
changed_at DATETIME NOT NULL,
10
INDEX sync_changes_tenant_cursor (tenant_id, change_id),
11
CONSTRAINT sync_changes_tenant_fk FOREIGN KEY (tenant_id) REFERENCES tenants(id)
12
);
13
14
CREATE TABLE IF NOT EXISTS sync_operations (
15
id CHAR(36) PRIMARY KEY,
16
tenant_id CHAR(36) NOT NULL,
17
operation_id VARCHAR(100) NOT NULL,
18
idempotency_key VARCHAR(200) NOT NULL,
19
request_hash CHAR(64) NOT NULL,
20
result_json LONGTEXT NULL,
21
http_status SMALLINT NULL,
22
created_at DATETIME NOT NULL,
23
completed_at DATETIME NULL,
24
UNIQUE KEY sync_operations_tenant_operation (tenant_id, operation_id),
25
UNIQUE KEY sync_operations_tenant_idempotency (tenant_id, idempotency_key),
26
CONSTRAINT sync_operations_tenant_fk FOREIGN KEY (tenant_id) REFERENCES tenants(id)
27
);
28
29
-- Seed the cursor with the current server state. NOT EXISTS keeps a partially
30
-- applied migration safely repeatable without duplicating the baseline.
31
INSERT INTO sync_changes (tenant_id, entity_type, entity_id, operation, row_version, data_json, changed_at)
32
SELECT c.tenant_id, 'customers', c.id, IF(c.deleted_at IS NULL, 'upsert', 'delete'), c.row_version,
33
JSON_OBJECT('id', c.id, 'tenant_id', c.tenant_id, 'name', c.name, 'contact', c.contact, 'email', c.email, 'phone', c.phone, 'address', c.address, 'row_version', c.row_version, 'created_at', c.created_at, 'updated_at', c.updated_at, 'deleted_at', c.deleted_at),
34
UTC_TIMESTAMP()
35
FROM customers c
36
WHERE NOT EXISTS (SELECT 1 FROM sync_changes sc WHERE sc.tenant_id = c.tenant_id AND sc.entity_type = 'customers' AND sc.entity_id = c.id);
37
38
INSERT INTO sync_changes (tenant_id, entity_type, entity_id, operation, row_version, data_json, changed_at)
39
SELECT s.tenant_id, 'sites', s.id, IF(s.deleted_at IS NULL, 'upsert', 'delete'), s.row_version,
40
JSON_OBJECT('id', s.id, 'tenant_id', s.tenant_id, 'customer_id', s.customer_id, 'name', s.name, 'address', s.address, 'row_version', s.row_version, 'created_at', s.created_at, 'updated_at', s.updated_at, 'deleted_at', s.deleted_at),
41
UTC_TIMESTAMP()
42
FROM sites s
43
WHERE NOT EXISTS (SELECT 1 FROM sync_changes sc WHERE sc.tenant_id = s.tenant_id AND sc.entity_type = 'sites' AND sc.entity_id = s.id);
44
45
INSERT INTO sync_changes (tenant_id, entity_type, entity_id, operation, row_version, data_json, changed_at)
46
SELECT j.tenant_id, 'jobs', j.id, IF(j.deleted_at IS NULL, 'upsert', 'delete'), j.row_version,
47
JSON_OBJECT('id', j.id, 'tenant_id', j.tenant_id, 'customer_id', j.customer_id, 'site_id', j.site_id, 'number', j.number, 'title', j.title, 'description', j.description, 'status', j.status, 'row_version', j.row_version, 'created_at', j.created_at, 'updated_at', j.updated_at, 'deleted_at', j.deleted_at),
48
UTC_TIMESTAMP()
49
FROM jobs j
50
WHERE NOT EXISTS (SELECT 1 FROM sync_changes sc WHERE sc.tenant_id = j.tenant_id AND sc.entity_type = 'jobs' AND sc.entity_id = j.id);
51
52
INSERT INTO sync_changes (tenant_id, entity_type, entity_id, operation, row_version, data_json, changed_at)
53
SELECT e.tenant_id, 'employee_profiles', e.id, IF(e.deleted_at IS NULL, 'upsert', 'delete'), e.row_version,
54
JSON_OBJECT('id', e.id, 'tenant_id', e.tenant_id, 'user_id', e.user_id, 'employee_number', e.employee_number, 'first_name', e.first_name, 'last_name', e.last_name, 'email', e.email, 'phone', e.phone, 'is_active', e.is_active, 'row_version', e.row_version, 'created_at', e.created_at, 'updated_at', e.updated_at, 'deleted_at', e.deleted_at),
55
UTC_TIMESTAMP()
56
FROM employee_profiles e
57
WHERE NOT EXISTS (SELECT 1 FROM sync_changes sc WHERE sc.tenant_id = e.tenant_id AND sc.entity_type = 'employee_profiles' AND sc.entity_id = e.id);
58
59
INSERT INTO sync_changes (tenant_id, entity_type, entity_id, operation, row_version, data_json, changed_at)
60
SELECT a.tenant_id, 'job_assignments', a.id, IF(a.deleted_at IS NULL, 'upsert', 'delete'), a.row_version,
61
JSON_OBJECT('id', a.id, 'tenant_id', a.tenant_id, 'job_id', a.job_id, 'employee_id', a.employee_id, 'assigned_from', a.assigned_from, 'assigned_until', a.assigned_until, 'row_version', a.row_version, 'created_at', a.created_at, 'updated_at', a.updated_at, 'deleted_at', a.deleted_at),
62
UTC_TIMESTAMP()
63
FROM job_assignments a
64
WHERE NOT EXISTS (SELECT 1 FROM sync_changes sc WHERE sc.tenant_id = a.tenant_id AND sc.entity_type = 'job_assignments' AND sc.entity_id = a.id);
65