A real-time democratic voting platform for organizations. Conduct formal voting sessions with support for simple majority, qualified majority, and Single Transferable Vote (STV) methods.
- Real-time voting sessions with live result tabulation via Server-Sent Events
- Multiple voting methods: Simple majority, qualified majority, and STV
- Meeting management: Create meetings, define votations, invite participants
- Role-based access: Admin, Counter, and Participant roles with granular permissions
- Secret ballot: Tracks who voted but not how they voted
- QR-based registration: Easy participant onboarding via QR codes or shared links
- Result review workflow: Counters approve results before publishing
- Runtime / Package Manager / Test Runner: Bun
- Framework: TanStack Start (React 19, Vite, Nitro)
- Database: PostgreSQL 17 with Drizzle ORM
- Auth: Better Auth (email/password)
- Styling: Tailwind CSS + shadcn/ui
- Linting / Formatting: oxlint + oxfmt
bun installbun run db:upThis starts a PostgreSQL 17 container via Docker Compose (user: vedtatt, password: vedtatt, database: vedtatt, port: 5432).
Create a .env.local file:
DATABASE_URL="postgresql://vedtatt:vedtatt@localhost:5432/vedtatt"
BETTER_AUTH_SECRET="<your-secret>"
VITE_APP_NAME="TIHLDE Voting" # Optional, defaults to "TIHLDE Voting"Generate the auth secret:
bunx @better-auth/cli secretOr
openssl rand -hex 32bun run db:generate
bun run db:migratebun run db:seedThis adds 2 users:
- Admin:
a@a.comwith password12345678 - Participant:
b@b.comwith password12345678
It also creates a meeting with everyone added to it in their respective roles.
This meeting has all the different voting methods already set up.
bun run devThe app will be available at http://localhost:3000.
| Script | Description |
|---|---|
bun run dev |
Start development server |
bun run build |
Build for production |
bun run preview |
Preview production build |
bun run test |
Run tests (Vitest) |
bun run lint |
Lint with oxlint |
bun run lint:fix |
Auto-fix lint issues |
bun run format |
Format code with oxfmt |
bun run format:check |
Check formatting |
bun run db:up |
Start PostgreSQL container |
bun run db:down |
Stop PostgreSQL container |
bun run db:generate |
Generate Drizzle migrations from schema |
bun run db:migrate |
Apply migrations |
bun run db:push |
Push schema changes directly |
bun run db:studio |
Open Drizzle Studio (visual DB browser) |
bun run db:seed |
Seed database with test data |
src/
├── components/ # React components (UI, voting, meeting management)
│ └── ui/ # shadcn/ui primitives
├── db/
│ ├── index.ts # Drizzle ORM instance
│ └── schema.ts # Database schema & relations
├── routes/ # File-based routing (TanStack Router)
│ ├── _authenticated/ # Protected routes (meetings, profile)
│ └── api/ # API routes (auth, SSE)
├── server/ # Server functions, voting logic, permissions
│ ├── sse/ # Server-Sent Events manager
│ └── stv.ts # STV algorithm implementation
├── lib/ # Auth config, utilities
└── hooks/ # React hooks (SSE subscriptions)