Skip to content

Audit log records event counts only — add structured per-event entries for tally verification #33

Description

@Just-Bamford

Summary

The README states that audit logs record event counts only — no
identity, no token values. GET /api/audit/:ballotId returns audit
event counts. This is correct for the privacy model but insufficient
for tally verification. When a dispute arises about whether a specific
ballot's result is correct, the only verifiable source of truth is the
Stellar ledger — but there is no way to cross-reference a specific
Stellar transaction ID against a specific ballot event in the audit log
because the log stores counts, not structured event records.

The resultEngine.ts calls the tally and publishes results but the
Stellar transaction ID returned from the manageData write is not
stored anywhere accessible. It needs to be stored per ballot event so
it can be surfaced on the public verification page.

Scope

  • Add a ballot_events table to the Prisma schema with fields:
    id, ballot_id, event_type (enum: ballot_created,
    token_issued, vote_cast, result_published), stellar_tx_id,
    created_at
  • Add a compound index on (ballot_id, created_at) to the table for
    efficient retrieval of all events for a ballot in chronological order
  • In each of the four service files, after a successful Stellar
    manageData write, insert a row into ballot_events with the
    returned transaction ID — wrap the Stellar write and the database
    insert in a single operation so they succeed or fail together
  • Update GET /api/audit/:ballotId to return both the existing event
    counts and an array of structured event records with event_type,
    stellar_tx_id, and created_at — the stellar transaction IDs
    must be included so anyone can verify each event independently on
    the Stellar explorer
  • Add a unit test confirming a ballot_created event record is
    written after ballot creation with a non-null stellar_tx_id
  • Add a unit test confirming the audit route returns structured event
    records alongside the existing counts

Relevant Files

  • backend/prisma/schema.prisma
  • backend/src/services/ballotEngine.ts
  • backend/src/services/identityManager.ts
  • backend/src/services/privacyEngine.ts
  • backend/src/services/resultEngine.ts
  • backend/src/routes/audit.ts

Acceptance Criteria

  • ballot_events table added to Prisma schema and migrated
  • All four service files insert a ballot_events row after
    every successful Stellar write
  • stellar_tx_id is never null in a ballot_events row
  • GET /api/audit/:ballotId returns structured event records
    with stellar_tx_id included
  • Both unit tests pass

Out of Scope

  • Switching from manageData to Soroban contract calls
  • Frontend audit display — a separate issue

Note for Contributors

Do not store any voter identifier, token value, or vote option in the
ballot_events table under any circumstances. The only data stored is
the event type, the Stellar transaction ID, and the timestamp. If you
find yourself adding any other field, stop and check against the privacy
model first.

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26backendBackend-related issuesenhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions