feat(5.19): auto-send toggle per cont + tinere manuala randuri (held)

Comutator accounts.auto_send_enabled per cont: Auto OFF (default) tine randurile
la ingestie (submissions.held=1), worker-ul (claim_one AND held=0) le sare pana la
eliberare umana (per rand/bulk/auto-release OFF->ON). Snapshot held prin chokepoint
unic held_for_account pe toate caile de ingestie (API, import, reresolve, reactivare).

- schema/migrare: coloana held + index partial idx_submissions_held; auto_send_enabled
- API: echo onest held+motiv (US-010), ruta /prezentari/{id}/trimite-acum
- web: toggle header, modal confirmare tipata, buton Trimite per rand + Trimite toate,
  banner coada tinuta imbatranita (L.142), contor "In asteptare (manual)"
- worker: expire_held (US-008, inchide gaura retentie PII), metrics held gauges
- ops: tools/carantina_held + runbook rollback (R4)

Nota review (/code-review high): re-snapshot held lipseste pe caile repune/corectie
(requeue_submission, post_corectie, bulk-fix) — de aliniat separat cu create_prezentari.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-07-06 08:34:40 +00:00
parent 2ec3292382
commit 3b5cf7a7d9
30 changed files with 2344 additions and 32 deletions

View File

@@ -83,6 +83,13 @@ def _migrate(conn: sqlite3.Connection) -> None:
"CHECK (rar_env IN ('test', 'prod'))"
)
_backfill_submissions_rar_env(conn)
if "held" not in sub_cols:
# PRD 5.19 US-001: flag rand tinut manual. Default 0 (randurile pre-migrare nu erau
# tinute — pastreaza comportamentul; comutatorul de cont e OFF/held la ingestie NOUA).
conn.execute(
"ALTER TABLE submissions ADD COLUMN held INTEGER NOT NULL DEFAULT 0 "
"CHECK (held IN (0, 1))"
)
# Coloane accounts
acc_cols = {r["name"] for r in conn.execute("PRAGMA table_info(accounts)").fetchall()}
@@ -113,6 +120,14 @@ def _migrate(conn: sqlite3.Connection) -> None:
"ALTER TABLE accounts ADD COLUMN on_unmapped_error_default INTEGER NOT NULL DEFAULT 0 "
"CHECK (on_unmapped_error_default IN (0, 1))"
)
if "auto_send_enabled" not in acc_cols:
# PRD 5.19 US-001: comutator Auto per cont. Default 0 (Auto OFF) — conturile existente
# trec pe „tine randurile" la ingestie noua pana cand operatorul porneste Auto explicit.
# Contul id=1 ramane pe default (0), fara tratament special.
conn.execute(
"ALTER TABLE accounts ADD COLUMN auto_send_enabled INTEGER NOT NULL DEFAULT 0 "
"CHECK (auto_send_enabled IN (0, 1))"
)
if "email" not in acc_cols:
# Email canonic de contact al firmei (US-001, PRD 5.12). Nullable pt. conturi legacy.
conn.execute("ALTER TABLE accounts ADD COLUMN email TEXT")
@@ -178,6 +193,12 @@ def _migrate(conn: sqlite3.Connection) -> None:
"CREATE INDEX IF NOT EXISTS idx_submissions_account_status "
"ON submissions(account_id, status)"
)
if "idx_submissions_held" not in existing_idx:
# PRD 5.19 US-001 (Eng MEDIUM): CREATE TABLE IF NOT EXISTS nu se declanseaza pe DB
# existent -> indexul partial trebuie creat si aici, nu doar in schema.sql.
conn.execute(
"CREATE INDEX IF NOT EXISTS idx_submissions_held ON submissions(held) WHERE held=1"
)
def _migrate_accounts_medii(conn: sqlite3.Connection, acc_cols: set[str]) -> None: