Skip to content

GDPR & tietosuoja

Sisäänrakennettu tietosuoja

qr3.app on rakennettu alusta alkaen GDPR-yhteensopivaksi:

  • IP-pseudonymisointi — IP-osoitteet muunnetaan Edge-Workerissa välittömästi HMAC-SHA-256 UTC-päiväpseudonyymeiksi. Alkuperäistä IP-osoitetta ei koskaan tallenneta; pseudonymi on edelleen henkilötieto.
  • Tietojen minimointi — Keräämme vain toiminnan kannalta välttämättömät tiedot.

Privacy-API

Tietojen yhteenveto (GDPR 15 artikla)

GET /v1/account/privacy — Palauttaa yhteenvedon kaikista tallennetuista tiedoista.

Terminal window
curl https://qr3.app/v1/account/privacy \
-H "Authorization: Bearer qr3_sk_..."

Vastaus:

{
"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 laskee tallennetut merkinnät. scan_records ovat QR-koodien skannauksia, dpp_scan_records tuotepasseihin julkisen DPP-resolverin kautta tehtyjä hakuja. Molemmat sisältävät IP-pseudonyymin.

dashboard_activity_records ja dashboard_document_activity_records laskevat päivät, jolloin jäsen avasi hallintapaneelin (kaksi taulua), api_operation_records päivittäiset pyyntölaskurit API-avaimen, toiminnon ja tuloksen mukaan ja webhook_delivery_records webhookien toimitusyritykset, myös poistettujen webhookien. Mikään niistä ei tallenna IP-osoitetta eikä User-Agent-tietoa; toimituslokiin tallennetaan kuitenkin tapahtuman payload ja vastaanottajan vastauksen ensimmäinen kilotavu (1 KB). Kaikki neljä poistetaan 90 UTC-päivän jälkeen (usage_retention, webhook_delivery_retention).

account nimeää pyynnön takana olevan henkilön — hallintapaneelissa kirjautuneen henkilön, muuten avaimen luoneen henkilön — sähköpostiosoitteineen, nimineen, kielineen ja luontipäivineen; Publishable Keyn kohdalla arvo on null. Muut laskurit kattavat jokaisen muun tilin tietoja sisältävän taulun: tuotepassit, DPP-asiakirjat, tiedostot, GS1-tunnisteet, kommentit, auditointimerkinnät, tuontiajot, workspacen jäsenet ja organisaation kiintiöilmoitukset (scan_quota_alerts). Pehmeästi poistetut rivit lasketaan mukaan, koska ne ovat yhä tallessa. erasure, backup_retention ja billing_records kuvaavat, mitä DELETE /v1/account poistaa ja mitä jää vielä joksikin aikaa; pii_in_export on true, koska vienti nimeää henkilön (sähköposti, nimi) — IP-pseudonyymit eivät koskaan poistu tietokannasta.


Tietojen siirtäminen (GDPR 20 artikla — Oikeus siirtää tiedot järjestelmästä toiseen)

GET /v1/account/export — Lataa kaikki tiedot JSON-tiedostona.

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

Vienti sisältää:

  • Kaikki QR-koodit (mukaan lukien poistetut)
  • Aggregoidut skannaustilastot (ei raakoja IP-tiivisteitä)
  • Aggregoidut DPP-haut tuotepassikohtaisesti (dpp_scan_aggregates, ei myöskään IP-tiivisteitä)
  • Käyttötilastot koosteina (dashboard_activity_aggregates, api_operation_aggregates): aktiiviset päivät ja aktiivisten käyttäjien määrä hallintapaneelin kanavaa kohden, pyyntölaskurit toiminnon ja tuloksen mukaan — ilman käyttäjä- ja avaintunnisteita
  • Webhookien toimitusyritykset webhookia ja tapahtumatyyppiä kohden (webhook_delivery_aggregates), ilman payloadia ja vastausta
  • Pyynnön takana olevan henkilön (account), organisaation (organization; laskutus- ja ilmoitusosoite vain organisaation ylläpitäjille) ja workspacen (workspace)
  • Tuotepassit, DPP-asiakirjojen ja tiedostojen metatiedot (ei itse tiedostoja), GS1-tunnisteet, niiden vahvistushakemukset ja tuontiajot (dpp_passports, dpp_documents, files, gs1_identifiers, gs1_verification_requests, dpp_import_jobs)
  • Kommentit ilman tekijäkenttiä (code_comments), auditointimerkinnät koosteina (audit_log_aggregates) ja jäsenet rooleittain (member_aggregates)
  • API-avaimet ilman tunnusta ja tiivistettä (api_keys), webhookit ilman URL-osoitetta ja salaisuutta (webhooks) sekä organisaation kiintiöilmoitukset (scan_quota_alerts)
  • Luonti- ja muokkausaikaleimat

Publishable Keys -avaimet (qr3_pk_) saavat vastauksen 403: tiedosto sisältää kaikkien koodien kohdeosoitteet ja muistiinpanot.


Tilin poistaminen (GDPR 17 artikla — Oikeus tulla unohdetuksi)

DELETE /v1/account — Poistaa pyynnön takana olevan henkilön tilin välittömästi ja peruuttamattomasti: hallintapaneelissa kirjautuneen henkilön, muuten avaimen luoneen henkilön. Sähköpostitse tehty poistopyyntö johtaa samaan poistoon: palvelun ylläpitäjä poistaa kirjautumisen Clerkistä, minkä jälkeen qr3 poistaa tilin.

Terminal window
curl -X DELETE https://qr3.app/v1/account \
-H "Authorization: Bearer qr3_sk_..."

Mitä tapahtuu:

  1. Henkilön omistamat organisaatiot poistetaan kaikkine workspaceineen, koodeineen, tuotepasseineen, tiedostoineen, tilastoineen ja lokeineen, myös niiden tiedostot tallennustilassa. Jos tällaisella organisaatiolla on toinen aktiivinen organisaation ylläpitäjä, organisaation ottaa sen sijaan haltuunsa pisimpään mukana ollut ylläpitäjä tietoineen ja tilauksineen.
  2. Tilaus: voimassa oleva tilaus päättyy välittömästi ilman suhteellista hyvitystä ja ilman loppulaskua; sen jälkeen Stripe-asiakas poistetaan. Laskut säilyvät Stripessä lakisääteisen säilytysajan (7 vuotta, § 132 BAO).
  3. Tiimit: henkilön jäsenyydet muissa organisaatioissa päättyvät; nämä tiimit säilyttävät tietonsa. Henkilön kommentit eivät enää nimeä tekijää, hänen auditointimerkinnöistään poistetaan IP-pseudonyymi ja user agent, ja hänen sinne luomansa API-avaimet mitätöidään.
  4. Henkilö: kirjautuminen (Clerk) ja käyttäjätietue poistetaan.

Vastaus on 200, jossa status: "completed" ja laskurit organizations_deleted, organizations_transferred, memberships_removed ja login_deleted. Hyvin suurissa organisaatioissa yksi pyyntö ei riitä: vastaus on silloin 202, jossa status: "in_progress", ja poisto valmistuu itsestään muutamassa tunnissa.

Vaatii kirjoitusoikeudella varustetun Secret- tai Test Key -avaimen tai hallintapaneelin istunnon (mikä tahansa rooli, koska kyse on omasta tilistä). Publishable Keys -avaimet ja vain luku -avaimet saavat vastauksen 403, avain, jonka takana ei ole henkilöä (created_by = 'system'), saa vastauksen 409. 503 tarkoittaa, että käyttöönotosta puuttuu poistossa tarvittava salaisuus; mitään ei poistettu.


Suostumusten hallinta

GET /v1/account/privacy/consents — Hae nykyiset suostumukset.

POST /v1/account/privacy/consents — Päivitä suostumukset.

Terminal window
# Nykyisten suostumusten haku
curl https://qr3.app/v1/account/privacy/consents \
-H "Authorization: Bearer qr3_sk_..."
# Markkinointisähköpostien poistaminen käytöstä
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 }'

Suostumuskentät:

KenttäOletusKuvaus
marketing_emailsfalseUutiskirjeet ja mainossähköpostit
analyticstrueAggregoidut käyttötilastot
product_updatestrueTuoteuutiset ja muutoslokit

Suostumusten muuttaminen vaatii kirjoitusoikeudet: rooli viewer ja Publishable Keys -avaimet saavat vastauksen 403.


Tekninen GDPR-toteutus

IP-pseudonymisointi (GDPR 25 artikla)

HTTP-pyyntö → Cloudflare Edge Worker
↓
CF-Connecting-IP-otsake → HMAC-SHA-256(IP_HASH_SALT, tarkoitus, UTC-päivä, IP)
↓
ip_hash (päiväpseudonymi) → D1-tietokanta
↓
Alkuperäistä IP-osoitetta ei koskaan tallenneta

IP_HASH_SALT on pitkäikäinen pääsalaisuus; tarkoitus ja UTC-päivä johtavat automaattisesti erilliset päiväpseudonyymit. Eri UTC-päivien pseudonyymit eivät ole suoraan samoja, mutta salaisuuden haltija voi laskea tunnetun IP-ehdokkaan uudelleen tietylle päivälle. KV-päiväsuolaa tai käsin tehtävää päivittäistä kiertoa ei käytetä.

Tietojen säilytysaika (automaattinen)

TilausSäilytysaika
Kaikki tilaukset90 päivää

Myös käyttötilastot (hallintapaneelin aktiivisuus, API:n käyttölaskurit) ja webhook-toimituslokit säilytetään 90 UTC-päivää: kuluva UTC-päivä ja 89 edeltävää päivää. Sama päivittäinen cron-tehtävä poistaa vanhemmat rivit (purgeOldDashboardActivity, purgeOldApiOperationUsage, purgeOldWebhookDeliveries).

Alihankkijoiden tietojenkäsittelysopimus (Sub-Processor DPA)

Cloudflare, Inc. käsittelee tietoja henkilötietojen käsittelijänä. Tietojenkäsittelysopimus (DPA) on saatavilla osoitteessa cloudflare.com/cloudflare-customer-dpa.

Cloudflare käsittelee tietoja EU-alueelle osoittavalla sijaintivihjeellä (mm. Frankfurt); sopimuksellisesti taattua EU-lainkäyttöaluetta ei ole tällä hetkellä varattu. Koska Cloudflare, Inc. sijaitsee Yhdysvalloissa, tietojen siirron perusteena sovelletaan GDPR 46 artiklan mukaisia vakiolausekkeita (SCC).


Yhteystiedot