Slopes Diaries #8: Web vs iPad

Slopes Diaries is my ongoing journey to turn my indie app into a more sustainable part of my business. First time reading? Catch up on the journey so far.

What is Slopes? Think Nike+, Runkeeper, Strava, MapMyRun, etc for skiers and snowboarders.


I've been tweeting bits about how I'm approaching things a little differently when it comes to a web backend for Slopes, and I've had quite a few people express interest in hearing about it in more depth. I'm going to detour a bit for #8 to talk about how I'm running and monitoring my business without any custom web frontend.

My bio always contains "usually working on web and iOS stuff." I've been on the web since back in the 90s and I've been with it as it moved from pixel.gif to responsive, from the early days of jQuery into rich clients using frameworks like Ember / Angular. Truth be told, though, I think I've fallen out of love with most of web development. When I heard .NET was open sourced and moving to Linux I had hope I could rekindle that love with Slopes 2 (my j-o-b job way back when was a C# dev on the MVC framework, and man, loved what Microsoft did with that) but it wasn't ready for Linux by the time I needed to ship Slopes 2.

(I'm stubborn enough that I don't want to rely on a backend as a service like Parse; I like owning my own stack. Slopes runs on a PHP stack using Laravel, which takes inspiration from .NET, but isn't quite as fast as I'd like. Good enough for now, though. The code is hosted on a few Digital Ocean servers.)

The lukewarm feeling towards the web, and a lack of a framework I actually enjoyed, left me wanting to minimize my web stack as much as possible. But at the same time I knew phpPgAdmin would really slow down my ability to manage data.


The Slopes prototype from back in the 0.x days evolved into a kind of debugging tools app over the years.

I needed a toolset to debug customer's data to see where my GPS logic was a bit off, but I didn't want to dirty my main executable with any of that. So instead of killing my prototype I extended it into a new target, Debug Tools.app. This is probably the oldest code in Slopes.

This app eventually expanded to help me build and test my various OpenGL views so I could manipulate everything in ways that I didn't want to just ifdef DEBUG enable in the main app.


Slopes 2.1 is adding support for automatic lift naming. Slopes has always been able to say "you were on a lift here" vs "you were going downhill on a trail here", but that was always without any knowledge of where the lifts were at any given resort. It was all GPS voodoo. 2.1 is going to start using knowledge of lifts at resorts to label which lift you were on ("Bear Mountain Quad").

All this data is to be crowdsourced through Slopes, by subscribers emailing me their .slopes file for a day at a resort they'd like supported, and I needed a way to manage this data as I built up my data set. I couldn't think of a more ideal way to build, visualize, and interact with all this data than with an actual interactive map; much more natural than working with a bunch of raw GPS coordinates in a database.

I could have used the Google Maps SDK on the web (and I would have had to re-implement a ton of logic in PHP to support importing and parsing user files, and keep that in sync going forward), but my lack of enthusiasm for the web lead me to try something slightly unconventional: instead of having a web-based frontend for the Slopes backend, have a native iOS frontend and limit the server to a REST API. Reuse all my existing data model code, parsing logic, GPS logic, and get away with a few custom UIs and a few extra administrative REST endpoints.

So I threw out most of the old code in Tools.app and started fresh as an iPad app focused on two things: managing this new lift naming effort, and debugging customers' GPS data.

A day's worth of work and I was able to not only do the basic CRUD updates on the lift data that I would have been able to through a web interface, but also drag/drop the lift endpoints, use user-submited activities to kick-start the lift identification efforts (coalescing multiple users' recordings to get an aggregate view of where lifts are using my existing lift detection code), and more.

Then I took the app further. Despite my "works everywhere" marketing, people always ask if Slopes works at resort X or Y. I used to answer this through queries in phpPgAdmin, but now I can search in app by name or near a given location. All this reuses existing logic in my iPhone app, save for the name-based search, and was just a quick custom map view.

One of the cool things I found out while reworking Tools.app was dragging and dropping files into the simulator works (it was broken for a bit in the Xcode 6 days, and I had forgotten about it). If your app is registered to open a file type, and you drop that onto the sim, your app will open the file as if the user had tapped open-in from an email attachment.

When I was first exploring alternatives to a web frontend I considered a full Mac app (I'd at least get some code reuse out of that), but drag-and-drop support makes the iPad simulator running Tools.app feel close enough to a Mac app that it isn't worth it, IMO. I can just drop any customer file from my desktop email client into the simulator, no spelunking into ~/Library/Developer/CoreSimulator required, and it'll open right up and I can get to debugging.

So, yeah, I have an app powering my app. If you just use the stock iOS controls, and don't get fancy, you'd be surprised how fast you can build out an admin dashboard on iOS.

All this took 2 days to set up.

There was some stuff I also wanted in my dream dashboard app, like a view of people buying subscriptions and revenue figures, but I wanted that via push notifications...

Slack + Custom RSS = A Poor Man's Dashboard w/ Push

Everything integrates with Slack.

The great thing about maintaining control over your own backend? It takes 15 minutes to throw together an RSS feed to aggregate what's going on in your system, point Slack to it, and get instant push notifications to your iPhone for your own stuff, too.

What do I have going into Slack?

  • Protected RSS from my server: I've always been a fan of AppFigures, but I hated waiting for iTunes Connect reports to see what my day's revenue looked like. Since I track/validate subscription purchases server-side I can now see instantly when someone subscribes, instead of 24 hours later.

  • I've upgraded this RSS feed to now include a report at midnight (server time) every day on my rolling subscription revenue over the last year, a look at how my annual recurring revenue was affected that day (churn vs renewals vs new subscriptions), and a theoretical annual recurring revenue snapshot. Individual subscription purchases give me great excuse to high-five my wife, but the ARR is what I need to keep an eye on as I build Slopes up.

  • I use AppFigures to aggregate App Store reviews into Slack.

  • Help Scout (my customer support system) has a Slack integration which posts any new support emails or replies to the support channel. I don't have push to my phone enabled on that (too much stress, I'd rather deal with support on my terms), but I do on the desktop.