Just because we're engineers, doesn´t mean we build ALL our applications ourselves. But sometimes inspiration hits and good things happen. So our company planner is now canvas-rendered, has a Rust backend and works like a charm.
Just because we're engineers, doesn´t mean we build ALL our applications ourselves. But sometimes inspiration hits and good things happen. So our company planner is now canvas-rendered, has a Rust backend and works like a charm.
Background
Tweede golf is by no means a mega-corporation (there's 18 of us), but keeping track of who works on which project, what they are currently doing and whether they're available to help out on an awesome project next week... is a bit of a hassle on paper.
In 2015, we were old-school and used a whiteboard. No lie. Here's a picture.

But today (and for a while now), we have a pretty neat online version, home-made, with TypeScript and Rust of course!
The Tech
Where it came from
Once it was decided that the whiteboard had to go, we started developing, mostly in React, with a NodeJS backend, and have since had several versions of this planner called TGenda.
As the company grew, and the number of actual plans to be recorded grew with it, so did the number of DOM elements. This resulted in performance issues for the React/HTML build we were using, because we used the drag-and-drop functionality a lot. This was problematic: we needed that to be smooth, so it was time for a reimplementation.
Wanting to get rid of the DOM elements brought me to the Canvas API, which uses pixels instead, because who doesn't love awesomely fast animations? (More about that later.)
We had previously experienced that maintaining a TypeScript frontend with many dependencies is tricky and tends to bring about security issues. So for the greater good I deciced to challenge myself to not use any runtime dependencies for the frontend at all, except of course for TypeScript itself, as a direct dependency.
The backend was created using Rust with the excellent Axum and SQLX crates.
The current version in Rust
This version has an exceptionally clean and organized codebase:
- A global state, that is updated through events and a reducer (inspired by redux)
- State updates trigger a render of the whole canvas
- Renders are quick - mere milliseconds
- The Rust backend has the same event type as the frontend, and a bus that several services can listen to
- A selection of frontend events is also sent to the backend through a websocket connection
- The backend broadcasts these events to all other clients, creating a live update mechanism
- The backend runs a service that listens to certain events and turns these into database updates
How it's made: our digital company planner
This event-based mechanism is very flexible; by changing only one line, I was able to make the scroll position a shared state, which means every client then shared a scroll position (for fun, just to test the performance). The combination of a websocket and the Rust backend provides such low latencies that multi-client scrolling is smooth!
The frontend looks similar to this example - try dragging an event to a different day!