- Surse complete web (React/Vite) + mobil (React Native/Expo) + extensie (MV3) - Documentație de livrare: ghid utilizare, matrice trasabilitate cerințe, raport testare furnizor - Artefacte binare: imagine Docker didi-frontend:lot3-1.0, APK, extensie v3.2.6 + SHA256SUMS - Configurare adresă platformă externalizată (build args / .env / config.js) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
155 lines
15 KiB
Markdown
155 lines
15 KiB
Markdown
% Matrice de trasabilitate a cerințelor — DiDi Lot 3 (Frontend)
|
||
% PNRR DIGI150 · contract 11.1.i3.c9 · Contract de furnizare nr. 19
|
||
|
||
---
|
||
|
||
# 1. Scop
|
||
|
||
Prezentul document asigură **trasabilitatea** dintre cerințele contractuale (Caietul de sarcini,
|
||
secțiunea LOT 3 + Propunerea Tehnică Lot 3) și livrabilele efective ale Lotului 3:
|
||
**aplicația web**, **aplicația mobilă (Android/iOS)** și **extensia de browser**. Pentru fiecare
|
||
cerință se indică **starea** și **dovada** (cod sursă, platformă live, test executat) prin care se
|
||
poate verifica îndeplinirea.
|
||
|
||
Legendă dovezi:
|
||
`COD`=cod sursă (repo `didi-lot3-frontend`) · `LIVE`=platformă în funcțiune pe `10.11.10.18` ·
|
||
`TEST`=test executat la 15.07.2026 (auth + analiză end-to-end prin Kong) ·
|
||
`PT`=Propunerea Tehnică Lot 3 (secțiunea indicată) · `HAND`=HANDOFF_Lot3_Rebrand_Integrare.md.
|
||
|
||
Stare: ✅ conform · ⚠️ conform cu observație asumată (detaliat în §6).
|
||
|
||
Livrabile: app web LIVE `https://10.11.10.18/` · APK `~/didi-app-clossers.apk` ·
|
||
extensie `~/didi-extension-clossers.zip` (sau `didi-lot3-frontend/extension/`).
|
||
|
||
---
|
||
|
||
# 2. Componenta 1 — Aplicație Web (`web/`)
|
||
|
||
| # | Cerință (caiet de sarcini) | Stare | Dovadă |
|
||
|---|---|---|---|
|
||
| W1 | Trimitere conținut pentru analiză: text, URL, imagini, audio, video | ✅ | COD `PipelineAnalysis/sections/InputForm.tsx`, `AnalysisTab.tsx`; LIVE Dashboard |
|
||
| W2 | Formular unificat de trimitere (tabs: Text / URL / Media) | ✅ | COD `InputForm.tsx` (`INPUT_TYPES`: text, url, image, audio, video) |
|
||
| W3 | Afișarea stării analizei (queued/running/completed/failed) | ✅ | COD `hooks/useAsyncAnalysis.ts` (polling 2,5s, stări complete); PT §1.2 |
|
||
| W4 | Pagină rezultate: scor/verdict + drill-down (claims, evidențe/surse, tehnici, recomandări, explicații) | ✅ | COD `PipelineAnalysis/sections/Verdict.tsx` + `details/{techniques,claims,source,ai}.tsx` |
|
||
| W5 | Istoric analize pentru utilizatori autentificați (listă paginată + navigare detalii + ștergere) | ✅ | COD `pages/History.tsx` (paginare 20/pag, ștergere cu confirmare) |
|
||
| W5b | Filtre istoric: nivel risc, status, tip input, interval date, căutare (PT §1.2) | ⚠️ | COD `pages/History.tsx` (rând filtre complet; filtrare client-side — v. §6.4) |
|
||
| W6 | Export / partajare raport | ✅ | COD `Reports/DownloadPdfButton.tsx` (export PDF) + `Reports/ShareReportButton.tsx` (navigator.share / link intern cu session_id) |
|
||
| W7 | Autentificare: Sign up / Sign in / Sign out, recuperare parolă, management sesiune | ✅ | COD `services/keycloak.service.ts` (login/register/logout, UPDATE_PASSWORD, auto-refresh); LIVE user demo |
|
||
| W8 | Integrare OIDC/OAuth2 cu modulul IAM al backend-ului | ✅ | COD `keycloak.service.ts` (PKCE S256, realm `didi-clients`, client `didi-web-app`); LIVE |
|
||
| W9 | Operațiuni exclusiv prin API (HTTPS), gestionare token-uri, tratare erori/timeout | ✅ | COD `services/http.client.ts` (Bearer, retry+backoff, AbortController, refresh la 401); nginx same-origin → Kong |
|
||
| W10 | Design modern, curat, mobile-first, layout responsive | ✅ | COD `theme/breakpoints.ts`, `theme/tokens.ts` (identitate Clossers); LIVE |
|
||
| W11 | Componente UI coerente (cards, stepper, tabs) + micro-interacțiuni (loading/progress, toasts) | ✅ | COD `ui/Card.tsx`, `ui/Button.tsx`, `AnalysisTab` (stepper), `Toast/Toast.tsx` |
|
||
| W12 | WCAG 2.1 AA: contrast, focus vizibil, navigare tastatură, ARIA, labels, alt-text, screen readers | ✅ | COD ARIA pe componente interactive; Toast cu `role=status/alert` + `aria-live`; `ui/Input.tsx` label+htmlFor |
|
||
| W13 | Font scaling + reduced motion | ✅ | COD `theme/typography.ts` (px→rem, clamp pe titluri); `App.css` + `LandingPage.css` (prefers-reduced-motion) |
|
||
| W14 | Validare input (URL valid, tip fișier, mărime) + mesaje de eroare explicite | ✅ | COD `utils/url-validation.ts`, `utils/file-validation.ts` (MIME+extensii+limite 20/50/100MB), `text-validation.ts` |
|
||
| W15 | Protecție SSRF la input URL | ✅ | COD `utils/url-validation.ts` (`isReservedHost`: IP private/localhost/link-local, trucuri hex/octal, IPv6) |
|
||
| W16 | Consimțământ explicit trimitere fișiere + informare confidențialitate | ✅ | COD `components/ConsentNotice/` (checkbox + politică; integrat în toate cele 5 fluxuri cu upload; persistat) |
|
||
| W17 | Comunicare doar prin API, rate limiting server-side | ✅ | Kong `rate-limiting` (Lot 2, `kong.yml.didi11-local`); frontend fără canale alternative |
|
||
| W18 | Temă dark/light comutabilă | ✅ | COD `contexts/ThemeContext.tsx` + `ThemeToggle` (dark/light/system; implicit light) |
|
||
| W19 | Analize per competență individuală + pipeline complet | ✅ | COD `ManipulationTechniques`, `AiTamper`, `ClaimAnalysis`, `DomainAnalysis`, `PipelineAnalysis` |
|
||
| W20 | Upload media cu afișare progres | ⚠️ | COD `useAsyncAnalysis.ts` (stare `uploading` + bară de progres; procent euristic — v. §6.5) |
|
||
|
||
---
|
||
|
||
# 3. Componenta 2 — Aplicație Mobilă (`android/didi-app-source/`)
|
||
|
||
| # | Cerință (caiet de sarcini) | Stare | Dovadă |
|
||
|---|---|---|---|
|
||
| M1 | Funcționalitate echivalentă web: trimitere + analiză text/URL/imagine/audio/video, UI mobilă | ✅ | COD `screens/PipelineScreen.tsx` (5 taburi, pickere native, upload) |
|
||
| M2 | Share-to-Analyze: conținut din social media/browser — link | ✅ | COD `hooks/useShareIntent.ts`, `utils/shareIntent.ts`; intent-filter SEND `text/plain` |
|
||
| M2b | Share-to-Analyze: text selectat (fără URL) | ✅ | COD `shareIntent.ts` (`SharedPayload kind:'text'`) → Pipeline/Skill cu text preîncărcat |
|
||
| M2c | Share-to-Analyze: imagine | ✅ | COD intent-filter SEND `image/*` (AndroidManifest + app.json); `expo-share-intent` files[] → ShareAction cu miniatură |
|
||
| M2d | Neautentificat: stocare temporară → login → revenire automată la flux | ✅ | COD `utils/socialShareStorage.ts` + `MainScreen`/`LoginScreen` (pending share generalizat) |
|
||
| M3 | Selectare regiune (crop) din imagine înainte de trimitere | ✅ | COD `PipelineScreen.tsx` + `SkillAnalysisScreen.tsx` (`allowsEditing: true` pe galerie + cameră → UI nativ de crop) |
|
||
| M4 | Rezultate optimizate mobil: verdict+scor, secțiuni expandabile, evidențe/surse, tehnici, recomandări | ✅ | COD `components/sections/Verdict.tsx`, `editorial/CollapseButton.tsx`, `ActionCallout.tsx`, `FindingCard` (surse cu Linking) |
|
||
| M5 | Autentificare OIDC/OAuth2 flow mobil | ✅ | COD `screens/auth/LoginScreen.tsx` (PKCE S256 + state CSRF, WebView incognito); client Keycloak `didi-mobile-app` |
|
||
| M6 | Stocare securizată token-uri + logout complet | ✅ | COD `store/authStore.ts` (expo-secure-store → Keystore; revocare refresh_token la logout) |
|
||
| M7 | Accesibilitate: font scaling, contrast, navigare asistivă, feedback erori | ✅ | COD `accessibilityRole/Label/State` pe elementele interactive (taburi, carduri, butoane, switch-uri); `maxFontSizeMultiplier` doar unde layout-ul e rigid; fără `allowFontScaling={false}` |
|
||
| M8 | Comunicare exclusiv prin API + gestionare token (retry 401, auto-refresh cu mutex) | ✅ | COD `api/axios.ts` (interceptori request/response), `authStore.ts` (single-flight refresh) |
|
||
| M9 | Validare input + SSRF + mesaje explicite | ✅ | COD `utils/validation.ts` (text 20–50k, URL, MIME/extensii/limite, durată media, `isPrivateHost`) |
|
||
| M10 | Consimțământ explicit la trimitere fișiere + confidențialitate | ✅ | COD `utils/uploadConsent.ts` + `components/UploadConsentModal.tsx` (checkbox obligatoriu; persistat; menționare discretă ulterior) |
|
||
| M11 | Istoric analize (paginat/infinite scroll, polling progres, ștergere cu confirmare) | ✅ | COD `screens/HistoryScreen.tsx` + `api/history.ts` |
|
||
| M12 | Competențe individuale + pipeline complet | ✅ | COD `SkillsScreen.tsx` (4 competențe) + `SkillAnalysisScreen.tsx` |
|
||
| M13 | Setări: profil, schimbare parolă, deconectare | ✅ | COD `SettingsScreen.tsx` + `SignOutSection.tsx` (hook comun `useSignOut`; și în Dashboard) |
|
||
| M14 | Disponibilitate Android/iOS dintr-un singur codebase | ⚠️ | COD React Native/Expo (cross-platform); livrat build Android (APK) — v. §6.2 |
|
||
|
||
---
|
||
|
||
# 4. Componenta 3 — Extensie Browser (`extension/`)
|
||
|
||
| # | Cerință (caiet de sarcini) | Stare | Dovadă |
|
||
|---|---|---|---|
|
||
| E1 | Trimitere URL: analiza tab-ului curent | ✅ | COD `popup.js` (buton „Pagina curentă" + prefill URL tab activ) + context menu „Analizează pagina curentă" |
|
||
| E1b | Trimitere URL: input manual (câmp dedicat) | ✅ | COD `popup.html` (`#urlInput` + validare http/https) → `background.js analyzeUrl` |
|
||
| E2 | Trimitere text: analiza textului selectat din pagină | ✅ | COD `popup.js prefillFromActiveTab()` (getSelection → prefill) + context menu „Analizează textul selectat" |
|
||
| E2b | Trimitere text: input manual (câmp dedicat) | ✅ | COD `popup.html` (`#textInput`, max 5000) → `analyzeTextContent` |
|
||
| E3 | Trimitere imagine: selectare din pagină (context menu „Analyze image") | ✅ | COD `background.js` (`chrome.contextMenus`, id `didi-analyze-image`: fetch imagine → upload → analiză) |
|
||
| E3b | Trimitere imagine: captură cu crop/selector de regiune | ✅ | COD `content.js` (snipping overlay + drag select) + `background.js` (`captureVisibleTab` + `OffscreenCanvas` + devicePixelRatio) |
|
||
| E4 | Panel rezultat: verdict+scor, rezumat, fact-check (claims+status), tehnici, surse/evidențe | ✅ | COD `render.js` (headline+gauge, `explanation_ro/en`, `claimsCard` cu surse, `techniquesCard`, `sourceCard`); modal în pagină + tab standalone |
|
||
| E5 | Autentificare prin IAM: OIDC/OAuth2 cu PKCE | ✅ | COD `auth.js` (launchWebAuthFlow → Keycloak `didi-clients`, client `didi-extension`, PKCE S256 + state; refresh single-flight; logout cu revocare); TEST flux token→analiză |
|
||
| E6 | Stocare securizată token-uri conform politicilor browserului | ✅ | COD `chrome.storage.local` (izolat per-extensie, MV3); fără chei statice în cod |
|
||
| E7 | Minimizarea datelor (strict URL/text/fragment imagine selectat) | ✅ | COD `background.js` payload minimal (`{text|url|media_url}` + identitate token); capturile trimit doar regiunea decupată |
|
||
| E8 | Integrare exclusiv prin API + stări asincrone (queued/running/completed) + timeouts + mesaje clare | ✅ | COD `submitAndPoll` (analyze-async → queue-status 2s → result; timeout 5 min; erori propagate ca notificări); TEST end-to-end |
|
||
| E9 | Comunicare prin API Gateway cu autorizare | ✅ | TEST: `POST /agent-v3/api/v3/pipeline/analyze-async` cu Bearer prin Kong (JWT validat; 401 fără token); rate limiting Kong |
|
||
| E10 | Istoric analize | ✅ | COD `history.html/js` (pagină dedicată, max 50 intrări, ștergere per element) |
|
||
| E11 | Extractoare conținut rețele sociale (Facebook, Twitter/X) | ✅ | COD `content.js` (`FacebookExtractor`, `TwitterExtractor`) cablate: buton „Selectează postare" (popup) → `contentExtracted` → analiză automată |
|
||
| E12 | Consimțământ explicit pentru capturi + confidențialitate | ✅ | COD `content.js ensureUploadConsent()` (modal la prima captură; persistat) + notă de confidențialitate în popup |
|
||
| E13 | Permisiuni minimale | ✅ | COD `manifest.json` v3.2.0 (`clipboardWrite` eliminat; `identity`+`contextMenus` adăugate pentru cerințele E3/E5) |
|
||
| E14 | Accesibilitate popup: labels/ARIA, focus vizibil, keyboard | ✅ | COD `popup.html` (aria-label pe toate controalele, `aria-live` pe status) + `popup.css` (`:focus-visible`) |
|
||
|
||
---
|
||
|
||
# 5. Cerințe comune + criterii de evaluare
|
||
|
||
| Cerință / criteriu | Stare | Dovadă |
|
||
|---|---|---|
|
||
| Design responsive/mobile-first, onboarding minim | ✅ | W10, M1, popup extensie |
|
||
| WCAG 2.1 AA pe web + extensie (focus/contrast/tastatură/labels/ARIA — criteriul 5) | ✅ | W12–W13, E14 |
|
||
| Validare input + mesaje explicite (toate componentele) | ✅ | W14, M9, E8 |
|
||
| Consimțământ explicit fișiere/capturi (toate componentele) | ✅ | W16, M10, E12 |
|
||
| Comunicare doar prin API, rate limiting și protecții server-side | ✅ | W17, M8, E9 (Kong: JWT + rate limiting + request-size-limiting) |
|
||
| E2 evaluare — IAM OIDC/OAuth2 funcțional pe web + mobil + extensie, TLS, validare token la gateway | ✅ | Toate cele 3 componente pe Keycloak realm `didi-clients` (clienți `didi-web-app`, `didi-mobile-app`, `didi-extension`); Kong validează JWT (TEST) |
|
||
| E4 evaluare — wireframes/mockups mapate pe endpoint-uri și stări | ✅ | PT Anexa C; implementare 1:1 în COD (endpoint-urile din PT §1.5 consumate identic) |
|
||
| Identitate vizuală Clossers (dezvoltată post-atribuire, conform PT §1.8) | ✅ | `clossers_brand_guide.html` aplicat pe toate 3 componentele (HAND §1–4) |
|
||
|
||
---
|
||
|
||
# 6. Observații asumate (nu afectează conformitatea funcțională)
|
||
|
||
1. **HTTPS cu certificat self-signed + HTTP în LAN.** Platforma rulează în rețea internă
|
||
(`10.11.10.18`); mobilul și extensia folosesc HTTP (nginx port 80 → Kong/Keycloak) deoarece
|
||
nu acceptă certificate self-signed. La expunere publică se instalează certificat valid și
|
||
se comută config-urile (o singură constantă per componentă). TLS este activ pe web (443).
|
||
2. **Build iOS.** Codebase-ul React Native/Expo este cross-platform (cerința de cod unic e
|
||
îndeplinită); build-ul iOS necesită mediu macOS/Apple Developer și se generează la cerere.
|
||
Livrat: APK Android semnat cu cheie de test (pentru Google Play se generează keystore de release).
|
||
3. **Autentificarea extensiei prin fereastra Keycloak HTTP** — de confirmat pe stația
|
||
beneficiarului că browserul permite flow-ul `launchWebAuthFlow` pe HTTP; alternativa este
|
||
certificatul valid de la pct. 1.
|
||
4. **Filtrele de istoric (web)** rulează client-side pe seturi de câte 100 de înregistrări
|
||
(maximul rutei user din backend); ruta backend cu filtre server-side există doar pe admin
|
||
(Lot 2). Comportamentul pentru utilizator este identic funcțional.
|
||
5. **Progresul la upload (web)** este afișat ca stare + bară euristică (fetch API nu expune
|
||
evenimente de progres byte-level); fișierele tipice (<100MB LAN) se încarcă în secunde.
|
||
|
||
---
|
||
|
||
# 7. Sinteză stare livrare
|
||
|
||
| Categorie | Rezultat |
|
||
|---|---|
|
||
| Cerințe caiet — App Web | **20/20** conforme (2 cu observație asumată) |
|
||
| Cerințe caiet — App Mobilă | **14/14** conforme (1 cu observație asumată) |
|
||
| Cerințe caiet — Extensie | **14/14** conforme |
|
||
| Cerințe comune + criterii evaluare | **8/8** |
|
||
| Autentificare unificată IAM (Keycloak OIDC/PKCE) | **3/3 componente** |
|
||
| Test end-to-end auth + analiză prin Kong (15.07.2026) | PASS (submit → poll → result + upload media, Bearer) |
|
||
| Verificare tip/build | `tsc` 0 erori (web + mobil) · `vite build` OK · APK build OK · extensie: syntax OK, manifest valid |
|
||
| Livrabile actualizate | imagine `didi-frontend:local` (LIVE) · `didi-app-clossers.apk` · `didi-extension-clossers.zip` |
|
||
|
||
Toate cerințele caietului de sarcini pentru LOT 3 și angajamentele din Propunerea Tehnică sunt
|
||
**implementate, livrate și verificabile**, cu dovezi trasabile în cod, pe platforma în funcțiune
|
||
și în testele executate. Neconformitățile identificate la analiza din 15.07.2026 (autentificare
|
||
extensie fără OIDC, analiza URL/text selectat/context-menu lipsă din UI extensie, crop mobil,
|
||
share imagini, consimțământ upload, filtre istoric, partajare raport, accesibilitate) au fost
|
||
**remediate integral** în aceeași zi, înainte de emiterea prezentei matrice.
|