GDPR & dataskydd
Dataskydd genom design
qr3.app är byggt från grunden för att vara GDPR-kompatibelt:
- IP-pseudonymisering — IP-adresser omvandlas omedelbart till HMAC-SHA-256-UTC-dagspseudonymer i Edge-workern. Den ursprungliga IP-adressen lagras aldrig; pseudonymen är fortfarande en personuppgift.
- Dataminimering — Endast de uppgifter som är nödvändiga för driften samlas in.
Privacy-API
Sammanfattning av personuppgifter (Art. 15 GDPR)
GET /v1/account/privacy — Returnerar en översikt över alla sparade uppgifter.
curl https://qr3.app/v1/account/privacy \ -H "Authorization: Bearer qr3_sk_..."Svar:
{ "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 räknar de sparade posterna. scan_records är skanningar av QR-koder, dpp_scan_records är förfrågningar till produktpass via den offentliga DPP-resolvern. Båda innehåller IP-pseudonymet.
dashboard_activity_records och dashboard_document_activity_records räknar de dagar då en medlem öppnade dashboarden (två tabeller), api_operation_records de dagliga anropsräknarna per API-nyckel, operation och utfall, och webhook_delivery_records leveransförsöken för webhooks, även för raderade webhooks. Ingen av dem lagrar någon IP-adress eller User-Agent; leveransloggen lagrar däremot händelsens payload och de första 1 KB av mottagarens svar. Alla fyra raderas efter 90 UTC-dagar (usage_retention, webhook_delivery_retention).
account anger personen bakom begäran — i dashboarden den inloggade personen, annars den person som skapade nyckeln — med e-post, namn, språk och skapandedatum; för en Publishable Key är värdet null. De övriga räknarna täcker varje ytterligare tabell med kontots data: produktpass, DPP-dokument, filer, GS1-identifierare, kommentarer, granskningsposter, importkörningar, workspace-medlemmar och organisationens kvotmeddelanden (scan_quota_alerts). Mjukt raderade rader räknas, eftersom de fortfarande är lagrade. erasure, backup_retention och billing_records beskriver vad DELETE /v1/account raderar och vad som finns kvar en tid; pii_in_export är true eftersom exporten anger personen (e-post, namn) — IP-pseudonymer lämnar aldrig databasen.
Dataexport (Art. 20 GDPR — dataportabilitet)
GET /v1/account/export — Laddar ner alla data som en JSON-fil.
curl https://qr3.app/v1/account/export \ -H "Authorization: Bearer qr3_sk_..." \ -o my-data.jsonExporten innehåller:
- Alla QR-koder (inklusive raderade)
- Aggregerad skanningsstatistik (inga råa IP-hashar)
- Aggregerade DPP-förfrågningar per produktpass (
dpp_scan_aggregates, inte heller några IP-hashar) - Användningsstatistik som aggregat (
dashboard_activity_aggregates,api_operation_aggregates): aktiva dagar och antal aktiva användare per dashboardkanal, anropsräknare per operation och utfall — utan användar- och nyckel-ID:n - Leveransförsök för webhooks per webhook och händelsetyp (
webhook_delivery_aggregates), utan payload och svar - Personen bakom begäran (
account), organisationen (organization; fakturerings- och aviseringsadress endast för organisationsadministratörer) och workspacet (workspace) - Produktpass, metadata för DPP-dokument och filer (inte själva filerna), GS1-identifierare, ansökningar om att verifiera dem och importkörningar (
dpp_passports,dpp_documents,files,gs1_identifiers,gs1_verification_requests,dpp_import_jobs) - Kommentarer utan författarfält (
code_comments), granskningsposter som aggregat (audit_log_aggregates) och medlemmar per roll (member_aggregates) - API-nycklar utan ID och hash (
api_keys), webhooks utan URL och hemlighet (webhooks) och organisationens kvotmeddelanden (scan_quota_alerts) - Tidsstämplar för skapande och ändring
Publishable Keys (qr3_pk_) får 403: filen innehåller måladresser och anteckningar för alla koder.
Radera konto (Art. 17 GDPR — rätten att bli bortglömd)
DELETE /v1/account — Raderar kontot för personen bakom begäran, omedelbart och oåterkalleligt: i dashboarden den inloggade personen, annars den person som skapade nyckeln. En raderingsbegäran via e-post leder till samma radering: operatören raderar inloggningen hos Clerk, och därefter raderar qr3 kontot.
curl -X DELETE https://qr3.app/v1/account \ -H "Authorization: Bearer qr3_sk_..."Vad som händer:
- Organisationer som tillhör personen raderas med alla workspaces, koder, produktpass, filer, statistik och loggar, inklusive deras filer i lagringen. Har en sådan organisation en annan aktiv organisationsadministratör tar i stället den som varit administratör längst över organisationen med data och prenumeration.
- Prenumeration: en pågående prenumeration upphör omedelbart, utan proportionell återbetalning och utan slutfaktura; därefter raderas Stripe-kunden. Fakturor finns kvar hos Stripe under den lagstadgade lagringstiden (7 år, § 132 BAO).
- Team: personens medlemskap i andra organisationer upphör; dessa team behåller sina data. Personens kommentarer anger inte längre någon författare, personens granskningsposter förlorar IP-pseudonym och user agent, och de API-nycklar som personen skapade där återkallas.
- Personen: inloggningen (Clerk) och användarposten raderas.
Svaret är 200 med status: "completed" och räknarna organizations_deleted, organizations_transferred, memberships_removed och login_deleted. För mycket stora organisationer räcker inte en begäran: svaret är då 202 med status: "in_progress", och raderingen slutförs automatiskt inom några timmar.
Kräver en Secret Key eller Test Key med skrivbehörighet eller en dashboard-session (vilken roll som helst, eftersom det gäller personens eget konto). Publishable Keys och skrivskyddade nycklar får 403, en nyckel utan person bakom (created_by = 'system') får 409. 503 betyder att driftsättningen saknar en hemlighet som raderingen behöver; ingenting har raderats.
Hantera samtycken
GET /v1/account/privacy/consents — Hämta aktuella samtycken.
POST /v1/account/privacy/consents — Uppdatera samtycken.
# Hämta aktuella samtyckencurl https://qr3.app/v1/account/privacy/consents \ -H "Authorization: Bearer qr3_sk_..."
# Inaktivera marknadsföringsmejlcurl -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 }'Samtyckesfält:
| Fält | Standard | Beskrivning |
|---|---|---|
marketing_emails | false | Nyhetsbrev och reklammejl |
analytics | true | Aggregerad användningsstatistik |
product_updates | true | Produktnyheter och ändringsloggar |
Att ändra samtycken kräver skrivbehörighet: rollen viewer och Publishable Keys får 403.
Teknisk GDPR-implementering
IP-pseudonymisering (Art. 25 GDPR)
HTTP-begäran → Cloudflare Edge Worker ↓CF-Connecting-IP-rubrik → HMAC-SHA-256(IP_HASH_SALT, syfte, UTC-dag, IP) ↓ip_hash (daglig pseudonym) → D1-databas ↓Den ursprungliga IP-adressen lagras aldrigIP_HASH_SALT är en långlivad huvudhemlighet; syfte och UTC-dag härleder automatiskt separata dagliga pseudonymer. Pseudonymer från olika UTC-dagar är inte direkt lika, men innehavaren av hemligheten kan beräkna om en känd IP-kandidat för en viss dag. Varken KV-dagssalt eller manuell daglig rotation används.
Datalagring (automatiserad)
| Abonnemang | Lagringstid |
|---|---|
| Alla abonnemang | 90 dagar |
Även användningsstatistik (dashboard-aktivitet, API-användningsräknare) och webhook-leveransloggar sparas i 90 UTC-dagar: den aktuella UTC-dagen och de 89 föregående dagarna. Samma dagliga cron-jobb raderar äldre rader (purgeOldDashboardActivity, purgeOldApiOperationUsage, purgeOldWebhookDeliveries).
Underbiträdesavtal (DPA)
Cloudflare, Inc. behandlar uppgifter som personuppgiftsbiträde. Underbiträdesavtalet (DPA) finns tillgängligt på cloudflare.com/cloudflare-customer-dpa.
Cloudflare behandlar uppgifter med en platshänvisning till EU-regionen (bland annat Frankfurt); en avtalsenligt garanterad EU-jurisdiktion är för närvarande inte bokad. Eftersom Cloudflare, Inc. är baserat i USA tillämpas standardavtalsklausuler (SCC) i enlighet med art. 46 GDPR som överföringsmekanism.
Kontakt
- Dataskyddsombud: [email protected]
- Personuppgiftsbiträdesavtal (PUB-avtal): [email protected] (på begäran)
- Integritetspolicy: qr3.app/de/legal/datenschutz