feat(account): CLI lifecycle conturi + accounts.active (PRD 3.1)

Inlocuieste crearea conturilor prin INSERT SQL manual cu un tool admin
dedicat, simetric cu tools/apikey.py. Fundatia Etapei 3 (3.2/3.3).

- app/accounts.py: create_account/set_active/list_accounts (helper pur,
  partajat CLI + viitor flux web 3.3). Normalizeaza CUI (trim+upper),
  prinde IntegrityError -> ValueError cu cauza+fix.
- accounts.active (lifecycle cont) + index unic partial ux_accounts_cui
  (unicitate la nivel de index, fara fereastra de coliziune). Migrare
  idempotenta in _migrate.
- tools/account.py: create (--name/--cui/--inactive/--with-key atomic),
  list [--pending], activate/deactivate --account N. Erori -> exit 2.
- 20 teste noi (12 helper + 8 CLI); suita 299 passed.

active e inert pana la gate-ul worker din 3.3 (documentat).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-06-17 12:38:13 +00:00
parent 6515de415b
commit 1c5b0cbc18
8 changed files with 475 additions and 5 deletions

View File

@@ -10,9 +10,14 @@ CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
cui TEXT,
active INTEGER NOT NULL DEFAULT 1, -- lifecycle cont (3.1); gate „in asteptare" consumat de 3.3
rar_creds_enc TEXT, -- creds RAR criptate (Fernet) durabile per-cont (D4/Eng#1)
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
-- Un CUI = un cont (cand e prezent). NULL ramane distinct nativ in SQLite -> conturi
-- fara CUI (ex. default) se pot crea multiplu. Unicitate la nivel de index (nu check
-- in helper) ca sa nu existe fereastra de coliziune intre doi create_account concurenti.
CREATE UNIQUE INDEX IF NOT EXISTS ux_accounts_cui ON accounts(cui) WHERE cui IS NOT NULL;
-- 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
-- operations_mapping sa fie valide; cand auth livreaza, account_id real va curge natural.