feat: GDPR compliance — anonymization, unsubscribe, consent tracking

- Add consent_given_at and anonymized_at fields + Alembic migration (002)
- Add GET /waitlist/unsubscribe endpoint (HMAC token, anonymizes PII)
- Add cleanup.py: cron-able script to anonymize unconfirmed entries after 48h
- Clear IP address on email confirmation (no longer needed)
- Add unsubscribe link in confirmation email footer
- Record consent timestamp on signup
- Add 4 new tests (unsubscribe, consent timestamp)
- Update .env.example, schemas
This commit is contained in:
Roberto Musso
2026-04-11 19:41:27 +02:00
parent 5f79ce87f9
commit 352e25d651
6 changed files with 232 additions and 14 deletions

View File

@@ -21,6 +21,12 @@ class WaitlistEntry(Base):
ip_address: Mapped[str | None] = mapped_column(String(45), nullable=True)
source: Mapped[str | None] = mapped_column(String(64), nullable=True)
confirmed: Mapped[bool] = mapped_column(Boolean, default=False, server_default=sa.text("0"))
consent_given_at: Mapped[datetime.datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True,
)
anonymized_at: Mapped[datetime.datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True,
)
created_at: Mapped[datetime.datetime] = mapped_column(
DateTime(timezone=True),
server_default=sa.text("CURRENT_TIMESTAMP"),