GDPR Implementation Status (Issue #42)

Date: 2025-10-30 Status: 🟢 In Progress - Backend Business Logic Complete Completion: ~50% (Domain + Application layers ready, Infrastructure pending)

✅ Completed (Phases 1-2.3)

Phase 1: Database & Domain Layer

1.1 Migration ✅

  • File: backend/migrations/20251030093756_add_gdpr_anonymization_fields.sql

  • Changes:

    • Added is_anonymized (BOOLEAN) to users and owners tables

    • Added anonymized_at (TIMESTAMPTZ) to users and owners tables

    • Created indexes: idx_users_is_anonymized, idx_owners_is_anonymized

  • Commit: ec376d9 - chore(db): add GDPR anonymization fields

  • Tests: Migration applied successfully ✅

1.2 Domain Entities ✅

  • File: backend/src/domain/entities/gdpr_export.rs

  • Entities:

    • GdprExport: Main aggregate

    • UserData: User account info

    • OwnerData: Owner profile info

    • RelatedData: Container for units, expenses, documents, meetings

    • Supporting types: UnitOwnershipData, ExpenseData, DocumentData, MeetingData

  • Features:

    • Pure domain logic, no dependencies

    • Builder methods for data aggregation

    • Anonymization status tracking

    • JSON serialization support

  • Commit: 3a4e11c - feat(domain): add GDPR export domain entities

  • Tests: 9/9 passed ✅

Phase 2: Application Layer (Ports & DTOs)

2.1 Repository Port ✅

  • File: backend/src/application/ports/gdpr_repository.rs

  • Trait: GdprRepository

  • Methods:

    • aggregate_user_data(user_id, organization_id) - Article 15 export

    • anonymize_user(user_id) - Article 17 erasure

    • anonymize_owner(owner_id) - Article 17 erasure

    • find_owner_ids_by_user(user_id, organization_id) - Helper

    • check_legal_holds(user_id) - Deletion eligibility

    • is_user_anonymized(user_id) - Status check

  • Features:

    • Async trait with Send + Sync bounds

    • Comprehensive documentation

    • Mock implementation for testing

  • Commit: ec916bc - feat(ports): define GdprRepository trait

  • Tests: 4/4 passed ✅

2.2 DTOs ✅

  • File: backend/src/application/dto/gdpr_dto.rs

  • DTOs:

    • GdprExportResponseDto: Complete export response

    • UserDataDto, OwnerDataDto, etc.: Nested DTOs

    • GdprEraseRequestDto: Erasure request

    • GdprEraseResponseDto: Erasure response

  • Features:

    • From trait implementations for domain-to-DTO conversion

    • RFC3339 timestamp formatting

    • UUID to String conversion

    • Full JSON serialization support

  • Commit: 8960840 - feat(dto): add GDPR export and erase DTOs

  • Tests: 6/6 passed ✅

2.3 Use Cases ✅

  • File: backend/src/application/use_cases/gdpr_use_cases.rs

  • Struct: GdprUseCases

  • Methods:

    • export_user_data(user_id, requesting_user_id, organization_id) - Export with authorization

    • erase_user_data(user_id, requesting_user_id, organization_id) - Erasure with validation

    • can_erase_user(user_id) - Check legal holds

  • Features:

    • Authorization: self-service + SuperAdmin bypass

    • Validation: anonymization status, legal holds

    • Transaction handling: user + multiple owners

    • Error handling: clear messages for all scenarios

  • Commit: 9729db6 - feat(use-case): implement GDPR use cases

  • Tests: 9/9 passed ✅


🚧 Remaining Work (Phases 3-14)

Phase 3: Repository Implementation (🔴 TODO - HIGH PRIORITY)

Files to create:

  • backend/src/infrastructure/database/repositories/gdpr_repository_impl.rs

Methods (implement GdprRepository trait):

pub struct GdprUseCases {
    gdpr_repository: Arc<dyn GdprRepository>,
}

impl GdprUseCases {
    // Export user data (GDPR Article 15)
    pub async fn export_user_data(
        &self,
        user_id: Uuid,
        organization_id: Option<Uuid>,
    ) -> Result<GdprExportResponseDto, String>

    // Erase user data (GDPR Article 17)
    pub async fn erase_user_data(
        &self,
        user_id: Uuid,
        requesting_user_id: Uuid,
    ) -> Result<GdprEraseResponseDto, String>

    // Check if user can be erased
    pub async fn can_erase_user(&self, user_id: Uuid) -> Result<bool, String>
}

Tests to write:

  • Unit tests with mock repository

  • Test export with/without data

  • Test erasure permissions

  • Test legal holds blocking


Phase 3.1: Repository Implementation (🔴 TODO)

Files to create:

  • backend/src/infrastructure/database/repositories/gdpr_repository_impl.rs

Implementation:

pub struct PostgresGdprRepository {
    pool: Arc<PgPool>,
}

impl GdprRepository for PostgresGdprRepository {
    async fn aggregate_user_data(...) -> Result<GdprExport, String> {
        // Complex SQL queries with JOINs:
        // 1. Fetch user from users table
        // 2. Fetch owners from owners table (WHERE user matches)
        // 3. Fetch units via unit_owners + units + buildings
        // 4. Fetch expenses from expenses table
        // 5. Fetch documents from documents table
        // 6. Fetch meetings from meetings table
        // Build GdprExport aggregate
    }

    async fn anonymize_user(...) -> Result<(), String> {
        // UPDATE users SET
        //   email = CONCAT('anonymized-', id, '@deleted.local'),
        //   first_name = 'Anonymized',
        //   last_name = 'User',
        //   is_anonymized = TRUE,
        //   anonymized_at = NOW()
        // WHERE id = user_id AND is_anonymized = FALSE
    }

    async fn anonymize_owner(...) -> Result<(), String> {
        // Similar UPDATE for owners table
    }

    // Implement remaining methods...
}

Tests to write:

  • Integration tests with testcontainers PostgreSQL

  • Test data aggregation with real database

  • Test anonymization transactions

  • Test referential integrity preservation


Phase 4.1: Web Handlers (🔴 TODO)

Files to create:

  • backend/src/infrastructure/web/handlers/gdpr_handlers.rs

Handlers:

// GET /api/v1/gdpr/export
pub async fn export_user_data_handler(
    state: web::Data<AppState>,
    user: AuthenticatedUser,
) -> impl Responder

// DELETE /api/v1/gdpr/erase
pub async fn erase_user_data_handler(
    state: web::Data<AppState>,
    user: AuthenticatedUser,
) -> impl Responder

Files to modify:

  • backend/src/infrastructure/web/routes.rs - Add GDPR routes

  • backend/src/infrastructure/web/app_state.rs - Add gdpr_use_cases

  • backend/src/infrastructure/web/handlers/mod.rs - Export handlers

Tests to write:

  • E2E tests with Actix test framework

  • Test authentication required (401 without token)

  • Test authorization (user can only export self)

  • Test SuperAdmin permissions


Phase 4.2: Audit Logging (🔴 TODO)

Files to modify:

  • backend/src/infrastructure/audit.rs

Changes:

pub enum AuditEventType {
    // ... existing events

    // GDPR events
    GdprDataExported,
    GdprDataErased,
    GdprExportFailed,
    GdprErasureFailed,
}

Integration:

  • Log all GDPR operations in handlers

  • Include user_id, organization_id, success/failure

  • Preserve audit logs even after anonymization (legal requirement)


Phase 5-7: Data Erasure Complete (🔴 TODO)

  • Extend use cases with erasure logic

  • Implement anonymization in repositories (with transactions)

  • Create erase endpoint handlers

  • Add comprehensive tests


Phase 8: Admin Endpoints (🔴 TODO)

Endpoints:

  • GET /api/v1/admin/gdpr/exports - List all export requests (SuperAdmin)

  • POST /api/v1/admin/gdpr/erase/:user_id - Manual erasure (SuperAdmin)


Phase 9: BDD Tests (🔴 TODO)

Files to create:

  • backend/tests/features/gdpr.feature

Scenarios:

Feature: GDPR Compliance
  Scenario: User exports personal data
    Given I am authenticated as "john.doe@example.com"
    When I request my GDPR data export
    Then I should receive a JSON with my complete data
    And the export should include user, owners, units, expenses

  Scenario: User requests account deletion
    Given I am authenticated as "jane.smith@example.com"
    When I request account deletion
    Then my personal data should be anonymized
    And my user account should be marked as anonymized

Phase 10-11: Frontend (🔴 TODO)

Privacy Settings Page

Files to create:

  • frontend/src/pages/privacy.astro

  • frontend/src/components/PrivacySettings.svelte

  • frontend/src/components/GdprExportModal.svelte

  • frontend/src/components/GdprEraseModal.svelte

Features:

  • “Download my data” button → triggers export API call

  • “Delete my account” button → confirmation modal → erasure API call

  • Display anonymization status

Admin Dashboard

Files to create:

  • frontend/src/pages/admin/gdpr.astro

  • frontend/src/components/admin/GdprDashboard.svelte

Features:

  • List of anonymized users

  • Manual erasure form (SuperAdmin only)

  • GDPR statistics (exports, erasures)


Phase 12: Playwright E2E Tests (🔴 TODO)

Files to create:

  • frontend/tests/e2e/gdpr-user.spec.ts

  • frontend/tests/e2e/gdpr-admin.spec.ts

Scenarios:

  • User journey: Login → Privacy page → Export data

  • User journey: Login → Privacy page → Delete account

  • Admin journey: Login as SuperAdmin → GDPR dashboard → Manual erase


Phase 13: Documentation (🔴 TODO)

Files to create/modify:

  • docs/GDPR_COMPLIANCE.md - Full compliance documentation

  • CLAUDE.md - Update with GDPR sections

  • docs/ROADMAP.md - Mark issue #42 as completed

Content:

  • Legal compliance procedures

  • Data retention policies (7 years Belgium)

  • Anonymization vs deletion strategy

  • API documentation with examples

  • User guide for privacy settings


Phase 14: Quality & Final Review (🔴 TODO)

Quality checks:

make format    # Auto-format
make lint      # Zero clippy warnings
make test      # All tests pass
make coverage  # > 80% coverage target

Final validation:

  • Manual E2E test of complete workflow

  • Verify audit logs in database

  • Validate JSON export format (GDPR Article 20 compliance)

  • Legal review (if applicable)


📊 Statistics

Completed ✅

  • Commits: 6

  • Files created: 10 (including plans)

  • Files modified: 6

  • Tests written: 28 (all passing ✅)

    • Domain entities: 9 tests

    • Repository port: 4 tests

    • DTOs: 6 tests

    • Use Cases: 9 tests

  • Lines of code: ~2500

Remaining 🔴

  • Estimated commits: 15-20

  • Files to create: ~12-15

  • Files to modify: ~8-10

  • Tests to write: ~40-50

  • Estimated time: 4-6 hours


🚀 Quick Start to Continue

Resume development:

# 1. Ensure DB is running
docker compose up -d postgres

# 2. Create use cases file
nano backend/src/application/use_cases/gdpr_use_cases.rs

# 3. Follow TDD: Write tests first, then implementation
cd backend && cargo test --lib application::use_cases::gdpr_use_cases

# 4. Implement repository
nano backend/src/infrastructure/database/repositories/gdpr_repository_impl.rs

# 5. Integration tests
cargo test --test integration

# 6. Create handlers
nano backend/src/infrastructure/web/handlers/gdpr_handlers.rs

# 7. Test complete backend
cargo test

# 8. Frontend development
cd frontend && npm install && npm run dev

📋 Architecture Summary

Layers Implemented ✅

  1. Domain Layer: Pure business entities (GdprExport, UserData, etc.)

  2. Application Layer - Ports: Repository interface (GdprRepository)

  3. Application Layer - DTOs: API contracts (Request/Response DTOs)

Layers Remaining 🔴

  1. Application Layer - Use Cases: Business logic orchestration

  2. Infrastructure Layer - Repository: PostgreSQL implementation

  3. Infrastructure Layer - Web: HTTP handlers and routes

  4. Infrastructure Layer - Audit: GDPR event logging

  5. Presentation Layer: Frontend pages and components

  6. Testing: Integration, E2E, BDD scenarios

Benefits of Foundation

  • ✅ Clean architecture validated

  • ✅ Type-safe domain models

  • ✅ Clear contracts (ports & DTOs)

  • ✅ Easy to test (mocks available)

  • ✅ GDPR-compliant data structures


🔗 References

  • Issue: #42

  • Plan: .claude/plans/GDPR_IMPLEMENTATION_PLAN.md & docs/plans/GDPR_IMPLEMENTATION_PLAN.md

  • Changelog: docs/CHANGELOG.md

  • Commits:

    • ec376d9 - Database migration

    • 3a4e11c - Domain entities

    • ec916bc - Repository port

    • 8960840 - DTOs

    • 8f707ad - Documentation status

    • 9729db6 - Use Cases


📝 Notes

  • Database schema ready for anonymization

  • Domain layer fully isolated (no deps)

  • Hexagonal architecture respected

  • All existing tests passing

  • Ready for repository implementation

  • Foundation stable and extensible