Photo: While thinking about my own Work In Progress, I remembered these mill stones waiting for collection at Froggatt Edge – for two hundred years
I’ve built an online service for Health and Safety Consultants called the Business Safety Net.
This is about how the parts fit together and how the development process has gone, from gathering requirements, writing tests, the back end Rails app, front end angular code and onwards to promoting it with potential users.
Who is it for ?
The Business Safety Net is for Health and Safety Consultants who are responsible for helping a bunch of other small businesses stay compliant with rules and regulations. A typical consultant might have dozens of clients, each having dozens of ways to stay compliant, cleaning kitchens, fridges, flues, ovens, insuring vehicles, paying road tax, carrying out vehicle MOTs and so on.
The service lets them send SMS and email messages to people when these checks become due and over due. There are demonstrations of the service working at business-safety-net.co.uk.
Building the service
I chose Postgres for the database instead of MySql because it offers Schemas. Together with the excellent Apartment gem, this provides a simple way to keep data from different customers separate. Another advantage is that Postgres can search jsonb data stored in a single column. I used this to let users configure extra attributes on their data on-the-fly.
Heroku still provides a simple way to deploy production Rails applications. In the past I’ve provisioned EC2 servers from scratch and found that Chef / Puppet becomes a time consuming task in itself.
Customers have their own subdomain and the Apartment gem arranges for them to be restricted to their own schema data.
Heroku provides a way to schedule cron jobs. This is handy for regularly updating the status of things in the database so that they cause events to happen as time passes and to send email and SMS messages asynchronously (because we want to batch up messages into digests, so that the user does not get too many)
The help and tutorials are on a WordPress site hosted on an Amazon EC2 server. Cloudflare filters out nuisance requests.
I’ve been developing a second way of accessing the app from mobile devices. It uses the Ionic framework to produce both iPhone and Android front ends, and best of all uses Angular, HTML and CSS so there is no need to learn the native apis.
I had to fork ng-token-auth because Ionic does not use the Angular Router component, instead using its own.
We use a suite of RSpec specs to show that the API works as expected. Each deployment triggers a git hook that causes Codeship to run these tests, and it will not deploy the code if any fail.
Test data is generated by FactoryGirl (FactoryBot).
The front end a suite of end to end protractor tests. Its good to watch these end to end tests open a browser, log in and click around doing stuff.
For authentication I used a fork of the Devise Token Auth gem together with ng-token-auth. I had to make a small change to this gem to add an extra check that not only is the user authenticated, but that the request came from the user’s unique subdomain.
Devise Token auth sends a different access token with each response and expects that it is used for the next request.
ng-token-auth is an Angular component that knows all about Devise token auth.
Emails to confirm sign up and to warn about overdue checks are created by merging templates with app data.
Instead of reinventing this expensive wheel, we use the wonderful API from sendwithus.com to define the templates. The API call uses credentials taken from environment variables (so not saved in git) together with data needed for the the message, and sendwithus takes care of merging and sending the messages using another service, mailgun.com.
Emails and SMS messages are queued in the database and sent using an asynchronous sidekiq worker thread. The result is also saved in the database.
Sending SMS messages
We use the esendex.com API to send text messages. The code to call their API is contained in one small class so it will be easy to swap to another provider if necessary.
As soon as a bug is found, an issue is raised in github and a test case is written to describe how to replicate the error.