Jul 03, 2023

Project: Climber

Climber is second version of a two-part application I have developed for my client for keeping track of people on climbing walls.

It is divided into two parts: web application (admin dashboard) and Windows native application (for employees) that are communicating with each other via REST api and web sockets.

Why second version?

First version was very limited. It was created when I had some experience with JavaScript and was switching to Node.js environment. Electron was pretty huge thing for me in that time and I did not fully understand things like IPC to create safe applications.

In this version I used secure boilerplate for Electron.

Development process

I knew that it's gonna be two-part project from the very beginning and I had to make some choices early on. Another thing I had to consider is how to save data in case of lost internet connection.

Native application

I have started developing application first, because I've done it once before. Purpose of the application was exactly the same:

With some extra things in my mind, I decided to use TypeScript, Electron, React, Chakra UI, Pusher, Prisma and SQLite.

Once I've got the basics done, I started to add configuration screen and prepare utilities for synchronization. This is where I've encountered most of the issues. I've learned the hard way why most of the applications restarts after configuration is finished.
Turns out it's easier to close app than to change variables, change window, refresh server connection, auto-log in, etc.

Another problem I had was with auto-update. Hours of debugging only to find out that repository had a bug.


Developing dashboard was pretty straightforward until I began to implement data fetching from client side. Climber has few tables for keeping dashboard users, people from climbing walls, devices and climbing walls itself. I needed to view each table, add and edit data and remove records.
Since logic was the same for every table, I decided to create small library to help me with that. That is how I created CSR controller. It creates REST api for database and generates type-safe functions for fetching the data.

How does synchronization work?

There are two ways Climber synchronize data. Real-time view using web sockets and data-saving using REST api.

Real-time view

I've chosen Pusher because of its nice free-tier and their great API. When app is launched, it performs multiple steps:

  1. Load variables from database (including credentials to dashboard)
  2. Login in to dashboard
  3. If there are any non-synced users, synchronize them
  4. Initialize Pusher connection (presence-channel)
  5. Check for updates

This Pusher setup allows me to identify each connection, so I can keep track of every device or user viewing dashboard and send data only when it's needed.

REST synchronization

I'm importing functions generated from CSR-controller from dashboard to application and using them to create and update people.

What could be improved?

Short answer: many things
Even though I tried to think of everything it's just not possible in reality. I could add custom themes that you get to choose from settings, dashboard customization, comparing two or more climbing walls with each other, more statistics. Database could also be improved to use Prisma migration engine (it's on my TODO list), but for now I don't plan to change database schema.

But for now, this version is a huge improvement over first. I really enjoyed developing it, even though sometimes I wanted to throw it into trash and start all over again.