feat: cookie consent management and accessibility fixes (Iubenda findings) - #528
Draft
victhorbi wants to merge 1 commit into
Draft
feat: cookie consent management and accessibility fixes (Iubenda findings)#528victhorbi wants to merge 1 commit into
victhorbi wants to merge 1 commit into
Conversation
Addresses the Iubenda compliance report. Only the findings that were verified against the code are changed here; docs/Compliance.md records the disposition of each one, including the three that cannot be closed in this repository. Consent (findings 2b, 5, 6, 7) Mixpanel previously initialised at module import with persistence in localStorage and ignore_dnt: true, so it collected before any consent existed and overrode Do Not Track. Under ePrivacy Art. 5(3) the consent requirement covers any device storage, not only HTTP cookies, so this applied even though VeVote sets no cookies of its own. - CookieConsentProvider owns the decision, persists it, and re-asks when the policy version changes or the consent is over a year old. - Mixpanel is now lazily initialised and only after the analytics category is granted; withdrawal opts out and clears its persistence. The analytics-only localStorage keys are removed on withdrawal too. - Banner gives Accept all and Reject all identical variant, size and width so refusing is no harder than accepting. - Footer carries a persistent Cookie Preferences entry and the CCPA/CPRA Do Not Sell or Share My Personal Information opt-out. - Global Privacy Control and Do Not Track are honoured without asking. - Every decision is stored with id, timestamp, policy version, granted categories, method and context, and the user can download that record. Accessibility (findings 3, 4) WCAG 2.1 level A failures found in the audit: - 1.1.1: footer-image.png had no alt; it is decorative, so alt="". - 4.1.2: icon-only buttons had no accessible name (table pagination, search clear, number increment/decrement, delete voting option). - 3.3.2: the search field was labelled only by its placeholder. - 2.4.1: no way to bypass the fixed navbar and hero repeated on every route; added a skip link and a <main> target. - 2.4.2: <title> was the constant "VeVote" on every route. - 1.3.1: no landmarks anywhere; nav, main and footer were all divs. Proposal cards, Chakra IconButton usages, modal focus handling and <html lang> were checked and already correct. Adds test/cookieConsent.test.tsx covering the consent state machine. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3MnNPUUFzQWGMX46S472o
|
🚀 Preview environment deployed!Preview URL: https://preview.vevote-dev.vechain.org/claudeiubenda-compliance-accessibility-xi69ok/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Addresses the Iubenda compliance report. I checked each finding against the code first — three of the seven are real but cannot be closed in this repository, and one is only partly as reported.
docs/Compliance.mdrecords the disposition of every finding plus the service inventory the policy pages need.Findings — what turned out to be real
vevote.vechain.org/privacy, outside this repoConsent (2b, 5, 6, 7)
The underlying problem was concrete: Mixpanel initialised at module import with
persistence: "localStorage"andignore_dnt: true, so it collected before any consent existed and deliberately overrode Do Not Track. Under ePrivacy Art. 5(3) the consent requirement covers any device storage, not just HTTP cookies — so this applied even though VeVote sets no cookies of its own.CookieConsentProviderowns the decision, persists it, and re-asks when the policy version changes or the consent is over a year old.localStoragekeys (mixpanel_user_id,vevote_last_tracked_wallet).Accessibility (3, 4)
WCAG 2.1 level A failures found and fixed — the whole app had 3
aria-labels and zero landmarks before this:footer-image.pnghad noalt— decorative, soalt=""<main>target<title>was the constant "VeVote" on every routenav,mainandfooterall rendered asdivChecked and already correct, no change needed: proposal cards are keyboard-operable, Chakra
IconButtonusages already carryaria-label, modals get focus trapping from Chakra, and<html lang="en">is right becauseenis the only locale shipped.Still open — needs a decision or a backend
docs/Compliance.mdis the input: Mixpanel and Google Fonts are the notable gaps, and the connected wallet address sent to Mixpanel is personal data.index.html, sending every visitor's IP to Google. Self-hosting removes the issue rather than merely disclosing it — left out as it touches build config.Testing
test/cookieConsent.test.tsx— 9 tests covering the consent state machine (default-deny, accept/reject/granular, proof record, version + age expiry, GPC). All pass.tsc --noEmitandeslintclean on all changed files.vite buildand the two pre-existing test files. They needpackages/contractsartifacts, andhardhat compilecannot download the solc list through this sandbox's TLS proxy. This is a pre-existing environment limit, not a regression — those tests fail onmainhere too. CI should be treated as the real check.🤖 Generated with Claude Code
https://claude.ai/code/session_01Q3MnNPUUFzQWGMX46S472o
Generated by Claude Code