# Registre des traitements (RGPD Article 30)

**Doc type:** Mandatory internal RGPD register. Presented to CNIL on request.
**Last reviewed:** 2026-05-26 (Supabase EU cutover)
**Controller:** [REGISTERED COMPANY NAME], SIRET [SIRET], registered at [REGISTERED ADDRESS], France.
**Contact for RGPD requests:** support@win2linux.org

This register documents every processing activity carried out by the controller, as required by Article 30 of Regulation (EU) 2016/679 (RGPD).

## Cross-reference

- Sub-processor list: [`sub-processors.md`](sub-processors.md)
- Retention schedule: [`data-retention-policy.md`](data-retention-policy.md)
- DPIA (Activity 3): [`dpia.md`](dpia.md)
- Security measures: [`security-statement.md`](security-statement.md)
- Public-facing notice: [`/privacy.html`](../privacy.html)

---

## Activity 1 — Learner account registration + authentication

| Field | Value |
|---|---|
| **Purpose** | Create + authenticate a learner account; serve the course; issue the certificate |
| **Categories of data subjects** | Individual learners (B2C) + enterprise learners (B2B cohort) |
| **Categories of personal data** | Email, name, bcrypt password hash, TOTP secret (encrypted at rest), JWT session ID, IP hash, user-agent hash, MFA enrolment timestamp |
| **Categories of recipients** | Internal Netlify Functions; no external recipients |
| **Storage location** | Supabase Postgres EU (Frankfurt) — `users`, `sessions` tables |
| **Transfers outside EU** | None for storage. Authentication emails routed via Resend (EU residency, see Activity 5) |
| **Retention** | Account lifetime + 5 years post-deletion request (training-records obligation under Code du Travail Art. L6353-9) |
| **Legal basis** | Article 6(1)(b) RGPD — performance of contract |
| **Technical + organisational security** | TLS in transit; AES-256 at rest (Supabase); bcrypt cost factor 12; TOTP secret encrypted with separate KMS-managed key; rate-limited login (5 attempts → 15-min lockout) |

## Activity 2 — Course progress tracking

| Field | Value |
|---|---|
| **Purpose** | Persist learner progress (quizzes, labs, final assessment); gate the completion certificate; show personal dashboard |
| **Categories of data subjects** | Learners |
| **Categories of personal data** | Learner email, learner UUID, module completion timestamps, quiz scores (0–100), lab scene completion booleans, final assessment score, certificate-issued timestamp |
| **Categories of recipients** | Internal functions; for enterprise learners — visible to the customer's authorised managers (see Activity 3) |
| **Storage location** | Supabase Postgres EU (Frankfurt) — `progress` table |
| **Transfers outside EU** | None |
| **Retention** | 5 years post-completion (Qualiopi indicator 32 — audit-trail integrity) |
| **Legal basis** | Article 6(1)(b) RGPD — performance of contract |
| **Erasure handling** | PII fields (email, learner_id, learner_name) redacted on RGPD erasure request; aggregate score row retained for Qualiopi audit |

## Activity 3 — Cohort progress (enterprise managers)

| Field | Value |
|---|---|
| **Purpose** | Allow employer to track training completion for their funded cohort, as required by their training obligation under Code du Travail |
| **Categories of data subjects** | Enterprise learners (whose progress is shared with their employer) |
| **Categories of personal data** | Same as Activity 2 + completion %, time spent per module, last activity timestamp |
| **Categories of recipients** | Enterprise managers belonging to the same customer; access scoped via RLS policy `progress_manager_scope` on customer name |
| **Storage location** | Supabase Postgres EU (Frankfurt) |
| **Transfers outside EU** | None |
| **Retention** | 5 years post-completion (Qualiopi) |
| **Legal basis** | Article 6(1)(b) RGPD — performance of contract (between customer + win2linux) |
| **DPIA** | YES — see [`dpia.md`](dpia.md). Cohort surveillance + automated scoring cross the CNIL DPIA threshold |
| **Learner notice** | Onboarding email + privacy notice (section 6 "Enterprise / Qualiopi learners") explicitly informs learners that their progress is shared with their employer |

## Activity 4 — Devis emission + invoice processing (B2B)

| Field | Value |
|---|---|
| **Purpose** | Generate a binding price quote, process a signed bon de commande, issue a SEPA invoice, take payment, provision cohort access |
| **Categories of data subjects** | Buyer's billing contact (procurement officer, finance lead, manager) |
| **Categories of personal data** | Contact email, contact name, company SIRET, company legal name, billing address, seat count, total amount, Stripe customer ID, hosted invoice URL, payment timestamp |
| **Categories of recipients** | Stripe Payments Europe Ltd (Ireland) for invoice + payment; internal functions |
| **Storage location** | Supabase Postgres EU (Frankfurt) — `quotes`, `stripe_events` tables. PDF artefacts in Supabase Storage (EU) buckets `devis-pdfs` + `po-uploads` |
| **Transfers outside EU** | Stripe Payments Europe (Ireland) — EU-internal. Stripe US affiliate may access payment metadata under the Stripe DPA + EU SCCs |
| **Retention** | 10 years (Code de commerce Art. L123-22 — accounting records); `stripe_events` row never deleted (financial audit trail) |
| **Legal basis** | Article 6(1)(b) RGPD — performance of contract; Article 6(1)(c) — legal obligation (commercial accounting) |

## Activity 5 — Transactional email

| Field | Value |
|---|---|
| **Purpose** | Magic-link delivery; password reset; receipt; devis link; invoice notification; completion-certificate email |
| **Categories of data subjects** | Learners, managers, buyers |
| **Categories of personal data** | Email address, name (where personalised), one-time token in URL, message content |
| **Categories of recipients** | Resend (Delaware US, with EU residency option enabled for our account) |
| **Storage location** | Resend (EU region — Frankfurt) |
| **Transfers outside EU** | Resend is US-headquartered. Account configured for EU residency; Resend DPA + EU SCCs in place. CLOUD Act residual risk documented in [`sub-processors.md`](sub-processors.md) |
| **Retention** | 30 days delivery logs at Resend; bounce/complaint suppression list retained indefinitely (`email_suppression` table) for delivery hygiene |
| **Legal basis** | Article 6(1)(b) RGPD — performance of contract |

## Activity 6 — Public marketing site + analytics

| Field | Value |
|---|---|
| **Purpose** | Operate the marketing site; measure aggregate traffic |
| **Categories of data subjects** | Site visitors |
| **Categories of personal data** | None directly identifiable in standard mode (Plausible EU operates cookieless, anonymised IP hashing). No cross-site tracking |
| **Categories of recipients** | Plausible (EU, Germany) — if/when enabled. None currently |
| **Storage location** | Plausible EU (Frankfurt) |
| **Transfers outside EU** | None |
| **Retention** | 24 months aggregate; no individual session reconstruction possible |
| **Legal basis** | Article 6(1)(f) RGPD — legitimate interest. Privacy impact: very low (no cookies, no individual identification) |

## Activity 7 — Support inbox + help bot

| Field | Value |
|---|---|
| **Purpose** | Answer learner support requests; provide AI-assisted help (Tux bot) grounded in course content |
| **Categories of data subjects** | Learners who initiate support |
| **Categories of personal data** | Email, message content, optional course context (current module, last error) |
| **Categories of recipients** | Internal email inbox; for the Tux bot — Anthropic Claude API (US) inference only, no training |
| **Storage location** | Inbox: standard EU email provider. Bot conversation logs: Supabase EU |
| **Transfers outside EU** | Anthropic Claude API (US) — covered by Anthropic Zero Data Retention DPA. Inputs not used for model training. CLOUD Act residual risk documented |
| **Retention** | Support thread: 3 years. Bot conversation logs: 90 days, then anonymised |
| **Legal basis** | Article 6(1)(b) RGPD — performance of contract |

---

## Joint controller / processor relationships

- **win2linux ↔ each enterprise customer** for Activity 3 (cohort progress sharing). win2linux is the controller for the platform; the customer is the joint controller for the cohort dataset within their scope. A short joint-controller addendum is included in the convention de formation.
- All other listed services in [`sub-processors.md`](sub-processors.md) are sub-processors under a Data Processing Agreement (DPA) with EU SCCs where the entity is non-EU.

## Procedure for data subject requests

1. Request arrives at `support@win2linux.org`.
2. Identity verified (matching email on record + one of: signed declaration, recent transaction reference, magic-link via the registered email).
3. Logged with timestamp in operator's CRM.
4. Routed to the relevant endpoint:
   - **Access / portability** → `gdpr-export.mjs` produces a JSON archive within 7 days.
   - **Erasure** → `gdpr-erase.mjs` redacts PII fields across `users`, `progress`, `quotes`; preserves audit-trail rows.
   - **Rectification** → handled manually for non-self-service fields (name on certificate, billing address).
   - **Objection / restriction** → manual review.
5. Response within 30 days (extendable to 90 days for complex requests under Art. 12(3); justified in writing).

## Breach notification procedure

1. On suspected or confirmed breach: operator escalates to controller within 1 hour of discovery.
2. Severity classification (high / medium / low) within 12 hours.
3. **HIGH** (e.g. credential exposure, mass-data exfiltration): CNIL notified within 72 hours via <https://notifications.cnil.fr> + affected data subjects notified by email within 5 working days.
4. **MEDIUM / LOW**: documented internally; CNIL notification only if risk threshold met.
5. Post-incident review + register update.

## Updates to this register

Material changes (new processing activity, new sub-processor, new transfer outside EU) → update this document + sub-processor list + privacy.html in the same change. Maintain a changelog at the bottom.

## Changelog

| Date | Change |
|---|---|
| 2026-05-26 | Initial production version. Supabase EU (Frankfurt) added as primary storage. Airtable retained as legacy fallback during cutover; will be removed from register once decommissioned. |
