feat(foundation): schema Treapta 2 + migrari aditive + openpyxl pinned (#1)
- accounts.rar_creds_enc TEXT (creds RAR durabile per-cont, D4) - submissions.batch_id, row_index (T7 scoping R1) - submissions.purge_after (T16 GDPR) - Tabele noi: column_mappings, import_batches, import_rows, import_attestations - _migrate idempotent pe DB veche (ALTER aditiv, pattern existent) - openpyxl==3.1.5 adaugat in requirements.txt (Issue 4, PINNED) - 15 teste noi: coloane, tabele, idempotenta, migrare DB veche, openpyxl Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,18 +1,17 @@
|
||||
-- Schema SQLite (WAL) pentru gateway RAR AUTOPASS.
|
||||
-- Vezi plan.md sect. 5. NICIUN camp pentru parole RAR.
|
||||
-- Validarea completa (T3) si criptarea PII (P2) vin ulterior; in schelet
|
||||
-- payload-ul e stocat ca JSON text (camp payload_json), de inlocuit cu BLOB
|
||||
-- criptat + purge_after cand se face T7/criptare.
|
||||
-- Vezi plan.md sect. 5 + plan-treapta2.md sect. 4.
|
||||
-- Treapta 2: adauga conturi cu creds RAR durabile, tabele import, atestari.
|
||||
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA foreign_keys = ON;
|
||||
|
||||
-- Conturi ROAAUTO (clientii care folosesc gateway-ul).
|
||||
CREATE TABLE IF NOT EXISTS accounts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
cui TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
cui TEXT,
|
||||
rar_creds_enc TEXT, -- creds RAR criptate (Fernet) durabile per-cont (D4/Eng#1)
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
-- Cont implicit (id=1): auth API-key (CORE) inca neimplementat, deci ingestiile vin
|
||||
-- cu account_id NULL. Le atribuim contului default ca FK + UNIQUE(account_id,...) din
|
||||
@@ -54,20 +53,79 @@ CREATE TABLE IF NOT EXISTS submissions (
|
||||
account_id INTEGER REFERENCES accounts(id) ON DELETE SET NULL,
|
||||
status TEXT NOT NULL DEFAULT 'queued'
|
||||
CHECK (status IN ('queued','sending','sent','needs_mapping','needs_data','error')),
|
||||
payload_json TEXT NOT NULL, -- TODO(P2): inlocuit cu BLOB criptat
|
||||
rar_creds_enc TEXT, -- creds RAR criptate (Fernet), sterse dupa primul login reusit (plan sect.5)
|
||||
payload_json TEXT NOT NULL,
|
||||
rar_creds_enc TEXT, -- creds RAR criptate (Fernet), sterse dupa primul login reusit
|
||||
rar_status_code INTEGER,
|
||||
rar_error TEXT,
|
||||
id_prezentare INTEGER, -- data.id intors de RAR la succes
|
||||
retry_count INTEGER NOT NULL DEFAULT 0,
|
||||
next_attempt_at TEXT, -- backoff: randul nu se ia inainte de acest moment (T2)
|
||||
sending_since TEXT, -- pentru lease/timeout pe randuri 'sending' orfane (T2)
|
||||
purge_after TEXT, -- sent + 90z (P2)
|
||||
purge_after TEXT, -- sent + 90z (T16)
|
||||
batch_id INTEGER, -- import batch (T7; NULL = canal API)
|
||||
row_index INTEGER, -- rand in batch (T7; NULL = canal API)
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_submissions_status ON submissions(status);
|
||||
-- Nota: idx_submissions_batch se creeaza in _migrate (dupa ALTER care adauga batch_id pe DB veche).
|
||||
|
||||
-- Mapare coloane fisier -> campuri canonice (retinuta per cont, semnatura coloane).
|
||||
CREATE TABLE IF NOT EXISTS column_mappings (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
|
||||
signature_coloane TEXT NOT NULL, -- hash/lista sortata a coloanelor fisierului
|
||||
json_mapare TEXT NOT NULL, -- {col_fisier: camp_canonic, ...} JSON
|
||||
format_data TEXT, -- ex. "DD.MM.YYYY"
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE (account_id, signature_coloane)
|
||||
);
|
||||
|
||||
-- Loturi de import (fisiere incarcate).
|
||||
CREATE TABLE IF NOT EXISTS import_batches (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id INTEGER NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
|
||||
filename TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'staging'
|
||||
CHECK (status IN ('staging','committed','error')),
|
||||
total INTEGER NOT NULL DEFAULT 0,
|
||||
ok INTEGER NOT NULL DEFAULT 0,
|
||||
needs_mapping INTEGER NOT NULL DEFAULT 0,
|
||||
needs_data INTEGER NOT NULL DEFAULT 0,
|
||||
needs_review INTEGER NOT NULL DEFAULT 0,
|
||||
already_sent INTEGER NOT NULL DEFAULT 0,
|
||||
duplicate_in_file INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
purge_after TEXT -- created_at + 90z (T16)
|
||||
);
|
||||
|
||||
-- Randuri din lot de import (PII criptat cu Fernet).
|
||||
CREATE TABLE IF NOT EXISTS import_rows (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
batch_id INTEGER NOT NULL REFERENCES import_batches(id) ON DELETE CASCADE,
|
||||
row_index INTEGER NOT NULL,
|
||||
raw_json TEXT NOT NULL, -- PII criptat (Fernet, ca submissions)
|
||||
resolved_status TEXT NOT NULL DEFAULT 'pending'
|
||||
CHECK (resolved_status IN (
|
||||
'pending','ok','needs_mapping','needs_data',
|
||||
'needs_review','already_sent','duplicate_in_file'
|
||||
)),
|
||||
error TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_import_rows_batch ON import_rows(batch_id);
|
||||
|
||||
-- Log atestare legala (confirmare import batch, L.142/2023).
|
||||
CREATE TABLE IF NOT EXISTS import_attestations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
batch_id INTEGER NOT NULL REFERENCES import_batches(id) ON DELETE CASCADE,
|
||||
account_id INTEGER NOT NULL,
|
||||
confirmed_by TEXT, -- email/identifier utilizator
|
||||
ts TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
rows_hash TEXT NOT NULL, -- sha256 peste valorile rezolvate confirmate
|
||||
n_confirmed INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- Heartbeat worker (un singur rand, id=1). /healthz citeste de aici.
|
||||
CREATE TABLE IF NOT EXISTS worker_heartbeat (
|
||||
|
||||
Reference in New Issue
Block a user