Things that unoriginal side projects should have in common

It’s a long title. I want to execute more than one unoriginal side project, so as many factors should be shared as possible, as easily as possible.

I’m not making original side projects anymore – I’m hunting for financially viable ideas that *have already been executed*.

I’ll cut down the scope and clone them as quickly as possible, and set them free. Each project will get sharper, build on the tools from the last, and eventually they will start finding a base.

Here’s a list of things that all of my unoriginal side projects will have.

  • They start free or very cheap, and slowly boil the frog (apparently that’s not a real thing).
  • A user can join as soon as they land on the site, and from every page on the site, and easily add the rest of their team. There’s access levels for different users (Owner, Editor, Viewer, for example).
  • Users don’t have remember an email and password – can sign in with google, github, and office 365. There is email & password signin though.
  • Billing uses Stripe Billing pre-built tools, to save writing that whole layer.
  • From the get-go, users get a subdomain for their tenant/team. E.g.
  • All of these unoriginal SaaS’s are an MVP. Throwing mud until it sticks. They must be serverless or zero maintenance. Not buying a domain name, standing up a server, buying a g email address and all that shit for an app that in all likelihood will have a quick death. It takes 6 months for a side project to get some SEO results/organic visitors cranking, and I don’t want dollars burning away in the process.
  • If e-commerce related, they are shopify-first.
  • Comprehensive getting started docs and videos.
  • They’re easy to cast a net with well targeted SEO. Templates, recipes, case studies, documentation.
  • The marketing site is very easy to sign into and quickly add an article (e.g. wordpress level of 5-minute-article)
  • All are API first, and can be consumed as an API (assuming there’s comprehensive documentation). This allows a faster road to app stores and integrations.
  • Where possible, the tools will use each other. E.g. A support ticket tool will be useful to all other platforms
  • They need to be delivered quick. 3 month (at night time, not full time!) build, a month of documentation and SEO.

No more original side projects.

I had a thought tonight while out for a walk. If I wanted to open a takeaway shop, I’d start keeping track of the ones that looked like they were going well, and basically copy the execution model.

A coffee shop, a burger shop, or a bakery. Maybe a sushi store. There’d be no real ultra unique secret sauce typically, and I sure as hell wouldn’t spend years of my life waiting for the right type of takeaway shop to appear in my mind.

I’m not sure why I’ve spent years coming up with an original idea for a side project, executing it quickly, trying to work out a sales ‘message’, and doing the slow grind to find users. It’s just buying lottery tickets and hoping for the best.

First unique idea: an app builder for ecommerce stores.

I built “WooToApp”, an app builder for ecommerce stores. It didn’t exist at the end of the market that I wanted to target.

There were HUGE technical limitations and problems, and I felt like I was really innovating when architecting secure payments, secure orders, and a true drag and drop mobile app store builder for ecommerce stores.

I spent so long fucking around and working on techniques. Writing a piece of code and finding issues and re-writing.

Some technical limitations I just didn’t have enough time to reliably overcome. How can a user sign up instantly and have the app on their phone? I spent, I think, hundreds of hours on this.

I never killed it off. Just stopped iterating one day and it slowly died itself, never returning a dollar.

Second unique idea – dropshipping facilitation

I built “Elvenda” with my brother in law, a dropshipping enabler. Supplier signs up and adds their product catalog. Dropshipper signs up and imports products. Happy days, we can take a clip!

Except for all the problems that we had to discover, etch out solutions and execute ourselves. With no revenue or help, and no time.

What happens if fake products get shipped? How do returns happen? What platforms should we support? What formats can you import from? How the hell do we sell the idea to a “real” supplier?

We haven’t killed this off, and likely won’t. There’s just so much to do.

Uncool ideas – copying shit that is working

In 2016, I did some integration work for a brand new payment gateway called “AfterPay”. It didn’t support my clients store platform. The PDF they supplied as API docs was pretty rough and incomplete.

I quoted 12 hours to integrate AfterPay in this guys store and busted my ass. His sales increased overnight. Within a few weeks, 30% of his orders were using this new payment method, and his average order value was far higher. It was stupid expensive too, he was paying 5.5% + 30c on transactions.

The PDF documentation was so bad that by the time the integration was finished, I’d reverse engineered half of the API with postman. I got it.

I decided there’s nothing to it, and took 2 weeks off from contracting and wrote an almost exact clone of everything I could see. All it did was charge the end customer with Stripe on a cron job, and send me an email telling me how much to pay the merchant the next day.

I approached a client and also a friend with ecommerce stores and asked them to add my payment gateway, “PayItLater”.

Within weeks, the gateway was turning over so much money that my wife and I were out of cash. It was the most stressful 6 months of my life, but the nasty 2 week clone was working.

It works like this: A customer of the ecommerce store paid with ‘PayItLater’ for their $100 purchase. We paid the ecommerce store $94.20 ($100 – 5.5% – 30c), and basically hoped like hell that we’d recover the $100 from the customers credit card. The payment comes out in 4 payments over the next 8 weeks – it’s an addictive model, and .. Everybody knows about AfterPay now. They didn’t then.

Some guesswork modeling suggested 2% of people would be bad actors. I did some modeling on late fees and return customers as well that I don’t remember. We didn’t have any machine learning, historical data, AI or identity verification like AfterPay did. I just assumed everyone was a good actor, and banned their mobile number if they weren’t.

Since my phone was full of transactions every morning, I added a postcode to the transaction email. If we had more than 2 bad actors from a postcode the whole area would get banned. “Sorry, PayItLater is unavailable right now”.

As an aside, I remember a “Fuck Warrnambool” comment in the codebase – people in rural Victoria were somehow ripping me off.

We had no money, and our best guess was that PayItLater was making money. At any point in time if we added up the money that was out with merchants (that we were waiting to collect from their customers), deducted 2% for bad actors, it looked like it was creeping upwards ever so slowly.

I had $20,000 of my family’s money in PayItLater, and I’ve never been so stressed in all my life. I finally gave in one day – I couldn’t afford to grow it (I had $0 in real terms in the bank!) and had no idea how to take on money. I wasn’t having any luck with family and friends, and really didn’t even know how to ask.

In January 2017, we flicked the switch and turned off PayItLater. Customers could not check out with it anymore. The $20,000 we’d invested in PayItLater 6 months earlier slowly dripped back in and we ended up with $30,000. I sold the codebase to somebody who is still operating the business.

Where was I with the uncool business concept?

PayItLater worked, and was working. There was absolutely 0 original ideas and insight. I reverse engineered the plugin, had a best guess at how the backend worked, made the same or similar flows and went and got a customer.

There was no tricky decisions. No architecting flows. No guessing how to handle refunds. Not sure? Check AfterPay. Need a merchant agreement? Check AfterPay. What do I need to tell customers when a transaction is successful? Check AfterPay.

Why punish ourselves coming up with original ideas?

I don’t want to build Tesla or Uber, carving out a unique piece of history and making a huge dent on the world. I want Friday lunch at the beach and sleep ins on Monday.

I’m not doing original ideas anymore. You want to start a takeaway shop? You buy a coffee machine, a cash register, get a coke fridge and find a supplier of muffins.

You don’t scour the world looking for original ideas or try to come up with a meat free hamburger in your spare time. Nobody would buy it.

Next time, I’m picking something with a revenue model, that clearly makes money, that people have heard about, that is overpriced.

I’ll chop it down, make it cheap, easy to sign in and use, and easy for me to sell.

It’s not going to be technically interesting, ground-breaking, and there’s going to be no complex decisions involved.

I’m finding the boring profitable downtown coffee shop of SaaS tools and opening another one down the road.

Moving from Gmail to Hey

As part of a long effort to de-google where practical, I’ve moved away from Gmail to email service.

The problem with decoupling anything online from Google is twofold –
1. all of your stuff already lives there – I’ve had a Gmail account for 16 years. It’s all perfectly designed to keep you in the flywheel, letting it capture your information.
2. the services are best of breed. Gmail is pretty good. Fast, works everywhere, filters nicely into subcategories.

I have no idea how to get the last 16 years of data out, in a searchable, indexed, private way. That’s for another day. This post is about futureproofing the transition to Hey.

The temptation to just set up an auto forward from Gmail to Hey won’t fix the problem. You won’t update your email address, your personal information won’t be untethered from Google, and you’ll be paying the Hey folks $99 a year for a pretty thin email client.

Do it this way instead:

Step 1: Create a new mail label: “To Be Ported”.

In Settings > See all Settings > Labels, create a new label “To Be Ported”.

In Settings > “Filters and blocked addresses”, create a new filter. If it was sent to you, skip the inbox and move it to “To Be Ported”.

Step 2: Start filtering/unsubscribing/etc.

This takes forever. Every single email you receive is either shit you don’t care about, something you should update, something you can’t update, or something that’s not worth updating yet.

Next to the new label “To Be Ported”, click the 3 dots and add 4 new sub labels. Cannot port, Irrelevant, Ported, Unsubscribed.

Step 2.a: Shit you don’t care about

All the mailing list subscriptions you’ve accumulated over the last 10+ years – open them one by one as they appear in the “To Be Ported” label, unsubscribe from them, and move them to the sub-label called ‘Unsubscribed’. That’s 90% of them solved by quantity.

Step 2.b: Pretty good newsletters

About half of these will allow you to click ‘Update preferences’ near the bottom of the email and change your email address on file. Of these, about half will actually work.

Generally, you’ll need to unsubscribe and then resubscribe with your new email address.

Move all these emails to the “Ported” label – just drag them.

Step 2.c: The stuff you can’t port

I have no idea if I can port my icloud identity away from my gmail account. Didn’t try, not worth the hassle. Also, the emails they send me are junk. Drag these to the “Cannot Port” label. The only use for this is keeping the “To Be Ported” label empty, so you can deal with emails as they arrive.

Step 2.d: The too hard basket

My wife will probably never update my email contact. I could get around to sorting that out, but I won’t. I drop those emails in here since they are important to me but not ported.

Step 3: Once the queue dies down

I’m getting there. Once the ‘To Be Ported’ inbox slows to a dribble of new emails, it’s time for you to set up that auto forwarder. This means when a random old contact from 5 years ago emails you, it’ll go straight to the imbox.

Create a new filter (Settings > “Filters and blocked addresses”) and send everything on over to the address.

Step 4: Somehow get that data out of Gmail

Not sure of this yet. Enjoy your new email!

Firebase functions and CORS

A simple firebase http function template:

// accessible at https://us-central1-<app name>
exports.testEndpoint = functions.https.onRequest(req, res) => {
  if (cors(req, res)) {

  // do something

  // make sure to 'end' the request or it'll time out

We need to handle CORS requests (see cors() above), because the browser will send an OPTIONS request first to see what’s accepted by the endpoint. Your function handler in this case will receive an empty body, throw a bunch of errors, and generally waste a ton of time.

A simple CORS handler template:

const cors = (req, res) => {

  if (ALLOWED_ORIGINS.includes(req.headers.origin)) {
    res.set('Access-Control-Allow-Origin', req.headers.origin)
    res.set('Access-Control-Allow-Headers', '*')

  if (req.method === 'OPTIONS') {
    return true
  return false

If it’s an OPTIONS request, send back the approved origin and end the response (via true response).

If it’s a different type of request, set the approved origin and continue (via false response).

Quick/Easy Laravel/Docker



cd toys (projects folder)

mkdir saml && cd saml (a bare saml project)

curl -LO -LO

docker-compose up

Connect to the dev server over SSH in vscode and access at http://devserver:3000/

A blog for Emmett

It may come back to bite us. I made Emmett a WordPress blog tonight, a new outlet for his creative energy that so far is spent on long term minecraft trap strategies.

He’s 6, and it’s hard to find productive outlets for him. He gets tunnel vision about a single project at any one time.

So far, he’s added a post about home schooling and a general images post. I hope it consumes him like Minecraft does.

Emmett from Bargo’s blog.

Nuxt.js – redirect

The router docs are a little bit muddy with redirects.

Push the new route onto the stack to redirect.


Replace the route on the stack to replace in the browser.


Extra: Updating querystring

Changes the querystring in the URL bar to match the filters parameter.

Uses ‘replace’ to save polluting the back history (I hate that so much!)

          { path: this.$route.path, query: this.filters },
          e => {}

Laravel – re-assign relationships in updates

Alternate title: Stop stuffing around with entity_id.

Working on a project with a representative – a user who looks after the company.

When changing the representative, I want to supply the whole representative to the update method – e.g. $customer->representative is an object with an id, name, etc. It’s just a pointer, but it means less double handling to send in the object.

I do not want to extract the ID from the object that the user supplied and pass that to the controller.

In the Company model, we need a ‘setRepresentativeAttribute’ method. This extracts the ID and puts it in the representative_id column.

    public function setRepresentativeAttribute($value)
        $this->attributes['representative_id'] = $value['id'];

Instead of making sure representative_id is fillable, we now need to make sure representative is fillable on the model.

protected $fillable = ['representative']; //not representative_id

It’s a simple pattern, but also one I’ve implemented the long way in the past.

Vue.js – mapGetters with Params

Using mapGetters with parameters isn’t well defined in the docs, and is a pattern I go to use pretty regularly.

I never find a good search result, so here goes:

1.Define the getter in the store. Take note that the naming convention will be [store namespace]/[getter name] later. Since this is in my users store, it’ll be users/usersForMember. Note the function accepts a parameter.

  usersForMember: (state) => (member) => {
    return => u.member_id ===

2.Connect the component side getter to the getter in the vuex store. I kept trying to mangle mapGetters to accept my params. This is the wrong approach – it just need to be directly wired up. Note the [namespace]/[getter name] convention from above, so vue can find the getter.

import { mapState, mapGetters } from 'vuex'

/* snip */

computed: {
      // other stuff
  // this is it.
      usersForMember: 'users/usersForMember'

Now, the piece I always miss! Write a method in the component to call the getter with the parameter.

  computed: {
    /* snip, from above */
// this is it:
    users () {
      return this.usersForMember({ id: this.user.member_id })

Over in the template, we can now output {{users}} and see the results of our handywork.

VueX Patterns: Updating in Array

When working on a type of entity, it’s common to post the new or updated entity to the server and then need to update it in the local vuex data store.

This is a simple pattern that propagates the changes to the UI displaying the list of entities.

1. Save the entity, from the UI.

          .dispatch('catalogs/create', {
            catalog: this.user

2. POST the entity to the server in a vuex action, and pass the response to a mutation.
Note we also return the response data, in case the UI needs it for a flash message.

 async create (context, { user }) {
    const responseUser = await this.$axios.$post('users', user)
    return responseUser

3. Replace the object in array if it already exists. If it doesn’t exist, push it to the bottom of the array. Clone the array to trigger a UI update.

  userFetched (state, user) {
    const existsAtIndex = => ===

    if (existsAtIndex !== -1) {[existsAtIndex] = user
    } else {
    } = []

4. The UI which lists these users (UserRow below) will update itself with the new entry.

 computed: mapState({ users: state => state.users.users }),
<UserRow v-for="user in" :key="" :user="user" />