Workflow — Public Voting
| Module | Voting |
| Actors | Voter (LinkedIn-verified), Applicant, Admin (restrictions/veto), System |
| SRS refs | UC-07, FR-0500, BR-003/004/005/006/008 |
| Status | Planned — ships with v0.6.0 |
Purpose
Turn each applicant's network into voters — via their personal share link — while keeping votes verifiable (LinkedIn), rule-enforced (admin-tunable), and blendable (70% public / 30% board, veto-aware).
Preconditions
- Applicant approved; event status =
voting_open; togglevotingon. - Applicant has shared link
https://event.production1.jugaar.ai/v/{public_token}(e.g., on LinkedIn/FB with their card).
Main flow — how a vote is cast
- Voter clicks the share link → candidate page loads: photo, name, category, (optional AI summary), Vote button, vote-count display policy per admin settings.
- Voter taps Vote → if not authenticated: Continue with LinkedIn (required, BR-008) → returns with verified identity (
user role=voter). - Optional prompt (toggle
vote.reason_enabled): "What is this person good at?" — single short line stored with the vote (or disabled → simple one-tap vote). - System validates restrictions (settings
voting.mode):one_per_candidate(default): unique (candidate, voter);one_per_event: voter votes for exactly one candidate in the event;open: voter may vote every candidate once.
- Vote saved; confirmation shown: "Your vote counted" + nudge to re-share; Open Graph tags make the link unfurl nicely.
- Applicant gets a notification and sees the vote (+ voter identity) on their dashboard (BR-006).
Alternate / error flows
- A1 Already voted → "You've already voted for this candidate" (no duplicate).
- A2 One-per-event mode, voter picks another candidate → error explains; (default: no switching — open question #6).
- A3 Voting closed / candidate excluded (veto) → page shows closed/excluded state; votes frozen.
- A4 LinkedIn fails → can retry; vote not saved until verified.
Scoring (used at finalization — see winner-announcement)
public_score = candidate_votes / max_candidate_votes_in_category (0–1)
board_score = admin/judge panel score normalized (0–1)
final = 0.70 × public_score + 0.30 × board_score (BR-004)
veto = admin exclusion overrides everything (BR-005)
Rules applied
BR-003, BR-004, BR-005, BR-006, BR-008.
Data touched
| Table | Change |
|---|---|
| users | INSERT/lookup voter (linkedin_id) |
| votes | INSERT (unique candidate+voter) |
| audit_log | vote.cast (+ restriction meta) |
| notifications | incoming-vote ping to applicant |
| settings | read weights/mode |
Sequence
sequenceDiagram
participant V as Voter
participant W as Website
participant LI as LinkedIn
participant DB as MariaDB
participant C as Candidate
V->>W: open /v/{token}
W-->>V: candidate page + Vote
V->>W: Vote
W->>LI: OAuth verify
LI-->>W: verified voter
W->>DB: insert vote (rule checks)
DB-->>W: ok
W->>DB: notification → candidate
W-->>V: "Vote counted" (+reshare)
C->>W: dashboard — sees vote & voter