feat(signup+admin): aliniere formular signup la landing + plan cerut, GDPR, control tier/trial in panou

Signup:
- /signup aliniat ca format la formularul din landing (campuri, etichete,
  placeholder-uri, select plan, checkbox GDPR, buton). Eticheta `name` = "Companie"
  (corecta: backendul salveaza nume de firma), uniform si in landing.
- Consimtamant GDPR validat server-side (functional, nu doar client-side) + salvat
  cu marca temporala (accounts.consent_at).
- Plan ales la signup salvat in accounts.requested_plan (intentie, NU drept): tier
  ramane sursa de adevar pentru gate-ul API; coloana pregateste integrarea platilor.
- landing: valorile `plan` = coduri tier (free/standard/pro/premium), data-plan
  sincronizat pe butoanele de pret; checkbox consimtamant primeste name.

Schema/DB:
- accounts: coloane noi requested_plan + consent_at (cu migrare aditiva in db.py).

Panou admin:
- Coloane noi: Plan curent (plan EFECTIV acum + zile trial ramase) si Plan cerut.
- Buton "Aplica" (POST /admin/set-tier): aloca plan real si INCHEIE trial-ul
  (efect imediat; altfel trial-ul Pro universal de 30z masca alegerea).
- Control "Trial Pro N zile" (POST /admin/set-trial via accounts.set_trial):
  acorda/prelungeste trial fara a schimba tier-ul de baza.

Teste: signup (consent obligatoriu, requested_plan persistat, tier ramane free),
panou admin (set-tier incheie trial, free opreste Pro imediat, set-trial, validari
+ CSRF). Call-site-urile existente POST /signup actualizate cu consent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-06-29 16:02:37 +00:00
parent a29896a790
commit 851f76ca16
14 changed files with 528 additions and 42 deletions

View File

@@ -109,6 +109,14 @@ def _migrate(conn: sqlite3.Connection) -> None:
if "trial_until" not in acc_cols:
# Trial Pro activ daca != NULL si > now. Nullable (NULL = fara trial).
conn.execute("ALTER TABLE accounts ADD COLUMN trial_until TEXT")
if "requested_plan" not in acc_cols:
# Planul cerut la signup (integrare plati). NU acorda drepturi; `tier` ramane sursa
# de adevar pt API/volum. Nullable. ALTER nu poate adauga CHECK pe coloana noua in
# SQLite -> validarea valorilor se face in cod (signup, fata de VALID_TIERS).
conn.execute("ALTER TABLE accounts ADD COLUMN requested_plan TEXT")
if "consent_at" not in acc_cols:
# Marca temporala consimtamant Termeni+GDPR (proba). Nullable (NULL = CLI/legacy).
conn.execute("ALTER TABLE accounts ADD COLUMN consent_at TEXT")
# Unicitate CUI (un CUI = un cont); NULL distinct nativ -> conturi fara CUI multiplu.
conn.execute(
"CREATE UNIQUE INDEX IF NOT EXISTS ux_accounts_cui ON accounts(cui) WHERE cui IS NOT NULL"