• Blog
  • A call to … WorkfromHub

A call to … WorkfromHub.

    By Jamie Chatterton / 2022-08-30

    Prologue

    In early 2021 we received a request to create an application. I was not privy to the specifics of how this happened. I heard a little that it was to do with spaces that people could work from, and that they would be something that could be locked.

    In late June of the same year, I was brought onto the project.

    It was at this time I discovered these were called “Hubs” and the idea that they were self-isolated, bookable, spaces, designed for a user to access, via the application.

    We were to provide the application that would give the ability to book, control access, and provide the payment system to the users and the client.

    This was quite exciting, not really anything I or we had done before. While we had built websites, applications, and Unity games before, interaction with real-world items was quite new.

    But wait, being new to us, we didn’t actually have the knowledge of what this entailed.

    It required quite a bit of research to get somewhere, there is not a lot of information readily available, to the point of discussion with the client and their purchasing of a lock and the discussions with the vendor of how to interact with the lock.

    This led to our first discovery of an API provider, and knowledge of the lock, and even the quite expansive Smart-device field that is available when you find it.

    However, controlling it and integrating it, requires an API. This was something else we needed to create. And as we also needed to prove the entire hub concept was even viable, we also needed to create a prototype.

    Chapter 1

    “Prototype”

    While the final product was going to launch with a mobile application, the prototype was a web application.

    This was split into two parts, the API and Admin website, both running on Node.

    The API was written using FeathersJS. This handled all the abstraction of the services used, including the third-party lock API, and used a Postgres Database. There was integration with Auth0 to provide authentication of users.

    The “admin” website ended up also hosting the website that the public would end up using, so the API also provided a degree of simple Authorisation, based on a simple Role system. Everything that the website presents is done via calls to the API, so that it can decide if the logged-in user actually has permissions to view the resources they request.

    The public side of the website allowed the users to view the hubs, the details, the locations, and from there choose a date and time range which they wanted to book and book the slot. At this point, there was no integration with any payment provider, and this had to be done manually, with the client. The client had a limited number of test customers, who they had arranged this with.

    The main problem with the prototype was the choice of technology. This was chosen mainly because it was used in my previous project and it was quick and easy to port it over to get a very quick API up and running. But that caused problems with the other developer, who was struggling to learn it. So… bad choice.

    What we did find as a few positives was that Auth0 was easy to integrate and the lock API was nice to use. We did learn there were a few shortcomings with our database model, which is always a good experience, it still worked, but things could be improved. And it gave us good knowledge for the final version.

    But in all, it gave us confidence that this would work and it gave the client the confidence that it was viable.

    Chapter 2

    “The Product”

    After some time, the prototype was used, some problems were found and we decided upon what we needed to change and improve.

    The first thing to change? Out with FeathersJS, but what to replace it with? I am very happy with using Node and Typescript in general, so I researched around this. Looking around, I discovered NestJS. This was entirely new to me. An Inversion-of-Control, modular, “progressive” framework.

    While it also provides the ability to host an entire website, I was more interested in it providing the API, in a very simple manner.

    With the removal of FeathersJS, we also had to decide on how to interact with the database. While I can handle SQL directly, I’m not a fan of writing SQL. I rather chose to use an ORM, and one I’ve had a good experience with was Sequelize. Thankfully Sequelize plays well with both NestJS and Typescript.

    Because of the change to a new framework, it became a bit of a learning curve to understand FeathersJS, dependency injection isn’t something I’d really done much of since my old Java days. What was nice though was having Decorators handle all the configuration, something I’ve gotten quite used to when programming Unity and C#. Being able to create decorators to handle authentication and authorisation, handle data mapping along with creating Swagger documentation is very useful.

    The website was also changed. Instead of being part of the API code, this was moved into a static React application. Also, it was only ever the Admin site. There was to be no more public access into the website. It would require an admin user to access and manage the data in the system.

    This Admin site would provide the ability to manage users, create locations, and create hubs in those locations. The admin could assign the locks to the hubs through the interface, and manage the passcodes on the bookings. If the Admin wanted to, they could create a booking for a user, be it out-of-hours for a hub, or at a different price than it should be for the type of booking. There was quite a bit of freedom for an Admin user in the interface.

    Again, we used Auth0 to prevent unauthorised access to the Admin website and also on the API to ensure calls to privileged endpoints also had access to both the call and any data returned.

    The data returned is also limited, using the integration of class-validator, a node library, and the integration into NestJS. Along with a Decorator I wrote, to add to the API calls, to make sure the values returned from the APIs only contain the data in the DTOs, so that we can explicitly define the data an API returns. This is mainly used in the public API, to prevent data showing up where it shouldn’t. But it also ensures the data is clean in the returned JSON.

    While all this was going on, the second developer had started on with developing the Mobile app. This was also a Typescript application, using Expo, as this was to be an Android iOS multi-platform application.

    The first major problem when this was being developed was we had started everything as a monorepo, everything in the same repository. This was causing issues deploying to the target servers. At least at the time. The decision was made to split it into the three different parts of the project. And while I’m getting ahead of myself in timescales, I kinda wish we’d just kept it as a single repository, juggling three repositories, when bugs occur, that need fixes in multiple places across repositories. It causes nightmares, especially when there’s just a single bug tracking the issue, when deploy times are different from each other, and you have to wait for each one to finish to ensure it’s “ready to test”. But this is a bed we created and now we have to lay in it. And no, don’t suggest git-submodules, it was a hellscape (very quickly dropped).

    So as development goes. Two-week sprints, features added, tasks added, tested, bugs found, bugs fixed, meet with the client, show off the new snazzy features, and so the cycle goes.

    We integrated Payments using Stripe as the payment provider. This was done both in the Admin and Mobile application. A severe bug was found in the version of the Stripe Expo payment plugin we were using, that required a full update to the Expo SDK version, which went fine thankfully.

    We found a few issues in the early data-model, that required moving data around to different places, database refactoring, new data added, etc etc.

    The new system also started using the NestJS scheduler to start sending emails, using Sendgrid. The new scheduler also did some basic housekeeping, removed things that were stale, well not removed, invalidated. There was a new requirement to add an external CRM, which was expected to take a while, but it turned out to be very easy.

    Chapter 3

    “The end … is near”

    Finally, when the horizon was close, we started to send the apps in for review at both Google and Apple.

    Of course Google was mostly happy.

    And of course, Apple wasn’t.

    We’d forgotten probably the most important thing, ignoring minor graphical issues with our submission.

    A user could sign up, but they couldn’t delete their account.

    So very quickly we thought about how to fix this. We don’t actually want to delete the data from the system, as it’s tied to all the other data. Instead, we had to obfuscate it in a non-reversible way.

    So when a user deletes their account. It is obfuscated. Their login details are removed. Their Auth0 login data is deleted. And all their private information is scrambled so we can’t recover them. And they can’t log in and recover it. They would have to create a completely new account to start using the system again.

    And with that, the final hurdle was crossed to getting the application out of the door.

    Epilogue

    Of course, it’s not finished. There are still issues I’d like to fix.

    There are always areas where you look at the code and think, I’d like to fix that, refactor it here and there. But I’m just a developer, a problem solver and I enjoy analysing and finding solutions, even if people don’t see the problem.

    I guess there’s going to be a point when I get, hope, to make those changes that I do see.

    Who knows?