boodle/doc/index.md -rw-r--r-- 3.5 KiB
33f03bd9Manuel Uberti Bump slf4j-simple 3 days ago

boodle is a single-page application for accounting, born out of my desire to learn more about Clojure and ClojureScript and build something useful for the family.

#Overview and rationale

boodle main features are:

  • expense tracking
  • monthly budgeting
  • savings management
  • short-term and long-term goal planning

boodle tries to be as simple as possible, providing only the functionalities I need at home. It’s not, and it doesn't want to be, a replacement for more powerful tools such as ledger.

boodle is intentionally provided as a self-hosted application. It's been running on my home server since its first deploy in mid-2017, and I do not plan to install it and run it elsewhere. I open-sourced it because it was about time to give something back to the Clojure community, which over the years has been immensely helpful and kind.



boodle is built and developed with Clojure CLI and shadow-cljs.

Originally there were Leiningen and Figwheel behind the curtains. I changed developing tools only to explore the Clojure ecosystem and learn something new. There is nothing wrong with the previously used tools.


boodle runs on PostgreSQL, which is always my go-to database when it comes to personal projects.

The initialisation is simple. I read the global configuration with aero to get the details for the database connection and the HTTP server. Then I call boodle.services.http/start-server!, which makes the datasource available to all my routes thanks to a handy Ring handler (boodle.services.http/add-datasource) and starts http-kit.

boodle is a single-page application, but to avoid 404 errors on random page reloading I added server-side routes matching the corresponding client-side panels: expenses (/), savings (/savings), and categories (/categories).


The core of the client-side is re-frame, and I tried my best to stick to its conventions. Every boodle topic (expenses, savings, categories, aims, funds, etc.) has its own set of events, subscriptions and views. This not only makes the code easier to understand, it also lets me focus on what a panel should do instead of how.

I also tried to isolate page components as much as possible. The rule of thumb is: if there is a subscription involved, that is a component I can inject wherever I need. Take a look at the expenses views for an example of what I mean.


boodle is localized in Italian, but I didn't want it to be an Italian-only application. Thanks to tongue localizing Clojure/ClojureScript applications is easy.

Anything you see on the screen is ready to be translated. If you plan to change the language you can find the translations in i18n.cljs.

You should also check out utils.clj and common.cljs which take care of the localization of dates and amounts according to Italian standards.