---
layout: page
title: Projects
subtitle: Things I like to work on
url: /projects
toc: false
---

These are the projects I like to work on, in no particular order. I prefer to open source everything I do, but sometimes the end results is more important than the code, as is the case with [We Ride](https://weride.social). The code is a bit of a mess, and that's ok! We Ride is a utility for me to find gravel and mountain bike partners.



{{< rawhtml >}}
<table>
  <thead>
    <tr><td>Project</td><td>Description</td></tr>

    <tr>
      <td><a href="#bench-bicycle-workshop-manager-">Bench, Bicycle Workshop Manager</a></td>
      <td>Bench is a SaaS that streamlines managing bicycle workshops</td>
    </tr>

    <tr>
      <td><a href="#we-ride-">weride.social</a></td>
      <td>A local-first social network for cyclists</td>
    </tr>

    <tr>
      <td><a href="#neoq-">neoq</a></td>
      <td>A queue-agnostic background job framework for Go</td>
    </tr>

    <tr>
      <td><a href="#ess-">ess (env sample sync)</a></td>
      <td>Automatically keep .env files in sync with env.sample</td>
    </tr>

    <tr>
      <td><a href="#di-tui-">di-tui</a></td>
      <td>A terminal UI player for di.fm premium</td>
    </tr>

    <tr>
      <td><a href="#hugo-htmx-go-template-">hugo-htmx-go-template</a></td>
      <td>A Hugo project template for making dyanmic Hugo sites. It's weird and I love it</td>
    </tr>

    <tr>
      <td><a href="#open-glide-club-">Open glide club</a></td>
      <td>Paragliding and Hanggliding site directory using Open Street Map as the database.</td>
    </tr>
    
  </thead>
</table>
{{< /rawhtml >}}

---

## [Bench, Bicycle Workshop Manager](https://bench.bike) (https://bench.bike)

_Bench_ is the only business venture that I'm comfortable sharing as one of my
"projects". Primarily because it's not only a business venture, but adjacent
to one of my primary pastimes -- cycling.  Noticing that bike shops almost
universally lack a good online service booking experience, I suspected that most
shops lacked good software systems for managing work orders.  So I started
talking to mechanics and shop owners about how they manage their bike workshops.
Eventually those conversations turned into Bench.

## We Ride (https://weride.social)

_We Ride_ is a local-first "social network" for cyclists to find riding partners and join group rides in their local communities. While "social network" is roughly how I describe it, the end goal is not to have large network effects and claim a large percentage of the world's cyclists. It's a tool that I built for myself.


Since I spend a lot of time traveling, I'm often in new places where I don't know any other riders. So to find new gravel routes, or to safely ride more consequential mountain bike trails, I need to tap into local rider base and knowledge. So what I do is create a _We Ride_ and post about it in the local Strava clubs. Strava clubs tend to not get many posts, even if they're over 1000 members, so when a new post arrives, a lot of people end up seeing it since by default Strava notifies club members of new posts.


If there are no local Strava clubs, a lot of trail systems have a cork board for posting community information. _We Ride_ has a "Print QR Flier" feature that I can use to print fliers for trailhead cork boards.


_We Ride_ also allows you to upload GPX routes and import them from Strava, which is my preference since I like to build ride routes in Strava.

## Neoq (https://github.com/acaloiaro/neoq)

Neoq is a background job framework for Go. Its central thesis is that background jobs shouldn't impose any additional infrastructure on projects. Neoq could hardly be simpler to use and has a [pleasant API](https://pkg.go.dev/github.com/acaloiaro/neoq) that makes writing background jobs dirt simple.

Does the world need another background job framework? No, but I do. I work on a lot of projects that never see the light of day. I'm ok with that, especially when I haven't put a lot of time into building infrastructure and code for them.

What does that have to do with Neoq? Since Neoq can be backed by _in-memory_ queues, _Postgres_ queues, or _Redis_ queues -- it's easy to match my application infrastructure with my background job infrastructure. For development/non-critical jobs, I use in-memory queues, and for "production" I use either Postgres or Redis, depending on my needs, without changing a line of application code. This makes it easy for me to get projects off the ground without creating additional infrastructure for background jobs.


**Example in-memory job handler code**
```go
ctx := context.Background()
nq, _ := neoq.New(ctx)
nq.Start(ctx, "hello_world", handler.New(func(ctx context.Context) (err error) {
  j, _ := jobs.FromContext(ctx)
  log.Println("got job id:", j.ID, "messsage:", j.Payload["message"])
  return
}))
```

Now, all you have to do is add jobs.

```go
nq.Enqueue(ctx, &jobs.Job{
  Queue: "hello_world",
  Payload: map[string]interface{}{
    "message": "hello world",
  },
})
```

Neat.

## ess (https://github.com/acaloiaro/ess)

env-sample-sync - automatically keep `.env` files in sync with `env.sample`.

Your `.env` is always in `.gitignore`, right...right?! So how do you document what goes in it? Easy, add a file named `env.sample` to your project and check it in to git.

The problem is that `env.sample` rarely gets updated when new environment variables are added to applications. `ess` is the solution to that problem.

Users can document `.env` with comments and extensive details about how env var values should be structured, or where one can get/generate values for them.

**Example `.env`**

```
APPLICATION_SECRET=supersekrit

# I got this FOO from the detailed process documented at: http:://wiki.example.com/how_to_get_a_foo
FOO="My super secret value for foo"
```

**`ess` converts the above `.env` example to:**


```
APPLICATION_SECRET=<APPLICATION_SECRET>

# I got this FOO from the detailed process documented at: http:://wiki.example.com/how_to_get_a_foo
FOO=<FOO>
```

After syncing the sample, it is immediately `git add`ed, ensuring that your sample is always up to date with reality.


## di-tui (https://github.com/acaloiaro/di-tui)

A terminal UI player for di.fm premium.

There's not much more to say about this one. I use this virtually every day that I'm at my computer. I'm using it as I write this, in fact.

It's totally unnecessary, and I love it.


![di-tui screenshot](https://user-images.githubusercontent.com/3331648/81481515-bb668400-91fe-11ea-8a7c-39e1bb76c55d.png)

## hugo-htmx-go-template (https://github.com/acaloiaro/hugo-htmx-go-template/)

Hugo is a fantastic static site build tool, and there are few things about Hugo that can or should be improved.

The existence of this project template should in no way suggest that static sites should be dynamic. If your site can be static, it should be static.

Yet there are instances in which one might need to add dynamic functionality to static Hugo sites. That is the purpose of this project template. Not to make all static sites dynamic, but to provide a simple solution to add islands of dynamic behavior to static sites.

This allows us to build fast, easily deployable HTML content, but with the added ability of meeting a new class dynamic behavior needs.

Example use cases include

- Contact forms
- Comment systems
- Up/Down vote systems
- You know ... website stuff

You shouldn't have to reach for a SaaS product to offer dynamic content on your static sites.

## Open glide club (https://openglide.club/)

Open glide club uses [Open Street Map](https://openstreetmap.org) as a database of free flying (paraglide/hangglide) sites.

I created OGC because the world is full of great gliding sites, and not all of them have a club that's taken time to map them out. By using Open Street Map, OGC not only makes gliding site data available to the world in an accessible way, but creates the first frontend / renderer of free flight data that pilots have been adding to OSM for years.

