@@ -1,439 +0,0 @@ |
||
| 1 |
-# SQLite Database |
|
| 2 |
- |
|
| 3 |
-Madagascar Local Authority folosește SQLite ca sursă de adevăr runtime pentru hosturi, aliasuri, vhosturi, Work Orders, workeri de date și certificate. |
|
| 4 |
- |
|
| 5 |
-Locația implicită în checkout: |
|
| 6 |
- |
|
| 7 |
-```text |
|
| 8 |
-var/host-manager.sqlite |
|
| 9 |
-``` |
|
| 10 |
- |
|
| 11 |
-Locația runtime pe jumper: |
|
| 12 |
- |
|
| 13 |
-```text |
|
| 14 |
-/usr/local/xdev-host-manager/var/host-manager.sqlite |
|
| 15 |
-``` |
|
| 16 |
- |
|
| 17 |
-Path-ul poate fi schimbat cu: |
|
| 18 |
- |
|
| 19 |
-```text |
|
| 20 |
-HOST_MANAGER_DB=/path/to/host-manager.sqlite |
|
| 21 |
-``` |
|
| 22 |
- |
|
| 23 |
-## Principii |
|
| 24 |
- |
|
| 25 |
-Hosturile sunt identificate prin FQDN complet, nu prin short name. Exemplu: `gw.local` și `gw.remote` sunt identități diferite. Coloana compatibilă `legacy_id` păstrează ID-ul scurt folosit de UI-ul curent, dar cheia reală este `hosts.fqdn`. |
|
| 26 |
- |
|
| 27 |
-Schema evită să transforme `hosts` într-un tabel cu prea multe coloane. Datele specializate sunt în tabele separate: |
|
| 28 |
- |
|
| 29 |
-- aliasuri: `host_aliases` |
|
| 30 |
-- roluri: `host_roles` |
|
| 31 |
-- surse: `host_sources` |
|
| 32 |
-- flaguri: `host_flags` |
|
| 33 |
-- SSH: `host_ssh` |
|
| 34 |
-- vhosturi mutabile: `vhosts` |
|
| 35 |
-- certificate: `certificates`, `certificate_dns_names` |
|
| 36 |
-- workeri și observații: `data_workers`, `dhcp_leases`, `mdns_observations` |
|
| 37 |
- |
|
| 38 |
-`documents` rămâne doar tabel legacy pentru migrarea din modelul vechi document-store. Aplicația nu îl mai folosește ca sursă de adevăr. |
|
| 39 |
- |
|
| 40 |
-## Schema Version |
|
| 41 |
- |
|
| 42 |
-Schema curentă este versiunea `2`. |
|
| 43 |
- |
|
| 44 |
-```sql |
|
| 45 |
-schema_meta('schema_version') = '2'
|
|
| 46 |
-``` |
|
| 47 |
- |
|
| 48 |
-`schema_meta` păstrează și metadate runtime precum `registry_updated_at`. |
|
| 49 |
- |
|
| 50 |
-## Catalog |
|
| 51 |
- |
|
| 52 |
-| Tabel | Rol | |
|
| 53 |
-|-------|-----| |
|
| 54 |
-| `schema_meta` | metadate de schemă/runtime | |
|
| 55 |
-| `documents` | document-store legacy pentru migrare | |
|
| 56 |
-| `hosts` | hosturi canonice, identificate prin FQDN | |
|
| 57 |
-| `host_aliases` | aliasuri păstrate inclusiv după retragere | |
|
| 58 |
-| `host_roles` | roluri active/retrase per host | |
|
| 59 |
-| `host_sources` | surse active/retrase per host | |
|
| 60 |
-| `host_flags` | flaguri extensibile per host | |
|
| 61 |
-| `host_ssh` | profile SSH per host | |
|
| 62 |
-| `vhosts` | vhosturi mutabile între hosturi | |
|
| 63 |
-| `data_workers` | workeri/surse care colectează date | |
|
| 64 |
-| `dhcp_leases` | date observate din DHCP lease/reservation | |
|
| 65 |
-| `mdns_observations` | date observate din mDNS | |
|
| 66 |
-| `certificates` | certificate emise de CA locală | |
|
| 67 |
-| `certificate_dns_names` | SAN DNS names pentru certificate | |
|
| 68 |
-| `work_orders` | Work Orders | |
|
| 69 |
-| `work_order_checklist` | checklist items pentru Work Orders | |
|
| 70 |
-| `work_order_actions` | acțiuni confirmabile pentru Work Orders | |
|
| 71 |
- |
|
| 72 |
-## Tabele |
|
| 73 |
- |
|
| 74 |
-### `hosts` |
|
| 75 |
- |
|
| 76 |
-```sql |
|
| 77 |
-CREATE TABLE hosts ( |
|
| 78 |
- fqdn TEXT PRIMARY KEY, |
|
| 79 |
- legacy_id TEXT NOT NULL UNIQUE, |
|
| 80 |
- status TEXT NOT NULL DEFAULT 'active', |
|
| 81 |
- hosts_ip TEXT NOT NULL DEFAULT '', |
|
| 82 |
- dns_ip TEXT NOT NULL DEFAULT '', |
|
| 83 |
- monitoring TEXT NOT NULL DEFAULT 'pending', |
|
| 84 |
- notes TEXT NOT NULL DEFAULT '', |
|
| 85 |
- created_at TEXT NOT NULL, |
|
| 86 |
- updated_at TEXT NOT NULL |
|
| 87 |
-); |
|
| 88 |
-``` |
|
| 89 |
- |
|
| 90 |
-Chei și indexuri: |
|
| 91 |
- |
|
| 92 |
-- PK: `hosts(fqdn)` |
|
| 93 |
-- UNIQUE: `hosts(legacy_id)` |
|
| 94 |
- |
|
| 95 |
-### `host_aliases` |
|
| 96 |
- |
|
| 97 |
-```sql |
|
| 98 |
-CREATE TABLE host_aliases ( |
|
| 99 |
- alias_name TEXT NOT NULL, |
|
| 100 |
- host_fqdn TEXT NOT NULL REFERENCES hosts(fqdn) |
|
| 101 |
- ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 102 |
- alias_kind TEXT NOT NULL DEFAULT 'declared', |
|
| 103 |
- status TEXT NOT NULL DEFAULT 'active', |
|
| 104 |
- is_dns_published INTEGER NOT NULL DEFAULT 1, |
|
| 105 |
- created_at TEXT NOT NULL, |
|
| 106 |
- retired_at TEXT, |
|
| 107 |
- notes TEXT NOT NULL DEFAULT '', |
|
| 108 |
- PRIMARY KEY (alias_name, host_fqdn) |
|
| 109 |
-); |
|
| 110 |
-``` |
|
| 111 |
- |
|
| 112 |
-Indexuri: |
|
| 113 |
- |
|
| 114 |
-```sql |
|
| 115 |
-CREATE UNIQUE INDEX idx_host_aliases_active_name |
|
| 116 |
-ON host_aliases(alias_name) |
|
| 117 |
-WHERE status = 'active'; |
|
| 118 |
- |
|
| 119 |
-CREATE INDEX idx_host_aliases_host_status |
|
| 120 |
-ON host_aliases(host_fqdn, status); |
|
| 121 |
-``` |
|
| 122 |
- |
|
| 123 |
-Reguli: |
|
| 124 |
- |
|
| 125 |
-- aliasurile retrase nu se șterg; se setează `status = 'retired'` |
|
| 126 |
-- un alias activ poate aparține unui singur host |
|
| 127 |
-- aliasurile scurte derivate, cum ar fi `baobab`, sunt păstrate cu `alias_kind = 'derived'` |
|
| 128 |
-- short aliases derivate din vhosturi, cum ar fi `pmx.baobab`, sunt păstrate cu `alias_kind = 'derived-vhost'` |
|
| 129 |
- |
|
| 130 |
-### `vhosts` |
|
| 131 |
- |
|
| 132 |
-```sql |
|
| 133 |
-CREATE TABLE vhosts ( |
|
| 134 |
- vhost_fqdn TEXT PRIMARY KEY, |
|
| 135 |
- host_fqdn TEXT NOT NULL REFERENCES hosts(fqdn) |
|
| 136 |
- ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 137 |
- status TEXT NOT NULL DEFAULT 'active', |
|
| 138 |
- service_name TEXT NOT NULL DEFAULT '', |
|
| 139 |
- upstream_url TEXT NOT NULL DEFAULT '', |
|
| 140 |
- tls_mode TEXT NOT NULL DEFAULT 'local-ca', |
|
| 141 |
- certificate_id TEXT REFERENCES certificates(certificate_id) |
|
| 142 |
- ON UPDATE CASCADE ON DELETE SET NULL, |
|
| 143 |
- notes TEXT NOT NULL DEFAULT '', |
|
| 144 |
- created_at TEXT NOT NULL, |
|
| 145 |
- updated_at TEXT NOT NULL |
|
| 146 |
-); |
|
| 147 |
-``` |
|
| 148 |
- |
|
| 149 |
-Indexuri: |
|
| 150 |
- |
|
| 151 |
-```sql |
|
| 152 |
-CREATE INDEX idx_vhosts_host_status |
|
| 153 |
-ON vhosts(host_fqdn, status); |
|
| 154 |
-``` |
|
| 155 |
- |
|
| 156 |
-Un vhost se mută de pe un host pe altul prin update pe `vhosts.host_fqdn`. Vhosturile retrase rămân în tabel cu `status = 'retired'`. |
|
| 157 |
- |
|
| 158 |
-### `host_roles`, `host_sources`, `host_flags`, `host_ssh` |
|
| 159 |
- |
|
| 160 |
-```sql |
|
| 161 |
-CREATE TABLE host_roles ( |
|
| 162 |
- host_fqdn TEXT NOT NULL REFERENCES hosts(fqdn) |
|
| 163 |
- ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 164 |
- role TEXT NOT NULL, |
|
| 165 |
- status TEXT NOT NULL DEFAULT 'active', |
|
| 166 |
- created_at TEXT NOT NULL, |
|
| 167 |
- retired_at TEXT, |
|
| 168 |
- PRIMARY KEY (host_fqdn, role) |
|
| 169 |
-); |
|
| 170 |
- |
|
| 171 |
-CREATE TABLE host_sources ( |
|
| 172 |
- host_fqdn TEXT NOT NULL REFERENCES hosts(fqdn) |
|
| 173 |
- ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 174 |
- source TEXT NOT NULL, |
|
| 175 |
- status TEXT NOT NULL DEFAULT 'active', |
|
| 176 |
- created_at TEXT NOT NULL, |
|
| 177 |
- retired_at TEXT, |
|
| 178 |
- PRIMARY KEY (host_fqdn, source) |
|
| 179 |
-); |
|
| 180 |
- |
|
| 181 |
-CREATE TABLE host_flags ( |
|
| 182 |
- host_fqdn TEXT NOT NULL REFERENCES hosts(fqdn) |
|
| 183 |
- ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 184 |
- flag TEXT NOT NULL, |
|
| 185 |
- value TEXT NOT NULL DEFAULT '1', |
|
| 186 |
- created_at TEXT NOT NULL, |
|
| 187 |
- updated_at TEXT NOT NULL, |
|
| 188 |
- PRIMARY KEY (host_fqdn, flag) |
|
| 189 |
-); |
|
| 190 |
- |
|
| 191 |
-CREATE TABLE host_ssh ( |
|
| 192 |
- host_fqdn TEXT NOT NULL REFERENCES hosts(fqdn) |
|
| 193 |
- ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 194 |
- profile_name TEXT NOT NULL DEFAULT 'default', |
|
| 195 |
- username TEXT NOT NULL DEFAULT '', |
|
| 196 |
- port INTEGER NOT NULL DEFAULT 22, |
|
| 197 |
- identity_file TEXT NOT NULL DEFAULT '', |
|
| 198 |
- address TEXT NOT NULL DEFAULT '', |
|
| 199 |
- local_forward_host TEXT NOT NULL DEFAULT '', |
|
| 200 |
- local_forward_port INTEGER, |
|
| 201 |
- remote_forward_host TEXT NOT NULL DEFAULT '', |
|
| 202 |
- remote_forward_port INTEGER, |
|
| 203 |
- notes TEXT NOT NULL DEFAULT '', |
|
| 204 |
- created_at TEXT NOT NULL, |
|
| 205 |
- updated_at TEXT NOT NULL, |
|
| 206 |
- PRIMARY KEY (host_fqdn, profile_name) |
|
| 207 |
-); |
|
| 208 |
-``` |
|
| 209 |
- |
|
| 210 |
-### `data_workers` |
|
| 211 |
- |
|
| 212 |
-```sql |
|
| 213 |
-CREATE TABLE data_workers ( |
|
| 214 |
- worker_id TEXT PRIMARY KEY, |
|
| 215 |
- worker_type TEXT NOT NULL, |
|
| 216 |
- name TEXT NOT NULL DEFAULT '', |
|
| 217 |
- status TEXT NOT NULL DEFAULT 'active', |
|
| 218 |
- source TEXT NOT NULL DEFAULT '', |
|
| 219 |
- last_run_at TEXT, |
|
| 220 |
- notes TEXT NOT NULL DEFAULT '', |
|
| 221 |
- created_at TEXT NOT NULL, |
|
| 222 |
- updated_at TEXT NOT NULL |
|
| 223 |
-); |
|
| 224 |
-``` |
|
| 225 |
- |
|
| 226 |
-Indexuri: |
|
| 227 |
- |
|
| 228 |
-```sql |
|
| 229 |
-CREATE INDEX idx_data_workers_type_status |
|
| 230 |
-ON data_workers(worker_type, status); |
|
| 231 |
-``` |
|
| 232 |
- |
|
| 233 |
-Seed implicit: |
|
| 234 |
- |
|
| 235 |
-- `dhcp-router`, type `dhcp` |
|
| 236 |
-- `mdns-listener`, type `mdns` |
|
| 237 |
- |
|
| 238 |
-### `dhcp_leases` |
|
| 239 |
- |
|
| 240 |
-```sql |
|
| 241 |
-CREATE TABLE dhcp_leases ( |
|
| 242 |
- lease_key TEXT PRIMARY KEY, |
|
| 243 |
- worker_id TEXT NOT NULL REFERENCES data_workers(worker_id) |
|
| 244 |
- ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 245 |
- host_fqdn TEXT REFERENCES hosts(fqdn) |
|
| 246 |
- ON UPDATE CASCADE ON DELETE SET NULL, |
|
| 247 |
- observed_name TEXT NOT NULL DEFAULT '', |
|
| 248 |
- ip_address TEXT NOT NULL, |
|
| 249 |
- mac_address TEXT NOT NULL DEFAULT '', |
|
| 250 |
- lease_state TEXT NOT NULL DEFAULT '', |
|
| 251 |
- first_seen TEXT NOT NULL, |
|
| 252 |
- last_seen TEXT NOT NULL, |
|
| 253 |
- raw TEXT NOT NULL DEFAULT '' |
|
| 254 |
-); |
|
| 255 |
-``` |
|
| 256 |
- |
|
| 257 |
-Indexuri: |
|
| 258 |
- |
|
| 259 |
-```sql |
|
| 260 |
-CREATE INDEX idx_dhcp_leases_ip ON dhcp_leases(ip_address); |
|
| 261 |
-CREATE INDEX idx_dhcp_leases_mac ON dhcp_leases(mac_address); |
|
| 262 |
-CREATE INDEX idx_dhcp_leases_worker_last_seen |
|
| 263 |
-ON dhcp_leases(worker_id, last_seen); |
|
| 264 |
-``` |
|
| 265 |
- |
|
| 266 |
-### `mdns_observations` |
|
| 267 |
- |
|
| 268 |
-```sql |
|
| 269 |
-CREATE TABLE mdns_observations ( |
|
| 270 |
- observation_key TEXT PRIMARY KEY, |
|
| 271 |
- worker_id TEXT NOT NULL REFERENCES data_workers(worker_id) |
|
| 272 |
- ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 273 |
- host_fqdn TEXT REFERENCES hosts(fqdn) |
|
| 274 |
- ON UPDATE CASCADE ON DELETE SET NULL, |
|
| 275 |
- observed_name TEXT NOT NULL, |
|
| 276 |
- ip_address TEXT NOT NULL, |
|
| 277 |
- rr_type TEXT NOT NULL DEFAULT 'A', |
|
| 278 |
- ttl INTEGER NOT NULL DEFAULT 0, |
|
| 279 |
- first_seen TEXT NOT NULL, |
|
| 280 |
- last_seen TEXT NOT NULL, |
|
| 281 |
- seen_count INTEGER NOT NULL DEFAULT 1, |
|
| 282 |
- last_peer TEXT NOT NULL DEFAULT '', |
|
| 283 |
- raw TEXT NOT NULL DEFAULT '' |
|
| 284 |
-); |
|
| 285 |
-``` |
|
| 286 |
- |
|
| 287 |
-Indexuri: |
|
| 288 |
- |
|
| 289 |
-```sql |
|
| 290 |
-CREATE INDEX idx_mdns_observations_name ON mdns_observations(observed_name); |
|
| 291 |
-CREATE INDEX idx_mdns_observations_ip ON mdns_observations(ip_address); |
|
| 292 |
-CREATE INDEX idx_mdns_observations_worker_last_seen |
|
| 293 |
-ON mdns_observations(worker_id, last_seen); |
|
| 294 |
-``` |
|
| 295 |
- |
|
| 296 |
-### `certificates` și `certificate_dns_names` |
|
| 297 |
- |
|
| 298 |
-```sql |
|
| 299 |
-CREATE TABLE certificates ( |
|
| 300 |
- certificate_id TEXT PRIMARY KEY, |
|
| 301 |
- host_fqdn TEXT REFERENCES hosts(fqdn) |
|
| 302 |
- ON UPDATE CASCADE ON DELETE SET NULL, |
|
| 303 |
- common_name TEXT NOT NULL DEFAULT '', |
|
| 304 |
- subject TEXT NOT NULL DEFAULT '', |
|
| 305 |
- issuer TEXT NOT NULL DEFAULT '', |
|
| 306 |
- serial TEXT UNIQUE, |
|
| 307 |
- status TEXT NOT NULL DEFAULT 'issued', |
|
| 308 |
- not_before TEXT NOT NULL DEFAULT '', |
|
| 309 |
- not_after TEXT NOT NULL DEFAULT '', |
|
| 310 |
- fingerprint_sha256 TEXT UNIQUE, |
|
| 311 |
- cert_path TEXT NOT NULL DEFAULT '', |
|
| 312 |
- csr_path TEXT NOT NULL DEFAULT '', |
|
| 313 |
- created_at TEXT NOT NULL, |
|
| 314 |
- updated_at TEXT NOT NULL, |
|
| 315 |
- notes TEXT NOT NULL DEFAULT '' |
|
| 316 |
-); |
|
| 317 |
- |
|
| 318 |
-CREATE TABLE certificate_dns_names ( |
|
| 319 |
- certificate_id TEXT NOT NULL REFERENCES certificates(certificate_id) |
|
| 320 |
- ON UPDATE CASCADE ON DELETE CASCADE, |
|
| 321 |
- dns_name TEXT NOT NULL, |
|
| 322 |
- PRIMARY KEY (certificate_id, dns_name) |
|
| 323 |
-); |
|
| 324 |
-``` |
|
| 325 |
- |
|
| 326 |
-Indexuri: |
|
| 327 |
- |
|
| 328 |
-```sql |
|
| 329 |
-CREATE INDEX idx_certificate_dns_names_dns_name |
|
| 330 |
-ON certificate_dns_names(dns_name); |
|
| 331 |
-``` |
|
| 332 |
- |
|
| 333 |
-Certificatele emise sunt sincronizate când aplicația citește lista CA prin `ca_manager.sh list-json`. |
|
| 334 |
- |
|
| 335 |
-### Work Orders |
|
| 336 |
- |
|
| 337 |
-```sql |
|
| 338 |
-CREATE TABLE work_orders ( |
|
| 339 |
- id TEXT PRIMARY KEY, |
|
| 340 |
- status TEXT NOT NULL DEFAULT 'pending', |
|
| 341 |
- title TEXT NOT NULL DEFAULT '', |
|
| 342 |
- reason TEXT NOT NULL DEFAULT '', |
|
| 343 |
- created_at TEXT NOT NULL, |
|
| 344 |
- confirmed_at TEXT NOT NULL DEFAULT '', |
|
| 345 |
- result TEXT NOT NULL DEFAULT '', |
|
| 346 |
- updated_at TEXT NOT NULL |
|
| 347 |
-); |
|
| 348 |
- |
|
| 349 |
-CREATE TABLE work_order_checklist ( |
|
| 350 |
- work_order_id TEXT NOT NULL REFERENCES work_orders(id) |
|
| 351 |
- ON UPDATE CASCADE ON DELETE CASCADE, |
|
| 352 |
- item_id TEXT NOT NULL, |
|
| 353 |
- text TEXT NOT NULL DEFAULT '', |
|
| 354 |
- status TEXT NOT NULL DEFAULT 'pending', |
|
| 355 |
- owner TEXT NOT NULL DEFAULT '', |
|
| 356 |
- notes TEXT NOT NULL DEFAULT '', |
|
| 357 |
- updated_at TEXT NOT NULL DEFAULT '', |
|
| 358 |
- PRIMARY KEY (work_order_id, item_id) |
|
| 359 |
-); |
|
| 360 |
- |
|
| 361 |
-CREATE TABLE work_order_actions ( |
|
| 362 |
- work_order_id TEXT NOT NULL REFERENCES work_orders(id) |
|
| 363 |
- ON UPDATE CASCADE ON DELETE CASCADE, |
|
| 364 |
- position INTEGER NOT NULL, |
|
| 365 |
- type TEXT NOT NULL, |
|
| 366 |
- host_fqdn TEXT REFERENCES hosts(fqdn) |
|
| 367 |
- ON UPDATE CASCADE ON DELETE SET NULL, |
|
| 368 |
- host_legacy_id TEXT NOT NULL DEFAULT '', |
|
| 369 |
- name TEXT NOT NULL DEFAULT '', |
|
| 370 |
- payload TEXT NOT NULL DEFAULT '', |
|
| 371 |
- PRIMARY KEY (work_order_id, position) |
|
| 372 |
-); |
|
| 373 |
-``` |
|
| 374 |
- |
|
| 375 |
-## Migrare și Seed |
|
| 376 |
- |
|
| 377 |
-La prima inițializare a unei baze fără rânduri în `hosts`, aplicația seed-uiește din: |
|
| 378 |
- |
|
| 379 |
-1. `documents.name = 'hosts_yaml'`, dacă există din vechiul model |
|
| 380 |
-2. `config/hosts.yaml`, dacă documentul legacy lipsește |
|
| 381 |
-3. document gol valid, dacă lipsește și seed-ul |
|
| 382 |
- |
|
| 383 |
-Work Orders se seed-uiesc similar din `documents.name = 'work_orders_yaml'` sau `config/work-orders.yaml`. |
|
| 384 |
- |
|
| 385 |
-Seed-ul curent produce: |
|
| 386 |
- |
|
| 387 |
-- 11 hosturi cunoscute |
|
| 388 |
-- aliasuri scurte derivate pentru hosturi și vhosturi |
|
| 389 |
-- vhosturile `hosts.*`, `pmx.*` și `pbs.*` |
|
| 390 |
-- workerii `dhcp-router` și `mdns-listener` |
|
| 391 |
-- Work Order-ul existent pentru retragerea numelor legacy |
|
| 392 |
- |
|
| 393 |
-`config/local-hosts.tsv` rămâne manifest generat explicit din tabelele runtime. |
|
| 394 |
- |
|
| 395 |
-## Inspecție |
|
| 396 |
- |
|
| 397 |
-Pe jumper: |
|
| 398 |
- |
|
| 399 |
-```bash |
|
| 400 |
-cd /usr/local/xdev-host-manager |
|
| 401 |
-sqlite3 var/host-manager.sqlite '.tables' |
|
| 402 |
-sqlite3 var/host-manager.sqlite '.schema hosts' |
|
| 403 |
-sqlite3 var/host-manager.sqlite '.schema host_aliases' |
|
| 404 |
-sqlite3 var/host-manager.sqlite '.schema vhosts' |
|
| 405 |
-sqlite3 var/host-manager.sqlite 'pragma foreign_key_list(vhosts);' |
|
| 406 |
-sqlite3 var/host-manager.sqlite 'pragma index_list(host_aliases);' |
|
| 407 |
-sqlite3 var/host-manager.sqlite 'select fqdn, legacy_id, status, dns_ip from hosts order by legacy_id;' |
|
| 408 |
-sqlite3 var/host-manager.sqlite 'select alias_name, host_fqdn, alias_kind, status from host_aliases order by alias_name;' |
|
| 409 |
-sqlite3 var/host-manager.sqlite 'select vhost_fqdn, host_fqdn, status from vhosts order by vhost_fqdn;' |
|
| 410 |
-``` |
|
| 411 |
- |
|
| 412 |
-## Backup |
|
| 413 |
- |
|
| 414 |
-Backup recomandat: |
|
| 415 |
- |
|
| 416 |
-```bash |
|
| 417 |
-cd /usr/local/xdev-host-manager |
|
| 418 |
-sqlite3 var/host-manager.sqlite ".backup 'backups/host-manager/host-manager.sqlite.$(date +%Y%m%d_%H%M%S).bak'" |
|
| 419 |
-``` |
|
| 420 |
- |
|
| 421 |
-Cu WAL activ, o copie brută trebuie să trateze fișierele ca set coerent: |
|
| 422 |
- |
|
| 423 |
-```text |
|
| 424 |
-var/host-manager.sqlite |
|
| 425 |
-var/host-manager.sqlite-wal |
|
| 426 |
-var/host-manager.sqlite-shm |
|
| 427 |
-``` |
|
| 428 |
- |
|
| 429 |
-## Restore |
|
| 430 |
- |
|
| 431 |
-Restore-ul înlocuiește sursa de adevăr runtime: |
|
| 432 |
- |
|
| 433 |
-```bash |
|
| 434 |
-sudo systemctl stop host-manager |
|
| 435 |
-sudo cp backups/host-manager/host-manager.sqlite.YYYYMMDD_HHMMSS.bak var/host-manager.sqlite |
|
| 436 |
-sudo chown host-manager:host-manager var/host-manager.sqlite |
|
| 437 |
-sudo systemctl start host-manager |
|
| 438 |
-curl -fsS http://127.0.0.1:8088/healthz >/dev/null |
|
| 439 |
-``` |
|
@@ -0,0 +1,157 @@ |
||
| 1 |
+# SQLite Database |
|
| 2 |
+ |
|
| 3 |
+Madagascar Local Authority folosește SQLite ca sursă de adevăr runtime pentru hosturi, aliasuri, vhosturi, Work Orders, workeri de date și certificate. |
|
| 4 |
+ |
|
| 5 |
+Locația implicită în checkout: |
|
| 6 |
+ |
|
| 7 |
+```text |
|
| 8 |
+var/host-manager.sqlite |
|
| 9 |
+``` |
|
| 10 |
+ |
|
| 11 |
+Locația runtime pe jumper: |
|
| 12 |
+ |
|
| 13 |
+```text |
|
| 14 |
+/usr/local/xdev-host-manager/var/host-manager.sqlite |
|
| 15 |
+``` |
|
| 16 |
+ |
|
| 17 |
+Path-ul poate fi schimbat cu: |
|
| 18 |
+ |
|
| 19 |
+```text |
|
| 20 |
+HOST_MANAGER_DB=/path/to/host-manager.sqlite |
|
| 21 |
+``` |
|
| 22 |
+ |
|
| 23 |
+## Principii |
|
| 24 |
+ |
|
| 25 |
+Hosturile sunt identificate prin FQDN complet, nu prin short name. Exemplu: `gw.local` și `gw.remote` sunt identități diferite. Coloana compatibilă `legacy_id` păstrează ID-ul scurt folosit de UI-ul curent, dar cheia reală este `hosts.fqdn`. |
|
| 26 |
+ |
|
| 27 |
+Schema evită să transforme `hosts` într-un tabel cu prea multe coloane. Datele specializate stau în tabele separate: |
|
| 28 |
+ |
|
| 29 |
+- aliasuri: [`host_aliases`](tables/host_aliases.md) |
|
| 30 |
+- roluri: [`host_roles`](tables/host_roles.md) |
|
| 31 |
+- surse: [`host_sources`](tables/host_sources.md) |
|
| 32 |
+- flaguri: [`host_flags`](tables/host_flags.md) |
|
| 33 |
+- SSH: [`host_ssh`](tables/host_ssh.md) |
|
| 34 |
+- vhosturi mutabile: [`vhosts`](tables/vhosts.md) |
|
| 35 |
+- certificate: [`certificates`](tables/certificates.md), [`certificate_dns_names`](tables/certificate_dns_names.md) |
|
| 36 |
+- workeri și observații: [`data_workers`](tables/data_workers.md), [`dhcp_leases`](tables/dhcp_leases.md), [`mdns_observations`](tables/mdns_observations.md) |
|
| 37 |
+ |
|
| 38 |
+[`documents`](tables/documents.md) rămâne doar tabel legacy pentru migrarea din modelul vechi document-store. Aplicația nu îl mai folosește ca sursă de adevăr. |
|
| 39 |
+ |
|
| 40 |
+## Schema Version |
|
| 41 |
+ |
|
| 42 |
+Schema curentă este versiunea `2`. |
|
| 43 |
+ |
|
| 44 |
+```sql |
|
| 45 |
+schema_meta('schema_version') = '2'
|
|
| 46 |
+``` |
|
| 47 |
+ |
|
| 48 |
+[`schema_meta`](tables/schema_meta.md) păstrează și metadate runtime precum `registry_updated_at`. |
|
| 49 |
+ |
|
| 50 |
+## Catalog |
|
| 51 |
+ |
|
| 52 |
+| Tabel | Rol | |
|
| 53 |
+|-------|-----| |
|
| 54 |
+| [`schema_meta`](tables/schema_meta.md) | metadate de schemă/runtime | |
|
| 55 |
+| [`documents`](tables/documents.md) | document-store legacy pentru migrare | |
|
| 56 |
+| [`hosts`](tables/hosts.md) | hosturi canonice, identificate prin FQDN | |
|
| 57 |
+| [`host_aliases`](tables/host_aliases.md) | aliasuri păstrate inclusiv după retragere | |
|
| 58 |
+| [`host_roles`](tables/host_roles.md) | roluri active/retrase per host | |
|
| 59 |
+| [`host_sources`](tables/host_sources.md) | surse active/retrase per host | |
|
| 60 |
+| [`host_flags`](tables/host_flags.md) | flaguri extensibile per host | |
|
| 61 |
+| [`host_ssh`](tables/host_ssh.md) | profile SSH per host | |
|
| 62 |
+| [`vhosts`](tables/vhosts.md) | vhosturi mutabile între hosturi | |
|
| 63 |
+| [`data_workers`](tables/data_workers.md) | workeri/surse care colectează date | |
|
| 64 |
+| [`dhcp_leases`](tables/dhcp_leases.md) | date observate din DHCP lease/reservation | |
|
| 65 |
+| [`mdns_observations`](tables/mdns_observations.md) | date observate din mDNS | |
|
| 66 |
+| [`certificates`](tables/certificates.md) | certificate emise de CA locală | |
|
| 67 |
+| [`certificate_dns_names`](tables/certificate_dns_names.md) | SAN DNS names pentru certificate | |
|
| 68 |
+| [`work_orders`](tables/work_orders.md) | Work Orders | |
|
| 69 |
+| [`work_order_checklist`](tables/work_order_checklist.md) | checklist items pentru Work Orders | |
|
| 70 |
+| [`work_order_actions`](tables/work_order_actions.md) | acțiuni confirmabile pentru Work Orders | |
|
| 71 |
+ |
|
| 72 |
+## Relații Principale |
|
| 73 |
+ |
|
| 74 |
+```mermaid |
|
| 75 |
+erDiagram |
|
| 76 |
+ hosts ||--o{ host_aliases : has
|
|
| 77 |
+ hosts ||--o{ vhosts : serves
|
|
| 78 |
+ hosts ||--o{ host_roles : has
|
|
| 79 |
+ hosts ||--o{ host_sources : has
|
|
| 80 |
+ hosts ||--o{ host_flags : has
|
|
| 81 |
+ hosts ||--o{ host_ssh : has
|
|
| 82 |
+ hosts ||--o{ dhcp_leases : may_match
|
|
| 83 |
+ hosts ||--o{ mdns_observations : may_match
|
|
| 84 |
+ hosts ||--o{ certificates : may_own
|
|
| 85 |
+ certificates ||--o{ certificate_dns_names : has
|
|
| 86 |
+ data_workers ||--o{ dhcp_leases : collects
|
|
| 87 |
+ data_workers ||--o{ mdns_observations : collects
|
|
| 88 |
+ work_orders ||--o{ work_order_checklist : has
|
|
| 89 |
+ work_orders ||--o{ work_order_actions : has
|
|
| 90 |
+ hosts ||--o{ work_order_actions : targets
|
|
| 91 |
+``` |
|
| 92 |
+ |
|
| 93 |
+## Migrare și Seed |
|
| 94 |
+ |
|
| 95 |
+La prima inițializare a unei baze fără rânduri în `hosts`, aplicația seed-uiește din: |
|
| 96 |
+ |
|
| 97 |
+1. `documents.name = 'hosts_yaml'`, dacă există din vechiul model |
|
| 98 |
+2. `config/hosts.yaml`, dacă documentul legacy lipsește |
|
| 99 |
+3. document gol valid, dacă lipsește și seed-ul |
|
| 100 |
+ |
|
| 101 |
+Work Orders se seed-uiesc similar din `documents.name = 'work_orders_yaml'` sau `config/work-orders.yaml`. |
|
| 102 |
+ |
|
| 103 |
+Seed-ul curent produce: |
|
| 104 |
+ |
|
| 105 |
+- 11 hosturi cunoscute |
|
| 106 |
+- aliasuri scurte derivate pentru hosturi și vhosturi |
|
| 107 |
+- vhosturile `hosts.*`, `pmx.*` și `pbs.*` |
|
| 108 |
+- workerii `dhcp-router` și `mdns-listener` |
|
| 109 |
+- Work Order-ul existent pentru retragerea numelor legacy |
|
| 110 |
+ |
|
| 111 |
+`config/local-hosts.tsv` rămâne manifest generat explicit din tabelele runtime. |
|
| 112 |
+ |
|
| 113 |
+## Inspecție |
|
| 114 |
+ |
|
| 115 |
+Pe jumper: |
|
| 116 |
+ |
|
| 117 |
+```bash |
|
| 118 |
+cd /usr/local/xdev-host-manager |
|
| 119 |
+sqlite3 var/host-manager.sqlite '.tables' |
|
| 120 |
+sqlite3 var/host-manager.sqlite '.schema hosts' |
|
| 121 |
+sqlite3 var/host-manager.sqlite '.schema host_aliases' |
|
| 122 |
+sqlite3 var/host-manager.sqlite '.schema vhosts' |
|
| 123 |
+sqlite3 var/host-manager.sqlite 'pragma foreign_key_list(vhosts);' |
|
| 124 |
+sqlite3 var/host-manager.sqlite 'pragma index_list(host_aliases);' |
|
| 125 |
+sqlite3 var/host-manager.sqlite 'select fqdn, legacy_id, status, dns_ip from hosts order by legacy_id;' |
|
| 126 |
+sqlite3 var/host-manager.sqlite 'select alias_name, host_fqdn, alias_kind, status from host_aliases order by alias_name;' |
|
| 127 |
+sqlite3 var/host-manager.sqlite 'select vhost_fqdn, host_fqdn, status from vhosts order by vhost_fqdn;' |
|
| 128 |
+``` |
|
| 129 |
+ |
|
| 130 |
+## Backup |
|
| 131 |
+ |
|
| 132 |
+Backup recomandat: |
|
| 133 |
+ |
|
| 134 |
+```bash |
|
| 135 |
+cd /usr/local/xdev-host-manager |
|
| 136 |
+sqlite3 var/host-manager.sqlite ".backup 'backups/host-manager/host-manager.sqlite.$(date +%Y%m%d_%H%M%S).bak'" |
|
| 137 |
+``` |
|
| 138 |
+ |
|
| 139 |
+Cu WAL activ, o copie brută trebuie să trateze fișierele ca set coerent: |
|
| 140 |
+ |
|
| 141 |
+```text |
|
| 142 |
+var/host-manager.sqlite |
|
| 143 |
+var/host-manager.sqlite-wal |
|
| 144 |
+var/host-manager.sqlite-shm |
|
| 145 |
+``` |
|
| 146 |
+ |
|
| 147 |
+## Restore |
|
| 148 |
+ |
|
| 149 |
+Restore-ul înlocuiește sursa de adevăr runtime: |
|
| 150 |
+ |
|
| 151 |
+```bash |
|
| 152 |
+sudo systemctl stop host-manager |
|
| 153 |
+sudo cp backups/host-manager/host-manager.sqlite.YYYYMMDD_HHMMSS.bak var/host-manager.sqlite |
|
| 154 |
+sudo chown host-manager:host-manager var/host-manager.sqlite |
|
| 155 |
+sudo systemctl start host-manager |
|
| 156 |
+curl -fsS http://127.0.0.1:8088/healthz >/dev/null |
|
| 157 |
+``` |
|
@@ -0,0 +1,33 @@ |
||
| 1 |
+# Table: `certificate_dns_names` |
|
| 2 |
+ |
|
| 3 |
+Stores DNS Subject Alternative Names for certificates. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `certificate_id` | `TEXT` | no | none | Certificate identifier. References `certificates(certificate_id)`. | |
|
| 10 |
+| `dns_name` | `TEXT` | no | none | DNS SAN value. | |
|
| 11 |
+ |
|
| 12 |
+## Keys And Indexes |
|
| 13 |
+ |
|
| 14 |
+- Primary key: `(certificate_id, dns_name)` |
|
| 15 |
+- Lookup index: `idx_certificate_dns_names_dns_name` on `dns_name` |
|
| 16 |
+ |
|
| 17 |
+## Relationships |
|
| 18 |
+ |
|
| 19 |
+- `certificate_id` references `certificates(certificate_id)` with `ON UPDATE CASCADE ON DELETE CASCADE` |
|
| 20 |
+ |
|
| 21 |
+## Definition |
|
| 22 |
+ |
|
| 23 |
+```sql |
|
| 24 |
+CREATE TABLE IF NOT EXISTS certificate_dns_names ( |
|
| 25 |
+ certificate_id TEXT NOT NULL, |
|
| 26 |
+ dns_name TEXT NOT NULL, |
|
| 27 |
+ PRIMARY KEY (certificate_id, dns_name), |
|
| 28 |
+ FOREIGN KEY (certificate_id) REFERENCES certificates(certificate_id) ON UPDATE CASCADE ON DELETE CASCADE |
|
| 29 |
+); |
|
| 30 |
+ |
|
| 31 |
+CREATE INDEX IF NOT EXISTS idx_certificate_dns_names_dns_name |
|
| 32 |
+ON certificate_dns_names(dns_name); |
|
| 33 |
+``` |
|
@@ -0,0 +1,60 @@ |
||
| 1 |
+# Table: `certificates` |
|
| 2 |
+ |
|
| 3 |
+Stores metadata for certificates issued by the local CA. |
|
| 4 |
+ |
|
| 5 |
+Certificate rows are synchronized when the app reads `ca_manager.sh list-json`. |
|
| 6 |
+ |
|
| 7 |
+## Columns |
|
| 8 |
+ |
|
| 9 |
+| Column | Type | Null | Default | Notes | |
|
| 10 |
+|--------|------|------|---------|-------| |
|
| 11 |
+| `certificate_id` | `TEXT` | no | none | Certificate identifier, currently derived from issued cert filename. Primary key. | |
|
| 12 |
+| `host_fqdn` | `TEXT` | yes | `NULL` | Matched host if known. References `hosts(fqdn)`. | |
|
| 13 |
+| `common_name` | `TEXT` | no | `''` | Common name or primary DNS name. | |
|
| 14 |
+| `subject` | `TEXT` | no | `''` | Certificate subject. | |
|
| 15 |
+| `issuer` | `TEXT` | no | `''` | Certificate issuer. | |
|
| 16 |
+| `serial` | `TEXT` | yes | `NULL` | Certificate serial. Unique when present. | |
|
| 17 |
+| `status` | `TEXT` | no | `'issued'` | Certificate lifecycle state. | |
|
| 18 |
+| `not_before` | `TEXT` | no | `''` | Certificate validity start. | |
|
| 19 |
+| `not_after` | `TEXT` | no | `''` | Certificate validity end. | |
|
| 20 |
+| `fingerprint_sha256` | `TEXT` | yes | `NULL` | SHA256 fingerprint. Unique when present. | |
|
| 21 |
+| `cert_path` | `TEXT` | no | `''` | Certificate file path. | |
|
| 22 |
+| `csr_path` | `TEXT` | no | `''` | CSR file path. | |
|
| 23 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 24 |
+| `updated_at` | `TEXT` | no | none | ISO UTC update timestamp. | |
|
| 25 |
+| `notes` | `TEXT` | no | `''` | Operator notes. | |
|
| 26 |
+ |
|
| 27 |
+## Keys And Indexes |
|
| 28 |
+ |
|
| 29 |
+- Primary key: `certificate_id` |
|
| 30 |
+- Unique: `serial` |
|
| 31 |
+- Unique: `fingerprint_sha256` |
|
| 32 |
+ |
|
| 33 |
+## Relationships |
|
| 34 |
+ |
|
| 35 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE SET NULL` |
|
| 36 |
+- Referenced by `certificate_dns_names.certificate_id` |
|
| 37 |
+- Referenced by `vhosts.certificate_id` |
|
| 38 |
+ |
|
| 39 |
+## Definition |
|
| 40 |
+ |
|
| 41 |
+```sql |
|
| 42 |
+CREATE TABLE IF NOT EXISTS certificates ( |
|
| 43 |
+ certificate_id TEXT PRIMARY KEY, |
|
| 44 |
+ host_fqdn TEXT, |
|
| 45 |
+ common_name TEXT NOT NULL DEFAULT '', |
|
| 46 |
+ subject TEXT NOT NULL DEFAULT '', |
|
| 47 |
+ issuer TEXT NOT NULL DEFAULT '', |
|
| 48 |
+ serial TEXT UNIQUE, |
|
| 49 |
+ status TEXT NOT NULL DEFAULT 'issued', |
|
| 50 |
+ not_before TEXT NOT NULL DEFAULT '', |
|
| 51 |
+ not_after TEXT NOT NULL DEFAULT '', |
|
| 52 |
+ fingerprint_sha256 TEXT UNIQUE, |
|
| 53 |
+ cert_path TEXT NOT NULL DEFAULT '', |
|
| 54 |
+ csr_path TEXT NOT NULL DEFAULT '', |
|
| 55 |
+ created_at TEXT NOT NULL, |
|
| 56 |
+ updated_at TEXT NOT NULL, |
|
| 57 |
+ notes TEXT NOT NULL DEFAULT '', |
|
| 58 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE SET NULL |
|
| 59 |
+); |
|
| 60 |
+``` |
|
@@ -0,0 +1,53 @@ |
||
| 1 |
+# Table: `data_workers` |
|
| 2 |
+ |
|
| 3 |
+Stores worker/source definitions for collected external data. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `worker_id` | `TEXT` | no | none | Worker identifier. Primary key. | |
|
| 10 |
+| `worker_type` | `TEXT` | no | none | Worker type, for example `dhcp` or `mdns`. | |
|
| 11 |
+| `name` | `TEXT` | no | `''` | Human-readable name. | |
|
| 12 |
+| `status` | `TEXT` | no | `'active'` | Worker lifecycle state. | |
|
| 13 |
+| `source` | `TEXT` | no | `''` | Source endpoint/file. | |
|
| 14 |
+| `last_run_at` | `TEXT` | yes | `NULL` | Last successful collection timestamp. | |
|
| 15 |
+| `notes` | `TEXT` | no | `''` | Operator notes. | |
|
| 16 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 17 |
+| `updated_at` | `TEXT` | no | none | ISO UTC update timestamp. | |
|
| 18 |
+ |
|
| 19 |
+## Keys And Indexes |
|
| 20 |
+ |
|
| 21 |
+- Primary key: `worker_id` |
|
| 22 |
+- Lookup index: `idx_data_workers_type_status` on `(worker_type, status)` |
|
| 23 |
+ |
|
| 24 |
+## Relationships |
|
| 25 |
+ |
|
| 26 |
+Referenced by: |
|
| 27 |
+ |
|
| 28 |
+- `dhcp_leases.worker_id` |
|
| 29 |
+- `mdns_observations.worker_id` |
|
| 30 |
+ |
|
| 31 |
+## Seed Rows |
|
| 32 |
+ |
|
| 33 |
+- `dhcp-router`, type `dhcp` |
|
| 34 |
+- `mdns-listener`, type `mdns` |
|
| 35 |
+ |
|
| 36 |
+## Definition |
|
| 37 |
+ |
|
| 38 |
+```sql |
|
| 39 |
+CREATE TABLE IF NOT EXISTS data_workers ( |
|
| 40 |
+ worker_id TEXT PRIMARY KEY, |
|
| 41 |
+ worker_type TEXT NOT NULL, |
|
| 42 |
+ name TEXT NOT NULL DEFAULT '', |
|
| 43 |
+ status TEXT NOT NULL DEFAULT 'active', |
|
| 44 |
+ source TEXT NOT NULL DEFAULT '', |
|
| 45 |
+ last_run_at TEXT, |
|
| 46 |
+ notes TEXT NOT NULL DEFAULT '', |
|
| 47 |
+ created_at TEXT NOT NULL, |
|
| 48 |
+ updated_at TEXT NOT NULL |
|
| 49 |
+); |
|
| 50 |
+ |
|
| 51 |
+CREATE INDEX IF NOT EXISTS idx_data_workers_type_status |
|
| 52 |
+ON data_workers(worker_type, status); |
|
| 53 |
+``` |
|
@@ -0,0 +1,54 @@ |
||
| 1 |
+# Table: `dhcp_leases` |
|
| 2 |
+ |
|
| 3 |
+Stores observed DHCP lease/reservation data. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `lease_key` | `TEXT` | no | none | Stable lease observation key. Primary key. | |
|
| 10 |
+| `worker_id` | `TEXT` | no | none | Collector worker. References `data_workers(worker_id)`. | |
|
| 11 |
+| `host_fqdn` | `TEXT` | yes | `NULL` | Matched host if known. References `hosts(fqdn)`. | |
|
| 12 |
+| `observed_name` | `TEXT` | no | `''` | Name reported by DHCP. | |
|
| 13 |
+| `ip_address` | `TEXT` | no | none | Observed IP address. | |
|
| 14 |
+| `mac_address` | `TEXT` | no | `''` | Observed MAC address. | |
|
| 15 |
+| `lease_state` | `TEXT` | no | `''` | DHCP state, if known. | |
|
| 16 |
+| `first_seen` | `TEXT` | no | none | First observation timestamp. | |
|
| 17 |
+| `last_seen` | `TEXT` | no | none | Last observation timestamp. | |
|
| 18 |
+| `raw` | `TEXT` | no | `''` | Raw source payload or diagnostic text. | |
|
| 19 |
+ |
|
| 20 |
+## Keys And Indexes |
|
| 21 |
+ |
|
| 22 |
+- Primary key: `lease_key` |
|
| 23 |
+- `idx_dhcp_leases_ip` on `ip_address` |
|
| 24 |
+- `idx_dhcp_leases_mac` on `mac_address` |
|
| 25 |
+- `idx_dhcp_leases_worker_last_seen` on `(worker_id, last_seen)` |
|
| 26 |
+ |
|
| 27 |
+## Relationships |
|
| 28 |
+ |
|
| 29 |
+- `worker_id` references `data_workers(worker_id)` with `ON UPDATE CASCADE ON DELETE RESTRICT` |
|
| 30 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE SET NULL` |
|
| 31 |
+ |
|
| 32 |
+## Definition |
|
| 33 |
+ |
|
| 34 |
+```sql |
|
| 35 |
+CREATE TABLE IF NOT EXISTS dhcp_leases ( |
|
| 36 |
+ lease_key TEXT PRIMARY KEY, |
|
| 37 |
+ worker_id TEXT NOT NULL, |
|
| 38 |
+ host_fqdn TEXT, |
|
| 39 |
+ observed_name TEXT NOT NULL DEFAULT '', |
|
| 40 |
+ ip_address TEXT NOT NULL, |
|
| 41 |
+ mac_address TEXT NOT NULL DEFAULT '', |
|
| 42 |
+ lease_state TEXT NOT NULL DEFAULT '', |
|
| 43 |
+ first_seen TEXT NOT NULL, |
|
| 44 |
+ last_seen TEXT NOT NULL, |
|
| 45 |
+ raw TEXT NOT NULL DEFAULT '', |
|
| 46 |
+ FOREIGN KEY (worker_id) REFERENCES data_workers(worker_id) ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 47 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE SET NULL |
|
| 48 |
+); |
|
| 49 |
+ |
|
| 50 |
+CREATE INDEX IF NOT EXISTS idx_dhcp_leases_ip ON dhcp_leases(ip_address); |
|
| 51 |
+CREATE INDEX IF NOT EXISTS idx_dhcp_leases_mac ON dhcp_leases(mac_address); |
|
| 52 |
+CREATE INDEX IF NOT EXISTS idx_dhcp_leases_worker_last_seen |
|
| 53 |
+ON dhcp_leases(worker_id, last_seen); |
|
| 54 |
+``` |
|
@@ -0,0 +1,32 @@ |
||
| 1 |
+# Table: `documents` |
|
| 2 |
+ |
|
| 3 |
+Legacy document-store table kept only for migration from the first SQLite implementation. |
|
| 4 |
+ |
|
| 5 |
+The application no longer uses this table as source of truth after relational tables are seeded. |
|
| 6 |
+ |
|
| 7 |
+## Columns |
|
| 8 |
+ |
|
| 9 |
+| Column | Type | Null | Default | Notes | |
|
| 10 |
+|--------|------|------|---------|-------| |
|
| 11 |
+| `name` | `TEXT` | no | none | Legacy document name. Known values: `hosts_yaml`, `work_orders_yaml`. | |
|
| 12 |
+| `content` | `TEXT` | no | none | Legacy YAML payload. | |
|
| 13 |
+| `updated_at` | `TEXT` | no | none | Legacy document update timestamp. | |
|
| 14 |
+ |
|
| 15 |
+## Keys And Indexes |
|
| 16 |
+ |
|
| 17 |
+- Primary key: `name` |
|
| 18 |
+- SQLite creates the internal primary-key index. |
|
| 19 |
+ |
|
| 20 |
+## Relationships |
|
| 21 |
+ |
|
| 22 |
+None. Migration code reads this table and imports the YAML into relational tables when `hosts` or `work_orders` are empty. |
|
| 23 |
+ |
|
| 24 |
+## Definition |
|
| 25 |
+ |
|
| 26 |
+```sql |
|
| 27 |
+CREATE TABLE IF NOT EXISTS documents ( |
|
| 28 |
+ name TEXT PRIMARY KEY, |
|
| 29 |
+ content TEXT NOT NULL, |
|
| 30 |
+ updated_at TEXT NOT NULL |
|
| 31 |
+); |
|
| 32 |
+``` |
|
@@ -0,0 +1,57 @@ |
||
| 1 |
+# Table: `host_aliases` |
|
| 2 |
+ |
|
| 3 |
+Stores aliases for canonical hosts. Aliases are retained after retirement for audit and collision prevention. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `alias_name` | `TEXT` | no | none | Alias DNS name or short alias. | |
|
| 10 |
+| `host_fqdn` | `TEXT` | no | none | Target host. References `hosts(fqdn)`. | |
|
| 11 |
+| `alias_kind` | `TEXT` | no | `'declared'` | `declared`, `derived`, or `derived-vhost`. | |
|
| 12 |
+| `status` | `TEXT` | no | `'active'` | Alias lifecycle state. | |
|
| 13 |
+| `is_dns_published` | `INTEGER` | no | `1` | Whether this alias should appear in generated DNS exports. | |
|
| 14 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 15 |
+| `retired_at` | `TEXT` | yes | `NULL` | ISO UTC retirement timestamp. | |
|
| 16 |
+| `notes` | `TEXT` | no | `''` | Operator notes. | |
|
| 17 |
+ |
|
| 18 |
+## Keys And Indexes |
|
| 19 |
+ |
|
| 20 |
+- Primary key: `(alias_name, host_fqdn)` |
|
| 21 |
+- Unique partial index: `idx_host_aliases_active_name` on `alias_name` where `status = 'active'` |
|
| 22 |
+- Lookup index: `idx_host_aliases_host_status` on `(host_fqdn, status)` |
|
| 23 |
+ |
|
| 24 |
+## Relationships |
|
| 25 |
+ |
|
| 26 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE RESTRICT` |
|
| 27 |
+ |
|
| 28 |
+## Rules |
|
| 29 |
+ |
|
| 30 |
+- A retired alias is not deleted; `status` changes to `retired` and `is_dns_published` is set to `0`. |
|
| 31 |
+- One active alias can point to only one host. |
|
| 32 |
+- Derived short names such as `baobab` are persisted with `alias_kind = 'derived'`. |
|
| 33 |
+- Derived vhost short names such as `pmx.baobab` are persisted with `alias_kind = 'derived-vhost'`. |
|
| 34 |
+ |
|
| 35 |
+## Definition |
|
| 36 |
+ |
|
| 37 |
+```sql |
|
| 38 |
+CREATE TABLE IF NOT EXISTS host_aliases ( |
|
| 39 |
+ alias_name TEXT NOT NULL, |
|
| 40 |
+ host_fqdn TEXT NOT NULL, |
|
| 41 |
+ alias_kind TEXT NOT NULL DEFAULT 'declared', |
|
| 42 |
+ status TEXT NOT NULL DEFAULT 'active', |
|
| 43 |
+ is_dns_published INTEGER NOT NULL DEFAULT 1, |
|
| 44 |
+ created_at TEXT NOT NULL, |
|
| 45 |
+ retired_at TEXT, |
|
| 46 |
+ notes TEXT NOT NULL DEFAULT '', |
|
| 47 |
+ PRIMARY KEY (alias_name, host_fqdn), |
|
| 48 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE RESTRICT |
|
| 49 |
+); |
|
| 50 |
+ |
|
| 51 |
+CREATE UNIQUE INDEX IF NOT EXISTS idx_host_aliases_active_name |
|
| 52 |
+ON host_aliases(alias_name) |
|
| 53 |
+WHERE status = 'active'; |
|
| 54 |
+ |
|
| 55 |
+CREATE INDEX IF NOT EXISTS idx_host_aliases_host_status |
|
| 56 |
+ON host_aliases(host_fqdn, status); |
|
| 57 |
+``` |
|
@@ -0,0 +1,35 @@ |
||
| 1 |
+# Table: `host_flags` |
|
| 2 |
+ |
|
| 3 |
+Stores extensible boolean/string flags for hosts without adding one column per flag to `hosts`. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `host_fqdn` | `TEXT` | no | none | Target host. References `hosts(fqdn)`. | |
|
| 10 |
+| `flag` | `TEXT` | no | none | Flag name. | |
|
| 11 |
+| `value` | `TEXT` | no | `'1'` | Flag value. | |
|
| 12 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 13 |
+| `updated_at` | `TEXT` | no | none | ISO UTC update timestamp. | |
|
| 14 |
+ |
|
| 15 |
+## Keys And Indexes |
|
| 16 |
+ |
|
| 17 |
+- Primary key: `(host_fqdn, flag)` |
|
| 18 |
+ |
|
| 19 |
+## Relationships |
|
| 20 |
+ |
|
| 21 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE RESTRICT` |
|
| 22 |
+ |
|
| 23 |
+## Definition |
|
| 24 |
+ |
|
| 25 |
+```sql |
|
| 26 |
+CREATE TABLE IF NOT EXISTS host_flags ( |
|
| 27 |
+ host_fqdn TEXT NOT NULL, |
|
| 28 |
+ flag TEXT NOT NULL, |
|
| 29 |
+ value TEXT NOT NULL DEFAULT '1', |
|
| 30 |
+ created_at TEXT NOT NULL, |
|
| 31 |
+ updated_at TEXT NOT NULL, |
|
| 32 |
+ PRIMARY KEY (host_fqdn, flag), |
|
| 33 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE RESTRICT |
|
| 34 |
+); |
|
| 35 |
+``` |
|
@@ -0,0 +1,35 @@ |
||
| 1 |
+# Table: `host_roles` |
|
| 2 |
+ |
|
| 3 |
+Stores host roles separately from `hosts` so the host table does not grow a role-specific column set. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `host_fqdn` | `TEXT` | no | none | Target host. References `hosts(fqdn)`. | |
|
| 10 |
+| `role` | `TEXT` | no | none | Role label, for example `proxmox`, `pbs`, `storage`. | |
|
| 11 |
+| `status` | `TEXT` | no | `'active'` | Role lifecycle state. | |
|
| 12 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 13 |
+| `retired_at` | `TEXT` | yes | `NULL` | ISO UTC retirement timestamp. | |
|
| 14 |
+ |
|
| 15 |
+## Keys And Indexes |
|
| 16 |
+ |
|
| 17 |
+- Primary key: `(host_fqdn, role)` |
|
| 18 |
+ |
|
| 19 |
+## Relationships |
|
| 20 |
+ |
|
| 21 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE RESTRICT` |
|
| 22 |
+ |
|
| 23 |
+## Definition |
|
| 24 |
+ |
|
| 25 |
+```sql |
|
| 26 |
+CREATE TABLE IF NOT EXISTS host_roles ( |
|
| 27 |
+ host_fqdn TEXT NOT NULL, |
|
| 28 |
+ role TEXT NOT NULL, |
|
| 29 |
+ status TEXT NOT NULL DEFAULT 'active', |
|
| 30 |
+ created_at TEXT NOT NULL, |
|
| 31 |
+ retired_at TEXT, |
|
| 32 |
+ PRIMARY KEY (host_fqdn, role), |
|
| 33 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE RESTRICT |
|
| 34 |
+); |
|
| 35 |
+``` |
|
@@ -0,0 +1,35 @@ |
||
| 1 |
+# Table: `host_sources` |
|
| 2 |
+ |
|
| 3 |
+Stores evidence/source labels for a host. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `host_fqdn` | `TEXT` | no | none | Target host. References `hosts(fqdn)`. | |
|
| 10 |
+| `source` | `TEXT` | no | none | Source label, for example `local-hosts.tsv` or `madagascar.json`. | |
|
| 11 |
+| `status` | `TEXT` | no | `'active'` | Source lifecycle state. | |
|
| 12 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 13 |
+| `retired_at` | `TEXT` | yes | `NULL` | ISO UTC retirement timestamp. | |
|
| 14 |
+ |
|
| 15 |
+## Keys And Indexes |
|
| 16 |
+ |
|
| 17 |
+- Primary key: `(host_fqdn, source)` |
|
| 18 |
+ |
|
| 19 |
+## Relationships |
|
| 20 |
+ |
|
| 21 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE RESTRICT` |
|
| 22 |
+ |
|
| 23 |
+## Definition |
|
| 24 |
+ |
|
| 25 |
+```sql |
|
| 26 |
+CREATE TABLE IF NOT EXISTS host_sources ( |
|
| 27 |
+ host_fqdn TEXT NOT NULL, |
|
| 28 |
+ source TEXT NOT NULL, |
|
| 29 |
+ status TEXT NOT NULL DEFAULT 'active', |
|
| 30 |
+ created_at TEXT NOT NULL, |
|
| 31 |
+ retired_at TEXT, |
|
| 32 |
+ PRIMARY KEY (host_fqdn, source), |
|
| 33 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE RESTRICT |
|
| 34 |
+); |
|
| 35 |
+``` |
|
@@ -0,0 +1,51 @@ |
||
| 1 |
+# Table: `host_ssh` |
|
| 2 |
+ |
|
| 3 |
+Stores SSH access profiles separately from `hosts`. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `host_fqdn` | `TEXT` | no | none | Target host. References `hosts(fqdn)`. | |
|
| 10 |
+| `profile_name` | `TEXT` | no | `'default'` | SSH profile name. | |
|
| 11 |
+| `username` | `TEXT` | no | `''` | SSH username. | |
|
| 12 |
+| `port` | `INTEGER` | no | `22` | SSH port. | |
|
| 13 |
+| `identity_file` | `TEXT` | no | `''` | SSH identity path or key label. | |
|
| 14 |
+| `address` | `TEXT` | no | `''` | Optional override address. | |
|
| 15 |
+| `local_forward_host` | `TEXT` | no | `''` | Optional local-forward host. | |
|
| 16 |
+| `local_forward_port` | `INTEGER` | yes | `NULL` | Optional local-forward port. | |
|
| 17 |
+| `remote_forward_host` | `TEXT` | no | `''` | Optional remote-forward host. | |
|
| 18 |
+| `remote_forward_port` | `INTEGER` | yes | `NULL` | Optional remote-forward port. | |
|
| 19 |
+| `notes` | `TEXT` | no | `''` | Operator notes. | |
|
| 20 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 21 |
+| `updated_at` | `TEXT` | no | none | ISO UTC update timestamp. | |
|
| 22 |
+ |
|
| 23 |
+## Keys And Indexes |
|
| 24 |
+ |
|
| 25 |
+- Primary key: `(host_fqdn, profile_name)` |
|
| 26 |
+ |
|
| 27 |
+## Relationships |
|
| 28 |
+ |
|
| 29 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE RESTRICT` |
|
| 30 |
+ |
|
| 31 |
+## Definition |
|
| 32 |
+ |
|
| 33 |
+```sql |
|
| 34 |
+CREATE TABLE IF NOT EXISTS host_ssh ( |
|
| 35 |
+ host_fqdn TEXT NOT NULL, |
|
| 36 |
+ profile_name TEXT NOT NULL DEFAULT 'default', |
|
| 37 |
+ username TEXT NOT NULL DEFAULT '', |
|
| 38 |
+ port INTEGER NOT NULL DEFAULT 22, |
|
| 39 |
+ identity_file TEXT NOT NULL DEFAULT '', |
|
| 40 |
+ address TEXT NOT NULL DEFAULT '', |
|
| 41 |
+ local_forward_host TEXT NOT NULL DEFAULT '', |
|
| 42 |
+ local_forward_port INTEGER, |
|
| 43 |
+ remote_forward_host TEXT NOT NULL DEFAULT '', |
|
| 44 |
+ remote_forward_port INTEGER, |
|
| 45 |
+ notes TEXT NOT NULL DEFAULT '', |
|
| 46 |
+ created_at TEXT NOT NULL, |
|
| 47 |
+ updated_at TEXT NOT NULL, |
|
| 48 |
+ PRIMARY KEY (host_fqdn, profile_name), |
|
| 49 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE RESTRICT |
|
| 50 |
+); |
|
| 51 |
+``` |
|
@@ -0,0 +1,55 @@ |
||
| 1 |
+# Table: `hosts` |
|
| 2 |
+ |
|
| 3 |
+Canonical host registry. Hosts are identified by full DNS name in `fqdn`. |
|
| 4 |
+ |
|
| 5 |
+`legacy_id` exists for compatibility with the current UI/API, but it is not the canonical identity. |
|
| 6 |
+ |
|
| 7 |
+## Columns |
|
| 8 |
+ |
|
| 9 |
+| Column | Type | Null | Default | Notes | |
|
| 10 |
+|--------|------|------|---------|-------| |
|
| 11 |
+| `fqdn` | `TEXT` | no | none | Canonical full host name. Primary key. | |
|
| 12 |
+| `legacy_id` | `TEXT` | no | none | Short ID used by the existing UI/API. Unique. | |
|
| 13 |
+| `status` | `TEXT` | no | `'active'` | Host lifecycle state, currently `active`, `planned`, or `retired`. | |
|
| 14 |
+| `hosts_ip` | `TEXT` | no | `''` | IP used for `/etc/hosts` on jumper. | |
|
| 15 |
+| `dns_ip` | `TEXT` | no | `''` | IP published to clients through local DNS. | |
|
| 16 |
+| `monitoring` | `TEXT` | no | `'pending'` | Monitoring state. | |
|
| 17 |
+| `notes` | `TEXT` | no | `''` | Operator notes. | |
|
| 18 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 19 |
+| `updated_at` | `TEXT` | no | none | ISO UTC update timestamp. | |
|
| 20 |
+ |
|
| 21 |
+## Keys And Indexes |
|
| 22 |
+ |
|
| 23 |
+- Primary key: `fqdn` |
|
| 24 |
+- Unique key: `legacy_id` |
|
| 25 |
+ |
|
| 26 |
+## Relationships |
|
| 27 |
+ |
|
| 28 |
+Referenced by: |
|
| 29 |
+ |
|
| 30 |
+- `host_aliases.host_fqdn` |
|
| 31 |
+- `host_roles.host_fqdn` |
|
| 32 |
+- `host_sources.host_fqdn` |
|
| 33 |
+- `host_flags.host_fqdn` |
|
| 34 |
+- `host_ssh.host_fqdn` |
|
| 35 |
+- `vhosts.host_fqdn` |
|
| 36 |
+- `dhcp_leases.host_fqdn` |
|
| 37 |
+- `mdns_observations.host_fqdn` |
|
| 38 |
+- `certificates.host_fqdn` |
|
| 39 |
+- `work_order_actions.host_fqdn` |
|
| 40 |
+ |
|
| 41 |
+## Definition |
|
| 42 |
+ |
|
| 43 |
+```sql |
|
| 44 |
+CREATE TABLE IF NOT EXISTS hosts ( |
|
| 45 |
+ fqdn TEXT PRIMARY KEY, |
|
| 46 |
+ legacy_id TEXT NOT NULL UNIQUE, |
|
| 47 |
+ status TEXT NOT NULL DEFAULT 'active', |
|
| 48 |
+ hosts_ip TEXT NOT NULL DEFAULT '', |
|
| 49 |
+ dns_ip TEXT NOT NULL DEFAULT '', |
|
| 50 |
+ monitoring TEXT NOT NULL DEFAULT 'pending', |
|
| 51 |
+ notes TEXT NOT NULL DEFAULT '', |
|
| 52 |
+ created_at TEXT NOT NULL, |
|
| 53 |
+ updated_at TEXT NOT NULL |
|
| 54 |
+); |
|
| 55 |
+``` |
|
@@ -0,0 +1,58 @@ |
||
| 1 |
+# Table: `mdns_observations` |
|
| 2 |
+ |
|
| 3 |
+Stores observed mDNS records. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `observation_key` | `TEXT` | no | none | Stable observation key. Primary key. | |
|
| 10 |
+| `worker_id` | `TEXT` | no | none | Collector worker. References `data_workers(worker_id)`. | |
|
| 11 |
+| `host_fqdn` | `TEXT` | yes | `NULL` | Matched host if known. References `hosts(fqdn)`. | |
|
| 12 |
+| `observed_name` | `TEXT` | no | none | Observed mDNS name. | |
|
| 13 |
+| `ip_address` | `TEXT` | no | none | Observed IP address. | |
|
| 14 |
+| `rr_type` | `TEXT` | no | `'A'` | DNS record type. | |
|
| 15 |
+| `ttl` | `INTEGER` | no | `0` | Observed TTL. | |
|
| 16 |
+| `first_seen` | `TEXT` | no | none | First observation timestamp. | |
|
| 17 |
+| `last_seen` | `TEXT` | no | none | Last observation timestamp. | |
|
| 18 |
+| `seen_count` | `INTEGER` | no | `1` | Number of times observed. | |
|
| 19 |
+| `last_peer` | `TEXT` | no | `''` | Last sender peer. | |
|
| 20 |
+| `raw` | `TEXT` | no | `''` | Raw source payload or diagnostic text. | |
|
| 21 |
+ |
|
| 22 |
+## Keys And Indexes |
|
| 23 |
+ |
|
| 24 |
+- Primary key: `observation_key` |
|
| 25 |
+- `idx_mdns_observations_name` on `observed_name` |
|
| 26 |
+- `idx_mdns_observations_ip` on `ip_address` |
|
| 27 |
+- `idx_mdns_observations_worker_last_seen` on `(worker_id, last_seen)` |
|
| 28 |
+ |
|
| 29 |
+## Relationships |
|
| 30 |
+ |
|
| 31 |
+- `worker_id` references `data_workers(worker_id)` with `ON UPDATE CASCADE ON DELETE RESTRICT` |
|
| 32 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE SET NULL` |
|
| 33 |
+ |
|
| 34 |
+## Definition |
|
| 35 |
+ |
|
| 36 |
+```sql |
|
| 37 |
+CREATE TABLE IF NOT EXISTS mdns_observations ( |
|
| 38 |
+ observation_key TEXT PRIMARY KEY, |
|
| 39 |
+ worker_id TEXT NOT NULL, |
|
| 40 |
+ host_fqdn TEXT, |
|
| 41 |
+ observed_name TEXT NOT NULL, |
|
| 42 |
+ ip_address TEXT NOT NULL, |
|
| 43 |
+ rr_type TEXT NOT NULL DEFAULT 'A', |
|
| 44 |
+ ttl INTEGER NOT NULL DEFAULT 0, |
|
| 45 |
+ first_seen TEXT NOT NULL, |
|
| 46 |
+ last_seen TEXT NOT NULL, |
|
| 47 |
+ seen_count INTEGER NOT NULL DEFAULT 1, |
|
| 48 |
+ last_peer TEXT NOT NULL DEFAULT '', |
|
| 49 |
+ raw TEXT NOT NULL DEFAULT '', |
|
| 50 |
+ FOREIGN KEY (worker_id) REFERENCES data_workers(worker_id) ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 51 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE SET NULL |
|
| 52 |
+); |
|
| 53 |
+ |
|
| 54 |
+CREATE INDEX IF NOT EXISTS idx_mdns_observations_name ON mdns_observations(observed_name); |
|
| 55 |
+CREATE INDEX IF NOT EXISTS idx_mdns_observations_ip ON mdns_observations(ip_address); |
|
| 56 |
+CREATE INDEX IF NOT EXISTS idx_mdns_observations_worker_last_seen |
|
| 57 |
+ON mdns_observations(worker_id, last_seen); |
|
| 58 |
+``` |
|
@@ -0,0 +1,37 @@ |
||
| 1 |
+# Table: `schema_meta` |
|
| 2 |
+ |
|
| 3 |
+Stores schema/runtime metadata as key-value rows. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `key` | `TEXT` | no | none | Metadata key. | |
|
| 10 |
+| `value` | `TEXT` | no | none | Metadata value. | |
|
| 11 |
+| `updated_at` | `TEXT` | no | none | ISO UTC timestamp written by the application. | |
|
| 12 |
+ |
|
| 13 |
+## Keys And Indexes |
|
| 14 |
+ |
|
| 15 |
+- Primary key: `key` |
|
| 16 |
+- SQLite creates the internal primary-key index. |
|
| 17 |
+ |
|
| 18 |
+## Known Keys |
|
| 19 |
+ |
|
| 20 |
+| Key | Meaning | |
|
| 21 |
+|-----|---------| |
|
| 22 |
+| `schema_version` | Current relational schema version. Current value: `2`. | |
|
| 23 |
+| `registry_updated_at` | Last registry update timestamp used for API/export metadata. | |
|
| 24 |
+ |
|
| 25 |
+## Relationships |
|
| 26 |
+ |
|
| 27 |
+None. |
|
| 28 |
+ |
|
| 29 |
+## Definition |
|
| 30 |
+ |
|
| 31 |
+```sql |
|
| 32 |
+CREATE TABLE IF NOT EXISTS schema_meta ( |
|
| 33 |
+ key TEXT PRIMARY KEY, |
|
| 34 |
+ value TEXT NOT NULL, |
|
| 35 |
+ updated_at TEXT NOT NULL |
|
| 36 |
+); |
|
| 37 |
+``` |
|
@@ -0,0 +1,55 @@ |
||
| 1 |
+# Table: `vhosts` |
|
| 2 |
+ |
|
| 3 |
+Stores virtual hosts separately from physical/logical hosts so a vhost can be moved between hosts. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `vhost_fqdn` | `TEXT` | no | none | Vhost DNS name. Primary key. | |
|
| 10 |
+| `host_fqdn` | `TEXT` | no | none | Current host serving the vhost. References `hosts(fqdn)`. | |
|
| 11 |
+| `status` | `TEXT` | no | `'active'` | Vhost lifecycle state. | |
|
| 12 |
+| `service_name` | `TEXT` | no | `''` | Service label, often inferred from first DNS label. | |
|
| 13 |
+| `upstream_url` | `TEXT` | no | `''` | Optional upstream URL. | |
|
| 14 |
+| `tls_mode` | `TEXT` | no | `'local-ca'` | TLS handling mode. | |
|
| 15 |
+| `certificate_id` | `TEXT` | yes | `NULL` | Optional issued certificate. References `certificates(certificate_id)`. | |
|
| 16 |
+| `notes` | `TEXT` | no | `''` | Operator notes. | |
|
| 17 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 18 |
+| `updated_at` | `TEXT` | no | none | ISO UTC update timestamp. | |
|
| 19 |
+ |
|
| 20 |
+## Keys And Indexes |
|
| 21 |
+ |
|
| 22 |
+- Primary key: `vhost_fqdn` |
|
| 23 |
+- Lookup index: `idx_vhosts_host_status` on `(host_fqdn, status)` |
|
| 24 |
+ |
|
| 25 |
+## Relationships |
|
| 26 |
+ |
|
| 27 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE RESTRICT` |
|
| 28 |
+- `certificate_id` references `certificates(certificate_id)` with `ON UPDATE CASCADE ON DELETE SET NULL` |
|
| 29 |
+ |
|
| 30 |
+## Rules |
|
| 31 |
+ |
|
| 32 |
+- Moving a vhost means updating `host_fqdn`. |
|
| 33 |
+- Retiring a vhost means setting `status = 'retired'`; the row remains. |
|
| 34 |
+ |
|
| 35 |
+## Definition |
|
| 36 |
+ |
|
| 37 |
+```sql |
|
| 38 |
+CREATE TABLE IF NOT EXISTS vhosts ( |
|
| 39 |
+ vhost_fqdn TEXT PRIMARY KEY, |
|
| 40 |
+ host_fqdn TEXT NOT NULL, |
|
| 41 |
+ status TEXT NOT NULL DEFAULT 'active', |
|
| 42 |
+ service_name TEXT NOT NULL DEFAULT '', |
|
| 43 |
+ upstream_url TEXT NOT NULL DEFAULT '', |
|
| 44 |
+ tls_mode TEXT NOT NULL DEFAULT 'local-ca', |
|
| 45 |
+ certificate_id TEXT, |
|
| 46 |
+ notes TEXT NOT NULL DEFAULT '', |
|
| 47 |
+ created_at TEXT NOT NULL, |
|
| 48 |
+ updated_at TEXT NOT NULL, |
|
| 49 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE RESTRICT, |
|
| 50 |
+ FOREIGN KEY (certificate_id) REFERENCES certificates(certificate_id) ON UPDATE CASCADE ON DELETE SET NULL |
|
| 51 |
+); |
|
| 52 |
+ |
|
| 53 |
+CREATE INDEX IF NOT EXISTS idx_vhosts_host_status |
|
| 54 |
+ON vhosts(host_fqdn, status); |
|
| 55 |
+``` |
|
@@ -0,0 +1,41 @@ |
||
| 1 |
+# Table: `work_order_actions` |
|
| 2 |
+ |
|
| 3 |
+Stores ordered actions attached to Work Orders. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `work_order_id` | `TEXT` | no | none | Parent Work Order. References `work_orders(id)`. | |
|
| 10 |
+| `position` | `INTEGER` | no | none | Ordered action position. | |
|
| 11 |
+| `type` | `TEXT` | no | none | Action type, for example `remove_name`. | |
|
| 12 |
+| `host_fqdn` | `TEXT` | yes | `NULL` | Target host if resolved. References `hosts(fqdn)`. | |
|
| 13 |
+| `host_legacy_id` | `TEXT` | no | `''` | Compatibility target ID from old Work Order format. | |
|
| 14 |
+| `name` | `TEXT` | no | `''` | Target name for action. | |
|
| 15 |
+| `payload` | `TEXT` | no | `''` | Reserved structured payload field. | |
|
| 16 |
+ |
|
| 17 |
+## Keys And Indexes |
|
| 18 |
+ |
|
| 19 |
+- Primary key: `(work_order_id, position)` |
|
| 20 |
+ |
|
| 21 |
+## Relationships |
|
| 22 |
+ |
|
| 23 |
+- `work_order_id` references `work_orders(id)` with `ON UPDATE CASCADE ON DELETE CASCADE` |
|
| 24 |
+- `host_fqdn` references `hosts(fqdn)` with `ON UPDATE CASCADE ON DELETE SET NULL` |
|
| 25 |
+ |
|
| 26 |
+## Definition |
|
| 27 |
+ |
|
| 28 |
+```sql |
|
| 29 |
+CREATE TABLE IF NOT EXISTS work_order_actions ( |
|
| 30 |
+ work_order_id TEXT NOT NULL, |
|
| 31 |
+ position INTEGER NOT NULL, |
|
| 32 |
+ type TEXT NOT NULL, |
|
| 33 |
+ host_fqdn TEXT, |
|
| 34 |
+ host_legacy_id TEXT NOT NULL DEFAULT '', |
|
| 35 |
+ name TEXT NOT NULL DEFAULT '', |
|
| 36 |
+ payload TEXT NOT NULL DEFAULT '', |
|
| 37 |
+ PRIMARY KEY (work_order_id, position), |
|
| 38 |
+ FOREIGN KEY (work_order_id) REFERENCES work_orders(id) ON UPDATE CASCADE ON DELETE CASCADE, |
|
| 39 |
+ FOREIGN KEY (host_fqdn) REFERENCES hosts(fqdn) ON UPDATE CASCADE ON DELETE SET NULL |
|
| 40 |
+); |
|
| 41 |
+``` |
|
@@ -0,0 +1,39 @@ |
||
| 1 |
+# Table: `work_order_checklist` |
|
| 2 |
+ |
|
| 3 |
+Stores checklist items for Work Orders. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `work_order_id` | `TEXT` | no | none | Parent Work Order. References `work_orders(id)`. | |
|
| 10 |
+| `item_id` | `TEXT` | no | none | Checklist item ID. | |
|
| 11 |
+| `text` | `TEXT` | no | `''` | Checklist item text. | |
|
| 12 |
+| `status` | `TEXT` | no | `'pending'` | Item state. | |
|
| 13 |
+| `owner` | `TEXT` | no | `''` | Optional owner. | |
|
| 14 |
+| `notes` | `TEXT` | no | `''` | Operator notes. | |
|
| 15 |
+| `updated_at` | `TEXT` | no | `''` | Item update timestamp. | |
|
| 16 |
+ |
|
| 17 |
+## Keys And Indexes |
|
| 18 |
+ |
|
| 19 |
+- Primary key: `(work_order_id, item_id)` |
|
| 20 |
+ |
|
| 21 |
+## Relationships |
|
| 22 |
+ |
|
| 23 |
+- `work_order_id` references `work_orders(id)` with `ON UPDATE CASCADE ON DELETE CASCADE` |
|
| 24 |
+ |
|
| 25 |
+## Definition |
|
| 26 |
+ |
|
| 27 |
+```sql |
|
| 28 |
+CREATE TABLE IF NOT EXISTS work_order_checklist ( |
|
| 29 |
+ work_order_id TEXT NOT NULL, |
|
| 30 |
+ item_id TEXT NOT NULL, |
|
| 31 |
+ text TEXT NOT NULL DEFAULT '', |
|
| 32 |
+ status TEXT NOT NULL DEFAULT 'pending', |
|
| 33 |
+ owner TEXT NOT NULL DEFAULT '', |
|
| 34 |
+ notes TEXT NOT NULL DEFAULT '', |
|
| 35 |
+ updated_at TEXT NOT NULL DEFAULT '', |
|
| 36 |
+ PRIMARY KEY (work_order_id, item_id), |
|
| 37 |
+ FOREIGN KEY (work_order_id) REFERENCES work_orders(id) ON UPDATE CASCADE ON DELETE CASCADE |
|
| 38 |
+); |
|
| 39 |
+``` |
|
@@ -0,0 +1,42 @@ |
||
| 1 |
+# Table: `work_orders` |
|
| 2 |
+ |
|
| 3 |
+Stores Work Order headers. |
|
| 4 |
+ |
|
| 5 |
+## Columns |
|
| 6 |
+ |
|
| 7 |
+| Column | Type | Null | Default | Notes | |
|
| 8 |
+|--------|------|------|---------|-------| |
|
| 9 |
+| `id` | `TEXT` | no | none | Work Order ID. Primary key. | |
|
| 10 |
+| `status` | `TEXT` | no | `'pending'` | Work Order state. | |
|
| 11 |
+| `title` | `TEXT` | no | `''` | Title. | |
|
| 12 |
+| `reason` | `TEXT` | no | `''` | Reason/context. | |
|
| 13 |
+| `created_at` | `TEXT` | no | none | ISO UTC creation timestamp. | |
|
| 14 |
+| `confirmed_at` | `TEXT` | no | `''` | Confirmation timestamp, empty until confirmed. | |
|
| 15 |
+| `result` | `TEXT` | no | `''` | Result summary. | |
|
| 16 |
+| `updated_at` | `TEXT` | no | none | ISO UTC update timestamp. | |
|
| 17 |
+ |
|
| 18 |
+## Keys And Indexes |
|
| 19 |
+ |
|
| 20 |
+- Primary key: `id` |
|
| 21 |
+ |
|
| 22 |
+## Relationships |
|
| 23 |
+ |
|
| 24 |
+Referenced by: |
|
| 25 |
+ |
|
| 26 |
+- `work_order_checklist.work_order_id` |
|
| 27 |
+- `work_order_actions.work_order_id` |
|
| 28 |
+ |
|
| 29 |
+## Definition |
|
| 30 |
+ |
|
| 31 |
+```sql |
|
| 32 |
+CREATE TABLE IF NOT EXISTS work_orders ( |
|
| 33 |
+ id TEXT PRIMARY KEY, |
|
| 34 |
+ status TEXT NOT NULL DEFAULT 'pending', |
|
| 35 |
+ title TEXT NOT NULL DEFAULT '', |
|
| 36 |
+ reason TEXT NOT NULL DEFAULT '', |
|
| 37 |
+ created_at TEXT NOT NULL, |
|
| 38 |
+ confirmed_at TEXT NOT NULL DEFAULT '', |
|
| 39 |
+ result TEXT NOT NULL DEFAULT '', |
|
| 40 |
+ updated_at TEXT NOT NULL |
|
| 41 |
+); |
|
| 42 |
+``` |
|
@@ -41,7 +41,7 @@ The web UI is OTP-protected for all registry data, downloads, exports, and write |
||
| 41 | 41 |
For agent/operator context, see: |
| 42 | 42 |
|
| 43 | 43 |
- [`agents.md`](agents.md) |
| 44 |
-- [`.doc/database.md`](.doc/database.md) |
|
| 44 |
+- [`.doc/database/`](.doc/database/README.md) |
|
| 45 | 45 |
- [`.doc/development-log.md`](.doc/development-log.md) |
| 46 | 46 |
- [`.doc/host-manager.md`](.doc/host-manager.md) |
| 47 | 47 |
- [`.doc/local-hosts.md`](.doc/local-hosts.md) |
@@ -5,7 +5,7 @@ Madagascar Local Authority is the local authority application for the Madagascar |
||
| 5 | 5 |
Start with these documents: |
| 6 | 6 |
|
| 7 | 7 |
- [README.md](README.md) - current repository, deployment model, runtime paths, GitPrep remote. |
| 8 |
-- [.doc/database.md](.doc/database.md) - SQLite runtime store schema, seed rules, backup and restore. |
|
| 8 |
+- [.doc/database/](.doc/database/README.md) - SQLite runtime store schema, table docs, seed rules, backup and restore. |
|
| 9 | 9 |
- [.doc/host-manager.md](.doc/host-manager.md) - application behavior, OTP, Work Orders, local CA, registry rules. |
| 10 | 10 |
- [.doc/local-hosts.md](.doc/local-hosts.md) - local DNS rules, resolver sync, source priority. |
| 11 | 11 |
- [.doc/development-log.md](.doc/development-log.md) - scope and architecture decisions over time. |