I created a simple kanban style to do list web application called Tinyban.
It is rather simple: You get as many boards as you want. Boards have a title and can either be private or public. Private boards can only be handled by their creators. Public boards can be viewed by anyone who knows the link.
After creating boards you are able to put tasks on them. Tasks have a title and a body. The body may contain a limited subset of markdown. Tasks can be in one of the three columns:
Work In Progress and
Tinyban is hosted on Heroku, because it is the easiest way to get a Rails application online. I wanted to spend my time and energy on developing the application rather than installing and securing some kind of server, providing a ruby runtime on it and setting up PostgreSQL, mail handling etc. pp.
Heroku supports custom domains via
CNAMEs. I chose Cloudflare as DNS provider, because they are the only company (I could find) offering
CNAME flattening on root domains for free.
CNAMEs can usually only be put on subdomains (
subdomain.domain.tld). If you put a
CNAME on a root domain (
domain.tld) on Cloudflare, they resolve whatever DNS name your
CNAME is pointing to and provide that as
Here is some shortened
dig output to show how it works:
user@host: ~$ dig CNAME www.tinyban.com ;; ANSWER SECTION: www.tinyban.com. 300 IN CNAME host.herokudns.com. user@host: ~$ dig CNAME tinyban.com ;; AUTHORITY SECTION: tinyban.com. 2817 IN SOA alex.ns.cloudflare.com. dns.cloudflare.com. 2031678281 10000 2400 604800 3600 user@host: ~$ dig A www.tinyban.com ;; ANSWER SECTION: www.tinyban.com. 101 IN CNAME host.herokudns.com. host.herokudns.com. 60 IN A 18.104.22.168 host.herokudns.com. 60 IN A 22.214.171.124 host.herokudns.com. 60 IN A 126.96.36.199 host.herokudns.com. 60 IN A 188.8.131.52 host.herokudns.com. 60 IN A 184.108.40.206 host.herokudns.com. 60 IN A 220.127.116.11 host.herokudns.com. 60 IN A 18.104.22.168 host.herokudns.com. 60 IN A 22.214.171.124 user@host: ~$ dig A tinyban.com ;; ANSWER SECTION: tinyban.com. 44 IN A 126.96.36.199 tinyban.com. 44 IN A 188.8.131.52 tinyban.com. 44 IN A 184.108.40.206 tinyban.com. 44 IN A 220.127.116.11 tinyban.com. 44 IN A 18.104.22.168 tinyban.com. 44 IN A 22.214.171.124 tinyban.com. 44 IN A 126.96.36.199 tinyban.com. 44 IN A 188.8.131.52
I put Cloudflare in
DNS only mode, so traffic goes directly to Heroku.
Beginning with the smallest paid plan ($7/month for one
Hobby dyno), Heroku handles TLS automatically with Let’s Encrypt.
Outgoing emails are handled by AWS Simple Email Service. They offer a SMTP interface which makes configuration with Rails’ ActionMailer very easy. Open a support ticket and request a sending limit increase to be moved out of the SES sandbox which enables you to send emails to all recipients.
To make logs search- and filterable, I added LogDNA from Herokus’ add-on marketplace to the app.
Unhandled exceptions are bad. Not noticing them is worse. Sentry is a nice solution to exception management. It groups them, opens issues and can even tell you which line of code caused the problem.
This setup relies on more external parties than I am accustomed to. But it has enabled me to concentrate on building the app alone. I managed to ship at least one tiny feature every day for the past two weeks because productivity feels very high.
There are some things I think I will want to have in the future: Task submission by email, task attachments and two factor authentication.
Building task submission by email should be rather easy, thanks to the new ActionMailbox framework in Rails 6. Like all nonessential features, this should be opt-in per board. Tinyban will set up one incoming SES email address for every board the user enables it on. Authentication and authorization will be handled by having a long and randomized username part in the email address. Whitelisting sender addresses will probably be implemented at a later point in time.
Task attachments will be done with ActiveRecord and ActiveStorage. I am going to try to implement an ActiveStorage adapter for Backblaze B2 because it is much cheaper than AWS S3. I am not sure whether B2 supports all operations necessary for ActiveStorage support, so let’s see where that is going.
At the beginning, I decided not to use Devise for user management in Tinyban. Customizing it to be as simple and datensparsam as I wanted it to be would have taken longer than implementing what I needed (:has_secure_password) by myself. This means I will have to do more than just include the devise-two-factor gem to enable two factor authentication, but rotp and attr_encrypted will certainly be of help.