Discobot — Discord bot platform

One Discord bot, six plugins configured per server from a web dashboard.

Discobot — Discord bot platform
Role
Founder, lead developer
Stack
Laravel 12 · discord.js 14
Plugins
6
Status
Live

Context

A Discord server admin who wants a welcome message, reaction roles, tickets and invite tracking ends up stacking different bots, each with its own permissions, settings and reliability. The project started as a subscription bot marketplace; that model never worked end to end, and an audit found inconsistencies in the one-process-per-bot architecture.

Business challenge

Let admins run a full set of server tools without hosting or configuring a bot themselves.

Solution

A single platform bot, connected to every authorised server and driven from a Laravel dashboard. The bot receives Discord events and asks Laravel what to do; plugins are PHP classes that return a list of actions, which the bot carries out. All business logic stays in Laravel, tested in PHP, and the bot only executes.

Outcome

Six plugins enabled server by server, a Free plan (three servers) or Pro plan (unlimited), monthly or yearly, live logs over Reverb and a searchable action history. Nearly 800 PHP tests run in CI, alongside Node tests run against the real discord.js library.

My role

Founder & full-stack developer

Architecture

Users

  • Web dashboard
  • Discord servers (Gateway)
  • Stripe Checkout

Application

  • Laravel 12 · Livewire 3
  • Plugin registry and classes
  • default and discord queues
  • Reverb (real time)
  • Node.js bot · discord.js 14
  • Executor: 35 action types

External services

  • Discord API · OAuth2
  • Stripe (subscriptions)
  • MariaDB / MySQL
  • Redis
  • Meilisearch (Scout)
  • Sentry · PostHog

The flow, step by step

  1. Sign-in

    The user signs in with Discord, then authorises the bot on a server; their plan quota is checked before authorisation and on return.

  2. Configuration

    They enable a plugin in the dashboard and set its options, validated against the plugin’s schema.

  3. Event

    A Discord event — a member joining, a reaction, a command — reaches the bot worker.

  4. Decision

    The bot calls the Laravel API with its token; the relevant PHP plugin returns the list of actions to perform.

  5. Execution

    The executor carries out the actions with discord.js: send a message, add a role, open a ticket channel…

  6. Feedback

    Each action’s result goes back to Laravel, which logs it and streams it live to the dashboard.

Data model

The main entities, their key fields and their relations.

User

  • discord_id
  • plan
  • stripe_subscription_id
  • grace_ends_at
  • 1—n DiscordServer
  • 1—n PlanHistory

DiscordServer

  • server_id (snowflake)
  • bot_authorized
  • permissions
  • 1—n ServerPlugin
  • 1—n ServerAction
  • 1—n BotAuthorization

PluginRegistry

  • plugin_id · category
  • config_schema
  • default_config
  • requires_permissions
  • 1—n ServerPlugin
  • 1—n DiscordCommand

ServerPlugin

  • is_active
  • config
  • error_streak
  • avg_execution_time_ms
  • n—1 DiscordServer
  • n—1 PluginRegistry

ServerAction

  • action_type
  • status
  • execution_time_ms
  • 1—n ActionExecution

Ticket

  • guild_id · ticket_number
  • status
  • claimed_by_id
  • n—1 TicketCategory
  • 1—n TicketMessage
  • 1—n TicketTranscript

PlanHistory

  • from_plan · to_plan
  • reason
  • n—1 User

Full technical sheet

Languages
PHP 8.3, JavaScript (ES modules)
Framework
Laravel 12
Front end
Livewire 3, Alpine 3, Tailwind 4, Vite 7
Bot
Node.js, discord.js 14, Express 5, node-cron; the bot runs in a worker thread
Database
MariaDB 11 in development, MySQL 8 in CI
Queues and cache
Laravel default and discord queues, Redis 7
Real time
Laravel Reverb, six broadcast events
Search
Laravel Scout and Meilisearch over the action log
Authentication
Discord OAuth2 through Socialite, Sanctum
Payments
Stripe Checkout subscriptions, verified webhook, grace period
Hosting
Multi-stage Docker, Docker Compose (app, queue, scheduler, Reverb, bot), image published to GHCR for amd64 and arm64
CI/CD
3 GitHub Actions workflows on a self-hosted runner: PHPUnit, Pest, Node tests, Pint, Composer and npm audits
Tests
PHPUnit 11 and Pest 3 (about 800 tests), Playwright (15 tests), node --test (15 tests)
Quality
Pint, Scribe API docs, Codecov coverage
Observability
Sentry, PostHog, in-house observability package, Pail
Security
Shared Bearer token between Laravel and the bot, compared in constant time on both sides; rate limiting; Ed25519 signature of Discord interactions verified

Key features

  • Welcome and goodbye

    Custom messages when members join and leave.

  • Reaction roles

    A role granted or removed depending on the reaction.

  • Tickets

    Categories, claiming and transcripts.

  • Invite tracking

    Who invited whom, suspicious invites flagged, top 10.

  • Announcements

    Written in a Discord modal.

  • Channel cleaner

    Bulk message deletion.

Problems solved

  1. Wrong discord.js version

    ProblemThe code called v14 APIs on the installed v13, and every error was silently swallowed.

    FixMigrated to v14, with Node tests run against the real discord.js in CI.

  2. Quota bypassable by URL

    ProblemThe Free plan limit only existed in the UI.

    FixServer-side check, before authorisation and on the OAuth return.

  3. Bot never restarted

    ProblemCarbon 3 returns a signed difference: a disconnected bot appeared to have been offline for a negative duration.

    FixDifference computed the right way round, covered by a test.

  4. Blocking sleep()

    ProblemA plugin could hold a PHP worker for up to five minutes.

    FixDelayed sends handed to a queued job.

  5. Tickets never saved

    ProblemThe table pointed to a table dropped during the redesign.

    FixForeign key fixed and new registration routes.

Technical choices

Choice Why
A single platform bot The inconsistencies found by the audit came from the one-process-per-bot model (ADR 001).
Logic in Laravel, execution in the bot Plugins are tested in PHP; the bot stays a simple executor.
Registry generated from the classes Hand-maintained copies of the registry had drifted from the code.
Free / Pro rather than a marketplace Per-bot payment never worked end to end.

Timeline

  1. October 2025 First commit, marketplace plan
  2. January 2026 From 20 to 6 plugins, centralised logs
  3. February 2026 ADR 001: single platform bot
  4. February 2026 Free and Pro plans with Stripe
  5. April 2026 Docker Compose stack
  6. September 2026 Migration to discord.js 14

In numbers

877
commits
146
migrations
35
bot action types
~800
PHP tests

Taken from the project’s source code and Git history on 8 October 2026. No usage or revenue figures are published.

Related projects

SaaS
FoundRC — Laravel Marketplace project
European radio-controlled modelling marketplace with Stripe Connect payments between sellers and buyers and Meilisearch search.
Laravel, Livewire, Stripe Connect, Meilisearch, MinIO
View project
SaaS
Jan 2024 — present
StreamCrea — Creator dashboard
Twitch, YouTube and Kick sync, multi-network publishing and a subscriber blog.
PHP, Laravel, Livewire, Stripe
View project
SaaS
Sep 2023 — present
Egonix Cards — NFC business cards
NFC business cards: tap the card, the contact lands in a space where it can be exported, segmented and followed up.
Laravel, Livewire, Filament, Stripe, TailwindCSS
View project
SaaS
Jan 2024 — present
Finnexus — Laravel Finance project
Enterprise finance SaaS with analytics, cash-flow forecasts and treasury insights.
Laravel, Livewire, TailwindCSS, Stripe
View project

Available for PHP / Laravel / WordPress / Silverstripe missions in Belgium and remote EU.