Mobile-First Static Site Publishing: Discord Bot Pipeline via Azure and GitHub

← Home | ← All posts | View Full Version

The problem

Ever since I published my first note(microblog post) on my website, I've always wanted a way to quickly publish while on the go. Unfortunately, I never found a good solution.

Because my website is statically generated and the source is hosted on GitHub(check out the colophon for more details), there is no backend for me to talk to. At the same time, I didn't want to build an entire backend to support my website because I want to keep things as lean and cost-efficient as possible.

Since my posts are just frontmatter and Markdown, I use VS Code as my editor. For some time, back when I used to have a Surface Duo, I authored posts from mobile using the github.dev experience. On two screens, while not ideal, it was manageable. After switching devices (because sadly there were no more security updates on the Surface Duo) and upgrading to a dumbphone and later a single screen smartphone, that workflow wasn't feasible.

At that point, what I resorted to was sending messages to myself via Element. The message would contain a link I wanted to check out later. Once I was on my laptop, I would check out the link and if I wanted to post about it on my website, I'd do so then.

That process, while it worked, wasn't necessarily scalable. In part that's a feature because I could spend more time digesting the content and writing a thoughtful article. However, it stopped me from sharing more in the moment and there were posts that were never authored or bookmarks that weren't captured because eventually that link got lost in the river of other links.

Basically what I wanted to replicate was the more instant posting that social media gives you, but do so on my own site.

That led me to doing some thinking and requirement gathering around the type of experience I wanted to have.

Requirements

When it came to requirements for my solution, I was focused more on the workflow and experience rather on technical details.

Here is a list of those solution requirements:

  • Mobile is the primary publishing interface. Desktop publishing is a nice to have.
  • Be as low-friction as sharing a link via Element or posting on social media
  • Doesn't require implementing my own client or frontend
  • Doesn't require me to use existing micropub clients
  • Handles short-form and media posts supported by my website
    • Notes
    • Responses
      • Repost
      • Reply
      • Like
    • Bookmark
    • Media
      • Image
      • Audio (not used as often but technically supported)
      • Video (not used as often but technically supported)
  • Low-cost

The solution

For years, I had been struggling with actually implementing this system. The main part that gave me pause was not implementing my own client or relying on existing micropub clients.

Eventually, I just accepted that it might never happen.

One day, it eventually hit me. If the notes to self Element workflow worked so well, why not use a chat client as the frontend for publishing. At least have it serve as the capture system that would then format the content into a post that gets queued for publishing on GitHub. I'd seen Benji do something similar with his micropub endpoint.

While I could've used Element since that's my preferred platform, I've been contemplating no longer hosting my own Matrix server. So if I went through with this, I'd want something that I didn't feel bad about investing the time on this solution if that chat client went away.

That then left me with Discord as the next best option. Primarily because of its support for bots as well as its cross-platform support across mobile and desktop.

In the end, the solution then ended up being fairly straightforward.

More importantly, with the help of AI, I wrote none of the code.

Using Copilot and Claude Sonnet 4, I was able to go from idea to deployment in 1-2 days. At that time the solution supported all of the posts except for media which I hadn't figured out what the best way of uploading media through Discord was. Figuring that out, implementing it, and deploying it took another day or two.

Since I wanted for my solution to be as low-cost as possible, serverless seemed like a good option. I only pay for compute when it's actually being used which can be infrequent in my case. I don't need the server running 24/7 or even to be powerful. However, I didn't want to write my system as an Azure Function. I wanted the flexibility of deploying on a shared VM or container. A VM though wasn't an option since it's running 24/7. Keeping all of that in mind, my choice was narrowed down to Azure Container Apps which gave me the characteristics I was looking for. Serverless containers.

Once that decision was made, I used Copilot again to figure out how to optimize my container image so that it's space and resource efficient. And while at it, I used Copilot again to figure out the right incantations to get the container deployed to Azure Container Apps.

All-in-all, the solution had been staring at me in the face since I already had a workflow that for the most part worked for me, it just needed some optimizations and with the help of AI, I was able to quickly build and deploy something I'd been ruminating over for years.

Workflow

The workflow for publishing is as follows:

  1. Invoke the bot in Discord to capture my input using slash command /post and the respective post type.

    [Image: Using slash commands to invoke discord publishing bot]

  2. Provide post details. For media posts, I can provide an attachment which gets uploaded to Azure Blob Storage.

    [Image: A modal in discord with note post fields filled in]

  3. Bot creates a branch and PR in my repo with the post content

  4. While logged into GitHub from my phone, if everything looks good, I merge the PR which kicks off my GitHub Actions workflow to build and publish the site including the new post.

  5. Post displays on my website.

Challenges

The solution is not perfect.

One of the problems I've run into is cold-start. Since I scale my solution down to zero when it's not being used to save on costs, I suffer from the cold start problem. Therefore, when I first invoke the bot, it fails. I have to give it a few seconds and retry the invocation. It's usually about 5 seconds so it's not a huge issue but it does add some friction.

Next steps

Overall I'm happy with my solution but there are

  • Open-source the repo - Currently I've kept the repo private since it was all AI generated. Since my system is already in production and processes were documented, I need to do a more thorough pass to make sure that no secrets or credentials are checked in or documented anywhere.
  • Improve UX - Discord limits modal fields to 5. Therefore, I'm playing around with the right balance between how much of the input should come from slash commands and how much should come from the modal.
  • Expand supported post types - I'd like to expand the number of posts supported by my publishing client. Reviews are a good example of the type of post I'd like to support as well as RSVPs. Reviews I already support on my website but RSVPs I don't yet. Also, I'd have to fix my Webmentions which are currently broken after upgrading my website.
  • Make it generator agnostic - Currently this only works for my website. With a few tweaks and refactoring, I think I can get the project to a place where it should work with other popular static site generators.
  • One-click deployment - Currently the solution is packaged up as a container so it can be deployed from anywhere. I want to make it even simpler to deploy. One click if possible.