Foster: how to build your own bookshelf management web application



1. Encourage the development of (something, especially something desirable). “the teacher’s task is to foster learning”

TLDR: I made a personal bookshelf management web application and named it Foster. Here’s what I did (with gifs), so you might build your own.



Something like Goodreads but self-hosted. So, preferably a web application where I could:

  • track my reading progress
  • keep track of my bookshelf

But I couldn’t find anything that fit, so I knew I probably had to roll my own. In simpler times MS Access could do this in a heartbeat. But it’s 2019 and I wanted a web application. However I am not a web developer and certainly not a frontend developer.

But when I came across I knew this was what I was looking for! So I emailed Hans. He was very kind in explaining his application was self-coded and not open-source, but he did provide some pointers. Thanks Hans! So with those tips I built my own application (front and back) from scratch. And I decided to pass the knowledge on, with this blog.

The Foster fronted (I am still adding books)

This is what the Foster frontend looks like. Pretty self-explanatory: I can search *my* books, track and see reading progress, track collections, click through to book details and see the activity feed (more on that later). Oh, and it’s fast! ♥


Other than the index.php file there is one search.php file to make up the frontend. This file takes care of presenting the book details and search output and log and lists views (more on that below). So, most of what can be done and seen in the frontend the search.php file handles it.

The frontend is of course nothing unique. It’s just a representation of the data. The backend is a bit more interesting!


Rule of thumb: start with a good design, and everything else that comes after will be a lot easier.

chrome_2019-11-11_15-19-42.png (885×385)
chrome_2019-11-11_15-19-42.png (885×385)
Self-explanatory view of the database design

The multiple foreign-key relations between tables (on ids etc.) are not defined in the database. I choose to do this in the code and the JOIN queries.

It’s not hard to understand the database design. The design could be a little tighter — two or three tables — but let me explain.

Log, actions and states

I figured you can do one of five things with a book (actions):

  • You want a book
  • You get/buy/own the book
  • You start reading it
  • You finish reading it
  • You purge/remove/sell/give away the book

Makes sense right? You could even call it a ‘life cycle proces’. With one input and one output.

But, some books you already own without wanting it first. Or, you can read the same book more than once. Or, you can give a book to a friend, and buy it again for yourself. Or, you can finish reading a book, that you lent — from a friend or library — so it is not on your shelf anymore. All of these things happen. So these ‘life cycle’ actions are not a chronological fixed start-to-end tollgate process, it’s continuous and messy.

Book log

The Activity feed

With this log I can keep track of books even after I got rid of them (because selling/purging is just one action). So I don’t lose the log history of a book.

And I can also add books to my wanted list even if have owned them before (maybe I gave them away etc.). And I can start/finish reading the same book more than once. It doesn’t matter, it is just a log entry.

But with all this log information I can generate four states:

  • Books I want
  • Books I own
  • Books I have read
  • Books I had

These states are generated by specific hardcoded queries per state. They are generated on the fly by what is in the log file, and where the most recent log records prevail to decide the current status.

So Foster will track the complete history per book and at all times represent all books I want, own, have read or have owned, at that specific moment in time.


I tend to collect and read specific genres of books, e.g. music, management and computer history books. So I tend to organize books like that. These descriptions/genres are all of course just lists.

Some books can be three of these things at the same time: part biography, part computer history part management. So one book can be a member of more than one list.

In the Foster backend I can add or delete books to and from as many lists as I like.

Easily adding/deleting books from a list with the same dropdown menu (click for a gif)

I can also easily create a new list. Say: a list of books that I want for my birthday, or books that are on loan, or books that are signed by the author etc. I just add one new list to my table, and the list will be available in the backend and presented in the frontend.


I can create or delete as many lists as I’d like, and it won’t affect the book log. So I can now organize my book collection far better than I could physically (a book can only have one spot on your physical shelf).

Adding books with the API

Adding a book via API (click for a gif)

Of course I can also edit book details when necessary, or just enter a book by hand without the API. Sometimes does not carry a book.


I have defined jQuery actions on the <select option> dropdown menus, which provide a popup — where I can fill in a date if necessary — and which trigger database inserts (there definitely might be some security concerns here: but the backend is not public).



Django does most of the backend for you, I know, so I briefly looked at it. But for Foster I still ended up using PHP / MariaDB / Bootstrap 4 / JavaScript / jQuery. It’s a familiar and very portable stack that you can mostly just drop and run anywhere (and most answers are on StackOverflow 🤓). I’ve thought about using SQLite, but I am very familiar with MySQL/MariaDB so that made more sense. Also I learned more about Bootstrap than I actually cared about, but that’s alright. And I think I wrote my first serious piece of JavaScript code ever (for the dropdown select actions). So that was fun.

All in all: I spent a few days pondering the database design in the back of my mind. And 4 evenings programming front and backend. And now I am just polishing little things: which is a lot of fun.

Further development

  • RSS feed for the activity log? Now that I am bulk adding books the activity feed is not so relevant, but when things settle down, who knows, people might be interested. After I wrote a draft of this blog I implemented this.
  • Twitter integration? Posting the log to a dedicated Twitter feed.
  • Adding books by scanning the barcode / ISBN with your phone camera? If I can just get the ISBN I can automate API to do the rest. Might speed things up a bit (and might be useful when you run a secondhand bookstore 😉).
  • Storing/tracking more than books? CDs, DVDs, podcasts I listened too, movies I watched etc.
  • Multi-user? In the first database design there were multiple users that could access / add the books that were already in the database but still create their own log and lists. I think I could still add this to the current design.
  • As you can see in the database design, there is a remarks table. I haven’t used this table. A remark is a ‘blog’ (or a short self-written review) of a book, that can be presented with the book details. This is a one-to-many relationship, because you might want to make new remarks each time you reread a book. But, I currently blog about every book I read, so the remarks might be just an embedded blog link?

Just share the source already!

  1. I made Foster specifically for me. So chances it will fit your needs are slim and you would probably still need to make changes. In this post I share my reasoning, but you should definitely try to build your own thing!
  2. When Foster was almost done, I learned about prepared statements (did I mention I am not a web developer?)… so I had to redo the frontend. But I haven’t redone the backend (yet): so it’s not safe from SQL injections or other pretty bad coding standards. Open sourcing it can of course generate code improvements, but it would first make my site vulnerable.
  3. But most importantly: Building a web application to scratch your own personal itch and learning new things can be one of the most fun and rewarding experiences you will have! And I hope this blog is useful to you, in achieving that goal.

Originally published at Jan van den Berg.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store