feat(5.16+5.17): tipografie/antet branded + tipuri cont, planuri si enforcement
PRD 5.16 — propagare design finalizata (system font stack, fara IBM Plex self-hostat): - US-001/002/008: tokeni --font-ui/--font-mono (system stack) + scala --fs-*; zero @font-face si zero /static/fonts/; landing aliniat la acelasi stack - US-003: RAR online = dot compact in antet + meniu burger; banda rosie DOAR pe blocat (invariant zero-silent-failures pastrat) - US-010: antet "ROMFAST AUTOPASS" + nume service + /login brandeit 2 coloane + badge plan; meniu burger cu separatoare; gate strict pe is_authenticated - US-011: selector tema pill icon+eticheta (reuse THEMES) - US-004/005/006/007: bug-fix editor prestatii (picker cod+denumire, add_extra in mod operatii, cod ales se salveaza fara "+", Renunta inchide via closest) - US-012/013: landing Autentificare->/login; wizard import colapsat + 4 pasi pe tokeni - fix VERIFY E2E: contoare duplicate pe 390px (inline display:flex batea @media) -> CSS + test-lock PRD 5.17 — tipuri de cont + trial Pro 30z + enforcement DUR: - US-001/002/008: accounts.tier + trial_until (migrare aditiva defensiva); app/plans.py sursa unica (PLANS, FREE_MONTHLY_LIMIT=60, effective_tier(now injectabil), monthly_usage, CONSUMED_STATUSES); create_account trial Pro 30z; CLI set-tier (protejat id=1, audit) - US-003/004/005: enforce volum 60/luna INAINTE de build_key pe ambele canale (PLAN_LIMITA_LUNARA, 3 niveluri + log_event); gate API Pro+ (PLAN_FARA_API 403 actionabil); valideaza/nomenclator raman permise; downgrade lazy; flag AUTOPASS_ENFORCE_PLANS (kill-switch) - US-006: badge plan antet + linie burger + consum N/60 + warn>=80% + 6 stari + copy RO pluralizat + banner one-time trial->Gratuit + pagina Cont Regresie: 1380 passed, 0 failed, 1 deselected (live). E2E browser pe 390/1280 confirmat. Backend trimitere (worker/masina stari/idempotenta/contract RAR) NEATINS. Lucrul 5.18 (corpus kNN) ramane separat, necomis. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,7 @@ import argparse
|
||||
import sqlite3
|
||||
import sys
|
||||
|
||||
from app.accounts import create_account, list_accounts, set_active
|
||||
from app.accounts import create_account, list_accounts, set_active, set_tier
|
||||
from app.auth import create_api_key
|
||||
from app.db import get_connection, init_db
|
||||
from app.users import set_admin
|
||||
@@ -68,6 +68,17 @@ def _set_active(conn: sqlite3.Connection, account_id: int, active: bool) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def _set_tier(conn: sqlite3.Connection, account_id: int, tier: str, trial_until: str | None) -> int:
|
||||
try:
|
||||
set_tier(conn, account_id, tier, trial_until=trial_until)
|
||||
except ValueError as exc:
|
||||
print(f"eroare: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
trial_msg = f", trial_until={trial_until}" if trial_until else ", fara trial"
|
||||
print(f"Cont {account_id}: tier={tier}{trial_msg}")
|
||||
return 0
|
||||
|
||||
|
||||
def _set_admin(conn: sqlite3.Connection, account_id: int, is_admin: bool) -> int:
|
||||
try:
|
||||
set_admin(conn, account_id, is_admin=is_admin)
|
||||
@@ -119,6 +130,29 @@ def main(argv: list[str] | None = None) -> int:
|
||||
p_sadmin.add_argument("--account", type=int, required=True, help="account_id")
|
||||
p_sadmin.add_argument("--remove", action="store_true", help="sterge rolul admin (implicit: adauga)")
|
||||
|
||||
p_stier = sub.add_parser(
|
||||
"set-tier",
|
||||
help="seteaza planul unui cont (free/standard/pro/premium)",
|
||||
description=(
|
||||
"Aloca manual un plan de cont. Tier invalid -> eroare clara. "
|
||||
"Contul de sistem id=1 e protejat."
|
||||
),
|
||||
)
|
||||
p_stier.add_argument("--account", type=int, required=True, help="account_id")
|
||||
p_stier.add_argument(
|
||||
"--tier", required=True,
|
||||
help="planul de alocat: free | standard | pro | premium"
|
||||
)
|
||||
_trial_grp = p_stier.add_mutually_exclusive_group()
|
||||
_trial_grp.add_argument(
|
||||
"--trial-days", type=int, metavar="N",
|
||||
help="seteaza trial_until = acum + N zile"
|
||||
)
|
||||
_trial_grp.add_argument(
|
||||
"--no-trial", action="store_true",
|
||||
help="sterge trial-ul (trial_until=NULL)"
|
||||
)
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
init_db() # asigura schema (accounts.active + index CUI) + cont default
|
||||
@@ -134,6 +168,16 @@ def main(argv: list[str] | None = None) -> int:
|
||||
return _set_active(conn, args.account, False)
|
||||
if args.cmd == "set-admin":
|
||||
return _set_admin(conn, args.account, is_admin=not args.remove)
|
||||
if args.cmd == "set-tier":
|
||||
# Calculeaza trial_until din --trial-days sau None daca --no-trial
|
||||
from datetime import datetime, timedelta, timezone
|
||||
trial_until: str | None = None
|
||||
if getattr(args, "trial_days", None):
|
||||
trial_until = (
|
||||
datetime.now(timezone.utc) + timedelta(days=args.trial_days)
|
||||
).strftime("%Y-%m-%d %H:%M:%S")
|
||||
# daca nici --trial-days nici --no-trial -> trial_until=None (fara trial)
|
||||
return _set_tier(conn, args.account, args.tier, trial_until)
|
||||
finally:
|
||||
conn.close()
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user