LocalAuthority / .doc / database.md
1 contributor
277 lines | 9.331kb

SQLite Database

Madagascar Local Authority folosește SQLite ca store runtime pentru registry și Work Orders.

Locația implicită în checkout:

var/host-manager.sqlite

Locația runtime pe jumper:

/usr/local/xdev-host-manager/var/host-manager.sqlite

Path-ul poate fi schimbat cu:

HOST_MANAGER_DB=/path/to/host-manager.sqlite

Rol

SQLite este sursa de adevăr runtime. Fișierele din config/ nu mai sunt store-ul live:

  • config/hosts.yaml seed-uiește documentul hosts_yaml dacă baza este nouă.
  • config/work-orders.yaml seed-uiește documentul work_orders_yaml dacă baza este nouă.
  • config/local-hosts.tsv este manifest generat explicit din registry-ul SQLite.
  • /download/hosts.yaml, /download/local-hosts.tsv și /download/monitoring.json sunt randate din SQLite.

Aplicația nu face commit/push automat după modificări. Exportul și arhivarea rămân pași operaționali separați.

Schema curentă

Schema este creată automat de scripts/host_manager.pl la prima citire/scriere a store-ului.

CREATE TABLE IF NOT EXISTS documents (
    name TEXT PRIMARY KEY,
    content TEXT NOT NULL,
    updated_at TEXT NOT NULL
);

Catalog

Obiect Tip Rol
documents table Document-store runtime pentru registry și Work Orders
sqlite_autoindex_documents_1 index intern SQLite Indexul automat creat pentru PRIMARY KEY (name)

Nu există alte tabele, view-uri, trigger-e sau indexuri definite de aplicație în schema curentă.

Tabel: documents

Coloană Tip declarat Null Default Cheie Descriere
name TEXT NOT NULL implicit prin PK none PRIMARY KEY Identificatorul documentului operațional. Valorile cunoscute sunt hosts_yaml și work_orders_yaml.
content TEXT NOT NULL none none Payload-ul documentului, serializat ca YAML strict compatibil cu parserul aplicației.
updated_at TEXT NOT NULL none none Timestamp ISO UTC setat de aplicație la insert/update.

Chei

Tabel Cheie Coloane Observații
documents Primary key name Garantează un singur rând pentru fiecare document operațional.

SQLite implementează cheia primară textuală prin indexul intern sqlite_autoindex_documents_1.

Indexuri

Index Tabel Coloane Unic Creat de Rol
sqlite_autoindex_documents_1 documents name da SQLite Lookup rapid pentru SELECT ... WHERE name = ? și enforcement pentru primary key.

Nu există indexuri explicite definite de aplicație. Nu există index pe updated_at, pentru că aplicația nu face query-uri de tip listare istorică sau filtrare temporală.

Relații

Nu există foreign keys între tabele, pentru că schema curentă are o singură tabelă.

Relațiile de business sunt în interiorul YAML-ului din content, nu modelate relational. De exemplu:

  • hosturile, numele, rolurile și sursele sunt structuri YAML în documentul hosts_yaml
  • checklist-ul și acțiunile unui Work Order sunt structuri YAML în documentul work_orders_yaml
  • acțiunile Work Order referă host_id textual în YAML, nu printr-un FOREIGN KEY

PRAGMA foreign_keys = ON este activat ca pregătire pentru o schemă viitoare cu tabele relaționale, dar în schema curentă nu are efect practic.

Constrângeri

Tabel Constrângere Efect
documents PRIMARY KEY (name) Nu permite două documente cu același name.
documents content TEXT NOT NULL Nu permite documente fără payload.
documents updated_at TEXT NOT NULL Nu permite rânduri fără timestamp de modificare.

Nu există CHECK constraints pentru valorile permise în name, formatul YAML sau formatul timestamp-ului. Aceste validări sunt făcute în codul Perl prin parserul strict YAML și prin fluxurile API.

Operațiuni SQL folosite de aplicație

Citire document:

SELECT content FROM documents WHERE name = ?;

Insert/update document:

INSERT INTO documents (name, content, updated_at)
VALUES (?, ?, ?)
ON CONFLICT(name) DO UPDATE
SET content = excluded.content,
    updated_at = excluded.updated_at;

Creare schemă:

CREATE TABLE IF NOT EXISTS documents (
    name TEXT PRIMARY KEY,
    content TEXT NOT NULL,
    updated_at TEXT NOT NULL
);

Setări aplicate la conectare:

PRAGMA journal_mode = WAL;
PRAGMA foreign_keys = ON;

Versiune schemă

Nu există încă tabelă schema_migrations sau schema_version. Schema este implicit versiunea 1 și este definită de blocul CREATE TABLE IF NOT EXISTS documents din scripts/host_manager.pl.

În schema curentă există o singură tabelă generică, documents. Conținutul operațional rămâne serializat în formatul YAML strict deja folosit de aplicație. Alegerea este deliberată pentru migrarea minimă: sursa de adevăr se mută din working tree în SQLite fără să schimbăm încă parserul, UI-ul sau formatul exporturilor.

Documente

hosts_yaml

Conține registry-ul de hosturi în formatul config/hosts.yaml.

Este citit de:

  • GET /api/hosts
  • GET /download/hosts.yaml
  • GET /download/local-hosts.tsv
  • GET /download/monitoring.json
  • POST /api/render/local-hosts-tsv

Este scris de:

  • POST /api/hosts/upsert
  • POST /api/hosts/delete
  • POST /api/work-orders/confirm, când o acțiune modifică registry-ul

Aplicația normalizează la salvare:

policy:
  storage_authority: "sqlite"
  runtime_database: "<HOST_MANAGER_DB>"

work_orders_yaml

Conține Work Orders în formatul config/work-orders.yaml.

Este citit de:

  • GET /api/work-orders
  • POST /api/work-orders/checklist
  • POST /api/work-orders/confirm

Este scris de:

  • POST /api/work-orders/checklist
  • POST /api/work-orders/confirm

Seed inițial

La prima accesare a unui document:

  1. Aplicația caută rândul în documents.
  2. Dacă rândul există, conținutul din SQLite câștigă.
  3. Dacă rândul lipsește, aplicația citește fișierul seed din config/.
  4. Dacă fișierul seed lipsește, aplicația creează un document gol valid.
  5. Documentul este inserat în SQLite și de atunci SQLite devine autoritatea.

Important: după seed, modificările ulterioare ale fișierelor config/hosts.yaml sau config/work-orders.yaml nu schimbă automat baza existentă.

Fișiere SQLite

Cu WAL activ, runtime-ul poate avea trei fișiere:

var/host-manager.sqlite
var/host-manager.sqlite-wal
var/host-manager.sqlite-shm

Toate trei aparțin store-ului runtime. Nu se comit în git și nu se înlocuiesc prin deploy de cod.

Inspecție

Pe jumper:

cd /usr/local/xdev-host-manager
sqlite3 var/host-manager.sqlite '.schema'
sqlite3 var/host-manager.sqlite '.tables'
sqlite3 var/host-manager.sqlite 'pragma table_info(documents);'
sqlite3 var/host-manager.sqlite 'pragma index_list(documents);'
sqlite3 var/host-manager.sqlite 'pragma index_info(sqlite_autoindex_documents_1);'
sqlite3 var/host-manager.sqlite 'pragma foreign_key_list(documents);'
sqlite3 var/host-manager.sqlite 'select name, updated_at, length(content) from documents order by name;'
sqlite3 var/host-manager.sqlite 'select content from documents where name = "hosts_yaml";'
sqlite3 var/host-manager.sqlite 'select content from documents where name = "work_orders_yaml";'

Pentru export YAML curent:

curl -fsS -b cookies.txt https://hosts.madagascar.xdev.ro/download/hosts.yaml

Endpoint-urile de download sunt OTP-protected; exemplul presupune o sesiune validă.

Backup

Backup recomandat, cu serviciul oprit sau prin API-ul SQLite:

cd /usr/local/xdev-host-manager
sqlite3 var/host-manager.sqlite ".backup 'backups/host-manager/host-manager.sqlite.$(date +%Y%m%d_%H%M%S).bak'"

Pentru o copie brută, include și fișierele WAL/SHM sau oprește serviciul înainte:

sudo systemctl stop host-manager
sudo cp -a var/host-manager.sqlite* backups/host-manager/
sudo systemctl start host-manager

Restore

Restore-ul înlocuiește sursa de adevăr runtime și trebuie făcut explicit:

sudo systemctl stop host-manager
sudo cp backups/host-manager/host-manager.sqlite.YYYYMMDD_HHMMSS.bak var/host-manager.sqlite
sudo chown host-manager:host-manager var/host-manager.sqlite
sudo systemctl start host-manager
curl -fsS http://127.0.0.1:8088/healthz >/dev/null

Dacă se restaurează o copie brută, tratează host-manager.sqlite, host-manager.sqlite-wal și host-manager.sqlite-shm ca set coerent.

Evoluție probabilă

Schema generică documents este potrivită pentru tranziția curentă. Dacă aplicația are nevoie de query-uri structurale, validări SQL sau merge/audit mai granular, următorul pas ar trebui să fie o migrare versionată către tabele dedicate, de exemplu:

  • hosts
  • host_names
  • host_roles
  • host_sources
  • work_orders
  • work_order_checklist
  • work_order_actions

Până atunci, contractul stabil este numele documentelor din documents și formatele YAML randate de aplicație.