Skip to content

feat: add user data export and privacy controls (#200) - #232

Merged
mudabs merged 3 commits into
oss-slu:mainfrom
Nayira:feat/200-user-data-export
Nov 13, 2026
Merged

mudabs merged 3 commits into
oss-slu:mainfrom
Nayira:feat/200-user-data-export

Conversation

@Nayira

@Nayira Nayira commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

Summary
Lets users download a copy of their stored health data from Account Settings and explains how the app currently handles retention, deletion, and consent.

Closes #200

Stacked PR: based on health-summary-export, which isn't merged yet. Once it is, the base will be changed to main.

Changes Made

  • Added GET /api/v1/users/me/data-export. It returns only the signed-in user's profile, consent record, submitted questionnaires, and saved risk assessments.
  • Exported fields are listed one by one, so credentials (such as the password hash) and internal fields are never included. The response is sent with Cache-Control: no-store.
  • Added a "Privacy and your data" section to Account Settings with a "Download my data" button. It has loading, success, empty-history, and error states.
  • Status and error messages are announced to screen readers
  • Moved /settings/account outside the health-consent gate, so users who haven't given (or no longer have) health consent can still export their data.
  • Added retention, deletion, and consent explanations, including the user's current consent status.
  • Added translations for English, Spanish, Hindi, Arabic, and Chinese.
  • Added backend and frontend tests for user scoping, credential exclusion, empty history, success, and failure.

Testing

  • Full frontend test suite passed (117 tests), including the 3 new Account privacy tests.
  • Frontend lint passed for the settings pages.
  • Backend tests passed (6 tests, including 2 new export tests).
  • All 5 locale files validated as JSON.

Checklist

  • The code follows project conventions
  • Documentation has been updated if needed
  • No sensitive information is included
  • Breaking changes are clearly documented
  • Reviewers have enough context to review this PR

Additional Notes

  • Deletion and consent withdrawal are explained to users but aren't self-service yet. The page tells users to contact the app administrator. This meets the issue's "understand retention, deletion, and consent behavior" criterion; self-service controls could be a follow-up if wanted.
  • The export is generated on request and isn't stored by the app.
  • No breaking changes. The only routing change makes Account Settings reachable without health consent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@Moon-dg Moon-dg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed the changes for issue #200. The data export endpoint in backend/src/main.py is secure with proper credential exclusion and cache headers, and decoupling settings from the consent gate ensures smooth data access.

Comment thread backend/src/main.py Resolved

@mudabs mudabs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, Nayira, for adding the user data export and privacy controls.

Please address these items before merge:

  • Derive the displayed consent status from consentStatus or the same validity rule used by the backend. Checking only user.consent_given can show consent as granted when data usage consent is false or the consent version is stale. Add coverage for invalid or withdrawn consent and confirm Account Settings remains accessible without health consent.
  • Add an endpoint-level authorization test proving unauthenticated requests are rejected and authenticated exports are limited to the signed-in user.
  • Confirm export coverage for stored profile photos and record metadata. The export currently includes only photo_url and omits fields such as questionnaire updated_at. Include eligible fields or document these exclusions clearly.

@mudabs mudabs left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, Nayira, for adding the user data export and privacy controls. CI is passing, but please address these items before approval:

  1. Derive the displayed consent status from the validated consentStatus or the shared consent-validity helper. Add tests for withdrawn, incomplete, and stale-version consent while confirming Account Settings remains accessible.
  2. Add endpoint-level authorization tests proving unauthenticated requests are rejected and authenticated exports remain scoped to the signed-in user.
  3. Include eligible questionnaire metadata such as updated_at, or document the intentional exclusions clearly. Profile photo URL coverage is already present.
  4. Update the Account test resources so tests assert translated text rather than raw translation keys.

Please push the fixes and request another review.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Copilot was unable to complete this review at the selected tier due to model policy or plan restrictions.

🟡 Changes recommended

The change still leaves a moderate test isolation issue in Account.test.jsx where URL.createObjectURL/URL.revokeObjectURL are overwritten and not restored by vi.restoreAllMocks(), risking leaked global stubs and order-dependent failures across the test suite.

1 open issue
What changed in this PR

This pull request adds an authenticated “export my data” feature end-to-end: a new backend endpoint to export the signed-in user’s stored data, plus an Account Settings “Privacy and your data” section (now accessible without health-consent gating) with localized, accessible status/error messaging.

Changes:

  • Backend: add GET /api/v1/users/me/data-export to return a strictly-scoped export payload for the current user and send Cache-Control: no-store.
  • Frontend: add “Download my data” UI with loading/success/empty/error states and screen-reader announcements; move /settings/account outside the health-consent gate (while remaining authenticated).
  • i18n + tests: add privacy/export/retention/consent strings for en/es/hi/ar/zh and add backend/frontend test coverage for export success/failure/empty and scoping/credential exclusion.

This pull request requires changes.

File Review notes / what changed
frontend/​src/​services/​authService.js Adds a client wrapper to call the new data-export endpoint.
frontend/​src/​pages/​settings/​Account.test.jsx Adds UI tests for export success/empty/error; needs fixes for global URL mock restoration and brittle assertions against i18n keys.
frontend/​src/​pages/​settings/​Account.jsx Implements the Privacy section and download flow; align authService import specifier to avoid mock/module-resolution issues.
frontend/​src/​App.jsx Updates routing so Account Settings is reachable without health-consent gating (still behind auth).
frontend/​public/​locales/​zh/​common.json Adds privacy/export/retention/consent strings (ZH).
frontend/​public/​locales/​hi/​common.json Adds privacy/export/retention/consent strings (HI).
frontend/​public/​locales/​es/​common.json Adds privacy/export/retention/consent strings (ES).
frontend/​public/​locales/​en/​common.json Adds privacy/export/retention/consent strings (EN).
frontend/​public/​locales/​ar/​common.json Adds privacy/export/retention/consent strings (AR).
backend/​tests/​test_health_summary.py Adds backend tests for export scoping, credential exclusion, cache header behavior, and empty-history export.
backend/​src/​main.py Adds the /api/v1/users/me/data-export endpoint and constructs an explicit export payload.

Review effort: Balanced

@Nayira

Nayira commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review! All items are addressed:

Consent status uses consentStatus from the backend, falling back to the shared userHasValidHealthConsent helper. Added tests for withdrawn, incomplete, declined and stale-version consent, and confirmed Account Settings stays accessible without health consent.
Added endpoint-level tests: missing, invalid and revoked tokens are rejected, and exports are scoped to the signed-in user.
Questionnaires now include id and updated_at. Exclusions are documented in docs/user-data-export.md.
Account tests now load the English locale and check translated text instead of raw keys.

@Nayira
Nayira requested a review from mudabs November 9, 2026 21:43

@mudabs mudabs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, Nayira, for addressing the previous privacy export feedback and getting CI green.

Please fix the remaining test isolation issue in frontend/src/pages/settings/Account.test.jsx. URL.createObjectURL and URL.revokeObjectURL are assigned directly in beforeEach, but vi.restoreAllMocks() does not restore direct assignments. Capture and restore the originals, or use restorable Vitest spies/stubs, then rerun the frontend tests and request another review.

This is required before approval because the stubs may leak into other test files and cause order-dependent failures.

@sonarqubecloud

Copy link
Copy Markdown

@Nayira

Nayira commented Nov 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks! Fixed the test isolation issue. jsdom doesn't define URL.createObjectURL/revokeObjectURL, so vi.spyOn can't wrap them. The suite now saves the original property descriptors and restores them (or deletes them if they were absent) in afterEach. Added a test that runs after the suite and fails if a mock is still installed. I confirmed it fails against the old cleanup. All 127 frontend tests pass.

@Nayira
Nayira requested a review from mudabs November 10, 2026 18:51

@mudabs mudabs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, Nayira, for addressing the requested consent, authorization, metadata, localization, and test-isolation fixes.

I verified that the URL object stubs are now restored correctly, all CI checks pass, and the export remains scoped to the authenticated user. This PR is approved for merge. Please update the outdated stacked PR note before merging.

@mudabs
mudabs merged commit b1572ae into oss-slu:main Nov 13, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Small Rock] Add user data export and privacy controls

4 participants