GDPR Art. 28
Data Processing Agreement
1. Scope and definitions
This Data Processing Agreement (DPA) governs the processing of personal data by the controller (the customer) and the processor (Altvisor) under EU/EEA data protection law, including the General Data Protection Regulation (Regulation (EU) 2016/679, **GDPR**) and applicable national implementing legislation.
Capitalised terms used and not defined have the meanings given in Article 4 GDPR.
2. Parties
- **Controller:** the customer identified in the signed order form or service agreement.
- **Processor:** Altvisor, operated by Hleb Malyshau (sole trader / jednoosobowa działalność gospodarcza), plac Trzech Krzyży 10/14, 00-499 Warszawa, Poland (NIP PL5213990822), acting under the customer's documented instructions. Contact: hi@altvisor.eu.
3. Processing details
| Field | Value |
|---|---|
| Subject matter | Automated generation of WCAG 2.1 AA alt-text; storage of generated alt-text, image metadata, and audit records; production of accessibility statements and compliance audit PDFs. |
| Duration | The term of the underlying service agreement plus the technical-documentation retention period defined in §6. |
| Nature and purpose | Provide the Altvisor service to enable customer compliance with the European Accessibility Act (Directive 2019/882). |
| Categories of data subjects | Customer's website end-users (where image alt-text may indirectly reference them) and customer's authorised users of the Altvisor dashboard. |
| Categories of personal data | Account data (email, hashed password, OAuth provider IDs), usage telemetry (timestamps, costs, model identifiers), and customer-uploaded image content (processed in-memory; not persisted — see image lifecycle in §5). |
| Special categories | None processed by design. Customer must not upload images depicting health, ethnicity, religion, sexual orientation, biometrics, or other Art. 9 categories. |
4. Subprocessors
The processor engages the subprocessors listed below. The customer is notified at least 30 days before any change to this list; customer may object in good faith for documented data-protection reasons.
| Subprocessor | Purpose | Location | Transfer basis |
|---|---|---|---|
| Mistral AI (La Plateforme) | EU-hosted multimodal inference for alt-text and report/statement generation on every tier (Free, Starter, Growth, Business). The sole AI subprocessor — no customer image data is processed outside the EU on any plan. | France (EU) | Same jurisdiction (EU/EEA) — no transfer mechanism required. |
| Supabase | Managed Postgres, authentication, storage (eu-west-1) | Ireland (EU) | Same jurisdiction (EU/EEA) — no transfer mechanism required. |
| Vercel | Edge runtime, serverless functions, static asset hosting | United States (with EU edge regions including fra1) | EU-US Data Privacy Framework + Standard Contractual Clauses |
| Stripe | Subscription billing, payment processing, EU VAT collection (Stripe Tax) | Ireland (EU) — with US parent processing | Standard Contractual Clauses + EU-US Data Privacy Framework |
| Resend | Transactional email (password reset, magic link, account notifications) | United States — with EU sending region | Standard Contractual Clauses |
| PostHog | Product analytics, web vitals, error tracking, session replay, LLM observability, and application logs. EU-hosted project; ingestion proxied via /ingest/* to avoid third-party origin in the browser. | Germany (EU) — eu.i.posthog.com | Same jurisdiction (EU/EEA) — no transfer mechanism required. |
| Google Analytics (GA4) | Marketing-site traffic measurement. Loaded only on /(marketing) routes; gated by Consent Mode v2 (default 'analytics_storage: denied'); cookies dropped only after user accepts via the marketing-page consent banner. | United States | EU-US Data Privacy Framework + Standard Contractual Clauses |
| GitHub (Microsoft Corp.) | Content hosting + CMS authentication. Hosts the public marketing blog MDX and authenticates the content partner via the Keystatic GitHub App. Only public marketing content and the partner's GitHub login identity flow here — no customer or data-subject personal data. | United States | EU-US Data Privacy Framework + Standard Contractual Clauses |
This list must remain identical to the table at `/legal/subprocessors`. CI enforces parity (`__tests__/subprocessor-dpa-parity.test.ts`).
5. Image lifecycle and data minimisation
Customer-uploaded images flow through the Altvisor platform in a strictly bounded lifecycle. Customer warrants that uploaded images do not contain Article 9 GDPR special categories.
- The browser obtains a signed upload URL from the Altvisor API.
- The browser uploads the image directly to Supabase Storage.
- The server processes the upload: resize to ≤1568px, compute SHA-256 hash, deduplicate.
- The server invokes the EU-hosted AI subprocessor (Mistral, La Plateforme) to generate alt-text.
- The server stores the generated alt-text, image hash, and dimensions in the Altvisor database.
- **The server deletes the image file from Supabase Storage.** Only the hash, dimensions, and alt-text remain.
The original image is never persisted beyond the duration of step 5. Subprocessor calls forward only the bytes necessary for inference and rely on the subprocessor's documented data-retention posture (Mistral: ≤30 days for abuse review). Customer accepts the residual retention at the subprocessor layer.
6. Retention
| Data class | Retention | Basis |
|---|---|---|
| Alt-text records (incl. version history via `superseded_by`) | Duration of the service + 5 years after termination | EAA Annex IV — technical documentation supporting the self-assessment |
| Audit reports (PDF + ledger row) | 5 years from generation | EAA Annex IV |
| Audit log (every state-changing action) | Duration of the service + 5 years | EAA Annex IV + GDPR Art. 5(2) accountability |
| Account data | Duration of the service + 30 days for orphan-cleanup pg_cron | Service delivery |
| Demo rate-limit bucket counters | ≤48 hours | Abuse prevention; deletes hourly |
| Daily-rotating IP salt | ≤2 days | Salt rotation cycle |
| Raw IP addresses | **Never stored.** Hashed with the daily salt at receipt and discarded. | Data minimisation (Art. 5(1)(c) GDPR) |
7. Cookies and tracking inventory
| Cookie | Purpose | Attributes | Retention | Lawful basis (ePrivacy Art. 5(3)) |
|---|---|---|---|---|
| `sb-<project-ref>-auth-token` | Session token issued by Supabase Auth | HttpOnly, Secure, SameSite=Lax, Path=/ | 30 days (sliding) | Strictly necessary — sign-in required for service |
| `altvisor_locale` | User-selected interface language | HttpOnly, Secure, SameSite=Lax, Path=/, 1 year | 1 year | Strictly necessary — user-selected preference |
| `altvisor_demo_session` | Per-session rate-limit bucket on the anonymous demo | HttpOnly, Secure, SameSite=Lax, Path=/api/v1/demo, 24 hours | 24 hours | Strictly necessary — abuse prevention |
| `altvisor_ga_consent` | Records whether the user accepted or rejected Google Analytics on marketing pages | Secure, SameSite=Lax, Path=/, 1 year | 1 year | Strictly necessary — records the user's own consent choice (CNIL guidance) |
| `ph_*` (PostHog) | Anonymous distinct-id + session identifier for product analytics & error tracking. EU project; ingestion proxied via /ingest/* (no third-party origin in the browser). | Secure, SameSite=Lax, Path=/ | 1 year (session id 30 min) | Legitimate interest — service-improvement analytics, EU-hosted, no advertising use; reviewed under GDPR Art. 6(1)(f) |
| `_ga`, `_ga_<container_id>` (Google Analytics 4) | Visitor identifier + session identifier on marketing pages only. Dropped only after user accepts via the marketing-page consent banner. | SameSite=Lax, Path=/, 2 years (`_ga`) / 90 days (`_ga_*`) | Per Google Analytics defaults | Consent (ePrivacy Art. 5(3)) — Consent Mode v2 default = denied; cookies only set on explicit Accept |
Analytics posture: PostHog runs on legitimate interest (EU-hosted, no advertising use, ingestion proxied through same origin). Google Analytics runs on consent only — Consent Mode v2 default `analytics_storage: 'denied'` means cookieless pings until the user accepts via the marketing-page banner. No advertising cookies, no third-party trackers beyond what is disclosed in §4.
8. Security measures
- All data in transit: TLS 1.3 (Caddy / Vercel edge / Supabase).
- All data at rest: Postgres encryption at rest (Supabase-managed).
- Authentication: Email + password (bcrypt via Supabase), federated OAuth (Google, GitHub), magic-link (Supabase OTP). Password minimum length: 12 characters.
- Authorisation: Row-Level Security on every customer-scoped table; service-role access restricted to signup bootstrap, webhooks, and `pg_cron` jobs.
- Audit log: append-only, `INSERT`-only RLS — `UPDATE` and `DELETE` blocked except via service role.
- Secret management: environment-variable injection at deploy time; no secrets in source.
- Vulnerability response: Dependabot weekly; error tracking and alerting via PostHog (EU-hosted).
9. Subject rights
The processor will assist the controller in fulfilling subject-access, rectification, erasure, restriction, portability, and objection requests in line with Articles 12–22 GDPR. Tooling:
- Organisation hard-delete (from account settings) cascades through all customer-scoped tables and emits a final usage-report email.
- Data access, rectification, and export requests are handled on request via hi@altvisor.eu within the statutory time limits.
10. Incident notification
The processor notifies the controller without undue delay (no later than 72 hours) of any personal-data breach, as defined in Art. 4(12) GDPR, including the categories and approximate number of data subjects, the likely consequences, and the mitigation measures taken.
11. Signatures
| Party | Name | Title | Date | Signature |
|---|---|---|---|---|
| Controller | ||||
| Processor |
*This template is maintained in `apps/web/legal/dpa-template.md`. Any change to the subprocessor table must be made in lockstep with `apps/web/legal/subprocessors.ts` — the CI parity test will fail otherwise.*