A complete scheduling solution for restaurants
A screenshot taken from the ShiftR web application, it displays a login modal where the user is asked for their email and password to log in.  The modal also displays the logo of the restaurant and an option to switch between the service- and kitchen department within the restaurant. A screenshot taken from the schedule editor within ShiftR, it shows a table-like view where each day is represented as a column while the rows represent an employee.  Some of the cells are filled with times, representing the start time for a given employee at a specific date.  Other cells contain an 'x' or 'v' indicating that the employee cannot work or has taken a free day, respectively.

Before I started university I worked at a local restaurant where the entire process around the schedule took part on paper. Modifications to the schedule were made by crossing out old start times, availability for all employees was written down on a single physical piece of paper, and hours worked were manually calculated and aggregated through a daily print out of a day-list.

With my experience in building web applications I discussed the option of building a custom scheduling solution for the restaurant with the owner of the restaurant. After some initial sketches and discussion I started work on a prototype. This project was the first real world application that I built for people to use.

Left side: A screenshot of a day-list, containing a row of employees working from opening until closing time. For each employee the screenshot shows their start time, end time, and total hours worked. Right side: An small snippet from the weekly schedule overview. For each day a column a list of employees combined with their profile pictures and starting time.

The application itself has quite a lot of functionality, but the main features are:

The process

The entire project has been built from the ground up by me, including the design. I gained deep exeprience with different concepts such as authentication, mobile web apps, how to build an API, how to interface with other applications, and how to manage and update state in a frontend VueJS application.

Throughout the development process I worked iteratively with the restaurant owner and, once we had a working prototype, with other employees to test and improve the application.

After completion (version 1.0.0) I maintained the application with several updates where I fixed bugs, implemented the ability for employees to exchange their shifts, and improved performance.

A screenshot showing a time-off request by Jeroen for a little more than a week in March. Logged in as an admin the user is able to accept or decline the request. In addition to the request a calendar is shown, highlighting the days for which the employee requested time off.

Over the years, developing and maintaining this product, I have learned many valuable lessons. I experienced the concequences of technical debt, the advantages to testing my application, the trade-off between building additional features and the complexity in maintenance, and the architectural cost of certain decisions such as not supporting multi-tenancy at the application layer. In addition to these technical lessons I also worked with the actual users of the product, learned how to translate their requests into designs, iterate upon them, and finally translate the design into working application code.

A highlight

One of the most challenging aspects to implement was the authorization system, after working on the authentication I needed to be able to create different roles for different types of employees. This specific restaurant required 4 roles:

As I planned to launch the system for different restaurants I decided to take a variable route such that I could make changes to the permissions setup on a per-system basis.

I annotated every API function with a required permission that the logged in account needs to be able to use it. This allowed me to define roles, each only with the permissions for the calls they are allowed to make. Employees are assigned a specific role and therefore inherit all the permissions from that role. This system made it easy to add additional roles where needed or to modify them for a different instance of the application.

New Version

As this was the first project I completed at this scale of complexity, I made early mistakes in the architecture of the system. Most importantly the system does not scale easily to multiple restaurants, it requires a separate instance of the application for each different restaurant. While I was able to automate the setup of a new system using Docker it still requires manual work.

In the new version I make use of multi-tenancy, a design pattern that allows the same system to handle separate, software isolated, workspaces for each restaurant.

Left side: A screenshot of the new availability tool, displayed as a calendar with every week on a new row, every date that has been marked available is marked in green. Top Right: A screenshot from the new schedule editor, displayed as a table with days for columns and employees as rows. New in this version is the ability to make (unpublished) edits to a published schedule. Bottom Right: A screenshot of the published schedule, as seen by employees for two separate days.

The new version does not include additional features over the original, instead I am building less, such that the supported features get the attention they deserve. The underlying thought is to build half a product, not a half-asssed product. This is important because I am working on this product by myself, in the hours next to my day job. The time I have is limited, and should be used as effectively as possible.

Additionally the new version is built on top of Ruby on Rails. This has resulted in a much simpler application compared to the previous architecture. The server-side rendered nature of Ruby On Rails eliminates an entire workload from the project, which in turn simplifies the maintanance required in the long run. There is no need to create a client-side data model, handle client side data storage and updating (using a framework like VueX), or to maintain a separate pipeline to build such a frontend application.

In addition, new developments in the world of Rails such as Turbo and Turbo Native have allowed me to easily set up native mobile companion applications, while staying (mostly) in Ruby world.