Post

Case Study: Daily Reflections

A project analysis of the Daily Reflections Discord bot.

Case Study: Daily Reflections

Discord bot that posts the Daily Reflections on recovery in Discord on a schedule or when users invoke the bot with /reflections.

repository

Overview

Tech Stack

Motivation

This side-project spawned from being active in several community Discord servers focused on sobriety and discussions referencing the Daily Reflections but users still uploading and sharing PDF files in chat. I didn’t have a well-formatted version of the Daily Reflections and thought about doing OCR on the PDFs but realized that would involved a fair number of OCR errors that would need manual correction. I found an easier solution by scraping an unsecured XML database for a well-structured version of the Daily Reflections that I persisted in Supabase. The Daily Reflections do not change, so a one-time scrape was sufficient and the project is not dependent on continuing access to the other database.

I knew from messing with Carlbot and Discohook as a Discord server admin that Discord embeds allow for well-structured formatting of rich text in Discord chat. I decided to build a bot to post the Daily Reflections as a structured embed into the Discord servers that I am active in.

Features and Functionality

  • Scheduled posting of the Daily Reflections to Discord servers
  • Users invoke the bot to post the reflection of that day using /reflections command in Discord chat
  • Supports multiple Discord servers via webhook URLs

example reflection post in Discord

Technical Choices

  • Leveraged the Discordjs SDK because it’s well documented and that made transforming the JSON data from my Supabase data API into Discord embeds straightforward.

  • Adopted hosted Supabase as the PostgreSQL database because of its ease of use, integrated data API, and uptime guarantees.

  • I combined my learnings from Tabletop’s API data fetching and transformation with Discordjs to rapidly develop and deploy a Minimum Viable Product.

  • Designed an event-driven architecture to leverage Discord’s webhook infrastructure and enable just-in-time delivery of messages and scheduled posts.

  • Deployed on Netlify over Vercel because of Vercel’s limits on scheduled cron jobs. I knew I wanted the ability to post the Daily Reflections into multiple servers (and make it configurable) so multiple crons would be helpful.

Challenges and Solutions

  1. Required a copy of the Daily Reflections - Evaluated doing Optical Character Recognition (OCR) on the Daily Reflection PDFs but knew that would have errors that would need manual correction. Instead I found and scraped an unsecured XML database for a well-structured version of the Daily Reflections that I persisted in Supabase.
  2. Local devlopment and testing of cron jobs - Leveraged the Netlify CLI for cron testing locally along with manually testing the endpoints with authorized requests sent from Postman.
  3. Debugging event-driven functions across services - Leveraged AVA with TypeScript for unit tests along with integration testing to ensure consistent and reliable performance.
  4. Transforming data into Discord Embeds - Implemented TypeScript just-in-time data transformation using Supabase table return types and a custom Discord embed type.

Lessons Learned

  1. Leverage social platforms for distribution - Pushing interactions to where users are is easier than getting them to leave platforms to use web clients. Discord is popular because how easy it is to use it as a frontend as opposed to developing your own web client and frontend.
  2. Serverless is designed for lightweight, asynchronous, and event-driven projects - the Lambda function infrastructure of serverless platforms are event-driven: they only listen for invocations to start their request cycle and shut down again after. It’s great to push for asynchronous, event-driven execution as much as possible for on-demand compute as opposed to paying for continuous access to cloud resources.
  3. AVA is much easier to run TypeScript tests than Jest - I tried to use Jest initially for its established ecosystem but quickly ended up in config hell. AVA TS support is just adding a tsimp dev dependency and one config object in package.json.

Future Considerations

  1. Explore potential monetization strategies such as premium subscription for advanced interaction features.
  2. Add admin configuration options:
    • Scheduled post time
    • Channel to post into

Impact

  • The Daily Reflections bot posts daily to over 1000 Discord users through Discord.
This post is licensed under CC BY 4.0 by the author.