GDPR & Protecția Datelor
Protecție a datelor implicită (Privacy by Design)
qr3.app este construit de la zero pentru a fi conform cu GDPR:
- Pseudonimizarea IP-urilor — Adresele IP sunt convertite instantaneu în pseudonime HMAC-SHA-256 ale zilei UTC în Edge Worker. IP-ul original nu este niciodată stocat; pseudonimul rămâne o dată cu caracter personal.
- Minimizarea datelor — Sunt colectate doar datele strict necesare pentru funcționare.
API de Confidențialitate (Privacy API)
Rezumatul datelor (Art. 15 GDPR)
GET /v1/account/privacy — Returnează o prezentare generală a tuturor datelor stocate.
curl https://qr3.app/v1/account/privacy \ -H "Authorization: Bearer qr3_sk_..."Response:
{ "data": { "workspace_id": "ws_xxx", "organization_id": "org_xxx", "account": { "name": "Alex Example", "locale": "en", "created_at": "2026-01-15T09:00:00.000Z" }, "stored_data": { "qr_codes": 42, "scan_records": 15000, "dpp_scan_records": 3200, "dashboard_activity_records": 0, "dashboard_document_activity_records": 36, "api_operation_records": 180, "webhook_delivery_records": 640, "api_keys": 2, "webhooks": 1, "dpp_passports": 12, "dpp_documents": 30, "files": 4, "gs1_identifiers": 2, "gs1_verification_requests": 1, "code_comments": 5, "audit_log_entries": 0, "dpp_import_jobs": 1, "workspace_members": 3, "scan_quota_alerts": 1 }, "gdpr_rights": { "access": "GET /v1/account/privacy", "export": "GET /v1/account/export", "erasure": "DELETE /v1/account", "consents": "GET /v1/account/privacy/consents" }, "data_processing": { "ip_storage": "Purpose-separated HMAC-SHA-256 UTC-day IP pseudonym — pseudonymous personal data", "scan_retention": "90 days by default", "usage_retention": "90 UTC days", "webhook_delivery_retention": "90 UTC days", "pii_in_export": true, "erasure": "DELETE /v1/account erases the person's account: organizations they own with all workspaces and data (unless another org admin takes them over), their memberships in other organizations, their login and their Stripe customer. A running subscription ends immediately, without refund.", "backup_retention": "Erased rows stay restorable from the database backups (Cloudflare D1 Time Travel) for up to 30 days, then they are gone.", "billing_records": "Invoices stay with Stripe for the statutory retention period (7 years, § 132 BAO)." } }, "meta": { "request_id": "req_xxx" }}stored_data numără înregistrările stocate. scan_records sunt scanări ale codurilor QR, iar dpp_scan_records sunt solicitări către pașapoartele de produs prin resolverul DPP public. Ambele conțin pseudonimul IP.
dashboard_activity_records și dashboard_document_activity_records numără zilele în care un membru a deschis dashboard-ul (două tabele), api_operation_records contoarele zilnice de cereri pe cheie API, operațiune și rezultat, iar webhook_delivery_records încercările de livrare a webhook-urilor, inclusiv pe cele ale webhook-urilor șterse. Niciunul nu stochează o adresă IP sau un User-Agent; jurnalul de livrare stochează însă payload-ul evenimentului și primul kilobyte (1 KB) din răspunsul destinatarului. Toate patru se șterg după 90 de zile UTC (usage_retention, webhook_delivery_retention).
account indică persoana din spatele cererii — în dashboard, persoana autentificată, altfel persoana care a creat cheia — cu e-mail, nume, limbă și data creării; pentru o Publishable Key valoarea este null. Celelalte contoare acoperă orice altă tabelă cu date ale contului: pașapoarte de produs, documente DPP, fișiere, identificatori GS1, comentarii, înregistrări de audit, rulări de import, membri ai workspace-ului și notificările de cotă ale organizației (scan_quota_alerts). Rândurile șterse logic se numără, deoarece sunt încă stocate. erasure, backup_retention și billing_records descriu ce șterge DELETE /v1/account și ce rămâne o vreme; pii_in_export este true, deoarece exportul indică persoana (e-mail, nume) — pseudonimele IP nu părăsesc niciodată baza de date.
Exportul de date (Art. 20 GDPR — Portabilitatea datelor)
GET /v1/account/export — Descarcă toate datele sub forma unui fișier JSON.
curl https://qr3.app/v1/account/export \ -H "Authorization: Bearer qr3_sk_..." \ -o my-data.jsonExportul conține:
- Toate codurile QR (inclusiv cele șterse)
- Statistici de scanare agregate (fără hash-uri IP brute)
- Solicitări DPP agregate per pașaport de produs (
dpp_scan_aggregates, de asemenea fără hash-uri IP) - Statistici de utilizare agregate (
dashboard_activity_aggregates,api_operation_aggregates): zile active și numărul de utilizatori activi pe canal al dashboard-ului, contoare de cereri pe operațiune și rezultat, fără ID-uri de utilizatori și de chei - Încercări de livrare a webhook-urilor pe webhook și tip de eveniment (
webhook_delivery_aggregates), fără payload și răspuns - Persoana din spatele cererii (
account), organizația (organization; adresa de facturare și de notificare doar pentru administratorii organizației) și workspace-ul (workspace) - Pașapoarte de produs, metadatele documentelor DPP și ale fișierelor (nu fișierele în sine), identificatori GS1, cereri de verificare a acestora și rulări de import (
dpp_passports,dpp_documents,files,gs1_identifiers,gs1_verification_requests,dpp_import_jobs) - Comentarii fără câmpuri de autor (
code_comments), înregistrări de audit ca agregate (audit_log_aggregates) și membri pe rol (member_aggregates) - Chei API fără ID și hash (
api_keys), webhook-uri fără URL și secret (webhooks) și notificările de cotă ale organizației (scan_quota_alerts) - Marcaje temporale de creare și modificare
Publishable Keys (qr3_pk_) primesc 403: fișierul conține adresele țintă și notele tuturor codurilor.
Ștergerea contului (Art. 17 GDPR — Dreptul de a fi uitat)
DELETE /v1/account — Șterge contul persoanei din spatele cererii, imediat și ireversibil: în dashboard, persoana autentificată, altfel persoana care a creat cheia. O cerere de ștergere prin e-mail duce la aceeași ștergere: operatorul șterge autentificarea din Clerk, iar apoi qr3 șterge contul.
curl -X DELETE https://qr3.app/v1/account \ -H "Authorization: Bearer qr3_sk_..."Ce se întâmplă:
- Organizațiile care aparțin persoanei sunt șterse cu toate workspace-urile, codurile, pașapoartele de produs, fișierele, statisticile și jurnalele lor, inclusiv fișierele lor din stocare. Dacă o astfel de organizație are un alt administrator activ al organizației, o preia în schimb cel cu cea mai mare vechime — împreună cu datele și abonamentul.
- Abonament: un abonament în curs se încheie imediat, fără rambursare proporțională și fără factură finală; apoi clientul Stripe este șters. Facturile rămân la Stripe pe durata termenului legal de păstrare (7 ani, § 132 BAO).
- Echipe: calitatea de membru a persoanei în alte organizații încetează; aceste echipe își păstrează datele. Comentariile persoanei nu mai indică un autor, înregistrările ei de audit pierd pseudonimul IP și user agent-ul, iar cheile API pe care le-a creat acolo sunt revocate.
- Persoana: autentificarea (Clerk) și înregistrarea de utilizator sunt șterse.
Răspunsul este 200 cu status: "completed" și contoarele organizations_deleted, organizations_transferred, memberships_removed și login_deleted. Pentru organizații foarte mari, o singură cerere nu ajunge: răspunsul este atunci 202 cu status: "in_progress", iar ștergerea se încheie automat în câteva ore.
Necesită o Secret Key sau Test Key cu drept de scriere ori o sesiune în dashboard (orice rol, deoarece este vorba de propriul cont). Publishable Keys și cheile doar pentru citire primesc 403, o cheie fără o persoană în spate (created_by = 'system') primește 409. 503 înseamnă că implementării îi lipsește un secret de care are nevoie ștergerea; nu s-a șters nimic.
Gestionarea consimțămintelor
GET /v1/account/privacy/consents — Obținerea consimțămintelor actuale.
POST /v1/account/privacy/consents — Actualizarea consimțămintelor.
# Obținerea consimțămintelor actualecurl https://qr3.app/v1/account/privacy/consents \ -H "Authorization: Bearer qr3_sk_..."
# Dezactivarea e-mailurilor de marketingcurl -X POST https://qr3.app/v1/account/privacy/consents \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "marketing_emails": false, "analytics": true, "product_updates": true }'Câmpurile de consimțământ:
| Câmp | Implicit | Descriere |
|---|---|---|
marketing_emails | false | Newslettere și e-mailuri promoționale |
analytics | true | Statistici de utilizare agregate |
product_updates | true | Noutăți despre produse și changelog-uri |
Modificarea consimțămintelor necesită drepturi de scriere: rolul viewer și Publishable Keys primesc 403.
Implementarea tehnică a GDPR
Pseudonimizarea IP-urilor (Art. 25 GDPR)
Cerere HTTP → Cloudflare Edge Worker ↓Antet CF-Connecting-IP → HMAC-SHA-256(IP_HASH_SALT, scop, zi UTC, IP) ↓ip_hash (pseudonim zilnic) → bază de date D1 ↓IP-ul original nu este niciodată stocatIP_HASH_SALT este un secret principal cu durată lungă; scopul și ziua UTC derivă automat pseudonime zilnice separate. Pseudonimele din zile UTC diferite nu sunt direct egale, dar deținătorul secretului poate recalcula un candidat IP cunoscut pentru o anumită zi. Nu se folosește sare zilnică în KV și nici rotație manuală zilnică.
Retenția datelor (automatizată)
| Plan | Retenție |
|---|---|
| Toate planurile | 90 de zile |
Statisticile de utilizare (activitatea din dashboard, contoarele de utilizare a API-ului) și jurnalele de livrare webhook se păstrează tot 90 de zile UTC: ziua UTC curentă și cele 89 de zile anterioare. Aceeași sarcină cron zilnică șterge rândurile mai vechi (purgeOldDashboardActivity, purgeOldApiOperationUsage, purgeOldWebhookDeliveries).
Acordul de prelucrare a datelor (DPA) cu subcontractanții
Cloudflare, Inc. prelucrează datele în calitate de persoană împuternicită de operator. Acordul DPA este disponibil la cloudflare.com/cloudflare-customer-dpa.
Cloudflare prelucrează datele cu o indicație de localizare către regiunea UE (inclusiv Frankfurt); o jurisdicție UE garantată contractual nu este rezervată în prezent. Deoarece Cloudflare, Inc. are sediul în SUA, clauzele contractuale standard (SCC) conform Art. 46 GDPR se aplică ca bază pentru transfer.
Contact
- Responsabil cu protecția datelor: [email protected]
- Acord de prelucrare a datelor (DPA): [email protected] (la cerere)
- Politică de confidențialitate: qr3.app/de/legal/datenschutz