Skip to content

Implement full ballot creation and admin setup flow #9

@grantfox-oss

Description

@grantfox-oss

Problem
The ballot creation flow is the foundation of everything in
AnonVote and it is incomplete at every layer. The backend route
accepts a title and deadline but does not validate option arrays,
does not enforce minimum or maximum option counts, and does not
anchor the ballot to Stellar on creation — meaning ballots exist
only in the database with no on-chain record. The frontend form
has no dynamic option management, no timezone-aware deadline
picker, and no feedback when creation fails. There are zero tests
covering ballot creation on either the backend or frontend.

Additionally the admin authentication flow has no session
expiry handling — an admin token issued 30 days ago is still
accepted as valid, which is a security gap that needs to be
closed as part of hardening this flow.

Solution
Implement the complete ballot creation and admin setup flow
so an admin can configure a ballot end to end, have it anchored
to Stellar on creation, and manage it from a properly secured
dashboard.

Backend

  • Validate all ballot creation inputs — title length, minimum
    2 and maximum 10 options, deadline must be at least 1 hour
    in the future, all fields required
  • Return structured field-level validation errors so the frontend
    can highlight exactly which input failed
  • Call create_ballot on the Soroban contract via Stellar SDK
    immediately after database write — store the returned
    transaction ID against the ballot record in the database
  • If the Soroban call fails, do not roll back the database
    write — instead mark the ballot as pending_anchor and queue
    a background retry so ballot creation is never blocked by
    a transient Stellar network issue
  • Implement session expiry on admin JWT — tokens older than
    8 hours must be rejected with a 401 and a SESSION_EXPIRED
    error code
  • Add GET /admin/ballots route that returns all ballots for
    the authenticated admin with status, vote count, and
    Stellar anchor status

Frontend

  • Build the full ballot creation form — title input with
    character count, dynamic option list with add and remove
    controls, minimum 2 options enforced client-side, timezone
    aware deadline picker that displays the admin's local time
    but submits UTC
  • Display field-level validation errors inline next to the
    relevant input — not as a single generic toast
  • Show Stellar anchor status on the ballot detail page —
    anchored with transaction link, pending, or failed with
    a manual retry button
  • Handle SESSION_EXPIRED error globally — redirect to login
    with a clear message rather than showing a broken state
  • Build the admin ballot list with status tabs — draft,
    active, closed — and a search input

Tests

  • Unit tests for ballot creation validation — missing fields,
    invalid deadline, too few options, too many options
  • Unit test for JWT expiry enforcement — expired token returns
    401 with SESSION_EXPIRED code
  • Unit test for pending_anchor retry queue — Soroban failure
    queues retry without rolling back database write
  • Component tests for the ballot creation form — validation
    errors display correctly, option add and remove work,
    deadline picker submits UTC
  • Integration test covering full creation flow from form
    submission to Stellar anchor confirmation

Acceptance Criteria

  • All ballot creation inputs are validated with field-level
    error responses
  • Ballot is anchored to Stellar on creation with transaction
    ID stored in the database
  • Soroban failure queues a retry without blocking ballot
    creation
  • Admin JWT tokens older than 8 hours are rejected with
    SESSION_EXPIRED
  • Admin ballot list shows correct status and anchor state
    for each ballot
  • Deadline is always stored and processed as UTC regardless
    of admin timezone
  • All unit, component, and integration tests pass

Note for contributors
The pending_anchor retry mechanism is important — do not make
ballot creation dependent on Stellar network availability.
The database is the source of truth for ballot state. Stellar
is the auditability layer. A transient Stellar outage must
never prevent an admin from creating a ballot.

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 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