A reliable, no-maintenance solution to replace tally lists.
During my time as the treasurer of my student dormitory, I hated counting the tally lists ontop of the drinks fridge. Not hesitant to waste hours implementing and optimizing a computer system to avoid a small manual task (relevant xkcd), I created the first version of strichliste. After it served us for a few years, a vision for a better system came to mind.
The requirements were:
- Robustness in the face of network failures or server downtime
- Foolproof to use for treasurers
- Snappy on cheap hardware (We currently deploy 35€ Kindle HD tablets)
- Completely zero-maintenance.
- Easy backups.
- Have pictures of both users and beverages
- Have some products only appear on certain tablets. Use one system for drinks, the washing maschine, coffee, ...
- Make statistics accessible to the users
- Have a dead-simple UI (users may be drunk from time to time)
- Be reasonably secure and temper-proof
- Easy deployment
- Simple, easy to change code
The result is this system. Its fits our use-case nicely and just works (tm).
The complete system is web-based. The user interface as well as the backoffice (called "backend" for historical reasons) is written in elm.
The source code for the UI is in the src
directory and split into Main.elm
for the user facing stuff, Backend.html
for backoffice and Common.elm
for the
network code they both share. To ease deployment, the compiled main.js
and backend.html
are checked into the git repo.
A PostgreSQL database serves as the main datastore. A postgREST instance sits between the database and the rest of the world and provides auth as well as a REST API.
All non-database api's are implemented in go. First, there's an /auth
enpoint that trades passwords for jwts and also validates jwts.
A second endpoint /api
is used to process images and serve some protected files like reports. Go is not nessessarily the best language for this
kind of use-case, but its robust standard library gives me confidence that the code will compile and run for the forseeable future.
Caddy is used as both a reverse proxy for all the HTTP endpoints and also serves static files. It does HTTPS by itself and just works.
The scripts in /cronjobs
are run by a docker container connected to the database to generate billings and backups.
The whole project is packaged as a docker compose unit. This makes both deployment and development easier. I also make extensive use of it to put services in private networks and limit their view on the filesystem. This should contain the effect of possible bugs.
$ git clone git@github.com:maxmunzel/strichliste2.0.git
$ cd strichliste2.0
$ pip3 install pyjwt # just needed to generate secrets. If you don't like python, send me an email and I generate secrets for you ;)
$ python3 init.py
Please Enter the Password used for setting up Tablets and backoffice access:
****************
Congig generation successful! Secrets stored in 'secrets.json'.
$ docker compose up --build
Thats basically it! The only thing left to do is configure the domain name in Caddyfile
i.e. replace :80
in the first line with example.com
or whatever. Also setup backups for the whole folder.