Chapter 5 · Own build5•1

Discord bot

A Discord bot for one community of about 2,000 members, built three times. V1 ran games, a points economy and roles; V3 is the rework, a small dictionary bot built to get the structure right.

What changed most is the shape of a command. In V1 every command was handed the same eight arguments, used or not; in V3 a command is one object with a name, a run and its help, and the router hands each the message, parsed once.

It was also Kevin's first GitHub Actions workflow: pushing a version tag rebuilds and restarts the bot on a self-hosted runner. Retired now, kept here as it was.

Entrant
Kevin, own build
Period
2017–2022
Status
Retired

Wiring key

Discord bot5•2

Fig. 5.1 · One message, three builds

How a message runs through each build of the bot, stage for stage.

Three diagrams side by side, one per build, each following a Discord message from top to bottom. V1, April 2018: the message goes into one entry file, which does everything in one housing: it checks which channel the message is in, picks a command from three lists, runs it with the same eight arguments as every other command, and also gives points, reacts and tells dad jokes; after every message it writes the members file back to disk. V2, late 2018: the work is split into a message handler, a command handler that reads each server's prefix from the database, and a function handler; commands are moving to run with only the message, 12 of 17 done; members move to MongoDB, one database per server. But the lead from Discord into the handlers is broken: the entry file never wires them in, 133 of its 162 lines are commented out. V3, 2021 to 2022: index.js parses the message once into details, the dictionary module matches the prefix d!, the matching command of three runs with the message and its details and fetches its own answer, and the answer goes back by direct message while the command is deleted from the channel. Nothing is stored.

Fig. 5.2 · One plug for every command

A command is the same shape every time, so the router never needs to know one. In V1 that shape was a run function with eight pins, all of them wired whether the command used them or not.

V1, every command: run(Discord, client, message, words, currencyMembers, axios, cleverbot, he)

V1: for each of its 17 working commands, which of the eight arguments the router hands it are used by its run function. 51 of 136 are used.
CommandDiscordclientmessagewordscurrencyMembersaxioscleverbothe
ask
color
currency
gamble
give
hangman
highlow
iam
iamnot
leaderboard
quiz
slots
snowball
stats
time
timeout
toptalkers
Used by1111799211

used handed over, unused51 of 136 pins used

V3, every command: { name, run(msg, details), help }

// index.js, shortened
modules.forEach(mod => mod.commands.forEach(command => {
  if (mod.prefix + command.name !== details.firstWord) return;
  command.run(msg, details);
}));
  • details is parsed once, before any command runs: args, firstWord, mentionOrAuthor, isOwner, hasMentions.
  • A command imports what it needs itself, axios or the HTML parser, instead of being handed everything.
  • A new command is one file, and one line in its module’s list.
Fig. 5.3 · Deploy by version tag

Kevin’s first GitHub Actions workflow. The result: pushing a version tag rebuilds and restarts the bot on a self-hosted runner.

Pushing a tag starting with v starts the workflow on a self-hosted runner. It stops the old container, clones the repo, writes the bot token from the repository's secrets into a .env file, builds the Docker image tagged with the version, and runs it.

Notes

  • Every count on these pages is read off the public repos of the three builds.
  • Source: V3, on GitHub

Pit limiter on

Kevin

Frontend developer at Zinderlabs since 2021. Professional Bachelor Applied Computer Science, KdG 2017–2021.

Code on github.com/kevhauma.

Stack

Experience

  1. 2021 – nowZinderlabsConsultant, frontend and full-stack · clients include VG Computers, Jumperke, Aurubis, ArCom, publiq, Clearmedia
  2. 2017–2021Professional Bachelor Applied Computer ScienceKdG · internship at Zinderlabs on Platform Planner, 2021

Projects

  1. 2026 – nowmoney-mosaic-v2 · own buildLocal-first finance: bank CSVs in, rules and a trained network, honest stats out, nothing sent
  2. 2021–2023Scrap yard management · AurubisPlanning to invoicing for a multi-plant copper scrapyard
  3. 2023Driver check-in kiosk · AurubisSelf-service check-in for delivery drivers, run by a state machine
  4. 2023–2024DBA tool · ArComA legacy C++ application rebuilt for the web, without its source code
  5. 2017–2022Discord bot · own buildOne Discord bot, built three times, down to one shape for every command
  6. 2025 – nowCommonGround · own buildA household's week in one app, open to an AI assistant over MCP

Other work

  1. 2025–2026 · 14 moMicrosoft services reselling platform · ClearmediaA B2B client portal and back office for reselling Microsoft services, including reseller packages and invoicing.
  2. 2024 · 4 moUiTPAS counter app · publiqA counter app for UiTPAS cards and profiles, migrated page by page from AngularJS to React, with a seamless fallback to the old pages.
  3. 2021 · 3 moRoute planning and order tool · JumperkeAdmin tools to plan delivery and pickup routes, plus bug fixes in the client-facing order tool.
  4. 2021 · 2 moWebstore · VG ComputersA webstore and its admin back office: Meteor components moved to React, plus user reviews and breadcrumbs.
  5. 2021 · 1 moPlatform Blog · ZinderlabsAn internal blog for knowledge sharing and meeting notes, with a Markdown editor.
  6. 2026 · 1 moPlatform Planner, Vue 3 upgrade · ZinderlabsThe planner Kevin built during his internship in 2021, upgraded page by page to Vue 3 with a redesign, falling back to the Vue 2 pages through iframes.
  7. 2026 – now · in progressBuilding installation planner · construction tech client, under NDAA planner for building installations, for a client in construction technology. Kevin leads the frontend and works across the stack.

Contact placeholder

Email and LinkedIn go here once Kevin adds them.

Download CV not uploaded