Venue booking & governance
election_votes
The CURRENT vote per voter — one row per (election, voter), upserted on change (G803). One real profile = one vote (G801 anti-stuffing). The tally uses this table (latest vote per voter); the full trail lives in electionVoteHistory.
Columns
| Column | Type | Null | Default | Keys |
|---|---|---|---|---|
| id | uuid | no | gen_random_uuid() | PK |
| election_id | uuid | no | — | |
| voter_dancer_id | uuid | no | — | |
| candidate_id | uuid | no | — | |
| created_at | timestamp | yes | now() | |
| updated_at | timestamp | yes | now() |
Value lists come from .$type<'a' | 'b'>() in the schema — enforced in TypeScript only, not by the database.
Keys, constraints & indexes
Unique
- (election_id, voter_dancer_id) election_votes_unique
Indexes
No secondary indexes.
Foreign keys
- election_id → moderator_elections.id on delete no action
- voter_dancer_id → dancers.id on delete no action
- candidate_id → election_candidates.id on delete no action
Used by
Code that reads or writes this table, found by static analysis of the tRPC routers and API handlers (including helpers they call).
REST & webhooks
- ANY /mcp
- ANY /mcp/public
Relations
Rendering diagram…
Diagram source
erDiagram
dancers {
uuid id PK
text email UK
text neon_auth_id UK
text username UK
}
election_candidates {
uuid id PK
uuid election_id FK
uuid dancer_id FK
}
election_votes {
uuid id PK
uuid election_id FK
uuid voter_dancer_id FK
uuid candidate_id FK
}
moderator_elections {
uuid id PK
uuid profile_id FK
}
moderator_elections ||--o{ election_candidates : "election_id"
dancers ||--o{ election_candidates : "dancer_id"
moderator_elections ||--o{ election_votes : "election_id"
dancers ||--o{ election_votes : "voter_dancer_id"
election_candidates ||--o{ election_votes : "candidate_id" Defined at server/database/schema.ts:630 as electionVotes.