Bowsley – building a Laravel application in public

I started building an app in public: Bowsley, an app to add reseller hosting features to Laravel Forge.

The idea is simple. Collect hosting fees from clients without you having to chase them.

In the spirit of openness, this is the first part in a series of posts that explains the process.

Coming up with the idea

I hate chasing clients for their hosting fees! Even though I’ve set up automatic invoicing, some clients ignore the invoice.

When I don’t pay my hosting fees – my hosting provider brings down my servers. Paying my hosting fee brings them back up.

I wanted a service that would extend that functionality to my clients. When I couldn’t find that online, I thought – hey, I can build this!

Getting traction

I gave myself some accountability by launching the landing page before I wrote any code.

That’s not entirely true… being a developer I bought a license for TailwindUI and built the landing page from their component library.

It was an excuse for me to try out TailwindUI (it’s something that I’d like to bring into the Mindbeat platform). I was able to get it together very quickly, but if I had to do it again I’d consider using a service like https://cardd.co.

I launched the marketing website on 19th April 2021.

Planning

There are three feature that Bowsley will need to do well:

  • Connect Laravel Forge sites to Bowsley
  • Yearly payment collection for hosting fees
  • Automatic website suspension for overdue payments

Even though I enjoy speccing out feature requirements at my day-job, I wanted to get a prototype going! So I did what I do best, and started a new Laravel project…

Tech stack

It’s been a while since I started a new project! Things move fast in the development world. I was looking at this as an opportunity for me to learn something new and keep up to date.

I settled on using Laravel’s Jetstream starter kit, with InertiaJs.

Scaffolding the application was very easy. I was ready to start working on the business logic within a few minutes. Thank you Taylor.

Connecting a Laravel Forge site

I wanted to build an easy flow to allow users to connect their Laravel Forge sites to Bowsley.

The Laravel Forge SDK makes consuming their API very easy.

Presenting a full list of sites and servers to the user required some API calls. I cached the results for future requests to speed up the response time.

$sites = Cache::remember("sites_{$request->user()->forge_api_token}", 60 * 60, function () use ($forge) {
            return collect($forge->servers())
                ->where('type', 'app')
                ->where('isReady', true)
                ->flatMap(function ($server) use ($forge) {
                    return collect($forge->sites($server->id))
                        ->map(function ($site) use ($server) {
                            return [
                                'id' => $site->id,
                                'name' => $site->name,
                                'server_id' => $server->id,
                                'server_name' => $server->name,
                            ];
                        })
                        ->values();
                })->values();
        });

The above piece of code will need some work eventually, but for now it suits my purposes fine.

Laravel Jetstream comes with many useful UI components out of the box. I built out a simple form to create a new “Site” resource using these components.

Using this flow allows me to work fast, and play to my strengths: I’m a good developer, I’m an “OK” designer. I try to use other people’s designs to be able to create high quality UIs without needing great design skills.

Configuring payment requests and website suspension

With the same workflow as above, I was able to (relatively) quickly get an “edit” screen going to collect some more information that I’d need to set up payment collection and website suspension.

I decided to make it possible to enable and disable these features. I might change my mind about this later, but it feels like a good amount of flexibility to offer my future users.

Website suspension

One of the features I wanted to see working was the website suspension one. I like using the concept of “Actions” to encapsulate business logic in my application, and started working on a couple of actions that leveraged the Forge API:

  • SuspendSiteAction
  • RestoreSuspendedSiteAction
  • ResetSuspendedStateAction

I’ll save exploring these actions in more depths for another post!

End

I’m happy with the progress I’m making so far.

  • It feels very organic.
  • The speed at which things are coming together is something that I’ve missed at my day job, which requires more planning.
  • I’m naturally prioritising features without too much stress in the order that I build them.
  • I have a good balance of “hacking things together” and using Test Driven Development to develop more business critical features.

I’m building this app in public, follow me on Twitter as I continue to document my journey.