docs(autoplan): review 5.16+5.17 + decizii porti umane + ROADMAP
Rulare /autoplan in paralel (2 agenti) pe PRD 5.16 si 5.17, faze CEO/Design/Eng(/DX), single-voice (Codex la plafon pana 2026-07-18). Audit trail + GSTACK REVIEW REPORT scrise in fiecare PRD; 0 decizii deschise pe ambele. Decizii inchise cu user: - 5.16 User Challenge -> system-ui (scoate IBM Plex self-hostat; risc per-OS + design slop acceptat constient). Pre-ship: teste Eng E1/E3. - 5.17 User Challenge -> enforcement DUR direct de la deploy; CRITICAL GAP migrare legacy = MOOT (pre-productie/fara conturi legacy); flag AUTOPASS_ENFORCE_PLANS optional; 3 taste decisions rezolvate pe recomandare (limita 60 = constanta config; banner one-time trial->Gratuit; valideaza dry-run permis pe orice plan). ROADMAP: linia "Ultima actualizare" + randuri noi 5.16/5.17 (TODO, gata de implementare) in tabelul Etapa 5. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,3 +1,4 @@
|
||||
<!-- /autoplan restore point: ~/.gstack/projects/romfast-rar-autopass/docs-prd-5.16-5.17-design-tiers-autoplan-restore-20260628-212525.md -->
|
||||
# PRD 5.16 — Tipografie uniforma (fonturi standard web) + bug-fix formular editare + E2E
|
||||
|
||||
**Stare**: draft
|
||||
@@ -496,3 +497,568 @@ Val 4: [US-009] E2E final + regresie (dupa toate)
|
||||
|
||||
> Acest PRD nu a fost inca trecut prin `/plan-ceo-review` / `/plan-eng-review`. Recomandat inainte de
|
||||
> executie (atinge `base.html` fierbinte + 4 bug-uri reale in calea de editare).
|
||||
|
||||
---
|
||||
|
||||
# /autoplan — Revizuire automata (CEO -> Design -> Eng)
|
||||
|
||||
> Pipeline rulat non-interactiv. Fiecare AskUserQuestion intermediar a fost AUTO-DECIS prin cele 6
|
||||
> principii (completitudine, boil-lakes, pragmatic, DRY, explicit>clever, bias-spre-actiune) si logat
|
||||
> in Decision Audit Trail (jos). Doua porti raman pentru confirmarea umana: (1) premisele Fazei 1,
|
||||
> (2) User Challenges (unde ambele modele cer schimbarea directiei userului). Acestea sunt RAPORTATE,
|
||||
> nu decise.
|
||||
|
||||
## FAZA 1 — CEO Review (Strategie & Scop)
|
||||
|
||||
Mod (override autoplan): **SELECTIVE EXPANSION** — iteratie pe un sistem existent (5.15 livrat);
|
||||
tin scopul ca baseline si semnalez expansiuni ca optiuni.
|
||||
|
||||
### 0A. Premise Challenge (de confirmat de user)
|
||||
|
||||
**Premisa P1 (bug-fix)** — „cele 4 bug-uri sunt reale si fac corectia frustranta/imposibila".
|
||||
VERIFICAT in cod, toate 4 confirmate:
|
||||
- US-007 (Renunta nu inchide): `base.html:1132` foloseste `e.target.hasAttribute('data-modal-close')`
|
||||
pe handler-ul de overlay; butonul Anuleaza (`_form_editare.html:106`) are atributul pe `<button>`
|
||||
dar contine `<span class="act-tx">`+SVG, deci click pe text/icon → `e.target` = copilul fara atribut
|
||||
→ `close()` nu se apeleaza. X-ul (`base.html:822`) merge doar fiindca `×` nu are copii. **Cauza
|
||||
exacta a planului e corecta.**
|
||||
- US-006 (save no-op): `post_corectie_trimitere` (`routes.py:1359`) citeste `form.getlist("cod_prestatie")`;
|
||||
selectul `chips_add_cod_flat` (`_chips_prestatii.html:142`) NU se numeste `cod_prestatie` si nu e citit
|
||||
→ la 0 chips, lista e goala → ramane `needs_mapping`. **Confirmat.**
|
||||
- US-004 (picker fara denumire): modul plat (`_chips_prestatii.html:147`) afiseaza doar `{{ n.cod_prestatie }}`;
|
||||
modul operatii (`:101`) afiseaza `cod — nume`. **Confirmat asimetria.**
|
||||
- US-005 (fara adaugare extra in mod operatii): controlul „+ cod nou" exista doar in ramura `else`
|
||||
(mod plat, `:139-161`); `post_form_chips` (`routes.py:1925`) trateaza add/add_flat/remove/remove_flat,
|
||||
fara `add_extra`. **Confirmat lipsa.**
|
||||
P1 = ACCEPTATA (verificata in cod). Premisa solida; jumatatea de bug-fix e clar problema corecta.
|
||||
|
||||
**Premisa P2 (tipografie) — CONTESTATA partial.** Planul afirma „vreau fonturi standard web (fara
|
||||
fisiere de font instalate)" si „zero dependente runtime". Dar IBM Plex e DEJA self-hostat ca woff2
|
||||
local cu subset latin-ext (`base.html:42-103`, `landing.html:10-18`) — fara CDN, fara dependenta de
|
||||
retea la runtime, fara „instalare" de catre operator (serverul serveste woff2 din acelasi origine).
|
||||
Deci „dependenta" eliminata = ~8-10 fisiere statice deja in repo (~200-400KB), nu o dependenta reala.
|
||||
In plus, obiectivul declarat e UNIFORMITATEA, dar system-ui se randeaza DIFERIT pe Windows/Mac/Linux
|
||||
(planul insusi listeaza asta ca risc acceptat) — IBM Plex self-hostat e MAI uniform cross-OS decat
|
||||
system-ui. `DESIGN.md` a ales explicit IBM Plex pentru identitatea „software serios". Premisa P2 e deci
|
||||
fragila: castigul real al userului („fonturi prea mici si neuniforme") se obtine din US-002 (scala in
|
||||
tokeni) FARA a scoate familia. **Vezi User Challenge #1.** P2 acceptata ca sa avansez, dar marcata
|
||||
pentru confirmare umana.
|
||||
|
||||
**Premisa P3 (badge plan citit din `accounts.tier`)** — US-010 afiseaza un badge de plan din 5.17.
|
||||
In 5.16 e doar afisare cu fallback `Gratuit`. ACCEPTATA, dar creeaza un cuplaj soft 5.16->5.17 (vezi
|
||||
Sec 1).
|
||||
|
||||
### 0B. Existing Code Leverage (ce exista deja)
|
||||
- **Scala/tokeni**: `base.html` are deja `--card2`/`--line2` (5.15) ca model de „token sursa-unica" —
|
||||
US-002 extinde acelasi pattern cu `--fs-*`. Reuse, nu reinventare. OK.
|
||||
- **Selector tema**: landing are deja `THEMES`/`#theme-label` (`landing.html:78-82`); US-011 deriva
|
||||
eticheta din structura `THEMES` existenta (E2 DRY din 5.15). Reuse confirmat.
|
||||
- **Pill „Live"**: `landing.html:117` exista deja ca model pentru dot-ul RAR (US-003). Reuse.
|
||||
- **`e.target.closest`**: deja folosit la `data-modal-retry` (`base.html:1166`) — US-007 reuse exact
|
||||
acelasi pattern. DRY, explicit.
|
||||
- **Chips server-driven** (`_chips_prestatii.html` + `post_form_chips`): US-004/005/006 extind handler-ul
|
||||
existent, nu construiesc un al doilea. Modalul de editare partajat (`_form_editare.html`) e refolosit
|
||||
in preview import (US-013) → fix-urile bug se propaga automat. Reuse arhitectural confirmat.
|
||||
- **Strip sanatate** (`_status.html:22-41`): US-003 il muta din corp in antet ca dot; pastreaza
|
||||
invariantul D6 (banda doar pe blocat). Refolosire, nu rescriere.
|
||||
|
||||
### 0C. Dream State
|
||||
```
|
||||
CURENT (5.15) ACEST PLAN (5.16) IDEAL 12 luni
|
||||
Dashboard propagat, dar -> Tipografie uniforma + 4 bug -> Produs care „pare ca landing-ul":
|
||||
fonturi mici/ad-hoc, reparate, antet branded, identitate ROMFAST consecventa,
|
||||
corectie rupta (save no-op, /login profesional, dot RAR, corectie fluida fara frustrare,
|
||||
Renunta blocat), antet generic wizard aliniat tipuri cont (5.17), self-serve
|
||||
```
|
||||
Delta: planul muta produsul clar spre ideal pe axa „incredere/corectie". Pe axa „identitate vizuala",
|
||||
trecerea la system-ui e o miscare LATERALA/inapoi (pierde caracter tipografic) — vezi User Challenge #1.
|
||||
|
||||
### 0C-bis. Implementation Alternatives (tipografie — punctul de decizie cheie)
|
||||
```
|
||||
APPROACH A: Pastreaza IBM Plex self-hostat, repara DOAR scala (US-002 tokeni) [minimal viable]
|
||||
Effort: S (human ~0.5 zi / CC ~20min) Risk: Low
|
||||
Pros: rezolva durerea reala (marime/uniformitate); pastreaza identitatea DESIGN.md; uniform cross-OS;
|
||||
zero risc de diacritice; respecta regula de design „no default font stacks".
|
||||
Cons: pastreaza ~10 woff2 in repo (cost real ~zero, deja servite local).
|
||||
Reuses: tot stack-ul de fonturi existent + pattern token --card2/--line2.
|
||||
|
||||
APPROACH B: System font stack, elimina IBM Plex (alegerea planului) [planul curent]
|
||||
Effort: M (human ~1 zi / CC ~30min) Risk: Med
|
||||
Pros: zero fisiere font; nimic de incarcat.
|
||||
Cons: pierde identitatea tipografica (DESIGN.md a ales IBM Plex intentionat); randare DIFERITA per OS
|
||||
(contrazice obiectivul „uniform"); incalca regula de design slop #11 (system-ui ca font primar);
|
||||
~40+ literale `'IBM Plex Sans'` fara fallback in landing.html ar cadea pe serif default daca sunt
|
||||
ratate; testul propus grep-uie doar `/static/fonts/`, nu literalele de familie.
|
||||
|
||||
APPROACH C: Hibrid — pastreaza IBM Plex, dar adauga stack system explicit ca fallback peste tot
|
||||
Effort: S-M Risk: Low
|
||||
Pros: degradare eleganta pe masini fara font; pastreaza identitatea cand fontul e prezent.
|
||||
Cons: nu satisface cererea literala „fara fisiere de font".
|
||||
```
|
||||
**RECOMANDARE (principiul P5 explicit + P1 completitudine + regula design „real typeface"):** APPROACH A.
|
||||
Livreaza durerea reala a userului (uniformitate) cu cel mai mic risc si pastreaza identitatea. DAR userul
|
||||
a cerut EXPLICIT system fonts — deci aceasta e **User Challenge #1**, nu o auto-decizie. Daca userul
|
||||
confirma B, planul e tehnic fezabil; vezi gap-urile de test din Faza 3.
|
||||
|
||||
### 0E. Temporal Interrogation
|
||||
- HOUR 1 (fundatii): valorile exacte `--fs-*` (Open Question din plan) — propuse in mockup, de validat
|
||||
pe ecran. Decizie: porneste din mockup, ajusteaza la executie. (auto-decis)
|
||||
- HOUR 2-3 (US-006 server path): implementatorul va ezita JS-vs-server. Planul deja fixeaza „server"
|
||||
(citeste picker-ul la submit). Bun — fara ambiguitate.
|
||||
- HOUR 4-5 (US-001 integrare): ratarea unui literal `'IBM Plex Sans'` fara fallback in landing → text
|
||||
pe serif default. Trebuie un test grep pe literale (vezi Faza 3, gap test).
|
||||
- HOUR 6+ (polish): diacritice RO pe system stack — de verificat in E2E (planul o cere).
|
||||
|
||||
### 0F. Mode confirmation
|
||||
SELECTIVE EXPANSION confirmat. Nicio expansiune noua adaugata in scop (planul e deja complet pentru
|
||||
durerea declarata); o singura expansiune marcata: **test grep pe literale de font** (P2 boil-lakes,
|
||||
in blast radius, <1 zi) — recomandata sa intre in US-001 (vezi Faza 3 T-uri).
|
||||
|
||||
### CLAUDE SUBAGENT (CEO — independenta strategica)
|
||||
[Vocea mea independenta, formata inainte de a citi Codex]
|
||||
1. **Problema corecta?** Jumatatea bug-fix: DA, fara echivoc — corectia e rupta pe cazul cel mai
|
||||
frecvent (rand needs_mapping cu 0 coduri: US-006 face save = no-op, US-007 te blocheaza in modal).
|
||||
Pentru un produs de conformitate legala unde corectiile TREBUIE sa plece, un formular de corectie rupt
|
||||
e risc direct de conformitate. Valoare mare, efort mic. Aceasta jumatate ar trebui sa fie PRIORITARA
|
||||
(hotfix), separat de tipografie.
|
||||
2. **Tipografia** e jumatatea discutabila. Contradictie interna: obiectivul e „uniform", dar system-ui
|
||||
randeaza diferit per OS; IBM Plex self-hostat e mai uniform. Premisa „fara dependente" e deja
|
||||
satisfacuta (woff2 local, zero CDN). Castigul real (marime/uniformitate) vine din US-002, nu din
|
||||
stergerea familiei. Risc de regret la 6 luni: app-ul isi pierde identitatea si arata „ca orice admin
|
||||
AI-generat" (chiar regula de slop #11 din canonul de design semnaleaza system-ui ca font primar).
|
||||
3. **Risc competitiv:** minim — gateway intern, useri captivi (obligatie legala). Identitatea conteaza
|
||||
pentru INCREDERE, nu pentru competitie.
|
||||
4. **Calibrare scop:** 12 stories, 6 ating `base.html` fierbinte serializat. Mare pentru un PRD „de
|
||||
polish", dar valurile separa corect bug-fix (Val 2, independent) de tipografie (Val 1). Recomand
|
||||
livrarea Val 2 intai.
|
||||
Verdict CEO independent: bug-fix = aproba si prioritizeaza; tipografie = contesteaza directia
|
||||
(pastreaza IBM Plex, repara doar scala) → User Challenge #1.
|
||||
|
||||
### Error & Rescue Registry (Faza 1 — relevanta limitata, PRD UI)
|
||||
| Codepath | Ce poate esua | Tratat? | User vede |
|
||||
|---|---|---|---|
|
||||
| `post_form_chips` add/add_extra | cod necunoscut in nomenclator | DA — `SELECT 1 FROM nomenclator_rar`, ignora daca lipseste | chip nu apare (silent) ← vezi GAP-1 |
|
||||
| `post_corectie_trimitere` cod nevalid | cod necunoscut | DA — re-randeaza `_trimitere_detaliu` cu mesaj | „Cod RAR necunoscut: X" |
|
||||
| US-006 citire picker la submit | picker gol + 0 chips | trebuie sa ramana needs_mapping cu mesaj | „Lipseste inca un cod RAR" |
|
||||
GAP-1: `post_form_chips` la cod invalid/neselectat IGNORA silentios (nu re-randeaza un mesaj). Pentru
|
||||
add_extra (US-005) ar trebui macar un semnal vizual daca selectul e gol. Minor (P3). Logat.
|
||||
|
||||
### Failure Modes Registry (Faza 1)
|
||||
| Codepath | Failure mode | Tratat? | Test? | User vede | Logat? |
|
||||
|---|---|---|---|---|---|
|
||||
| modal close (US-007) | click pe copil fara atribut | NU (azi) → DA dupa fix `closest` | test lock propus | ramane blocat → inchide | n/a |
|
||||
| save cod ales (US-006) | picker necitit la submit | NU (azi) → DA dupa fix server | test lock propus | no-op → queued | n/a |
|
||||
| literal font ratat (US-001) | `'IBM Plex Sans'` fara fallback | risc dupa stergere @font-face | grep doar /static/fonts ← GAP | text pe serif | nu |
|
||||
Niciun CRITICAL GAP cu impact tacut+silentios+netestabil pe backend (PRD nu atinge worker/trimitere).
|
||||
GAP de test pe literale font = important, mutat in Faza 3.
|
||||
|
||||
### Sectiuni 1-11 (CEO) — sinteza
|
||||
- **Sec 1 Arhitectura:** cuplaj nou 5.16->5.17 (badge `accounts.tier`). Mitigat de fallback `Gratuit`.
|
||||
`base.html` fierbinte: regula autor-unic respectata in plan. Fara SPOF nou. OK.
|
||||
- **Sec 2 Erori:** vezi registrul; GAP-1 (silent pe add_extra cod invalid) logat P3.
|
||||
- **Sec 3 Securitate:** US-005 `add_extra` valideaza fata de nomenclator (invariant ORA-12899 pastrat) —
|
||||
bine, NU trimite cod raw. CSRF mostenit din `post_form_chips`/`post_corectie` existente. Scope pe cont
|
||||
pastrat. Niciun vector nou. Examinat: input cod (validat), niciun endpoint nou nedeprotejat.
|
||||
- **Sec 4 Data/UX edge:** dublu-click pe „+", navigare in timpul editarii — modalul cu focus-trap exista;
|
||||
US-006 server-path acopera „salveaza fara +". Edge: lista chips foarte lunga (overflow picker) — minor.
|
||||
- **Sec 5 Calitate:** DRY bun (reuse `_form_editare`/`closest`/THEMES). Risc: ~40+ literale font in
|
||||
landing → recablare manuala mare (vezi Faza 3).
|
||||
- **Sec 6 Teste:** 4 teste-lock cerute (bug-uri reproduse inainte/reparate dupa) — corect. Lipseste grep
|
||||
pe literale font. E2E cerut.
|
||||
- **Sec 7 Perf:** stergerea woff2 reduce ~10 request-uri statice (neglijabil, acelasi origine). Fara N+1
|
||||
(PRD UI). OK.
|
||||
- **Sec 8 Observabilitate:** US-003 pastreaza vizibilitatea blocaj (banda rosie pe blocat). OK.
|
||||
- **Sec 9 Deploy:** fara migrare schema (non-goal). woff2 raman pe disc (non-goal stergere). Reversibil
|
||||
prin git revert. Risc redus.
|
||||
- **Sec 10 Trajectorie:** Reversibilitate 5/5 (UI/template). Datorie: daca system-ui se dovedeste prost,
|
||||
re-adaugarea IBM Plex e usoara (woff2 raman pe disc). Path 5.17 (tier) pregatit de badge.
|
||||
- **Sec 11 Design:** vezi Faza 2.
|
||||
|
||||
### NOT in scope (CEO)
|
||||
- Backend trimitere (worker/masina stari/idempotenta/contract RAR) — non-goal explicit, corect.
|
||||
- Stergerea fizica woff2 — follow-up, corect (reduce riscul de revert).
|
||||
- Tipuri cont/planuri — 5.17 separat.
|
||||
- Redesign layout landing — doar fonturi.
|
||||
|
||||
### Dream-state delta
|
||||
Planul livreaza ~90% din axa „incredere/corectie" (bug-fix + antet + login). Pe axa „identitate
|
||||
vizuala", User Challenge #1 determina daca planul avanseaza (pastreaza IBM Plex) sau lateral (system-ui).
|
||||
|
||||
### CEO Completion Summary
|
||||
```
|
||||
| Mod | SELECTIVE EXPANSION |
|
||||
| Sec 1 Arch | 1 (cuplaj soft 5.16->5.17, mitigat) |
|
||||
| Sec 2 Erori | 1 GAP minor (silent add_extra) P3 |
|
||||
| Sec 3 Securitate | 0 (validare nomenclator pastrata) |
|
||||
| Sec 4 Data/UX | 0 critice (edge minore) |
|
||||
| Sec 5 Calitate | 1 (recablare literale font landing) |
|
||||
| Sec 6 Teste | 1 GAP (grep literale font) |
|
||||
| Sec 7-10 | 0 critice |
|
||||
| Sec 11 Design | -> Faza 2 |
|
||||
| User Challenges | 1 (system-ui vs IBM Plex) |
|
||||
| Reversibilitate | 5/5 |
|
||||
```
|
||||
|
||||
### CODEX SAYS (CEO) — [codex-unavailable: usage limit, reset 2026-07-18]
|
||||
Codex CLI e autentificat dar a atins plafonul de utilizare (eroare „usage limit" la toate apelurile).
|
||||
Degradare per matricea autoplan -> **[subagent-only]** pe toate fazele. Consensul de mai jos foloseste
|
||||
DOAR vocea Claude independenta; semnalele single-voice nu se ridica la „cross-model consensus".
|
||||
|
||||
### CEO DUAL VOICES — CONSENSUS TABLE
|
||||
```
|
||||
Dimensiune Claude Codex Consensus
|
||||
─────────────────────────────────── ──────── ─────── ──────────
|
||||
1. Premise valide? PARTIAL N/A N/A (P2 fragila — single-voice flag)
|
||||
2. Problema corecta? DA(bug) N/A N/A (bug-fix solid; tipografie contestata)
|
||||
3. Calibrare scop corecta? DA N/A N/A (valuri separa corect)
|
||||
4. Alternative explorate suficient? NU N/A N/A (A vs B nedeliberat in plan)
|
||||
5. Riscuri competitive acoperite? DA N/A N/A (intern, useri captivi)
|
||||
6. Traiectorie 6-luni sanatoasa? PARTIAL N/A N/A (risc identitate tipografica)
|
||||
```
|
||||
CONFIRMED=ambele de acord. Cu Codex indisponibil, niciun rand nu e CONFIRMED; semnalele raman
|
||||
single-voice. Finding critic single-voice ridicat oricum: **User Challenge #1 (system-ui vs IBM Plex)**.
|
||||
|
||||
> **FAZA 1 COMPLETA.** Codex: indisponibil (usage limit). Claude subagent: 1 User Challenge + 4 gap-uri
|
||||
> minore (1 test, 1 cuplaj soft, 1 silent add_extra, 1 recablare literale). Trec la Faza 2 (Design).
|
||||
|
||||
## FAZA 2 — Design Review (7 passes)
|
||||
|
||||
UI scope = DA (clar). DESIGN.md exista (calibrez fata de el). 5 mockup-uri HTML exista deja in
|
||||
`docs/mockups/prd-5.16-*.html` ca referinta vizuala — folosite in locul generarii de mockup-uri noi.
|
||||
Rating initial design completeness: **7/10** (interactiuni bune + mockup-uri + tokeni; lipsesc cateva
|
||||
stari de eroare ale picker-ului si exista un conflict de canon tipografic).
|
||||
|
||||
### Pass 1 — Information Architecture: 8/10
|
||||
Planul defineste explicit ce vede userul intai/al doilea/al treilea: ordine verticala Acasa
|
||||
(1 contoare → 2 import colapsat → 3 tab-uri → 4 lista), dot RAR in antet, banda doar pe blocat. Mockup
|
||||
confirma. Constraint worship aplicat (import colapsat ca lista sa fie primul lucru). Minor: 5 contoare
|
||||
pe desktop fara titlu de grup — risc de a parea „mosaic de carduri" (regula App UI „avoid dashboard-card
|
||||
mosaics"); mitigat de bara compacta pe mobil. **Fara issue blocant.**
|
||||
|
||||
### Pass 2 — Interaction State Coverage: 6/10
|
||||
| Feature | LOADING | EMPTY | ERROR | SUCCESS | PARTIAL |
|
||||
|---|---|---|---|---|---|
|
||||
| Dot RAR | n/a | n/a | banda rosie (blocat) | dot verde + ora | n/a |
|
||||
| Picker cod (US-004/006) | (HTMX submit?) | **GAP** | „cod necunoscut" | chip adaugat | needs_mapping ramane |
|
||||
| Add operatie extra (US-005) | — | **GAP-1** (silent daca select gol) | cod invalid silent | chip nou | — |
|
||||
| Modal corectie (US-007) | — | — | „nu s-a putut incarca" (exista) | inchide + focus | — |
|
||||
**GAP (design):** in mod plat picker-ul e randat doar `{% if nomenclator_rar %}` (`_chips_prestatii.html:140`).
|
||||
Daca nomenclatorul e gol/neincarcat, un rand `needs_mapping` NU mai are NICIO cale de a adauga cod —
|
||||
„No items found" tacut. Trebuie o stare empty cu mesaj+actiune (ex. „Nomenclator indisponibil — reincarca").
|
||||
**GAP-1:** add_extra cu select gol nu da feedback (vezi Faza 1). Recomandare: mesaj inline scurt.
|
||||
|
||||
### Pass 3 — User Journey & Emotional Arc: 8/10
|
||||
Arc clar: frustrare (corectie rupta, text inghesuit) → usurare (Salveaza merge, Renunta inchide, text
|
||||
lizibil). US-007/006 ataca direct momentele de frustrare maxima. 5-sec visceral (antet branded inspira
|
||||
incredere), 5-min behavioral (corectie fluida), 5-an (identitate ROMFAST). Bun.
|
||||
|
||||
### Pass 4 — AI Slop Risk: 4/10 ← DIMENSIUNEA CRITICA
|
||||
**[HARD CONFLICT cu canonul de design]** Regula de slop #11: „system-ui sau -apple-system ca font PRIMAR
|
||||
de display/body — semnalul «am renuntat la tipografie». Alege o familie reala." Regula universala: „No
|
||||
default font stacks (Inter, Roboto, Arial, system)." US-001 face EXACT asta: inlocuieste o familie reala
|
||||
(IBM Plex, aleasa intentionat in DESIGN.md pentru caracter ingineresc) cu `system-ui, -apple-system, ...`.
|
||||
Acesta e cel mai puternic argument de design pentru **User Challenge #1**: pentru un „software serios
|
||||
pentru o obligatie legala serioasa" (citat DESIGN.md), trecerea la system stack e o pierdere de
|
||||
identitate, nu un castig. Restul UI-ului NU e slop (fara grid 3-coloane, fara gradient violet, pill-uri
|
||||
cu un singur accent — bun). Singurul issue major de slop e fontul. **Ridicat ca prim item.**
|
||||
|
||||
### Pass 5 — Design System Alignment: 7/10
|
||||
US-001 rescrie `DESIGN.md §Tipografie` (care azi mandateaza IBM Plex „self-host woff2"). Asta REZOLVA
|
||||
inconsistenta interna (planul nu lasa DESIGN.md sa contrazica codul) — bine ca e in scop. DAR noua
|
||||
directie contrazice rationamentul de brand din acelasi DESIGN.md („caracter ingineresc, software serios").
|
||||
Tokenii `--fs-*` + `--card2`/`--line2` se aliniaza la vocabularul existent (DRY). Mockup intern landing
|
||||
„Confirma Vin" ramane debt vizual — corect flagat ca non-goal. Pill-uri/dot consistente cu landing.
|
||||
|
||||
### Pass 6 — Responsive & Accessibility: 8/10
|
||||
Solid: 390/1280 specificate per componenta; tinte 44px pastrate; dot RAR poarta sensul prin
|
||||
`title`/`aria-label` (NU doar culoare — daltonisti), banda blocat cu text explicit pentru screen-reader;
|
||||
contrast AA in toate temele. Bara compacta pe mobil bine gandita. Minor: pe bara compacta mobil,
|
||||
„De corectat" (azi link `<a>` catre lista in `_status.html:64`) — de pastrat afordanta de tap; spec
|
||||
nu confirma ca raman tap-abile. Recomandare: pastreaza tinta tap pe contorul „De corectat" si pe mobil.
|
||||
|
||||
### Pass 7 — Unresolved Design Decisions
|
||||
| Decizie | Daca amanata |
|
||||
|---|---|
|
||||
| Valori exacte `--fs-*` | implementatorul ghiceste; mockup da punct de pornire — OK |
|
||||
| Dot RAR puls DA/NU | implicit DA (ca „Live"); dezactivabil — OK |
|
||||
| Empty-state picker fara nomenclator | „No items found" tacut → rand needs_mapping nereparabil ← de rezolvat |
|
||||
| System-ui vs IBM Plex | **User Challenge #1 — neauto-decis** |
|
||||
Toate (mai putin empty-state picker) sunt deja in §8 Open Questions al planului. Empty-state picker =
|
||||
adaugat ca finding nou.
|
||||
|
||||
### CODEX SAYS (design) — [codex-unavailable: usage limit]
|
||||
### CLAUDE SUBAGENT (design — independent) — incorporat in pasele de mai sus.
|
||||
|
||||
### DESIGN OUTSIDE VOICES — LITMUS SCORECARD
|
||||
```
|
||||
Check Claude Codex Consensus
|
||||
─────────────────────────────────────── ─────── ─────── ─────────
|
||||
1. Brand unmistakable in first screen? YES(antet ROMFAST) N/A single-voice
|
||||
2. One strong visual anchor? YES N/A single-voice
|
||||
3. Scannable by headlines only? YES N/A single-voice
|
||||
4. Each section has one job? YES N/A single-voice
|
||||
5. Cards actually necessary? MOSTLY (5 contoare = risc mosaic) N/A single-voice
|
||||
6. Motion improves hierarchy? YES (dot puls discret) N/A single-voice
|
||||
7. Premium without decorative shadows? PARTIAL (system-ui slabeste premium) N/A single-voice
|
||||
Hard rejections triggered: 1 (slop #11: system-ui font primar) N/A
|
||||
```
|
||||
|
||||
### Design NOT in scope
|
||||
- Redesign layout landing (doar fonturi) — corect.
|
||||
- Mockup intern „Confirma Vin" — debt vizual acceptat.
|
||||
|
||||
### Design — What already exists (reuse)
|
||||
DESIGN.md (sistem 7 teme + tokeni), `landing.html` pill „Live"/selector tema, componente slim 5.15,
|
||||
`_form_editare`/`_chips_prestatii` partajate. Planul reutilizeaza corect.
|
||||
|
||||
### DESIGN Completion Summary
|
||||
```
|
||||
Pass 1 (Info Arch) 8/10
|
||||
Pass 2 (States) 6/10 (2 GAP: empty-state picker, silent add_extra)
|
||||
Pass 3 (Journey) 8/10
|
||||
Pass 4 (AI Slop) 4/10 ← font system-ui = hard conflict (User Challenge #1)
|
||||
Pass 5 (Design Sys) 7/10
|
||||
Pass 6 (Responsive) 8/10 (minor: tap „De corectat" pe mobil)
|
||||
Pass 7 (Decisions) 3 in Open Questions + 1 nou (empty-state picker)
|
||||
Overall design 7/10 -> 7/10 (deciziile cheie raman la user: font + empty-state)
|
||||
```
|
||||
|
||||
> **FAZA 2 COMPLETA.** Codex: indisponibil. Claude subagent: 1 hard-conflict de font (intareste User
|
||||
> Challenge #1) + 2 GAP de stare (empty-state picker, silent add_extra) + 1 minor (tap mobil). Trec la
|
||||
> Faza 3 (Eng).
|
||||
|
||||
## FAZA 3 — Eng Review (Arhitectura, Calitate, Teste, Performanta)
|
||||
|
||||
### Step 0 — Scope Challenge
|
||||
PRD UI/template: atinge `base.html` (fierbinte, 6 stories), `_chips_prestatii.html` + `routes.py`
|
||||
(handlere editare), `landing.html`, `login.html`, `auth_routes.py`, `DESIGN.md`, teste. 12 stories,
|
||||
dar majoritatea sunt CSS/markup; logica reala doar in US-005/006 (handlere). Complexity check: >8 fisiere,
|
||||
DAR fara clase/servicii noi, fara infra, fara migrare — e in mod natural „polish + bugfix", nu
|
||||
overbuild. Scop acceptat ca-i (FULL_REVIEW). Reuse confirmat (Faza 1 0B). Backend trimitere NEATINS.
|
||||
|
||||
### Arhitectura — diagrama dependente (componente noi vs existente)
|
||||
```
|
||||
base.html (FIERBINTE — autor unic, serializat)
|
||||
┌──────────────────────────┬───────────────────┬────────────────────────┐
|
||||
│ :root --font-ui/--font-mono│ :root --fs-* scala │ header branded + dot RAR│
|
||||
│ (US-001) │ (US-002) │ (US-003/010/011) │
|
||||
└──────────┬────────────────┴─────────┬─────────┴───────────┬────────────┘
|
||||
│ consumat de │ consumat de │ context din
|
||||
┌──────────▼─────────┐ ┌───────────▼──────────┐ ┌───────▼──────────┐
|
||||
│ landing.html │ │ componente slim 5.15 │ │ routes.py/_status │
|
||||
│ (@font-face sterse,│ │ (.contor/.slim/.chip)│ │ (sanatate in layout│
|
||||
│ literale->var) │ │ │ │ US-003; account_name│
|
||||
└────────────────────┘ └──────────────────────┘ │ US-010)+auth_routes│
|
||||
└──────────────────┘
|
||||
|
||||
Val 2 (INDEPENDENT de base.html — poate paraleliza):
|
||||
_chips_prestatii.html ──> post_form_chips (add_extra, US-005)
|
||||
│ │
|
||||
└──> post_corectie_trimitere (citeste picker la submit, US-006; by-index align)
|
||||
_form_editare.html ──(mostenit de)──> _preview_import.html (US-013, fix-uri propagate gratis)
|
||||
```
|
||||
Cuplaj nou: doar soft 5.16->5.17 (badge `accounts.tier`, fallback `Gratuit`). Fara SPOF, fara endpoint
|
||||
nou nedeprotejat. Rollback: git revert (UI). Reversibilitate 5/5.
|
||||
|
||||
### CLAUDE SUBAGENT (eng — independent) + CODEX SAYS (eng) [codex-unavailable: usage limit]
|
||||
|
||||
**E1 (P1) — Test gap: literale de font fara fallback.** US-001 testeaza `grep negativ pe /static/fonts/`.
|
||||
Dar dupa stergerea `@font-face`, raman ~40+ literale `'IBM Plex Sans'`/`'IBM Plex Mono'` in template-uri
|
||||
(in special `landing.html`: ex. `:94 font:700 50px/1.06 'IBM Plex Sans'` FARA fallback). Cu `@font-face`
|
||||
sters, `'IBM Plex Sans'` nematchat + fara fallback → font default browser (frecvent serif/Times), NU
|
||||
stack-ul de sistem dorit. Testul `/static/fonts/` NU prinde asta. **Fix:** adauga test grep care esueaza
|
||||
la orice literal `'IBM Plex Sans'`/`'IBM Plex Mono'` ramas FARA `var(--font-*)` sau fara fallback de
|
||||
sistem in coada. (conf: 9/10 — verificat in `landing.html`.)
|
||||
|
||||
**E2 (P2) — US-001 nu enumera stergerea `@font-face` din `base.html`.** AC numeste cele 9 `@font-face`
|
||||
din `landing.html`, dar `base.html:42-103` are ~8 reguli `@font-face` proprii care refera `/static/fonts/`.
|
||||
AC „zero /static/fonts/ in template-uri" le CERE sterse, dar proza nu le enumera. **Fix:** US-001 sa
|
||||
enumere explicit si `base.html` `@font-face` la stergere. (conf: 10/10 — citit `base.html:42-103`.)
|
||||
|
||||
**E3 (P2) — US-006 risc de aliniere by-index la merge picker->prestatii.** `post_corectie_trimitere`
|
||||
(`routes.py:1388`) aliniaza codurile cu itemele `prestatii` PE INDEX. Pickerele per-operatie se numesc
|
||||
`chips_add_cod_{op_idx}` (index de OPERATIE), nu pozitie de `cod_prestatie`. Cand US-006 citeste pickerul
|
||||
la submit, serverul trebuie sa mapeze corect op-index→pozitie item, altfel codul ales se ataseaza la
|
||||
operatia GRESITA. Bucla existenta suporta append corect pentru mod plat (0 chips → item nou), dar modul
|
||||
operatii cu mai multe pozitii nemapate e riscant. **Fix + test:** alege cod in pickerul operatiei #2,
|
||||
Salveaza fara „+", asserteaza ca aterizeaza pe op #2, nu pe #1. (conf: 7/10 — citit handler-ul.)
|
||||
|
||||
**E4 (P3) — `add_extra` silent la cod invalid/gol** (cross-ref Faza 1 GAP-1, Faza 2 GAP-1). `post_form_chips`
|
||||
ignora silentios cand selectul e gol sau codul nu e in nomenclator. Pentru `add_extra` adauga un semnal
|
||||
inline. (conf: 8/10.)
|
||||
|
||||
**E5 (P3) — empty-state picker fara nomenclator** (cross-ref Faza 2 GAP). `{% if nomenclator_rar %}`
|
||||
ascunde pickerul cand nomenclatorul e gol → rand `needs_mapping` nereparabil tacut. Adauga mesaj+actiune.
|
||||
(conf: 8/10 — citit `_chips_prestatii.html:140`.)
|
||||
|
||||
### ENG DUAL VOICES — CONSENSUS TABLE
|
||||
```
|
||||
Dimensiune Claude Codex Consensus
|
||||
─────────────────────────────────── ──────── ─────── ──────────
|
||||
1. Arhitectura sound? DA N/A single-voice (cuplaj soft OK)
|
||||
2. Acoperire teste suficienta? NU N/A single-voice (E1 gap font, E3 gap by-index)
|
||||
3. Riscuri perf adresate? DA N/A single-voice (UI; -10 req woff2 = pozitiv)
|
||||
4. Amenintari securitate acoperite? DA N/A single-voice (validare nomenclator pastrata)
|
||||
5. Cai de eroare tratate? PARTIAL N/A single-voice (E4/E5 silent states)
|
||||
6. Risc deploy gestionabil? DA N/A single-voice (git revert, fara migrare)
|
||||
```
|
||||
Codex indisponibil (usage limit) → niciun rand CONFIRMED; toate single-voice.
|
||||
|
||||
### Sectiunea 3 (Test Review) — diagrama de acoperire
|
||||
```
|
||||
NEW/CHANGED CODEPATHS COVERAGE
|
||||
[~] base.html fonturi/scala (US-001/002)
|
||||
├── token --font-ui/--font-mono pe body [GAP→add] test_font_stack_system_in_base
|
||||
├── @font-face sterse (base.html + landing) [GAP→add] test_zero_referinte_static_fonts
|
||||
└── literale 'IBM Plex *' fara fallback [GAP→E1] test grep literale (LIPSESTE in plan)
|
||||
[~] base.html modal close (US-007)
|
||||
└── closest('[data-modal-close]') [GAP→add] test_anuleaza_are_data_modal_close +
|
||||
test_modal_close_pe_element_interior (LOCK)
|
||||
[~] _chips_prestatii.html picker (US-004)
|
||||
├── flat: cod — denumire [GAP→add] test_picker_flat_arata_cod_si_denumire
|
||||
└── op: cod — denumire (exista deja :101) [★★ are]
|
||||
[~] post_form_chips add_extra (US-005)
|
||||
├── add_extra valideaza nomenclator [GAP→add] test_extra_cod_validat_nomenclator
|
||||
├── persista la salvare [GAP→add] test_extra_cod_persistat_la_salvare
|
||||
└── cod invalid/gol → semnal [GAP→E4] (lipsa in plan)
|
||||
[~] post_corectie_trimitere citeste picker (US-006)
|
||||
├── flat 0 chips: cod ales se aplica fara „+" [GAP→add] test_cod_ales_in_picker_se_salveaza_fara_buton_add
|
||||
└── op-mode: cod aterizeaza pe operatia CORECTA [GAP→E3] (lipsa in plan — RISC by-index)
|
||||
[~] empty-state picker fara nomenclator [GAP→E5] (lipsa in plan)
|
||||
[~] header branded / dot RAR / selector tema [GAP→add] test_titlu_romfast_autopass,
|
||||
(US-003/010/011) test_rar_dot_in_antet_ok, test_selector_tema_are_eticheta
|
||||
[~] landing Autentificare->/login (US-012) [GAP→add] test_landing_autentificare_link_login
|
||||
[~] E2E final (US-009) [→E2E] Playwright/headless 390+1280, 2 teme
|
||||
|
||||
COVERAGE: planul cere ~18 teste noi + 4 lock-uri de bug. LIPSESC: E1 (grep literale), E3 (by-index op),
|
||||
E4/E5 (empty/silent states). Regresie ceruta: `pytest -q -m "not live"` verde (baseline 5.15: 1256 passed).
|
||||
```
|
||||
**REGRESSION RULE:** cele 4 teste-lock (US-004..007 reproduse-inainte/reparate-dupa) sunt P1 obligatorii.
|
||||
|
||||
### Performance Review
|
||||
PRD UI: fara N+1 (handlerele citesc nomenclatorul o data, deja cache-uit pe request). Stergerea woff2
|
||||
elimina ~8-10 request-uri statice (pozitiv marginal). `load_nomenclator` in `post_form_chips` per add —
|
||||
deja existent, nu nou. **0 issue perf.**
|
||||
|
||||
### Eng NOT in scope
|
||||
Backend trimitere, migrare schema, stergere woff2 fizica, redesign landing, tipuri cont (5.17). Corect.
|
||||
|
||||
### Eng — What already exists
|
||||
`post_form_chips`/`post_corectie_trimitere`/`_form_editare`/`_chips_prestatii`/`closest`-pattern/THEMES/
|
||||
tokeni `--card2`/`--line2`. Planul extinde, nu rescrie.
|
||||
|
||||
### Failure Modes Registry (Eng) — CRITICAL GAP scan
|
||||
| Codepath | Failure | Rescued? | Test? | User vede | Logat? | Verdict |
|
||||
|---|---|---|---|---|---|---|
|
||||
| literal font fara fallback | serif default | n/a (CSS) | NU (E1) | text urat | nu | gap test (nu critical-silent) |
|
||||
| US-006 by-index op | cod pe op gresita | partial | NU (E3) | cod pe alta operatie | nu | **gap — adauga test** |
|
||||
| add_extra cod invalid | ignorat | DA (validare) | partial | nimic (silent) | nu | E4 minor |
|
||||
Niciun CRITICAL GAP (silent+netestat+netratat) pe trimiterea reala — PRD nu atinge worker. E3 e cel mai
|
||||
serios (corectitudine), recomandat test inainte de ship.
|
||||
|
||||
### Worktree parallelization
|
||||
- Lane A: US-001→002→003→010→011→007 (base.html, SECVENTIAL — autor unic) + US-008/012 (landing) la coada.
|
||||
- Lane B: US-004→005→006 (`_chips_prestatii.html`+`routes.py`, INDEPENDENT de base.html) — paralelizabil.
|
||||
- Lane C: US-013 (wizard) dupa US-002 (tokeni) + US-004/5/6 (chips). US-009 (E2E) dupa tot.
|
||||
Conflict: niciunul intre Lane A si B (fisiere disjuncte). **Recomandare: livreaza Lane B (bug-fix) intai
|
||||
ca hotfix — e durerea reala si nu depinde de tipografie.**
|
||||
|
||||
### Eng Completion Summary
|
||||
```
|
||||
Step 0 Scope FULL_REVIEW (scope acceptat ca-i)
|
||||
Arhitectura 0 issue (cuplaj soft mitigat)
|
||||
Code Quality 1 (E2: base.html @font-face neenumerat)
|
||||
Test Review diagrama produsa, 4 gap-uri (E1,E3,E4,E5)
|
||||
Performance 0 issue
|
||||
NOT in scope scris
|
||||
What already exists scris
|
||||
Failure modes 0 CRITICAL GAP (E3 = gap de corectitudine, recomandat test)
|
||||
Parallelization 3 lanes (B independent — hotfix intai)
|
||||
```
|
||||
|
||||
> **FAZA 3 COMPLETA.** Codex: indisponibil. Claude subagent: 5 findings (E1 P1 test font, E2/E3 P2,
|
||||
> E4/E5 P3). Faza 3.5 (DX) SKIP — fara scop developer-facing (UI operator; API/integratori neatins).
|
||||
|
||||
## Cross-Phase Themes
|
||||
- **Tema 1 — Tipografia system-ui (CEO Pass + Design Pass 4):** semnalata independent in Faza 1 (premisa
|
||||
P2 fragila, contradictie „uniform" vs per-OS) SI Faza 2 (hard-conflict slop #11 + identitate DESIGN.md).
|
||||
Doua faze, acelasi semnal → **User Challenge #1**, semnal puternic (chiar single-model, Codex indisponibil).
|
||||
- **Tema 2 — Stari tacute in picker/chips (Design GAP + Eng E4/E5):** add_extra silent + empty-state picker
|
||||
fara nomenclator apar atat in design (Pass 2) cat si in eng (E4/E5). Convergenta → de rezolvat la executie.
|
||||
- **Tema 3 — Acoperire de test sub obiectiv (Eng E1/E3):** „grep doar /static/fonts" + „by-index op
|
||||
netestat" — planul are 4 lock-uri bune dar lasa 2 gap-uri reale de test.
|
||||
|
||||
## Deferred to TODOS.md
|
||||
- Stergerea fizica `static/fonts/*.woff2` — follow-up (deja non-goal in plan; pastreaza usurinta revert).
|
||||
- Aliniere mockup intern landing „Confirma Vin" la VIN unic — debt vizual, non-goal 5.16.
|
||||
(Niciun TODO nou critic; ambele deja in plan.)
|
||||
|
||||
## Implementation Tasks (aggregated across phases)
|
||||
> Nota: T-C1 (CEO) si T-E4 (Eng) sunt acelasi finding (semnal add_extra) surprins din doua unghiuri —
|
||||
> trateaza-le ca o singura sarcina la executie.
|
||||
|
||||
- [ ] **T-UC1 (P1, human: ~1h / CC: ~10min) — tipografie** — DECIZIE USER: pastreaza IBM Plex self-hostat + repara doar scala (Approach A) SAU confirma trecerea la system-ui (Approach B)
|
||||
- Surfaced by: ceo-review — User Challenge #1 (system-ui contrazice obiectivul uniform + DESIGN.md identity)
|
||||
- Files: docs/prd/prd-5.16-..., DESIGN.md, app/web/templates/base.html
|
||||
- [ ] **T-D1 (P1, human: ~30min / CC: ~10min) — picker** — Empty-state picker cand nomenclatorul lipseste (rand needs_mapping nereparabil)
|
||||
- Surfaced by: design-review — Pass 2 GAP + Pass 7 · Files: app/web/templates/_chips_prestatii.html
|
||||
- [ ] **T-E1 (P1, human: ~30min / CC: ~10min) — tipografie** — Test grep care esueaza la orice literal 'IBM Plex Sans'/'IBM Plex Mono' fara fallback dupa stergerea @font-face
|
||||
- Surfaced by: eng-review — E1 · Files: tests/test_web_responsive.py, landing.html, base.html
|
||||
- [ ] **T-E2 (P2, human: ~10min / CC: ~5min) — tipografie** — US-001 sa enumere explicit stergerea @font-face din base.html (nu doar landing.html)
|
||||
- Surfaced by: eng-review — E2 (base.html:42-103) · Files: PRD, base.html
|
||||
- [ ] **T-E3 (P2, human: ~45min / CC: ~15min) — chips** — Test US-006 mod operatii: cod ales pe pickerul op#2 aterizeaza pe op#2 nu #1 (aliniere by-index)
|
||||
- Surfaced by: eng-review — E3 · Files: app/web/routes.py, tests/test_web_corectie_prestatii.py
|
||||
- [ ] **T-C1/T-E4 (P3, human: ~20min / CC: ~5min) — chips** — Semnal vizibil cand add_extra are select gol / cod invalid
|
||||
- Surfaced by: ceo + eng · Files: app/web/routes.py, _chips_prestatii.html
|
||||
- [ ] **T-D2 (P3, human: ~15min / CC: ~5min) — contoare** — Pastreaza afordanta de tap pe „De corectat" in bara compacta mobil
|
||||
- Surfaced by: design-review — Pass 6 · Files: _status.html, base.html
|
||||
- [ ] **T-E5 (P3, human: ~20min / CC: ~5min) — picker** — Empty-state picker fara nomenclator
|
||||
- Surfaced by: eng-review — E5 · Files: _chips_prestatii.html
|
||||
|
||||
## Decision Audit Trail
|
||||
|
||||
| # | Faza | Decizie | Clasificare | Principiu | Rationament | Respins |
|
||||
|---|------|---------|-------------|-----------|-------------|---------|
|
||||
| 1 | Setup | Ruleaza Codex toate fazele | Mecanica | P6 | Dual-voice standard | — |
|
||||
| 2 | Setup | Codex usage-limit → degradare [subagent-only] | Mecanica | P6 | Plafon hard pana 2026-07-18; nu blocheaza | astept reset |
|
||||
| 3 | CEO | Mod = SELECTIVE EXPANSION | Mecanica | P2 | Iteratie pe sistem 5.15 livrat | EXPANSION/HOLD |
|
||||
| 4 | CEO | Premisa P1 (4 bug-uri) ACCEPTATA | Mecanica | — | Toate 4 verificate in cod | — |
|
||||
| 5 | CEO | Premisa P2 (system fonts) → User Challenge | User Challenge | — | Contrazice „uniform"+DESIGN.md; NU auto-decis | — |
|
||||
| 6 | CEO | Alternative font A/B/C documentate, recomand A | Taste | P5+P1 | A livreaza durerea reala cu risc minim | B (plan) |
|
||||
| 7 | CEO | Nu adaug expansiuni noi in scop | Mecanica | P3 | Plan deja complet pt durerea declarata | — |
|
||||
| 8 | CEO | GAP-1 add_extra silent → P3 TODO/task | Mecanica | P1 | Edge minor, nu blocheaza | — |
|
||||
| 9 | Design | Fara generare mockup-uri noi | Mecanica | P3 | 5 mockup-uri HTML exista deja ca referinta | — |
|
||||
| 10 | Design | Pass 4 hard-conflict font = intareste UC#1 | Taste→UC | P5 | Regula slop #11 (system-ui font primar) | — |
|
||||
| 11 | Design | Empty-state picker = finding nou P1 | Mecanica | P1 | „No items found" tacut = rand nereparabil | — |
|
||||
| 12 | Eng | DX scope = NU → Faza 3.5 SKIP | Mecanica | — | UI operator; API/CLI/integratori neatins | — |
|
||||
| 13 | Eng | Scope = FULL_REVIEW (fara reducere) | Mecanica | P2 | >8 fisiere dar fara clase/infra noi | REDUCTION |
|
||||
| 14 | Eng | E1 (grep literale font) = P1 | Mecanica | P1 | Testul curent nu prinde literalele fara fallback | — |
|
||||
| 15 | Eng | E3 (by-index op) = P2 + test | Mecanica | P1 | Risc cod pe operatia gresita | — |
|
||||
| 16 | Eng | Recomand livrare Lane B (bug-fix) intai | Taste | P6 | Durerea reala, independent de base.html | un singur val |
|
||||
| 17 | Gate | **User Challenge #1 REZOLVAT = system-ui** (decizia userului) | User Challenge — rezolvat | — | Userul RESPINGE challenge-ul; directia originala (system fonts) prevaleaza. Risc AI-Slop #11 (system-ui ca font primar) = ACCEPTAT CONSTIENT. E1/E3 raman pre-ship. | Approach A (IBM Plex) |
|
||||
|
||||
## GSTACK REVIEW REPORT
|
||||
|
||||
| Review | Trigger | Why | Runs | Status | Findings |
|
||||
|--------|---------|-----|------|--------|----------|
|
||||
| CEO Review | `/plan-ceo-review` | Scope & strategy | 1 | issues_open | mode SELECTIVE_EXPANSION, 1 User Challenge, 0 critical gaps |
|
||||
| Codex Review | `/codex review` | Independent 2nd opinion | 0 | — (usage limit) | indisponibil pana 2026-07-18 |
|
||||
| Eng Review | `/plan-eng-review` | Architecture & tests (required) | 1 | issues_open | 5 issues, 0 critical gaps |
|
||||
| Design Review | `/plan-design-review` | UI/UX gaps | 1 | issues_open | score 7/10 → 7/10, 2 GAP-uri de stare |
|
||||
| DX Review | `/plan-devex-review` | Developer experience gaps | 0 | skipped | fara scop developer-facing |
|
||||
|
||||
- **CROSS-MODEL:** indisponibil — Codex la plafon de utilizare (reset 2026-07-18); toate vocile sunt
|
||||
single-voice (Claude). Semnalele nu se ridica la „cross-model consensus", dar Tema 1 (font) apare in 2 faze.
|
||||
- **DECIZIE USER (User Challenge #1):** REZOLVAT = **system-ui** (userul a respins challenge-ul; directia
|
||||
lui originala prevaleaza). Trecerea de la IBM Plex la system font stack ramane in scop. Riscul de design
|
||||
AI-Slop #11 (system-ui ca font primar, identitate tipografica mai slaba, randare per-OS) = **risc acceptat
|
||||
constient** de catre user, nu o omisiune. Approach A (pastreaza IBM Plex) respins.
|
||||
- **VERDICT:** Plan SOLID pe jumatatea bug-fix (toate 4 cauze verificate in cod, fezabile, reuse curat) si
|
||||
pe tipografie (directie confirmata de user). Inainte de ship raman ACTIONABILE (nu blocante de decizie,
|
||||
ci sarcini de implementare/test): **E1** (test grep literale `'IBM Plex Sans'`/`'IBM Plex Mono'` fara
|
||||
fallback dupa stergerea @font-face) — P1; **E3** (test US-006 mod operatii, aliniere by-index op corecta)
|
||||
— P2; **E2** (US-001 sa enumere stergerea @font-face si din `base.html`). Cele 4 teste-lock de bug
|
||||
(US-004..007) raman P1. ENG `issues_open` doar pe aceste sarcini de test, niciun critical gap, nicio
|
||||
decizie de produs deschisa.
|
||||
|
||||
NO UNRESOLVED DECISIONS
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- /autoplan restore point: /home/claude/.gstack/projects/romfast-rar-autopass/docs-prd-5.16-5.17-design-tiers-autoplan-restore-20260628-212453.md -->
|
||||
# PRD 5.17 — Tipuri de cont (planuri) + trial Pro 30 zile + enforcement
|
||||
|
||||
**Stare**: draft
|
||||
@@ -292,7 +293,7 @@ ingestie si nu vreau sa blochez gresit conturi legitime.
|
||||
- [ ] "Prestatie consumata" = acceptate-in-coada (queued+sending+sent) sau doar `sent`? (implicit: acceptate)
|
||||
- [ ] Lot care depaseste partial limita → respingere totala sau enqueue partial? (implicit: respingere totala clara)
|
||||
- [ ] `POST /v1/prezentari/valideaza` (dry-run) — gated pe Pro sau permis tuturor? (implicit: permis)
|
||||
- [ ] Migrare conturi legacy active: raman `free` (risc limitare brusca) sau primesc un trial/plan? (de confirmat cu user)
|
||||
- [x] ~~Migrare conturi legacy active: raman `free` sau primesc un trial/plan?~~ **REZOLVAT (user, 2026-06-28): NU exista conturi legacy (produs in TESTE, pre-productie) -> intrebare moot; enforcement DUR direct de la deploy.**
|
||||
- [ ] Standard (39 lei) si Premium difera de Pro doar prin API + suport in landing — pastram exact maparea
|
||||
de capabilitati din landing in `plans.py`? (implicit: da)
|
||||
|
||||
@@ -315,3 +316,645 @@ Val 5: [US-009] regresie + E2E matrice (dupa toate)
|
||||
|
||||
> Acest PRD nu a fost inca trecut prin `/plan-ceo-review` / `/plan-eng-review`. Recomandat inainte de
|
||||
> executie (enforcement de business cu risc de blocare gresita + decizia de migrare a conturilor legacy).
|
||||
|
||||
---
|
||||
|
||||
# REVIZIE /autoplan (2026-06-28)
|
||||
|
||||
> Pipeline complet rulat: CEO -> Design -> Eng -> DX. Mod: **SELECTIVE EXPANSION**.
|
||||
> Sesiune spawned (non-interactiva): fiecare AskUserQuestion intermediar a fost auto-decis cu cele
|
||||
> 6 principii; deciziile "taste" si "user challenges" sunt colectate la poarta finala (Faza 4).
|
||||
> **Codex INDISPONIBIL** (limita de utilizare atinsa pana la 2026-07-18) -> toate vocile duale
|
||||
> ruleaza `[codex-unavailable] / [subagent-only]` cu vocea analitica independenta Claude ca model unic.
|
||||
> Restore point: vezi comentariul HTML din capul fisierului.
|
||||
|
||||
## Faza 0 — Intake
|
||||
|
||||
- **Scop UI detectat: DA** (dashboard, badge antet, meniu burger, `_status.html`/`_cont.html`,
|
||||
avertizare vizuala, mockup-uri 5.16) -> Faza 2 (Design) ruleaza.
|
||||
- **Scop DX detectat: DA** (endpointuri `/v1/*`, 403/erori 3-niveluri, CLI `tools.account set-tier`,
|
||||
cheie API, mesaje pentru integratori) -> Faza 3.5 (DX) ruleaza.
|
||||
- Cod citit: `app/accounts.py`, `app/schema.sql` (accounts/submissions/app_events), `app/errors.py`,
|
||||
`app/auth.py` (`resolve_account_id`), `app/api/v1/router.py` (`create_prezentari`/`valideaza`),
|
||||
`app/api/v1/import_router.py` (`commit_import`), `tools/account.py`, `app/web/templates/landing.html`.
|
||||
|
||||
## Faza 1 — CEO Review (Strategie & Scop) [subagent-only]
|
||||
|
||||
### 0B. Ce exista deja (leverage map)
|
||||
| Sub-problema 5.17 | Cod existent reutilizabil | Reuse? |
|
||||
|---|---|---|
|
||||
| Sursa unica de adevar (definitii) | `app/errors.py` (pattern CATALOG + `eroare()`) | DA — `plans.py` copiaza pattern-ul |
|
||||
| Eroare 3 niveluri | `app/errors.py::eroare()` (problema/cauza/fix) | DA — adauga `PLAN_LIMITA_LUNARA`, `PLAN_FARA_API` in CATALOG |
|
||||
| Migrare aditiva defensiva | `_migrate` in `db.py` (ALTER ca `email`/`status` 5.5/5.12) | DA |
|
||||
| Scope pe cont la ingestie | `auth.py::resolve_account_id` (Depends) | DA — gate API se ataseaza aici/ruta |
|
||||
| Lifecycle cont + protectie id=1 | `accounts.py` (`set_status`, `_PROTECTED_ACCOUNT_ID`) | DA — `set_tier` urmeaza acelasi tipar |
|
||||
| Audit fara PII | `observ.py::log_event` -> `app_events` (5.6) | DA — log schimbare plan |
|
||||
| CLI admin | `tools/account.py` (argparse) | DA — subcomanda `set-tier` |
|
||||
| Consum lunar | `submissions.created_at` + `idx_submissions_account_status` | DA — fara coloana noua |
|
||||
|
||||
### 0C. Dream state
|
||||
```
|
||||
CURENT 5.17 IDEAL 12 LUNI
|
||||
landing promite 4 planuri, -> model de cont real (tier+trial), -> facturare self-service
|
||||
app nu stie de tipuri; enforcement volum+API, (Stripe), upgrade din UI,
|
||||
trial inexistent; downgrade lazy la expirare, dunning, conversie masurata,
|
||||
limita 100 doar pe hartie admin manual aloca plan platit re-trial/nurture automat
|
||||
```
|
||||
Delta: 5.17 aliniaza app-ul cu promisiunea landing-ului, DAR ramane fara calea de conversie
|
||||
(plata self-service) — enforcement-ul musca inainte sa existe un buton de upgrade.
|
||||
|
||||
### 0C-bis. Alternative de implementare
|
||||
```
|
||||
APROACH A: Enforcement DUR (planul actual)
|
||||
Rezumat: respinge la enqueue free>60 + 403 API non-Pro; downgrade lazy.
|
||||
Efort: M (human ~2-3z / CC ~45min) Risc: Mediu-Inalt (blocare gresita fara cale de upgrade)
|
||||
Pro: aliniere completa cu landing; diferentiator hard real.
|
||||
Contra: friction fara conversie self-service; risc fals-block legacy.
|
||||
Reuse: errors.py, auth.py, app_events.
|
||||
|
||||
APROACH B: Soft-first (warn + overgrace + flag admin) [recomandat de revizie]
|
||||
Rezumat: la depasire limita -> avertizare clara + enqueue permis cu marcaj, alerta admin;
|
||||
API gate ramane DUR (capability, nu volum). Hard-block volum activabil ulterior prin flag.
|
||||
Efort: M (human ~2-3z / CC ~45min) Risc: Scazut.
|
||||
Pro: zero fals-block; conversie prin contact, nu prin churn; deploy mai sigur.
|
||||
Contra: nu "forteaza" upgrade; cota e mai degraba un semnal decat un zid.
|
||||
Reuse: identic cu A.
|
||||
|
||||
APROACH C: Model + copy now, enforcement sub feature flag (deferat)
|
||||
Rezumat: adauga tier/trial + plans.py + fix landing; enforcement scris dar OFF (flag),
|
||||
pornit dupa migrare legacy confirmata.
|
||||
Efort: S-M Risc: Foarte scazut.
|
||||
Pro: deploy incremental, decuplaza copy-fix (banal) de enforcement (riscant).
|
||||
Contra: promisiunea landing nu e inca "reala" la deploy.
|
||||
```
|
||||
**RECOMANDARE revizie:** combina **C (feature flag de enforcement) + B (soft-first pe VOLUM)**,
|
||||
pastrand **A pe gate-ul API** (capability, risc mic). Principii P1 (completeness pe model) + P6
|
||||
(bias to action: deploy incremental). Vezi TASTE DECISION T-CEO-1 si T-CEO-2 la poarta.
|
||||
|
||||
### 0E. Interogare temporala
|
||||
- HOUR 1 (foundations): valorile exacte ale planurilor (sursa unica `plans.py`); valoarea `60` ca
|
||||
CONSTANTA unica; politica legacy (free fara trial vs trial calculat din `created_at`).
|
||||
- HOUR 2-3 (core): definitia "prestatie consumata" (acceptate-in-coada vs sent); bucketare luna
|
||||
timp local RO (lectia E7/5.15); interactiunea enforce-inainte-de-`build_key` (idempotenta).
|
||||
- HOUR 4-5 (integrare): unde se ataseaza gate-ul API (dependinta de ruta vs in `resolve_account_id`);
|
||||
lot care depaseste partial limita (respingere totala vs partial); `valideaza` dry-run gated sau nu.
|
||||
- HOUR 6+ (polish/teste): matrice plan x capabilitate x canal x trial; granita de luna; dev id=1 exceptat.
|
||||
|
||||
### 0F. Mod: SELECTIVE EXPANSION (default pentru iteratie pe sistem existent). Approach: B+C pe volum, A pe API.
|
||||
|
||||
### Voci duale (CEO)
|
||||
**CODEX SAYS (CEO — strategy challenge):** `[codex-unavailable]` — limita de utilizare (pana 2026-07-18).
|
||||
Voce omisa; consensul se calculeaza N/A pe coloana Codex.
|
||||
|
||||
**CLAUDE SUBAGENT (CEO — strategic independence)** (voce analitica independenta, inainte de orice Codex):
|
||||
1. **Problema corecta?** Gap real: landing-ul promite planuri pe care app-ul nu le sustine. DAR
|
||||
enforcement-ul DUR pe volum apare INAINTEA oricarei cai de plata. Reframe: "onestitate landing +
|
||||
diferentiere capability" se poate atinge fara a ZIDI free-ul la 60. (HIGH)
|
||||
2. **Premise asumate:** (a) "promisiunile trebuie impuse DUR acum" — asumata; un fix de copy + gate API
|
||||
ar inchide 80% din gap cu 20% din risc. (b) "60 in loc de 100" — decizie user, dar fara rationament;
|
||||
scade atractivitatea free-ului exact cand nu exista upgrade self-service. (MEDIUM)
|
||||
3. **Regret la 6 luni:** un cont free real face 80/luna, e migrat la free si blocat brusc la 60 ->
|
||||
churn in loc de conversie (nu exista buton de upgrade, doar "contacteaza-ne"). (HIGH, deploy-blocker
|
||||
pe migrarea legacy.)
|
||||
4. **Alternative neexplorate:** soft-enforcement (warn+overgrace) vs hard-block; planul sare direct la hard.
|
||||
5. **Risc competitiv:** nisa B2B reglementata (RAR), switching cost real -> risc competitiv scazut;
|
||||
riscul dominant e INTERN (friction fara conversie).
|
||||
|
||||
```
|
||||
CEO DUAL VOICES — CONSENSUS TABLE:
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Dimensiune Claude Codex Consensus
|
||||
───────────────────────────────────── ─────── ─────── ─────────
|
||||
1. Premise valide? Partial N/A N/A (Codex indisp.)
|
||||
2. Problema corecta? Da* N/A N/A
|
||||
3. Calibrare scop corecta? Nu** N/A N/A
|
||||
4. Alternative explorate suficient? Nu N/A N/A
|
||||
5. Riscuri piata acoperite? Da N/A N/A
|
||||
6. Traiectorie 6 luni sanatoasa? Partial N/A N/A
|
||||
═══════════════════════════════════════════════════════════════
|
||||
* problema reala, dar solutia (hard enforce) e mai agresiva decat o cere problema.
|
||||
** scop corect ca model; enforcement-ul DUR pe volum e calibrat prea agresiv pentru un produs fara plata.
|
||||
Single-model: niciun consens incrucisat; constatarile critice ale vocii Claude sunt semnalate oricum.
|
||||
```
|
||||
|
||||
### Sectiunile 1-11 (CEO)
|
||||
|
||||
**S1 Arhitectura.** Componenta noua `plans.py` = modul PUR (ca `errors.py`), fara import DB/HTTP, dict
|
||||
`PLANS` + `effective_tier(account_row, now)` + `monthly_usage(conn, account_id, now)`. Cuplare noua:
|
||||
rutele de ingestie (`router.py`, `import_router.py`, `routes.py` commit) depind de `plans.py` + citesc
|
||||
`accounts.tier/trial_until` -> cuplare justificata (un singur punct de adevar). Diagrama: vezi Faza 3 (Eng).
|
||||
Constatare CEO-S1-1 (MEDIUM): `effective_tier` are nevoie de `now` injectabil (nu `datetime.now()` intern)
|
||||
ca testele de granita trial/luna sa fie deterministe. Auto-decis (P5 explicit): semnatura cu `now` parametru.
|
||||
|
||||
**S2 Error & Rescue (registry mai jos).** Coduri noi: `PLAN_LIMITA_LUNARA`, `PLAN_FARA_API`. Ambele
|
||||
sunt erori de business (nu exceptii) -> 3 niveluri din `errors.py`, returnate ca raspuns structurat
|
||||
(nu 500). Fara catch-all. Constatare CEO-S2-1 (LOW): trial expirat NU e o eroare — e o stare; nu necesita
|
||||
cod de eroare, doar `effective_tier` care vede `free`.
|
||||
|
||||
**S3 Securitate (detaliu in Eng S3).** Suprafata: gate API (autorizare pe capability) + enforce volum.
|
||||
DOR (direct object reference) la `set-tier` admin: trebuie scoped + protejat id=1 (ca `set_status`).
|
||||
Risc privilege: un cont free NU trebuie sa-si poata seta singur tier (doar admin CLI / panou admin CSRF).
|
||||
Constatare CEO-S3-1 (HIGH): enforce pe volum/API trebuie sa ruleze DUPA `resolve_account_id` (cont
|
||||
autenticat), niciodata pe baza unui camp din body. Auto-decis (P1): gate ca dependinta server-side.
|
||||
|
||||
**S4 Data flow & edge cases.** Granita de luna (timp local RO), idempotenta vs cota (retry nu consuma
|
||||
de 2x), lot care depaseste partial. Vezi Failure Modes Registry. Edge: 2 cereri concurente la 59/60 ->
|
||||
race pe cota (ambele trec checkul, ajung la 61). Constatare CEO-S4-1 (MEDIUM): cota nu e tranzactionala
|
||||
cu enqueue -> mic overshoot posibil sub concurenta. Auto-decis (P3 pragmatic): accepta overshoot mic
|
||||
(±lot) documentat; un lock per-cont ar fi over-engineering pentru un cap soft. (Daca se alege hard-block,
|
||||
re-evalueaza.)
|
||||
|
||||
**S5 Code quality.** `plans.py` sursa unica evita DRY-violation intre backend si UI. Risc: valoarea `60`
|
||||
sa fie hardcodata in 3 locuri (router, import, web). Auto-decis (P4 DRY): O singura definitie in `PLANS`,
|
||||
consumata peste tot; templating UI primeste `monthly_limit` din context, nu literal.
|
||||
|
||||
**S6 Teste (diagrama in Eng S3).** Matrice plan x capabilitate x canal x trial. Gap-uri critice: granita
|
||||
luna timp local RO; retry idempotent; dev id=1 ne-blocat. Toate cerute in US-009.
|
||||
|
||||
**S7 Performanta.** `monthly_usage` = un COUNT cu `WHERE account_id=? AND status IN (...) AND created_at>=...`.
|
||||
Exista `idx_submissions_account_status(account_id,status)` dar NU acopera `created_at`. Constatare CEO-S7-1
|
||||
(MEDIUM): la volume mari un COUNT pe luna per-cerere e O(randuri luna); acceptabil la scara curenta, dar
|
||||
indexul nu acopera intervalul de timp. Auto-decis (P3): acceptabil acum (SQLite, volume mici); TODO index
|
||||
`(account_id, created_at)` daca apar conturi cu mii/luna. -> TODOS.
|
||||
|
||||
**S8 Observabilitate.** Fiecare respingere pe plan (volum/API) trebuie sa emita `app_events`
|
||||
(cod + cont + count), nu doar sa intoarca 4xx. Altfel "de ce a fost blocat clientul X?" e invizibil.
|
||||
Auto-decis (P_prime zero-silent-failures): log_event pe fiecare respingere de plan. (Adaugat ca AC.)
|
||||
|
||||
**S9 Deploy.** Migrare aditiva defensiva (idempotenta). **REZOLVAT (decizie user 2026-06-28):**
|
||||
enforcement DUR direct de la deploy — fara conturi legacy, produs in TESTE (pre-productie), deci riscul
|
||||
de fals-block e moot. Feature-flag `AUTOPASS_ENFORCE_PLANS` ramane **OPTIONAL** (nice-to-have de operare,
|
||||
kill-switch), NU blocant pentru deploy. Vezi T-CEO-1 (rezolvat).
|
||||
|
||||
**S10 Traiectorie.** Reversibilitate 4/5 (model aditiv; enforcement sub flag = usor de oprit). Path
|
||||
dependency: fara billing, `set-tier` manual devine gatuire daca adoptia creste -> Phase 2 = plata
|
||||
self-service. Datorie: cuplarea enforcement de ingestie e curata; datoria reala e "lipsa caii de upgrade".
|
||||
|
||||
**S11 Design & UX (deep in Faza 2).** Plasare badge plan in antet + meniu burger (aliniat 5.16),
|
||||
avertizare la >=80%, mesaje oneste cu cale de iesire. Recomand /plan-design-review (rulat ca Faza 2).
|
||||
|
||||
### Iesiri obligatorii CEO
|
||||
|
||||
**NOT in scope (deferat, cu rationament):**
|
||||
- Integrare plata/facturare (Stripe) — non-goal explicit; Phase 2.
|
||||
- Upgrade self-service din UI — depinde de billing; doar afisaj + "contacteaza-ne".
|
||||
- Index `(account_id, created_at)` — deferat pana apar conturi de volum mare (TODO P3).
|
||||
- Job eager de normalizare `trial_until` expirat -> NULL — optional, igiena; lazy acopera corectitudinea.
|
||||
- Diferentiere capability de produs (sugestii/mapare) pe planuri — non-goal; diferentierea e volum+API.
|
||||
|
||||
**What already exists:** vezi tabelul 0B (errors.py, auth.py, accounts.py, observ/app_events, db._migrate,
|
||||
submissions.created_at + index, tools/account.py — toate reutilizate; 5.17 nu reconstruieste nimic).
|
||||
|
||||
**Dream state delta:** 5.17 face promisiunea landing-ului REALA in app, dar lasa golul "conversie
|
||||
self-service"; urmatorul pas logic e billing (Phase 2). Enforcement-ul fara upgrade self-service e
|
||||
delta-ul de risc.
|
||||
|
||||
### Error & Rescue Registry (S2)
|
||||
```
|
||||
CODEPATH | CE POATE ESUA | COD / EXCEPTIE
|
||||
---------------------------------|--------------------------------|------------------------
|
||||
create_prezentari (enqueue) | free peste 60/luna | PLAN_LIMITA_LUNARA (business)
|
||||
commit_import (web+API) | free peste 60/luna | PLAN_LIMITA_LUNARA (business)
|
||||
import API / POST /v1/prezentari | cont fara api_access (non-Pro) | PLAN_FARA_API (403, business)
|
||||
effective_tier(account, now) | trial_until malformat/NULL | trateaza ca free (fallback)
|
||||
monthly_usage(conn, acct, now) | created_at NULL/malformat | exclus din count (defensiv)
|
||||
set-tier (CLI/admin) | tier invalid | ValueError -> mesaj clar
|
||||
set-tier pe id=1 | mutare cont sistem | protejat (ca set_status)
|
||||
|
||||
COD / STARE | RESCUED? | ACTIUNE | USER VEDE
|
||||
------------------------|----------|----------------------------------|---------------------------
|
||||
PLAN_LIMITA_LUNARA | Y | respinge inainte de build_key | "Ai atins limita Gratuit (60/luna)" + fix
|
||||
PLAN_FARA_API | Y | 403 inainte de procesare | "Importul API e pe Pro" + fix
|
||||
trial_until malformat | Y | fallback free, log WARNING | comportament free (fara crash)
|
||||
created_at malformat | Y | exclus din count, log WARNING | nimic (transparent)
|
||||
tier invalid (set-tier) | Y | ValueError, exit!=0 | "tier invalid: X"
|
||||
```
|
||||
|
||||
### Failure Modes Registry
|
||||
```
|
||||
CODEPATH | FAILURE MODE | RESCUED? | TEST? | USER VEDE | LOGGED?
|
||||
--------------------------|--------------------------|----------|-------|------------------|--------
|
||||
enforce volum (enqueue) | free peste 60 | Y | Y | eroare 3 niveluri| Y (app_events)
|
||||
enforce volum | race concurent la 59/60 | Partial | Y(*) | overshoot mic | Y
|
||||
gate API | non-Pro pe /v1 import | Y | Y | 403 onest | Y
|
||||
downgrade lazy | trial expirat | Y | Y | aplica free | N (stare, nu eveniment)
|
||||
migrare legacy | cont activ -> free brusc | N/A(MOOT)| n/a | n/a | n/a
|
||||
bucketare luna | granita timp local RO | Y | Y | reset corect | n/a
|
||||
idempotenta vs cota | retry consuma cota 2x | Y | Y | nimic | n/a
|
||||
```
|
||||
**~~CRITICAL GAP~~ REZOLVAT (MOOT, 2026-06-28):** decizia userului — NU exista conturi legacy, produsul
|
||||
e in TESTE (pre-productie). Migrarea unui cont activ -> free brusc nu se poate produce (nu exista conturi
|
||||
reale de migrat). Gap inchis ca N/A. Enforcement DUR de la deploy, fara mitigare necesara.
|
||||
|
||||
### Completion Summary (CEO)
|
||||
```
|
||||
+====================================================================+
|
||||
| MEGA PLAN REVIEW — COMPLETION SUMMARY (CEO) |
|
||||
+====================================================================+
|
||||
| Mode | SELECTIVE EXPANSION |
|
||||
| Approach ales | B+C pe volum, A pe gate API |
|
||||
| S1 Arhitectura | 1 (now injectabil) |
|
||||
| S2 Errors | 2 coduri noi, 0 GAP-uri rescue |
|
||||
| S3 Securitate | 1 HIGH (gate server-side), DOR set-tier |
|
||||
| S4 Data/UX | 1 race cota (overshoot mic acceptat) |
|
||||
| S5 Quality | 1 (DRY pe valoarea 60) |
|
||||
| S6 Teste | matrice ceruta, 3 gap-uri acoperite US-009 |
|
||||
| S7 Perf | 1 (index timp) -> TODO |
|
||||
| S8 Observ | 1 (log pe respingere plan) -> AC nou |
|
||||
| S9 Deploy | enforcement DUR direct (user); flag optional |
|
||||
| S10 Future | Reversibilitate 4/5; datorie = lipsa billing|
|
||||
| S11 Design | -> Faza 2 |
|
||||
| NOT in scope | scris (5 items) |
|
||||
| Failure modes | 7 total, 0 CRITICAL GAP (legacy REZOLVAT moot)|
|
||||
| Outside voice | codex indisponibil (subagent-only) |
|
||||
| Unresolved decisions | 0 (toate inchise 2026-06-28: challenge + 3 taste)|
|
||||
+====================================================================+
|
||||
```
|
||||
|
||||
**Phase 1 complete.** Codex: indisponibil. Claude subagent: 9 constatari (2 HIGH, 5 MEDIUM, 2 LOW) +
|
||||
1 USER CHALLENGE + 2 TASTE. Consens: N/A (single-model). Trec la Faza 2.
|
||||
|
||||
## Faza 2 — Design Review [subagent-only]
|
||||
|
||||
> Scop UI confirmat. 5.17 aduce DATELE (tier/trial/consum); 5.16 aduce LOCUL (antet + meniu burger).
|
||||
> Aceasta revizie e la nivel de plan (intentionalitate de design), nu audit de pixeli.
|
||||
> Completitudine design initiala: **6/10** (plasare numita, dar stari incomplete + copy nespecificat).
|
||||
|
||||
**CODEX SAYS (design — UX challenge):** `[codex-unavailable]`.
|
||||
|
||||
**CLAUDE SUBAGENT (design — independent review):**
|
||||
1. **Ierarhie informatie:** badge plan in antet e corect (status, nu actiune); consumul `N/60` apartine
|
||||
contextului secundar (meniu/Cont), NU trebuie sa concureze cu stripul de sanatate. OK.
|
||||
2. **Stari lipsa:** planul numeste "trial activ / free consum / platit fara contor" dar NU specifica:
|
||||
(a) ULTIMA zi de trial ("expira azi" vs "1 zi"), (b) starea "limita ATINSA" (60/60, nu doar >=80%),
|
||||
(c) ce vede operatorul in MOMENTUL respingerii (toast? banner persistent?). GAP (HIGH).
|
||||
3. **Arc emotional:** trial -> "ai Pro 18 zile" (pozitiv) -> ziua 30 trecere tacuta pe free -> prima
|
||||
respingere la 61 = surpriza negativa daca nu a existat avertizare progresiva. Avertizarea >=80% e
|
||||
buna; lipseste un semnal la trecerea trial->free (ziua 0). GAP (MEDIUM).
|
||||
4. **Specificitate vs generic:** "afiseaza discret planul" e generic; mockup-urile 5.16 dau forma, dar
|
||||
copy-ul exact al badge-ului ("Pro · trial 18 zile" / "Gratuit · 47/60") trebuie fixat ca string-uri,
|
||||
nu lasat implementatorului. GAP (MEDIUM).
|
||||
5. **Decizii care vor bantui implementatorul:** prag exact warn (>=80% = 48/60?), pluralizare RO
|
||||
("1 zi" vs "18 zile", "1 zile" e gresit), ce se intampla la 0 zile ramase in trial in aceeasi zi.
|
||||
|
||||
```
|
||||
DESIGN LITMUS SCORECARD (0-10):
|
||||
Dimensiune Claude Codex Consensus
|
||||
────────────────────────────────── ─────── ─────── ─────────
|
||||
1. Ierarhie informatie 8 N/A N/A
|
||||
2. Acoperire stari (load/empty/err) 5 N/A N/A <- gap
|
||||
3. Coerenta user journey 6 N/A N/A
|
||||
4. Specificitate (nu generic) 5 N/A N/A <- gap
|
||||
5. Aliniere design system (5.15/16) 8 N/A N/A
|
||||
6. Intentie responsive 7 N/A N/A
|
||||
7. Accesibilitate (contrast/kbd) 6 N/A N/A
|
||||
────────────────────────────────── ─────── ─────── ─────────
|
||||
Overall design (plan-level) ~6.4/10
|
||||
```
|
||||
|
||||
### Pass-uri 1-7 (constatari + auto-decizii)
|
||||
- **P1 Ierarhie:** badge in antet (status), consum in meniu/Cont. OK, fara modificare.
|
||||
- **P2 Stari (CRITIC):** adauga stari explicite: `trial-activ(N zile)`, `trial-ultima-zi`,
|
||||
`free-sub-prag`, `free-warn(>=80%)`, `free-limita-atinsa(60/60)`, `platit(fara contor)`. Auto-decis
|
||||
(P1 completeness): toate 6 stari intra ca AC in US-006. Matrice stare->afisaj in plan.
|
||||
- **P3 Journey:** adauga un semnal one-time la trecerea trial->free (banner discret "Trial Pro
|
||||
expirat — esti pe Gratuit, 60/luna"). Auto-decis (P1): adaugat ca AC optional in US-006 (non-blocant
|
||||
daca lazy; afisat la prima incarcare dupa expirare). TASTE T-DES-1 (banner one-time vs doar badge).
|
||||
- **P4 Specificitate:** fixeaza string-urile de copy exact (RO, cu pluralizare corecta) in US-006.
|
||||
Auto-decis (P5 explicit): tabel de copy in plan (vezi mai jos).
|
||||
- **P5 Design system:** tokeni `--fs-*`, fonturi system, fara hex hardcodat (5.16). OK; reuse `_status.html`.
|
||||
- **P6 Responsive:** badge in antet + linie in burger acopera desktop+mobil (mockup-uri 5.16). OK.
|
||||
- **P7 Accesibilitate:** tonul "warn" NU doar prin culoare (adauga text/icon); contrast pe badge;
|
||||
badge-ul nu e buton (status) -> fara rol interactiv inselator. Auto-decis (P1): warn = culoare + text.
|
||||
|
||||
**Copy fix (RO, propus, auto-decis P5):**
|
||||
```
|
||||
trial activ: "Plan: Pro · trial {n} {zi|zile} ramase" (1->"zi", 2+->"zile")
|
||||
trial ultima zi: "Plan: Pro · trial expira azi"
|
||||
free sub prag: "Plan: Gratuit · {u}/60 luna asta"
|
||||
free warn (>=80%): "Plan: Gratuit · {u}/60 — aproape de limita"
|
||||
free limita atinsa: "Plan: Gratuit · 60/60 — limita atinsa"
|
||||
platit: "Plan: {Standard|Pro|Premium}"
|
||||
```
|
||||
|
||||
**Required: user flow ASCII (stari + tranzitii)**
|
||||
```
|
||||
[cont nou] --create--> (TRIAL Pro: badge "trial N zile") --N scade zilnic-->
|
||||
(trial ultima zi) --trial_until<=now (lazy)--> (FREE sub prag: "u/60")
|
||||
--u>=48--> (FREE warn ">=80%") --u==60--> (FREE limita atinsa "60/60")
|
||||
|
|
||||
a 61-a cerere -> RESPINS (eroare 3 niveluri / toast)
|
||||
(admin set-tier pro) --------------------------------> (PLATIT: fara contor)
|
||||
```
|
||||
|
||||
**Phase 2 complete.** Codex: indisponibil. Claude subagent: 4 constatari design (1 HIGH stari, 2 MEDIUM,
|
||||
1 accesibilitate) + 1 TASTE (T-DES-1). Overall ~6.4/10 -> tinta dupa AC-uri ~8.5/10. Trec la Faza 3.
|
||||
|
||||
## Faza 3 — Eng Review (Arhitectura & Teste) [subagent-only]
|
||||
|
||||
### Step 0 — Scope challenge (cod citit)
|
||||
- `app/errors.py`: CATALOG + `eroare(cod, field, cauza)` -> pattern de copiat exact pentru coduri noi.
|
||||
- `app/auth.py`: `resolve_account_id` (Depends) intoarce `account_id`; gate-ul API se ataseaza ca a doua
|
||||
dependinta (`require_api_access`) care reuseaza `account_id` -> nu reimplementa auth.
|
||||
- `app/api/v1/router.py`: `create_prezentari` itereaza prestatiile, face `canonicalize_row` -> `build_key`
|
||||
-> enqueue. Gate-ul de VOLUM trebuie INAINTE de bucla de `build_key`/enqueue (idempotenta intacta).
|
||||
- `app/api/v1/import_router.py`: `commit_import` face enqueue per-rand cu ON CONFLICT DO NOTHING; gate
|
||||
volum la inceputul commit-ului (nr randuri `ok` vs cota ramasa).
|
||||
- `app/accounts.py`: `set_status` + `_PROTECTED_ACCOUNT_ID=1` -> `set_tier` urmeaza acelasi tipar (validare
|
||||
tier, protectie id=1, update). `create_account` adauga `tier='free'` + `trial_until=now+30z`.
|
||||
- `tools/account.py`: argparse; adauga subparser `set-tier`.
|
||||
- Complexitate: ramane sub 8 fisiere de logica + `plans.py` nou. Sub pragul de smell. OK.
|
||||
|
||||
**CLAUDE SUBAGENT (eng — independent review):**
|
||||
1. **Arhitectura:** `plans.py` PUR + consum din rute = curat. Singura cuplare noua justificata.
|
||||
2. **Edge:** race pe cota sub concurenta (overshoot ±lot); `now` trebuie injectabil pentru teste de granita.
|
||||
3. **Teste:** matricea e ceruta, dar lipsesc explicit: testul de retry idempotent care NU re-consuma cota,
|
||||
si testul ca `valideaza` dry-run NU consuma cota. (HIGH — sunt invariante usor de stricat.)
|
||||
4. **Securitate:** gate API server-side (nu din body); `set-tier` scoped + protejat id=1.
|
||||
5. **Complexitate ascunsa:** definitia "prestatie consumata" + bucketarea lunii timp local RO sunt sursa
|
||||
reala de bug-uri (off-by-a-day, status care iese din count cand un rand devine `error`).
|
||||
|
||||
```
|
||||
ENG DUAL VOICES — CONSENSUS TABLE:
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Dimensiune Claude Codex Consensus
|
||||
───────────────────────────────────── ─────── ─────── ─────────
|
||||
1. Arhitectura sanatoasa? Da N/A N/A
|
||||
2. Acoperire teste suficienta? Partial N/A N/A
|
||||
3. Riscuri performanta tratate? Partial N/A N/A
|
||||
4. Amenintari securitate acoperite? Da N/A N/A
|
||||
5. Cai de eroare tratate? Da N/A N/A
|
||||
6. Risc deploy gestionabil? Partial N/A N/A (flag + legacy)
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Single-model (codex indisponibil).
|
||||
```
|
||||
|
||||
### Section 1 — Architecture (ASCII)
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ app/plans.py (NOU) │ modul PUR (ca errors.py)
|
||||
│ PLANS{tier->limite} │ effective_tier(acct,now)
|
||||
│ api_access, limita │ monthly_usage(conn,acct,now)
|
||||
└──────────┬──────────┘
|
||||
┌───────────────┬───────┼───────────────┬──────────────────┐
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
api/v1/router.py import_router web/routes.py auth.py web/templates
|
||||
create_prezentari commit_import commit web require_api_access _status/_cont.html
|
||||
│ gate VOLUM │ gate VOLUM │ gate VOLUM │ gate API (403) badge plan
|
||||
▼ ▼ ▼ ▼
|
||||
errors.eroare(PLAN_LIMITA_LUNARA / PLAN_FARA_API) observ.log_event(app_events)
|
||||
│
|
||||
▼ (daca trece)
|
||||
canonicalize_row -> build_key -> enqueue submissions <-- NESCHIMBAT (worker/idempotenta/reconcile)
|
||||
|
||||
accounts.py: create_account(tier='free', trial_until=now+30z) ; set_tier(acct,tier,trial)
|
||||
db._migrate: ALTER accounts ADD tier / trial_until (aditiv defensiv, idempotent)
|
||||
tools/account.py: subcomanda set-tier
|
||||
config.py: AUTOPASS_ENFORCE_PLANS (flag, vezi T-CEO-1)
|
||||
```
|
||||
Cuplare before/after: inainte rutele depind doar de auth+idempotency+validation; dupa adauga o dependinta
|
||||
catre `plans.py` (pur, fara cicluri). Single point of failure: niciunul nou (modul pur, fara IO).
|
||||
Rollback: revert + flag OFF; migrarea e aditiva (coloanele raman, inofensive).
|
||||
|
||||
### Section 2 — Code quality
|
||||
- DRY: valoarea 60 + maparea capability EXCLUSIV in `PLANS`. Constatare ENG-S2-1: nu duplica `status IN
|
||||
(...)` (definitia consumului) intre `monthly_usage` si teste — exporta o constanta `CONSUMED_STATUSES`.
|
||||
- Naming: `effective_tier`, `monthly_usage`, `api_access`, `monthly_limit` — clare.
|
||||
- Over/under-engineering: NU adauga tabela `plan_usage` (coloana noua) — `submissions.created_at` ajunge
|
||||
(respecta non-goal migrare minima). Lock per-cont pe cota = over-engineering pentru cap soft.
|
||||
|
||||
### Section 3 — Test Review (diagrama completa — NU se sare)
|
||||
```
|
||||
NEW DATA FLOWS:
|
||||
- cerere ingestie -> citeste effective_tier -> compara monthly_usage+nr vs limita -> permite/respinge
|
||||
- cont nou -> create_account seteaza trial_until
|
||||
- trial_until <= now -> effective_tier randeaza free (lazy)
|
||||
NEW CODEPATHS / BRANCHES:
|
||||
- tier in {free,standard,pro,premium}; api_access T/F; monthly_limit None/60
|
||||
- effective_tier: trial activ vs expirat vs plan platit (nu downgrada)
|
||||
- enforce volum: sub limita / la limita / peste / lot care depaseste partial
|
||||
- gate API: free/standard -> 403 ; pro/premium/trial -> ok ; nomenclator public ; valideaza permis
|
||||
- dev id=1: ne-blocat (AUTOPASS_REQUIRE_API_KEY=false)
|
||||
NEW INTEGRATIONS/EXTERNAL: niciuna (totul intern; worker/RAR neatins)
|
||||
NEW ERROR/RESCUE: PLAN_LIMITA_LUNARA, PLAN_FARA_API (+ log_event)
|
||||
|
||||
ITEM | TIP TEST | EXISTA? | HAPPY / FAIL / EDGE
|
||||
--------------------------------------|--------------|---------|---------------------------------
|
||||
migrare tier+trial defensiva | unit (db) | NOU | re-rulare idempotenta; legacy->free
|
||||
PLANS definitii + capability map | unit | NOU | free=60/noAPI; pro=None/API
|
||||
effective_tier trial activ/expirat | unit (now inj)| NOU | viitor->pro; trecut->free; platit persista
|
||||
monthly_usage count | unit | NOU | numara queued+sending+sent; reset luna noua
|
||||
monthly_usage granita timp local RO | unit | NOU | rand la 23:30 UTC ultima zi -> luna RO corecta
|
||||
enforce volum free>60 API | integration | NOU | a 61-a respinsa 3 niveluri
|
||||
enforce volum free>60 import web | integration | NOU | commit respins peste cota
|
||||
enforce volum lot partial | integration | NOU | 50 folosite + lot 20 -> respingere totala (default)
|
||||
retry idempotent NU re-consuma cota | integration | NOU | <-INVARIANT critic
|
||||
valideaza dry-run NU consuma cota | integration | NOU | <-INVARIANT critic
|
||||
gate API free/standard 403 | integration | NOU | 403 onest
|
||||
gate API pro/trial 200 | integration | NOU | trece
|
||||
nomenclator public ramane | integration | reuse | fara cheie -> 200
|
||||
dev id=1 ne-blocat | integration | NOU | dogfooding nu pica
|
||||
set-tier CLI + invalid + id=1 protejat| unit | NOU | tier ok; invalid err; id=1 respins
|
||||
regresie aur (POST -> queued) | integration | reuse | ramane verde
|
||||
```
|
||||
Test 2am-Friday: "un cont Pro NU e blocat niciodata pe volum, indiferent de consum". Test ostil:
|
||||
"trimit 100 cereri concurente la 59/60 pe free" -> verifica overshoot marginit + log. Flakiness: testele
|
||||
de granita luna/trial trebuie sa injecteze `now` (fara `datetime.now()` intern) — altfel flaky.
|
||||
LLM/eval: 5.17 NU atinge prompturi/mapare LLM -> fara eval suites (confirmat: non-goal pe backend trimitere).
|
||||
|
||||
### Section 4 — Performance
|
||||
- `monthly_usage`: COUNT per-cerere; index `(account_id,status)` exista, NU acopera `created_at`.
|
||||
ENG-S4-1 (MEDIUM): la conturi de volum mare scaneaza randurile lunii. Auto-decis (P3): acceptabil acum;
|
||||
TODO index `(account_id, created_at)` (P3) cand apar conturi cu mii/luna.
|
||||
- Fara N+1, fara conexiuni noi, fara job nou (downgrade = lazy).
|
||||
|
||||
### Iesiri obligatorii Eng
|
||||
**NOT in scope (eng):** tabela `plan_usage` dedicata (nu necesara); lock tranzactional pe cota (overshoot
|
||||
mic acceptat); job eager downgrade (lazy ajunge); index timp (TODO).
|
||||
**What already exists (eng):** errors.eroare, auth.resolve_account_id, accounts.set_status pattern,
|
||||
db._migrate, observ.log_event, idempotency.build_key/canonicalize_row, submissions index — toate reutilizate.
|
||||
**Failure modes (eng) cu gap critic:** vezi Failure Modes Registry (CEO) — singurul CRITICAL GAP =
|
||||
migrare legacy active (acoperit de flag + decizie user T-CEO-1).
|
||||
|
||||
### Completion Summary (Eng)
|
||||
```
|
||||
| S1 Arhitectura | curata, 1 cuplare justificata, diagrama produsa |
|
||||
| S2 Quality | 1 (CONSUMED_STATUSES constanta) |
|
||||
| S3 Teste | diagrama produsa; 2 invariante critice (retry, dry-run) |
|
||||
| S4 Perf | 1 (index timp -> TODO P3) |
|
||||
| Artifact teste | scris in ~/.gstack/projects/romfast-rar-autopass/ |
|
||||
| Critical gaps | 1 (legacy) -> flag + decizie user |
|
||||
| Outside voice | codex indisponibil (subagent-only) |
|
||||
```
|
||||
|
||||
**Phase 3 complete.** Codex: indisponibil. Claude subagent: 4 constatari (1 HIGH teste-invariante,
|
||||
3 MEDIUM). Artifact test-plan scris pe disc. Trec la Faza 3.5 (DX).
|
||||
|
||||
## Faza 3.5 — DX Review [subagent-only]
|
||||
|
||||
> Scop DX confirmat: integratorul ROAAUTO/soft propriu foloseste `/v1/*` cu cheie API; adminul foloseste
|
||||
> CLI `tools.account`. Tip produs: **gateway API B2B + CLI admin**. Persona: dezvoltator integrator RO
|
||||
> (consuma `POST /v1/prezentari`) + admin gateway.
|
||||
|
||||
**CODEX SAYS (DX — developer experience challenge):** `[codex-unavailable]`.
|
||||
|
||||
**CLAUDE SUBAGENT (DX — independent review):**
|
||||
1. **Time-to-hello-world:** neschimbat de 5.17 pentru cont cu drept; DAR un integrator pe cont free care
|
||||
incearca `POST /v1/prezentari` va primi acum 403 (PLAN_FARA_API) la primul apel. Daca mesajul nu spune
|
||||
clar "API e pe Pro, dar `valideaza` merge", dezvoltatorul crede ca integrarea e stricata. (HIGH)
|
||||
2. **Mesaje de eroare:** `PLAN_FARA_API` si `PLAN_LIMITA_LUNARA` trebuie problema+cauza+fix (au structura
|
||||
din errors.py). Fix-ul trebuie sa fie actionabil ("Treci pe Pro: contacteaza-ne / set-tier"), nu doar 403.
|
||||
3. **API/CLI naming:** `set-tier --tier pro --trial-days 30|--no-trial` e consistent cu `tools.account`
|
||||
existent (create/activate/deactivate). OK. Sugestie: si `--account` (deja folosit).
|
||||
4. **Docs:** `/v1/nomenclator` ramane public (bun pentru explorare pre-upgrade). `valideaza` permis pe orice
|
||||
plan = excelent DX (integrezi+testezi inainte de a plati). Trebuie documentat explicit ca "poti dezvolta
|
||||
pe free cu valideaza, dar trimiterea reala cere Pro".
|
||||
5. **Upgrade path:** fara self-service -> 403 zice "contacteaza-ne"; un dezvoltator vrea un link/email
|
||||
concret, nu "contact". (MEDIUM)
|
||||
|
||||
```
|
||||
DX DUAL VOICES — CONSENSUS TABLE:
|
||||
Dimensiune Claude Codex Consensus
|
||||
───────────────────────────────────── ─────── ─────── ─────────
|
||||
1. Getting started < 5 min? Da* N/A N/A (*free->403 surprinde)
|
||||
2. Naming API/CLI ghicibil? Da N/A N/A
|
||||
3. Mesaje de eroare actionabile? Partial N/A N/A
|
||||
4. Docs gasibile & complete? Partial N/A N/A
|
||||
5. Upgrade path sigur? Partial N/A N/A (fara self-service)
|
||||
6. Mediu dev fara friction? Da N/A N/A (valideaza permis)
|
||||
```
|
||||
|
||||
### Developer journey map (9 etape)
|
||||
| Etapa | Azi | Cu 5.17 | Friction |
|
||||
|---|---|---|---|
|
||||
| 1 Descoperire | landing | landing aliniat (60, Pro) | — |
|
||||
| 2 Signup | cont + trial Pro | trial Pro 30z automat | — |
|
||||
| 3 Cheie API | CLI apikey | idem | — |
|
||||
| 4 Primul apel | 200 | 200 in trial; 403 pe free dupa trial | mesaj clar necesar |
|
||||
| 5 Dezvoltare | — | `valideaza` permis pe orice plan | excelent |
|
||||
| 6 Trimitere reala | 200 | gated pe Pro+ | upgrade path |
|
||||
| 7 Atingere limita | — | free 60/luna -> respins | mesaj 3 niveluri |
|
||||
| 8 Upgrade | — | contact admin (fara self-service) | link concret |
|
||||
| 9 Operare | dashboard | + badge plan/consum | — |
|
||||
|
||||
### Developer empathy narrative (persoana intai)
|
||||
"Mi-am facut cont, am cheia, trimit prima prestatie — merge (sunt in trial). Construiesc integrarea,
|
||||
folosesc `valideaza` ca sa testez fara sa consum nimic — perfect. Peste o luna, trial-ul expira; brusc
|
||||
`POST /v1/prezentari` da 403. Daca mesajul zice doar '403 Forbidden', cred ca mi-am stricat cheia si pierd
|
||||
o ora. Daca zice 'Importul prin API e pe planul Pro — scrie-ne la X ca sa activam', stiu exact ce sa fac."
|
||||
|
||||
### DX Scorecard (8 dimensiuni, 0-10)
|
||||
```
|
||||
1. TTHW 7 (free->403 dupa trial surprinde fara mesaj clar)
|
||||
2. Naming consistency 9
|
||||
3. Error actionability 6 -> tinta 9 dupa copy fix
|
||||
4. Docs/exemple 6 -> documenteaza valideaza-pe-free + upgrade
|
||||
5. Progressive disclosure 8 (nomenclator+valideaza publice/permise)
|
||||
6. Escape hatches 7 (dev id=1; flag enforcement)
|
||||
7. Upgrade safety 6 (manual; link concret lipseste)
|
||||
8. Consistency cross-canal 8
|
||||
--------------------------------
|
||||
Overall DX ~7.1/10 (TTHW: ~5 min ramane; tinta erori/docs ~8.5)
|
||||
```
|
||||
|
||||
### DX Implementation Checklist
|
||||
- [ ] `PLAN_FARA_API`: fix actionabil cu canal de contact concret (email/telefon), mentioneaza `valideaza`.
|
||||
- [ ] `PLAN_LIMITA_LUNARA`: fix cu "mai poti trimite N luna asta" + cum treci pe alt plan.
|
||||
- [ ] Doc scurt pentru integratori: "dezvolta pe free cu `valideaza`; trimiterea reala cere Pro".
|
||||
- [ ] `set-tier` help text clar (CLI) + audit in app_events.
|
||||
- [ ] Confirma `valideaza` ramane permis pe orice plan (decizie -> default PERMIS).
|
||||
|
||||
**Phase 3.5 complete.** DX overall ~7.1/10. TTHW ~5 min (neschimbat pentru cont cu drept). Codex:
|
||||
indisponibil. Claude subagent: 3 constatari (1 HIGH mesaj-403, 2 MEDIUM docs/upgrade-link) + leaga
|
||||
T-CEO-3 (valideaza gated vs permis). Trec la Faza 4.
|
||||
|
||||
<!-- AUTONOMOUS DECISION LOG -->
|
||||
## Decision Audit Trail
|
||||
|
||||
| # | Faza | Decizie | Clasificare | Principiu | Rationament | Respins |
|
||||
|---|------|---------|-------------|-----------|-------------|---------|
|
||||
| 1 | CEO | Mod = SELECTIVE EXPANSION | Mechanical | override autoplan | iteratie pe sistem existent | EXPANSION/HOLD/REDUCTION |
|
||||
| 2 | CEO | `effective_tier(acct, now)` cu `now` injectabil | Mechanical | P5 explicit | teste de granita deterministe | now intern (flaky) |
|
||||
| 3 | CEO | Coduri noi ca erori business 3-niveluri (nu 500) | Mechanical | P4 DRY/errors.py | reuse pattern existent | exceptii/catch-all |
|
||||
| 4 | CEO | Gate volum/API server-side dupa resolve_account_id | Mechanical | P1 completeness/sec | nu pe camp din body | gate din body (nesigur) |
|
||||
| 5 | CEO | Accepta overshoot mic cota sub concurenta | Taste->auto | P3 pragmatic | lock per-cont = over-eng pt cap soft | lock tranzactional |
|
||||
| 6 | CEO | Valoarea 60 + capability EXCLUSIV in PLANS | Mechanical | P4 DRY | o singura sursa | hardcodare in 3 locuri |
|
||||
| 7 | CEO | log_event pe fiecare respingere de plan | Mechanical | zero-silent-failures | "de ce blocat X?" vizibil | doar 4xx tacut |
|
||||
| 8 | CEO | Index `(account_id,created_at)` deferat -> TODO | Mechanical | P3 | volume mici acum | index acum (premature) |
|
||||
| 9 | CEO | T-CEO-1: enforcement sub flag + soft-first volum | **USER CHALLENGE -> REZOLVAT** | decizie user (2026-06-28) | **enforcement DUR direct de la deploy**; fara conturi legacy, pre-productie -> riscul de fals-block e moot | soft-first / flag-OFF respinse |
|
||||
| 10 | CEO | T-CEO-2: limita 60 ca o constanta config | Taste | P5 | tunabila fara cod | hardcodat |
|
||||
| 11 | Design | 6 stari explicite afisaj in US-006 | Mechanical | P1 completeness | acoperire stari | doar 3 stari |
|
||||
| 12 | Design | Copy RO fix cu pluralizare (zi/zile) | Mechanical | P5 explicit | nu lasa implementatorului | generic |
|
||||
| 13 | Design | T-DES-1: banner one-time la trial->free | Taste | P1 | semnal la trecere | doar badge tacut |
|
||||
| 14 | Design | warn = culoare + text (nu doar culoare) | Mechanical | P1 a11y | accesibilitate | doar culoare |
|
||||
| 15 | Eng | `CONSUMED_STATUSES` constanta exportata | Mechanical | P4 DRY | nu duplica definitia consum | duplicare in teste |
|
||||
| 16 | Eng | Fara tabela `plan_usage` (foloseste created_at) | Mechanical | P3/non-goal | migrare minima | coloana/tabela noua |
|
||||
| 17 | Eng | 2 invariante critice ca teste (retry, dry-run) | Mechanical | P1 completeness | usor de stricat | a le omite |
|
||||
| 18 | DX | `valideaza` ramane PERMIS pe orice plan (default) | Taste->auto | P1 DX | dezvolti pe free, trimiti pe Pro | gated ca restul API |
|
||||
| 19 | DX | Fix erori plan cu canal de contact concret | Mechanical | P1 completeness | actionabil | "contacteaza-ne" vag |
|
||||
| 20 | All | "prestatie consumata" = queued+sending+sent | Taste->auto | P1 | limita pe ce trimitem la RAR | doar sent |
|
||||
| 21 | All | Lot peste limita -> respingere totala clara | Taste->auto | P5 explicit | evita surprize enqueue partial | partial tacut |
|
||||
| 22 | All | **Enforcement DUR direct de la deploy** (rezolva T-CEO-1) | **USER DECISION (2026-06-28)** | user-stated | fara conturi legacy, produs in TESTE/pre-productie -> riscul de fals-block e moot; flag = optional kill-switch | soft-first / flag-OFF |
|
||||
| 23 | CEO | **T-CEO-2 REZOLVAT: limita 60 = constanta config tunabila** (o singura sursa in plans.py/config) | **USER DECISION (2026-06-28)** | user-stated (pe recomandare) | DRY/tunabil fara arheologie de cod | hardcodat |
|
||||
| 24 | Design | **T-DES-1 REZOLVAT: banner one-time la expirarea trial->Gratuit** | **USER DECISION (2026-06-28)** | user-stated (pe recomandare) | semnal clar la trecere, evita surpriza la prima respingere | doar badge |
|
||||
| 25 | DX | **T-DX-3 REZOLVAT: `valideaza` dry-run ramane PERMIS pe orice plan** | **USER DECISION (2026-06-28)** | user-stated (pe recomandare) | dezvolti pe free, trimiti pe Pro — DX excelent | gated ca restul API |
|
||||
|
||||
## Cross-Phase Themes
|
||||
- **Tema: enforcement fara cale de conversie** — semnalata in CEO (S9/S10) + DX (upgrade path). Semnal
|
||||
inalt: hard-block + lipsa self-service = friction. -> sustine T-CEO-1.
|
||||
- **Tema: mesaje oneste, actionabile** — CEO (S2/S8) + Design (P4 copy) + DX (erori). Convergent:
|
||||
fiecare respingere are problema+cauza+fix + canal de contact.
|
||||
- **Tema: determinism temporal** — CEO (S1 now injectabil) + Eng (S3 teste granita) + Design (pluralizare
|
||||
zile). `now` injectabil + timp local RO sunt fundatia testelor.
|
||||
|
||||
## TODOS.md (propuneri)
|
||||
- **[P3] Index `(account_id, created_at)` pe submissions** — cand apar conturi cu mii prestatii/luna,
|
||||
`monthly_usage` scaneaza randurile lunii. Efort S. Depinde de: aparitia volumului mare. (A: adauga la TODOS)
|
||||
- **[P2] Job eager downgrade `trial_until` expirat -> NULL** — igiena in purjarea orara T16; lazy acopera
|
||||
corectitudinea. Efort S. (A: adauga la TODOS, optional)
|
||||
- **[P1->Phase 2] Billing self-service (upgrade din UI)** — golul strategic; fara el enforcement-ul produce
|
||||
churn in loc de conversie. Efort XL. PRD separat. (A: adauga la TODOS ca Phase 2)
|
||||
- **[P3] Re-trial / nurture la expirare** — email "trial expirat, treci pe Pro". Efort M. (A: TODOS)
|
||||
|
||||
## Implementation Tasks (sintetizate)
|
||||
- [ ] **T1 (P1, human ~3h / CC ~25min) — schema/plans** — `accounts.tier`+`trial_until` (migrare aditiva
|
||||
defensiva) + `app/plans.py` (PLANS, `effective_tier(acct,now)`, `monthly_usage(conn,acct,now)`,
|
||||
`CONSUMED_STATUSES`). Surfaced by: CEO S1 / Eng S1-S2. Files: schema.sql, db.py, app/plans.py, accounts.py.
|
||||
Verify: test_migrare_*, test_plan_definitii, test_effective_tier_*.
|
||||
- [ ] **T2 (P1, human ~2h / CC ~15min) — accounts** — `create_account` seteaza trial Pro 30z; `set_tier`
|
||||
(protejat id=1); legacy -> free fara trial. Surfaced by: CEO 0B / Eng. Files: accounts.py, tools/account.py.
|
||||
- [ ] **T3 (P1, human ~3h / CC ~25min) — enforce volum** — gate INAINTE de build_key pe ambele canale +
|
||||
cod `PLAN_LIMITA_LUNARA` + log_event; lot peste limita -> respingere totala. Surfaced by: CEO S3/S4/S8.
|
||||
Files: api/v1/router.py, import_router.py, web/routes.py, errors.py. Verify: test_free_peste_60_*, retry.
|
||||
- [ ] **T4 (P1, human ~2h / CC ~15min) — gate API** — `require_api_access` (Pro+/trial) pe rutele de
|
||||
ingestie API; `valideaza`+`nomenclator` raman permise; dev id=1 exceptat; cod `PLAN_FARA_API` (403 actionabil).
|
||||
Files: auth.py, api/v1/router.py, import_router.py, errors.py. Verify: test_*_api_403/ok.
|
||||
- [ ] **T5 (P3 OPTIONAL, human ~30min / CC ~5min) — flag enforcement (kill-switch)** — `AUTOPASS_ENFORCE_PLANS`
|
||||
(config). NU blocant: enforcement DUR e activ implicit de la deploy (decizie user). Flag-ul = doar
|
||||
comoditate de operare. Files: config.py + gate-urile. Surfaced by: CEO S9 (rezolvat).
|
||||
- [ ] **T6 (P2, human ~3h / CC ~20min) — UI dashboard** — badge plan antet + linie burger + consum N/60 +
|
||||
warn>=80% + 6 stari + copy RO pluralizat + pagina Cont. Surfaced by: Design P2/P4. Files: web/routes.py,
|
||||
templates/_status.html,_cont.html. Verify: test_afisaj_*, test_copy_pluralizare.
|
||||
- [ ] **T7 (P1, human ~30min / CC ~5min) — landing copy** — 100->60 (linii 7,65,92,266,388);
|
||||
"Premium gratuit 30 zile"->"Pro gratuit 30 zile" (256,350). Files: landing.html. Verify: test_landing_*.
|
||||
- [ ] **T8 (P2, human ~1h / CC ~10min) — teste matrice E2E** — plan x capabilitate x canal x trial +
|
||||
granita luna RO + dev id=1. Files: tests/test_plans.py, test_api_scope.py, test_web_*. Verify: pytest -q.
|
||||
- [ ] **T9 (P2, human ~30min / CC ~5min) — docs integrator** — "dezvolta pe free cu valideaza, trimiterea
|
||||
reala cere Pro". Surfaced by: DX. Files: docs/ + integrare_examples.
|
||||
|
||||
## GSTACK REVIEW REPORT
|
||||
|
||||
| Review | Trigger | Why | Runs | Status | Findings |
|
||||
|--------|---------|-----|------|--------|----------|
|
||||
| CEO Review | `/plan-ceo-review` | Scop & strategie | 1 | issues_open | 9 constatari, CRITICAL GAP legacy REZOLVAT (moot), mode SELECTIVE_EXPANSION |
|
||||
| Codex Review | `/codex review` | A 2-a opinie | 0 | indisponibil | limita utilizare (pana 2026-07-18) |
|
||||
| Eng Review | `/plan-eng-review` | Arhitectura & teste (required) | 1 | issues_open | 4 constatari, gap legacy moot, 2 invariante critice teste |
|
||||
| Design Review | `/plan-design-review` | UI/UX | 1 | issues_open | 4 constatari, overall ~6.4/10 |
|
||||
| DX Review | `/plan-devex-review` | Developer experience | 1 | issues_open | 3 constatari, DX ~7.1/10 |
|
||||
|
||||
- **VERDICT:** CEO + Design + Eng + DX rulate (subagent-only, codex indisponibil). Toate deciziile inchise
|
||||
(2026-06-28): USER CHALLENGE rezolvat (enforcement DUR direct de la deploy; CRITICAL GAP migrare = moot,
|
||||
fara conturi legacy/pre-productie) + cele 3 taste decisions rezolvate pe recomandare (T-CEO-2 constanta
|
||||
config, T-DES-1 banner one-time trial->Gratuit, T-DX-3 `valideaza` permis pe orice plan). Plan gata de executie.
|
||||
|
||||
NO UNRESOLVED DECISIONS
|
||||
|
||||
Reference in New Issue
Block a user