-- Fleet DNS: zones, locations, nodes, aliases, sync CREATE TABLE IF NOT EXISTS zones ( id TEXT PRIMARY KEY NOT NULL, cf_zone_id TEXT, name TEXT NOT NULL UNIQUE, role TEXT NOT NULL DEFAULT 'routing', naming_template TEXT NOT NULL DEFAULT '{loc}-{role}{nn}.{zone}', default_ttl INTEGER NOT NULL DEFAULT 300, last_sync_at TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE IF NOT EXISTS locations ( id TEXT PRIMARY KEY NOT NULL, code TEXT NOT NULL UNIQUE, name TEXT NOT NULL, country TEXT, sort_order INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE TABLE IF NOT EXISTS nodes ( id TEXT PRIMARY KEY NOT NULL, zone_id TEXT NOT NULL REFERENCES zones(id) ON DELETE CASCADE, location_id TEXT NOT NULL REFERENCES locations(id), hostname TEXT NOT NULL, role TEXT NOT NULL, index_num INTEGER NOT NULL DEFAULT 1, provider_tag TEXT, notes TEXT, sync_status TEXT NOT NULL DEFAULT 'pending', cf_a_record_id TEXT, cf_aaaa_record_id TEXT, last_error TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE (zone_id, hostname) ); CREATE INDEX IF NOT EXISTS idx_nodes_zone ON nodes(zone_id); CREATE INDEX IF NOT EXISTS idx_nodes_location ON nodes(location_id); CREATE INDEX IF NOT EXISTS idx_nodes_sync ON nodes(sync_status); CREATE TABLE IF NOT EXISTS node_addresses ( id TEXT PRIMARY KEY NOT NULL, node_id TEXT NOT NULL REFERENCES nodes(id) ON DELETE CASCADE, family TEXT NOT NULL, ip TEXT NOT NULL, UNIQUE (node_id, family) ); CREATE TABLE IF NOT EXISTS aliases ( id TEXT PRIMARY KEY NOT NULL, zone_id TEXT NOT NULL REFERENCES zones(id) ON DELETE CASCADE, name TEXT NOT NULL, purpose TEXT NOT NULL DEFAULT 'geo', mode TEXT NOT NULL DEFAULT 'primary', target_node_id TEXT NOT NULL REFERENCES nodes(id) ON DELETE RESTRICT, sync_status TEXT NOT NULL DEFAULT 'pending', cf_record_id TEXT, last_error TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE (zone_id, name) ); CREATE INDEX IF NOT EXISTS idx_aliases_zone ON aliases(zone_id); CREATE INDEX IF NOT EXISTS idx_aliases_target ON aliases(target_node_id); CREATE INDEX IF NOT EXISTS idx_aliases_sync ON aliases(sync_status); CREATE TABLE IF NOT EXISTS sync_jobs ( id TEXT PRIMARY KEY NOT NULL, zone_id TEXT NOT NULL REFERENCES zones(id) ON DELETE CASCADE, status TEXT NOT NULL DEFAULT 'pending', diff_json TEXT, error TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), finished_at TEXT ); CREATE INDEX IF NOT EXISTS idx_sync_jobs_zone ON sync_jobs(zone_id); CREATE TABLE IF NOT EXISTS sync_events ( id TEXT PRIMARY KEY NOT NULL, job_id TEXT NOT NULL REFERENCES sync_jobs(id) ON DELETE CASCADE, kind TEXT NOT NULL, record_name TEXT, record_type TEXT, detail TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_sync_events_job ON sync_events(job_id); CREATE TABLE IF NOT EXISTS ignored_orphans ( id TEXT PRIMARY KEY NOT NULL, zone_id TEXT NOT NULL REFERENCES zones(id) ON DELETE CASCADE, record_name TEXT NOT NULL, record_type TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE (zone_id, record_name, record_type) ); -- Seed locations (IATA / routing codes from naming doc) INSERT OR IGNORE INTO locations (id, code, name, country, sort_order) VALUES ('loc-msk', 'msk', 'Москва', 'RU', 10), ('loc-fra', 'fra', 'Франкфурт', 'DE', 20), ('loc-ams', 'ams', 'Амстердам', 'NL', 30), ('loc-hel', 'hel', 'Хельсинки', 'FI', 40), ('loc-par', 'par', 'Париж', 'FR', 50); -- Extend settings defaults for naming / TTL ALTER TABLE app_settings ADD COLUMN default_ttl INTEGER NOT NULL DEFAULT 300; ALTER TABLE app_settings ADD COLUMN naming_template TEXT NOT NULL DEFAULT '{loc}-{role}{nn}.{zone}'; ALTER TABLE app_settings ADD COLUMN proxied_lock INTEGER NOT NULL DEFAULT 1;