Skip to content

Implement public results page, self-verification and audit export #11

@grantfox-oss

Description

@grantfox-oss

Problem
AnonVote's public verifiability guarantee is the feature that
differentiates it from every other voting tool — and it does
not exist yet. The results page renders hardcoded placeholder
data. The tally engine is not implemented. The Soroban
finalise_result contract is never called from core. There
is no self-verification flow for voters. There is no audit
export for organisations that need a record of the election
for compliance or governance purposes. The results page
requires a login to view which defeats the purpose of
public verifiability entirely.

These gaps mean AnonVote currently cannot deliver on its
core value proposition after a ballot closes.

Solution
Implement the full post-ballot flow — tally computation,
on-chain finalisation, public results display, voter
self-verification, and audit export — so the outcome of
every AnonVote election is independently verifiable by
anyone.

Backend

  • Implement the tally engine — fetch all encrypted vote
    payloads for a closed ballot, decrypt each via decryptVote
    from @anonvote/crypto using the per-ballot encryption key,
    count by option, produce a final tally map
  • Add POST /admin/ballots/:id/finalise route — run the tally
    engine, call finalise_result on the Soroban contract, store
    the transaction ID, mark the ballot as finalised — make
    this fully idempotent so calling it twice returns the
    existing result without a duplicate on-chain write
  • Add GET /ballots/:id/results public route — returns tally,
    total vote count, Stellar transaction ID, and direct
    explorer link — no authentication required, accessible
    by anyone
  • Add POST /ballots/:id/verify route — accepts a raw token,
    hashes it server side, checks whether that hash exists
    in the votes table for this ballot — returns a boolean
    confirmed field only, no vote option, no other voter data
  • Add GET /admin/ballots/:id/audit route — returns a
    structured audit export with event log, vote count
    timeline, token issuance summary, and Stellar transaction
    IDs for all on-chain events — exportable as JSON and CSV

Frontend

  • Remove the login requirement from the results page —
    it must be publicly accessible via a shareable URL
  • Build the public results page — option breakdown with
    vote counts and percentages, total participation rate,
    ballot metadata, Stellar transaction ID with explorer
    link, and a copy link button for sharing
  • Add a self-verification widget — token input field,
    submit button, clear yes/no confirmation display —
    no additional data shown beyond the boolean result
  • Show a pre-results state when a ballot is still active
    — display a live countdown to the deadline
  • Build the audit export panel in the admin dashboard —
    summary stats, downloadable JSON and CSV export buttons

Tests

  • Unit test for tally engine — correct count per option,
    handles empty ballot, handles single vote, handles
    maximum voter count
  • Unit test for idempotent finalisation — second call
    returns existing result without triggering a second
    Soroban write
  • Unit test for self-verification — correct true for
    a token that voted, correct false for a token that
    did not vote, no vote option data in response
  • Unit test confirming results route requires no
    authentication — request without token returns 200
  • Component test for self-verification widget — correct
    confirmation display for true and false responses
  • E2E test covering full post-ballot flow from finalisation
    trigger to public results page with working Stellar link

Acceptance Criteria

  • Tally engine correctly decrypts and counts all votes
  • Finalisation is idempotent and anchors result to Stellar
  • Public results page is accessible without authentication
  • Stellar transaction ID links directly to the explorer
  • Self-verification returns boolean only — no vote option
    or other voter data exposed
  • Audit export contains full event log and is downloadable
    as JSON and CSV
  • Pre-results countdown displays correctly for active ballots
  • All unit, component, and E2E tests pass

Note for contributors
The self-verification endpoint is a privacy boundary. It must
return only a boolean. Do not return the vote option, the
voter's identifier hash, the token hash, or any aggregate
data about the ballot that is not already on the public
results page. If in doubt, return less.

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignbackendBackend-related issuesenhancementNew feature or requestfrontendFrontend-related issuestestingTesting-related issues

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions