A free, open-source real-time quiz platform inspired by Kahoot. Hosts run live sessions from a browser; players join instantly — no app required.
- Multiple question types — True/False, single-answer Quiz, and Multi-correct (select all that apply)
- Real-time gameplay — answers, scores, and round transitions pushed to all clients simultaneously over SignalR
- Vote distribution — bar chart shown between rounds so everyone sees how others answered
- Latency-aware scoring — faster correct answers earn more points; the scoring formula accounts for network latency
- Time extension — host can add extra seconds mid-round; scoring adjusts fairly for all players
- QR code join — host screen shows a scannable QR code so players can jump straight into the room
- Localization — English and Brazilian Portuguese (pt-BR)
| Layer | Technology |
|---|---|
| Language | C# / .NET 10 |
| Frontend | Blazor Server + SignalR |
| UI components | MudBlazor |
| Actor model | Akka.NET (Cluster Sharding, Persistence) |
| Persistence | PostgreSQL via Akka.Persistence.Sql |
| Auth | GitHub OAuth |
| Orchestration | .NET Aspire |
The app authenticates users via GitHub. Create an OAuth app at github.com/settings/developers with the callback URL https://localhost:<port>/signin-github, then store the credentials as user secrets:
dotnet user-secrets set "GithubAuth:ClientSecret" "<your-secret>" --project "./Kanelson/"
dotnet user-secrets set "GithubAuth:ClientId" "<your-client-id>" --project "./Kanelson/"The easiest way to run everything locally:
docker-compose upThis starts PostgreSQL and the application together.
You need a running PostgreSQL instance, then:
dotnet run --project Kanelson/Kanelson.csprojOr use the Aspire AppHost for a full local orchestration experience:
dotnet run --project Kanelson.AppHost/Kanelson.AppHost.csproj# Build
dotnet build Kanelson.sln
# Run all tests
dotnet test Kanelson.sln
# Run a specific test
dotnet test Kanelson.Tests/Kanelson.Tests.csproj --filter "ClassName.MethodName"Kanelson uses the actor model via Akka.NET with event sourcing. All game state lives in persistent actors distributed across the cluster via Akka Cluster Sharding.
AllRoomsIndexActor (singleton) ← registry of active rooms
└── Room (sharded per room ID) ← core game state machine (in-memory)
└── SignalrActor (per room) ← bridges actor events to browser clients
└── LocalRoomActorManager ← per-node local proxy for room actors
RoomTemplateIndex (sharded) ← quiz template CRUD
User (sharded per user ID) ← user profiles [persistent]
UserHistory (sharded per user ID) ← game results history [persistent]
UserQuestions (sharded per user ID) ← user question bank [persistent]
User, UserHistory, UserQuestions, and RoomTemplateIndex persist their state as events to PostgreSQL. Snapshots are taken every N events and on graceful shutdown to speed up recovery. Room state is in-memory only.
Pull requests are welcome. Please open an issue first to discuss significant changes.