Přeskočit na obsah

GDPR & ochrana osobních údajů

Ochrana soukromí od návrhu (Privacy by Design)

qr3.app je od základu navržen v souladu s GDPR:

  • Pseudonymizace IP adres — IP adresy jsou v Edge Workeru okamžitě převedeny na denní pseudonymy HMAC-SHA-256 UTC. Původní IP adresa se nikdy neukládá; pseudonym zůstává osobním údajem.
  • Minimalizace dat — Shromažďují se pouze data nezbytná pro provoz.

Privacy API

Přehled údajů (čl. 15 GDPR)

GET /v1/account/privacy — Vrací přehled všech uložených dat.

Terminál
curl https://qr3.app/v1/account/privacy \
-H "Authorization: Bearer qr3_sk_..."

Response:

{
"data": {
"workspace_id": "ws_xxx",
"organization_id": "org_xxx",
"account": {
"email": "[email protected]",
"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 počítá uložené záznamy. scan_records jsou skeny QR kódů, dpp_scan_records dotazy na produktové pasy přes veřejný DPP resolver. Oba obsahují IP pseudonym.

dashboard_activity_records a dashboard_document_activity_records počítají dny, kdy člen otevřel dashboard (dvě tabulky), api_operation_records denní čítače požadavků podle API klíče, operace a výsledku a webhook_delivery_records pokusy o doručení webhooků, včetně pokusů smazaných webhooků. Žádná z nich neukládá IP adresu ani User-Agent; log doručení však ukládá payload události a první kilobajt (1 KB) odpovědi příjemce. Všechny čtyři se mažou po 90 dnech UTC (usage_retention, webhook_delivery_retention).

account uvádí osobu, která stojí za požadavkem — v dashboardu přihlášenou osobu, jinak osobu, která klíč vytvořila — s e-mailem, jménem, jazykem a datem vytvoření; u Publishable Key je hodnota null. Ostatní čítače pokrývají každou další tabulku s daty účtu: produktové pasy, dokumenty DPP, soubory, identifikátory GS1, komentáře, záznamy auditu, běhy importu, členy workspace a upozornění na kvótu organizace (scan_quota_alerts). Měkce smazané řádky se počítají, protože jsou stále uložené. erasure, backup_retention a billing_records popisují, co DELETE /v1/account smaže a co ještě nějakou dobu zůstává; pii_in_export je true, protože export uvádí osobu (e-mail, jméno) — pseudonymy IP adres databázi nikdy neopouštějí.


Export dat (čl. 20 GDPR — přenositelnost údajů)

GET /v1/account/export — Stáhne všechna data jako soubor JSON.

Terminál
curl https://qr3.app/v1/account/export \
-H "Authorization: Bearer qr3_sk_..." \
-o my-data.json

Export obsahuje:

  • Všechny QR kódy (včetně smazaných)
  • Agregované statistiky skenování (žádné surové hashe IP adres)
  • Agregované dotazy na DPP pro každý produktový pas (dpp_scan_aggregates, rovněž bez hashů IP adres)
  • Statistiky využití jako agregáty (dashboard_activity_aggregates, api_operation_aggregates): aktivní dny a počet aktivních uživatelů podle kanálu dashboardu, čítače požadavků podle operace a výsledku — bez ID uživatelů a klíčů
  • Pokusy o doručení webhooků podle webhooku a typu události (webhook_delivery_aggregates), bez payloadu a odpovědi
  • Osobu, která stojí za požadavkem (account), organizaci (organization; fakturační a notifikační adresu jen pro správce organizace) a workspace (workspace)
  • Produktové pasy, metadata dokumentů DPP a souborů (ne soubory samotné), identifikátory GS1, žádosti o jejich ověření a běhy importu (dpp_passports, dpp_documents, files, gs1_identifiers, gs1_verification_requests, dpp_import_jobs)
  • Komentáře bez polí autora (code_comments), záznamy auditu jako agregáty (audit_log_aggregates) a členy podle role (member_aggregates)
  • API klíče bez ID a hashe (api_keys), webhooky bez URL a tajného klíče (webhooks) a upozornění na kvótu organizace (scan_quota_alerts)
  • Časová razítka vytvoření a změny

Publishable Keys (qr3_pk_) dostanou 403: soubor obsahuje cílové adresy a poznámky všech kódů.


Smazání účtu (čl. 17 GDPR — právo být zapomenut)

DELETE /v1/account — Okamžitě a nevratně smaže účet osoby, která stojí za požadavkem: v dashboardu přihlášenou osobu, jinak osobu, která klíč vytvořila. Žádost o smazání e-mailem vede ke stejnému smazání: provozovatel smaže přihlášení u Clerk a qr3 poté smaže účet.

Terminál
curl -X DELETE https://qr3.app/v1/account \
-H "Authorization: Bearer qr3_sk_..."

Co se stane:

  1. Organizace, které osobě patří, se smažou se všemi workspace, kódy, produktovými pasy, soubory, statistikami a protokoly, včetně jejich souborů v úložišti. Má-li taková organizace dalšího aktivního správce organizace, převezme ji místo toho ten nejdéle působící — i s daty a předplatným.
  2. Předplatné: běžící předplatné končí okamžitě, bez poměrného vrácení peněz a bez závěrečné faktury; poté se smaže zákazník ve Stripe. Faktury zůstávají ve Stripe po zákonnou dobu uchování (7 let, § 132 BAO).
  3. Týmy: členství osoby v cizích organizacích končí; tyto týmy si svá data ponechají. Komentáře osoby už neuvádějí autora, její záznamy auditu ztratí pseudonym IP adresy a user agent a API klíče, které tam vytvořila, se zneplatní.
  4. Osoba: přihlášení (Clerk) a uživatelský záznam se smažou.

Odpověď je 200 se status: "completed" a čítači organizations_deleted, organizations_transferred, memberships_removed a login_deleted. U velmi velkých organizací jeden požadavek nestačí: odpověď je pak 202 se status: "in_progress" a smazání se během několika hodin dokončí samo.

Vyžaduje Secret nebo Test Key s právem zápisu, nebo relaci v dashboardu (jakákoli role, protože jde o vlastní účet). Publishable Keys a klíče jen pro čtení dostanou 403, klíč bez osoby za ním (created_by = 'system') dostane 409. 503 znamená, že nasazení chybí tajný klíč, který smazání potřebuje; nic nebylo smazáno.


Správa souhlasů

GET /v1/account/privacy/consents — Získat aktuální souhlasy.

POST /v1/account/privacy/consents — Aktualizovat souhlasy.

Terminál
# Načtení aktuálních souhlasů
curl https://qr3.app/v1/account/privacy/consents \
-H "Authorization: Bearer qr3_sk_..."
# Vypnutí marketingových e-mailů
curl -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 }'

Pole souhlasu:

PoleVýchozíPopis
marketing_emailsfalseNewslettery a reklamní e-maily
analyticstrueAgregované statistiky používání
product_updatestrueNovinky o produktech a changelogy

Změna souhlasů vyžaduje oprávnění k zápisu: role viewer a Publishable Keys dostanou 403.


Technická implementace GDPR

Pseudonymizace IP adres (čl. 25 GDPR)

HTTP požadavek → Cloudflare Edge Worker
↓
Hlavička CF-Connecting-IP → HMAC-SHA-256(IP_HASH_SALT, účel, den UTC, IP)
↓
ip_hash (denní pseudonym) → databáze D1
↓
Původní IP adresa se nikdy neukládá

IP_HASH_SALT je dlouhodobé hlavní tajemství; účel a den UTC automaticky odvozují oddělené denní pseudonymy. Pseudonymy z různých dnů UTC nejsou přímo stejné, držitel tajemství však může pro konkrétní den znovu spočítat známého kandidáta IP adresy. Nepoužívá se denní sůl v KV ani ruční denní rotace.

Uchovávání dat (automatizované)

TarifUchovávání (Retention)
Všechny tarify90 dní

Statistiky využití (aktivita v dashboardu, čítače využití API) a logy doručení webhooků se rovněž uchovávají 90 dnů UTC: aktuální den UTC a 89 předchozích dnů. Tatáž denní úloha cron maže starší řádky (purgeOldDashboardActivity, purgeOldApiOperationUsage, purgeOldWebhookDeliveries).

Zpracovatelská smlouva (DPA) subdodavatelů

Společnost Cloudflare, Inc. zpracovává data jako zpracovatel. Smlouva DPA je k dispozici na adrese cloudflare.com/cloudflare-customer-dpa.

Cloudflare zpracovává data s lokalizačním tipem (location hint) pro region EU (mj. Frankfurt); smluvně garantovaná jurisdikce v EU není v současné době předplacena. Vzhledem k tomu, že společnost Cloudflare, Inc. sídlí v USA, platí jako základ pro předávání standardní smluvní doložky (SCC) podle čl. 46 GDPR.


Kontakt