ADR-005: Data Retention
Source: ADR-005-data-retention-privacy.md
ADR-005: Data Retention & Privacy Design — Minimal PII, Time-Bounded Storage
Date: 2026-04-09 | Amended: 2026-04-10 (v2.0 Cloudflare adaptation)
Status: Accepted (amended)
Deciders: Platform Engineering Lead, Security Lead, DPO (if applicable)
CODITECT Classification: Architecture Decision Record · A6
Context
The scheduling tool collects the following data from participants:
- Display name (free-text, may contain real name — participant's choice)
- Slot availability responses (available / tentative / unavailable per slot)
- Edit token (UUID, stored as PBKDF2 hash + salt)
- Browser cookie (edit token, HttpOnly, scoped to poll path)
From organizers (optional):
- Email address (for result notification — optional at poll creation)
- Organizer PIN (6-digit, stored as PBKDF2 hash + salt)
The tool operates in CODITECT's regulated enterprise context, which spans jurisdictions including EU (GDPR), Brazil (LGPD), and US (CCPA for California-based participants).
Key questions to resolve:
1. How long should poll data be retained?
2. What constitutes PII in this context, and how should it be handled?
3. How do we support a right-to-erasure request if a participant wants their response deleted?
4. Should IP addresses be logged or stored?
Decision
D1: Retention Policy
- Polls have a maximum lifetime of
POLL_EXPIRY_DEFAULT_DAYS(default: 14 days, configurable by organizer up to 30 days) - After expiry, poll status is set to
EXPIREDby theexpire-pollscron job - A
purge-pollscron job hard-deletes all poll data (cascade: slots, responses, slot_responses) whereexpires_at < now() - POLL_PURGE_GRACE_DAYS(default grace: 30 days) - No archiving — data is permanently deleted, not moved to cold storage
- Organizer email (if provided) is deleted with the poll record — not retained separately
D2: PII Classification
- Display name: Treat as potentially personal data. Display in UI with a note: "Use a nickname if you prefer not to share your real name."
- Organizer email: Personal data. Stored only if provided. Used only for result notification. Not shared with participants.
- Edit token: Pseudonymous identifier. Stored as PBKDF2 hash + salt — raw value only in browser cookie.
- IP addresses: Not stored. Used transiently by the rate limiter (KV fixed-window key for general limits; Durable Object sliding-window for PIN verification) with TTLs of 60s–15min. Not written to any persistent log or DB table.
v2.0 amendment: bcrypt replaced by PBKDF2 (100k iterations, SHA-256) — bcrypt unavailable in Workers runtime. Redis replaced by KV (general rate limiting) and Durable Objects (PIN lockout). IP addresses are never persisted in any Cloudflare primitive.
D3: Right to Erasure (GDPR Art. 17 / LGPD Art. 18)
Participants can delete their own response via the organizer management page or by contacting the organizer (who has the management URL). The organizer can delete individual responses. On poll expiry + purge, all data is automatically erased. This design avoids a complex erasure API by making the default retention so short (14–44 days maximum) that erasure requests are likely resolved by natural expiry.
D4: Logging PII
Structured logs must not contain display names in plaintext. Log displayName_length (integer) instead. Poll slugs may appear in logs (they are not PII — they are pseudonymous routing tokens). Organizer email must not appear in logs.
Consequences
Positive:
- Short default retention (14 days + 30-day grace = 44 days maximum) minimises GDPR/LGPD exposure surface
- Hard delete (not soft delete or archival) means no residual PII in backup snapshots after the backup retention window
- No IP storage eliminates a common GDPR compliance concern (IP addresses are personal data under GDPR recital 30)
- Participant-visible note about nickname reduces likelihood of real names being submitted
- Erasure-by-expiry model avoids building a complex DSAR (Data Subject Access Request) workflow for v1.0
Negative:
- No audit trail of past polls after purge — organizers who need records must export before expiry
- If organizer email is required in a future version, the privacy model must be re-evaluated (currently optional, so most polls have no organizer PII beyond the hashed PIN)
- Backup retention policy must align — if DB backups are kept for 90 days, purged poll data technically persists in backups. Documented as a known gap; recommend backup encryption and restricted access rather than shorter backup retention.
Regulatory notes:
- Under GDPR, the
legitimate interestlawful basis is appropriate for this tool in an enterprise scheduling context. Participants are acting in a professional capacity. Documented in CODITECT's Article 30 Records of Processing Activities (RoPA). - CCPA: No sale of personal data. No sharing for cross-context behavioural advertising. Privacy policy must reflect this.
- LGPD:
legitimate interestbasis available (Art. 7 IX). Brazilian participants must be able to request erasure — handled by the organizer-delete pathway and natural expiry.
[LEGAL REVIEW REQUIRED] — Confirm lawful basis selection and RoPA entry with DPO before production launch in EU/BR jurisdictions.
Alternatives Rejected
Longer retention (90+ days): Increases privacy risk with no product benefit. Most scheduling decisions are resolved within days of the meeting date. Rejected.
IP address logging for fraud detection: The abuse risk (fake responses) is adequately mitigated by rate limiting without persistent IP storage. Storing IPs would require GDPR documentation and increases compliance surface. Rejected.
Soft delete (status flag instead of hard delete): Retains data indefinitely in practice. Incompatible with GDPR erasure obligations unless a separate purge job is added anyway. Hard delete from the start is cleaner.
Review Trigger
Revisit when CODITECT embeds this tool in the enterprise platform under authenticated user accounts — at that point, the privacy model changes significantly (responses are linked to authenticated identities, not anonymous display names), and a full DPIA (Data Protection Impact Assessment) is required.