Mosen / Swamp Machine
Mosen, also known as Swamp Machine, is a local self-checkout and accounting system used on DTU’s weekend cabin trips for new students, as well as on other student-run trips. It is one of those projects where the software is small enough to understand, but real enough that bugs matter: if a purchase is not registered correctly, someone pays the wrong amount, loses trust in the system, or has to clean up the mess manually.
I joined an existing project and have mainly worked on making it more reliable and easier to reason about, especially around purchase handling, database access, admin workflows, performance and tests.

What I worked on
- Reorganized the database code into separate connection, table and business layers, with typed table access and shared transaction handling.
- Made multi-table operations atomic, so failures can roll back without leaving behind half-finished purchases, imports or settings changes.
- Made purchase submission idempotent by processing purchases serially under the global database lock and emptying the shopping cart in the same transaction that records its purchases.
- Cached every database table in memory and made database work happen under one global lock, keeping reads fast without letting the cache and database drift apart.
- Tightened barcode validation, represented guests as actual users and prevented users or products referenced by transactions from being deleted accidentally.
- Standardized user-facing errors with clear visual messages and a hard-to-miss warning sound.
- Expanded settlement with early payments, configurable ways of sharing unaccounted stock loss, bill-preview buffers and checks that prevent payments from being exported against an outdated stock count.
- Added an off-by-default per-person leaderboard for selected product subsets, mostly to settle very serious questions such as who had bought the most Cocio.
Reliability under real use
The interesting part of the project is not that it uses exotic technology. It is that real people use it in a slightly chaotic environment. People scan quickly, use the barcode printed on the can instead of the one provided by the system, misunderstand the interface, or assume something worked when it did not.
A purchase changes both the permanent transaction history and the temporary shopping cart. Checkout operations now happen serially under the global database lock. Within that lock, one transaction reads the basket, records its purchases and empties it. The first checkout therefore consumes the basket, while a repeated or concurrent checkout runs afterwards, finds the basket empty and has nothing to record. If recording or emptying the basket fails, the entire transaction is rolled back and the basket remains intact.
I also added a reusable error component that displays the problem clearly and plays an annoying warning sound. This makes it much harder to miss a rejected scan and walk away believing the purchase was registered.
A missed scan does not simply disappear. When the stock is counted, it shows up as a product missing without a corresponding registered purchase. The app calls this unaccounted stock loss “waste,” and its cost eventually has to be covered by the users. Making errors harder to miss therefore reduces both incorrect bills and the amount of cleanup left for the admin.
Guest handling had a similar hidden failure mode. Guests could make purchases, but were assigned barcodes based on the current highest user barcode. If more users were imported during a trip, a new user could receive the same barcode as an existing guest. I changed guests to be persisted users with an explicit guest flag, so their purchases remain attached to the right person.
Admin and settlement workflows
The admin side has to account for registered purchases, unaccounted stock loss, people who leave early and the final settlement for everyone else. I worked on moving more of that accounting into the system instead of leaving it as manual work for the admin.
Early payments are now recorded properly, block later purchases and are taken into account when the remaining waste is allocated. Admins can choose how waste is shared. By default, the loss within each product category is shared between the users who bought something from that category. Bill previews can also include a configurable waste buffer, so users are less surprised when the final stock count changes what they owe.
Payment export is blocked if purchases have been registered since the latest stock count. Deleting a transaction also invalidates that stock count, forcing the admin to confirm the stock again before producing the final payments.
Data imports and transaction deletions create database backups first. I also added transaction-row deletion and search by name or barcode in the economy table, making early checkout and recovery from incorrect purchases less dependent on manual SQL.

Technical shape
Swamp Machine is a local Python application built with Dash, SQLite, Pandas and Plotly. It normally runs offline on an older Windows laptop, so simple dependencies, predictable recovery and responsive barcode input matter more than architectural novelty.
A trip only produces fairly small tables, but the application reads them constantly while serving both as a purchase system and a dashboard. I cache the tables in memory so those reads are cheap. All database work happens under one global re-entrant lock, and multi-step operations reuse the same SQLite transaction until they either commit or roll back. This keeps the database and its cached representation in step with each other.
I used measurements to find the slow parts of the main purchase workflow, then vectorized the relevant calculations and replaced expensive high-level chart construction with more direct Plotly operations. The performance tests simulate more users and purchases than OPtur, the largest trip on which the system is normally used. This gives later changes a realistic regression target instead of testing only with conveniently small inputs.
The repository had no automated test suite when I started. I added tests covering the database, callbacks, settlement rules, concurrent operations, generated edge cases and performance-sensitive workflows. The project became a useful exercise in practical backend work: not just adding features, but making existing behavior safe, understandable and dependable under real use.