Money

Money is a browser-based personal finances management software that I maintain since 2013.

Old generation

Up to late 2012 I was a happy user of Jumsoft Money 3 to keep track of my personal finances. In early 2013 I got rid of my MacBook Pro and went back to my old desktop with Debian, and given Jumsoft only published for Apple-based platforms, I had to find a replacement software for this purpose.

I tried several Linux-native options, a few SaaS offerings and a few other clever projects like MoneyLog, but none of them were either as simple as Jumsoft’s software, neither customisable to my needs at the time. I was also young and naïve, and thought I could somehow make money out of this (but I had no idea how), so I decided to write the software myself.

The early iterations of the software were just a CRUD application revolving around a transactions table and a few auxiliary forms to input/filter to be useful to me. I just ran it in my machine (http://localhost/money) and MySQL for data storage.

The trick is that this project was never finished. I would implement the barebones, make it somewhat usable for myself, but given I had access to the database and could do things there, some data management features were never built. In hindsight, I couldn’t afford to maintain such software neither had the desire to maintain it, but I had no other options that I both liked and didn’t had a big switching cost.

I also used this project as some sort of playground, although that wasn’t really planned. The software started with Zend Framework 1, but also got rewritten in Ruby on Rails, Symfony and .NET Core. Every so often I’d rewrite the software to get some feeling of a new framework, half-write some of the features and keep using it, and eventually it got neglected again.

Some of the old iterations of the project can be seen in GitHub:

  • https://github.com/kassner/finances
  • https://github.com/kassner/money
  • https://github.com/kassner/FinancesDotNet

Current geneneration

By early 2019, a lot had changed: I had moved to Sweden, so I had to manage money in two different countries; I had joined Yubico, which allowed me to learn a lot about software security from people far smarter than me; and my girlfriend would be soon moving in with me in Sweden, which meant I didn’t want to spend time fighting my tools anymore. At this point I was also back to using both this project, but also Jumsoft Money, which I started using again once I’ve moved, because the old-gen Money wasn’t in a good state and I wanted to keep finances separated. Jumsoft had moved away from perpetual licenses in favour of subscriptions (which I disliked), and their new version didn’t please my taste anymore.

I honestly didn’t look around that much for other options at this point. SaaS at this point was completely ruled out for data privacy concerns, and I wanted something both self-hosted and multiplatform (Linux and Mac). I had some technical things I wanted to try, so I decided to give it another shot and build it again. Once and for all.

Architecture

As the old-gen, this software is a basic CRUD with some custom forms/views. The new things I wanted were more in the realm of security and usability:

1) Jumsoft Money 3 allowed you to have multiple databases, each being a different file on disk. I wanted something similar, as I was managing money in different countries separately. I achieved this by using SQLite databases;

2) I used to have my old-gen software permanently running at http://localhost/money, which wasn’t secure, specially because I was more often than not having my local webserver exposed to the network. While I didn’t deploy TLS for the current generation, now I’m only exposing the software locally in a random port (and binding to 127.0.0.1) only when it’s in use;

3) Jumsoft Money databases were encrypted, and you had to type a password every time you opened the file. I wanted such feature again, specially because I’d like to sync my databases to Dropbox. I achieved this by using gpg and a wrapper script that would encrypt/decrypt based on a password from stdin;

4) As a stretch goal, I’d like to have a single binary to manage all of this, so I could just type money ~/Dropbox/my.db, instead of having to deal with git clone and composer install and other developer-focused tools. While I didn’t manage to get a single binary, I managed to make it in two: a wrapper bash script that would handle SIGINT/SIGTERM, encrypt/decrypt the database and a single money.phar (built on GitHub Actions) containing the entire project.

I eventually achieved all of those goals, and I do use the software weekly. I’ve finished the build by mid-2019 and since then I’ve been slowly adding the features as I need. As the database rests encrypted, it’s cumbersome enough for me to not edit it manually all the time, but still possible for special cases.

User experience

Using the software starts in the terminal:

1
2
3
4
5
6
7
8
9
10
[kassner@yeti ~]$ ~/bin/money ~/Dropbox/money/test.db
temp file: /tmp/tmp.zTS5N3YzjS
Password:
gpg: AES256.CFB encrypted data
gpg: encrypted with 1 passphrase
Running Doctrine Migrations

 [OK] Already at the latest version ("DoctrineMigrations\Version20210917140234")

Server running at http://127.0.0.1:9174/

And then accessing the exposed port on the browser would give me access to the software. Some screenshots:

dashboard screenshot

transactions list screenshot

net worth report screenshot

Once done, pressing Control+C in the terminal window would close up the port, re-encrypt the database and save it to the original location:

1
2
3
4
5
6
^CSIGINT called

Encrypting
Saving
Done
[kassner@yeti ~]$

Future

I have a small list of application features that I have pending, such as tracking my mortgage, but other than that I consider this software done. It serves me well, it is quite low maintenance thanks to Symfony LTS policy and is as flexible as I need it to be.

However, I do realize it’s not the best tool for the job. Jumsoft Money is a desktop-based software, and the hybrid CLI/browser model that I have can be cumbersome at times. Also, PHP isn’t quite the right language to achieve the single binary goal, even with PHARs, and while I’d love to rewrite this project in Golang or Rust, I’m yet to find the motivation for it.