- TypeScript 38.6%
- Go 33.5%
- Nix 14.7%
- SCSS 9.5%
- Dockerfile 2.7%
- Other 1%
| backend | ||
| frontend | ||
| .gitignore | ||
| .woodpecker.yaml | ||
| docker-compose.dev.yml | ||
| docker-compose.prod.yml | ||
| docker-compose.yml | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| module.nix | ||
| README.md | ||
Exam Poll
Exam Poll was a tool for creating polls about exam results. It aimed to be simplistic and accessible. Anyone can create a poll and share a link to it. Polls can be edited by their creator and run for a specified time span.
The current implementation consists of a backend written in Go, which uses MongoDB, and a server-side rendered frontend using NextJS.
Post-mortem
On 2025-10-09, the public instance of Exam Poll at poll.fugi.dev was replaced with a static archive website, and this repo was subsequently archived as well.
All of the 79 polls that were created in its lifetime are still viewable under their respective URLs, and some functionality can still be tried out.
The reason why I originally wanted to create Exam Poll was that my university did not offer any statistics on exam grades, which many of us students were very curious about. We started making Strawpoll polls, which was insightful, but also quite tedious. So the idea to make a specialized, minimal polling tool arose.
Exam Poll filled this role quite nicely and was actively used for about three years. It received contributions from a few other people, and every once in a while incremental improvements were made.
Then, in fall 2024, my university migrated to a different exam registration platform (which is crap, but that's another story) that finally offered official exam grade stats. So, Exam Poll effectively became obsolete. I had planned to make some more improvements, but obviously there was little point to it now. ^^
As it was definitely no longer in use now, apart from people occasionally poking around, I decided to archive it. This way, I'm not burdened with maintaining it or else having outdated software running on my server anymore.
I'm still proud of this little project of mine, and I have learned quite a lot from it (and be it because I would not do some things the same way again). Feel free to poke around the repo and the website if you'd like. :)
Some more thoughts/learnings:
- Build user interfaces with accessibility in mind from the very beginning.
- Don't let someone else write parts of your project without coordination
- or in a programming language that you don't know, meaning you will have a hard time maintaining that later.
- Don't use some hyped technology just because it sounds cool – looking at you mongodb, god I'm glad I finally could throw this piece of crap off my server. It caused annoyances like nothing else.
- Keep things minimal... Why even have a separate backend, when NextJS (and an sqlite db or something) would have done just fine. This just complicated things immensely for absolutely no benefit.
Development
See the README file in the frontend and backend directories, respectively.
Deployment
Docker Compose
The compose files I use are provided for reference. You can use them with slight adjustments.
Replace the domains for frontend and api in docker-compose.prod.yml and hook up your reverse proxy (which can access the containers via the swag-net network, in my case).
Then run the following command to deploy everything:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
NixOS module
This repository includes a Flake that provides a NixOS module for exam poll. You can use it like this:
# flake.nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
exam-poll.url = "git+https://codeberg.org/fugi/exam-poll.git";
};
outputs = { self, nixpkgs, exam-poll }: {
# change `yourhostname` to your actual hostname
nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem {
# customize to your system
system = "x86_64-linux";
modules = [
exam-poll.nixosModules.default
./configuration.nix
];
};
};
}
# configuration.nix
{
services.exam-poll = {
enable = true;
frontend = {
# optionally specify the local port
# port = 3000;
hostName = "poll.example.com";
};
backend = {
# optionally specify the local port
# port = 8000;
hostName = "poll-api.example.com";
};
mongodb = {
# provide your own mongodb instance, this is currently not handled by the module
uri = "mongodb://localhost:27017";
database = "exam-poll";
collection = "polls";
};
};
}
Nginx will (by default) be automatically configured as reverse proxy with https. This can be disabled by setting services.exam-poll.configureNginx = false;.
The creation of a MongoDB instance is currently not handled by the module. Because of MongoDB's non-free license, your options are to use its NixOS module and compile it yourself (requires a lot of resources) or to run it in Docker or Podman.
See module.nix for all available options and their explanations.