Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
68c659e
build: introduce quarkus bom
eggy03 May 29, 2026
424903d
refactor(bootstrap): migrate application to Quarkus framework
eggy03 May 29, 2026
4145be5
refactor(config): move default values to `application.properties`
eggy03 May 29, 2026
adb18fe
refactor: remove deprecated StackWalkerUtils and its references
eggy03 May 29, 2026
b1299ef
refactor(misc-listeners): use CDI annotations and virtual threads
eggy03 May 29, 2026
f93d480
refactor: move main classes to parent bot package
eggy03 May 29, 2026
61a8b39
refactor: reorganize package structure for listeners and helpers
eggy03 May 29, 2026
ee68bc7
refactor(automod): consolidate auto-moderation helpers into a service
eggy03 May 29, 2026
dd4d25e
refactor(listeners): extract audit log event handling to new class
eggy03 May 29, 2026
2864446
refactor(auditlog): migrate static helpers to managed services
eggy03 May 29, 2026
82b4ca0
revert: 2864446, dd4d25e and ee68bc7
eggy03 May 29, 2026
1b3ad28
refactor(auditlog): restructure audit log event handling
eggy03 May 29, 2026
88d3d6d
refactor(auditlog): rename abstract audit log event handler
eggy03 May 29, 2026
0034060
refactor(listeners): remove virtual thread annotations from listeners
eggy03 May 29, 2026
b29e4c0
refactor(auditlog): simplify event routing and rename handler classes
eggy03 May 30, 2026
19cadbb
refactor(automod): merge helpers into `AutoModEventHandler`
eggy03 May 30, 2026
2219bcf
refactor(nodactions): merge helpers into `ModActionEventHandler`
eggy03 May 30, 2026
14da4a8
docs(auditlog): document unknown and unimplemented event handlers
eggy03 May 30, 2026
d52e3d4
refactor(channelevents): merge helpers into three handlers
eggy03 May 30, 2026
2bd3647
refactor(threadevents): merge helpers into ThreadEventHandler
eggy03 May 30, 2026
07dcdf8
refactor(roleevents): merge helpers into RoleEventHandler
eggy03 May 31, 2026
7f22410
refactor(emojievents): merge helpers into EmojiEventHandler
eggy03 May 31, 2026
e57443d
refactor(stickerevents): merge helpers into StickerEventHandler
eggy03 May 31, 2026
6e98a61
feat(auditlog): implement basic logging for prune events
eggy03 May 31, 2026
e65f183
refactor(guildupdateevents): merge helpers into GuildUpdateEventHandler
eggy03 May 31, 2026
b3cd6e7
refactor(homesettingseevents): merge helpers into HomeSettingsEventHa…
eggy03 May 31, 2026
b16bf2b
refactor(webhookevents): merge helpers into WebhookEventHandler
eggy03 May 31, 2026
da626ba
refactor(integrationevents): merge helpers into IntegrationEventHandler
eggy03 May 31, 2026
d335d92
refactor(inviteevents): merge helpers into InviteEventHandler
eggy03 May 31, 2026
4336b02
refactor(memberstatusevents): merge helpers into MemberStatusEventHan…
eggy03 May 31, 2026
bb7bb41
feat(auditlog): add message event handler for audit logs
eggy03 May 31, 2026
6908083
refactor(messagepinevents): merge helpers into MessagePinEventHandler
eggy03 May 31, 2026
744dbf9
refactor(onboardingevents): migrate onboarding helpers to two handlers
eggy03 May 31, 2026
a3ad549
refactor(scheduledevents): merge helpers into ScheduledEventEventHandler
eggy03 May 31, 2026
45ff37b
refactor(stageinstanceevents): merge helpers into StageInstanceEventH…
eggy03 May 31, 2026
3375813
refactor(soundboardevents): merge helpers into SoundboardEventHandler
eggy03 May 31, 2026
9658dfe
refactor(auditlog): replace generic helper with event handlers
eggy03 May 31, 2026
fabd683
refactor(auditlog): clarify implementation notices and fix log message
eggy03 May 31, 2026
726d735
refactor: make classes final and update bean provider annotations
eggy03 May 31, 2026
ec49224
refactor(guild): rename auditlogsupl and messagelog packages
eggy03 May 31, 2026
e9597b0
refactor(bot): move event handlers from service to handlers package
eggy03 May 31, 2026
e46f155
refactor(commands): delegate listener logic to dedicated handlers
eggy03 May 31, 2026
dcbe58c
feat: allow for shard shutdown on exit
eggy03 May 31, 2026
63e1ac9
refactor(guildboostevents): consolidate boost event helpers into sing…
eggy03 Jun 1, 2026
0f6352b
refactor(guildmemberevents): consolidate member event helpers into si…
eggy03 Jun 1, 2026
a694d07
refactor(guild-poll): delegate poll event handling
eggy03 Jun 1, 2026
36cdf09
refactor(guild-voice-events): delegate voice event handling
eggy03 Jun 1, 2026
21c32d0
refactor(message-logging): consolidate message event handling
eggy03 Jun 1, 2026
462460c
chore: replace `@NotNull` from jetbrains with `@NonNull` from lombok
eggy03 Jun 1, 2026
ab11aac
build: add quarkus packaging type
eggy03 Jun 1, 2026
64862f6
build: bump project version to `4.0.0-SNAPSHOT`
eggy03 Jun 1, 2026
028250c
build: update jar name
eggy03 Jun 1, 2026
4c65cc3
build: bump papertrail-sdk version to 2.0.5
eggy03 Jun 1, 2026
4e2a4c2
ci: update actions checkout and docker login versions
eggy03 Jun 1, 2026
77fd0a6
feat(health): add liveness and readiness checks
eggy03 Jun 1, 2026
08b1475
chore(config): externalize log level
eggy03 Jun 1, 2026
f57e5e2
docs: add health checks and custom port config info
eggy03 Jun 1, 2026
d55bb7a
build(native-image): add reflection metadata
eggy03 Jun 2, 2026
3cd6870
build: remove uber jar packaging system
eggy03 Jun 2, 2026
205257a
docs: update to include an indefinite timeline for a guideline
eggy03 Jun 2, 2026
ee6dfee
docs: add ai usage declaration and policy
eggy03 Jun 2, 2026
5adf49b
build: set project version to 4.0.0
eggy03 Jun 2, 2026
b749903
docs: update proxy url environment variable name
eggy03 Jun 2, 2026
ad8fb5a
docs: add default values and optionality to env var tables
eggy03 Jun 2, 2026
547dcf3
refactor: make GuildMemberEventHandler final
eggy03 Jun 2, 2026
14c8543
refactor: make GuildMessageEventHandler final
eggy03 Jun 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/publish-container-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
Expand Down
8 changes: 5 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
This project does not accept pull requests.
This project does not accept pull requests. I haven't been getting enough time to set up a contribution guideline.
I will start accepting PRs once a guideline is in effect.

If you would like to modify or extend the bot, please feel free to fork the repository and maintain your own version.
Meanwhile, please feel free to fork the repository and maintain your own version. In case of any doubt or question
regarding the codebase, you can open an issue in GitHub.

Bug reports and suggestions are welcome through the Issues tab. I may review and address them as time permits.
Bug reports and suggestions are also welcome through the Issues tab. I may review and address them as time permits.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ WORKDIR /app
VOLUME /tmp

# Copy the JAR from the build stage
COPY --from=build --chown=papertrail:papertrail /app/target/papertrailbot-jar-with-dependencies.jar papertrailbot.jar
COPY --from=build --chown=papertrail:papertrail /app/target/quarkus-app bot
USER papertrail
ENTRYPOINT ["java","-jar","papertrailbot.jar"]
ENTRYPOINT ["java","-jar","bot/quarkus-run.jar"]
78 changes: 63 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
* [Self-Host (Manual Configuration)](#self-host-manual-configuration)
* [Sharding (Advanced Configuration)](#sharding-advanced-configuration)
* [Synchronizing Rate Limits (Advanced Configuration)](#synchronizing-rate-limits-advanced-configuration)
* [Health Checks and Custom Port Configuration](#health-checks-and-custom-port-configuration)
* [License](#license)
* [AI Usage Declaration and Policy](#ai-usage-declaration-and-policy)
* [Help](#help)

# Overview
Expand Down Expand Up @@ -97,10 +99,10 @@ Don't forget to copy the `bot token` as it will be required in the next step

### Step 2.2: Get Required Secrets

| Variable | Description |
|-----------|--------------------------------------------------------------------|
| `TOKEN` | Discord application bot token (from the Developer Portal) |
| `API_URL` | Internal URL of the PaperTrail API (e.g., `http://localhost:8080`) |
| Variable | Description | Default Value | Optional |
|-----------|--------------------------------------------------------------------|------------------|----------|
| `TOKEN` | Discord application bot token (from the Developer Portal) | No Default Value | No |
| `API_URL` | Internal URL of the PaperTrail API (e.g., `http://localhost:8080`) | No Default Value | No |

Example `.env` file:

Expand Down Expand Up @@ -172,11 +174,11 @@ Discord allows you to have up to 2500 guilds per shard but the recommended confi

You will need the following additional environment variables for custom shard configuration.

| Variable | Description |
|----------------|-------------------------------------------------------------------------------|
| `TOTAL_SHARDS` | Total number of shards used by the bot across all running processes/instances |
| `MIN_SHARD_ID` | The first shard ID handled by this specific bot instance |
| `MAX_SHARD_ID` | The last shard ID handled by this specific bot instance |
| Variable | Description | Default Value | Optional |
|----------------|-------------------------------------------------------------------------------|---------------|----------|
| `TOTAL_SHARDS` | Total number of shards used by the bot across all running processes/instances | 1 | Yes |
| `MIN_SHARD_ID` | The first shard ID handled by this specific bot instance | 0 | Yes |
| `MAX_SHARD_ID` | The last shard ID handled by this specific bot instance | 0 | Yes |

Shard IDs start at 0.

Expand Down Expand Up @@ -277,9 +279,9 @@ This will set the discord token to `"my token"` and map the bound port to port `

Add the following environment variable to your bot:

| Variable | Description |
|-------------|----------------------------------------------------------------------------------------------------------------------------|
| `PROXY_URL` | Base URL for the HTTP proxy that will receive Discord API requests instead of discord.com (Example: http://localhost:3000) |
| Variable | Description | Default Value | Optional |
|---------------------------|----------------------------------------------------------------------------------------------------------------------------|---------------|----------|
| `TWILIGHT_HTTP_PROXY_URL` | Base URL for the HTTP proxy that will receive Discord API requests instead of discord.com (Example: http://localhost:3000) | Blank | Yes |

When configured, all Discord API requests made by the bot will be routed through the proxy.

Expand All @@ -300,12 +302,58 @@ as the instance-level. While this should not create functional conflicts,
it may lead to under-utilization of the rate limits provided by Discord and can reduce the overall throughput of your
bot cluster.

# Health Checks and Custom Port Configuration

## Health Checks

Since v4, it is possible to get health information by probing any of the following health endpoints:

| Endpoint | Description |
|---------------------|-------------------------------------------------------------------------------------------------------|
| `/q/health` | Aggregated health status containing all registered checks. |
| `/q/health/live` | Liveness probe. Verifies that the bot process is healthy and that all shards are operating normally. |
| `/q/health/ready` | Readiness probe. Verifies that all shards are fully connected to Discord and ready to receive events. |
| `/q/health/started` | Startup probe. Indicates whether the application has completed its startup sequence. |

### Liveness Check

The liveness check reports **UP** when all shards belonging to this instance are in one of the following states:

* `CONNECTED`
* `ATTEMPTING_TO_RECONNECT`
* `RECONNECT_QUEUED`
* `WAITING_TO_RECONNECT`

### Readiness Check

The readiness check reports **UP** only when every shard belonging to this instance is fully `CONNECTED` to Discord.

## Custom Port Configuration

By, default PaperTrail runs on port 8080. If port 8080 is occupied by a different service, or you wish to
run the application on a different port, you can manually set the `PORT` environment variable.

| Variable | Description | Default Value | Optional |
|----------|-------------------------------------------------------|---------------|----------|
| `PORT` | Port Number on which the instance of the bot will run | 8080 | Yes |

# License

This project is licensed under the [AGPLv3](/LICENSE) license.
Read this
easy-to-understand [Medium](https://medium.com/swlh/understanding-the-agpl-the-most-misunderstood-license-86fd1fe91275)
article about AGPLv3 and it's scope.

# AI Usage Declaration and Policy

No AI or LLM agents have been used to generate any part of the project's source code.
This policy applies to all existing source code and future code contributions.

After two years of development and manual testing, the application has reached a fairly stable and maintainable state.
To preserve code quality, maintainability, format, and stability,
AI-generated source code is **not accepted** for inclusion in this repository and the repositories related to the
application.

Limited use of AI for non-code tasks, such as commit message generation, spelling correction,
or documentation proofreading, may be permitted at the maintainer's discretion.
Such usage does not constitute authorship of the project's source code.

# Help

Expand Down
165 changes: 103 additions & 62 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,66 +1,87 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>io.github.eggy03</groupId>
<artifactId>papertrailbot</artifactId>
<version>3.7.3</version>
<version>4.0.0</version>
<name>PaperTrail Bot</name>
<description>A simple bot for logging all server and member actions</description>
<packaging>quarkus</packaging>

<properties>
<!-- Project Properties -->
<maven.compiler.release>25</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.release>25</maven.compiler.release>

<!-- Quarkus Properties -->
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.35.4</quarkus.platform.version>
<skipITs>true</skipITs>

<!-- Dependency Versions -->
<jda.version>6.4.1</jda.version>
<papertrail.sdk.version>2.0.4</papertrail.sdk.version>
<tinylog.version>2.7.0</tinylog.version>
<dotenv.version>3.2.0</dotenv.version>
<papertrail.sdk.version>2.0.5</papertrail.sdk.version>
<commons-lang3.version>3.20.0</commons-lang3.version>
<guava.version>33.5.0-jre</guava.version>
<jetbrains.annotations.version>26.1.0</jetbrains.annotations.version>
<lombok.version>1.18.46</lombok.version>

<!-- Plugin Versions -->
<maven.assembly.plugin.version>3.8.0</maven.assembly.plugin.version>
<maven-compiler-plugin.version>3.15.0</maven-compiler-plugin.version>

<!-- Extras -->
<app.main.class>io.github.eggy03.papertrail.bot.main.Start</app.main.class>
<compiler-plugin.version>3.15.0</compiler-plugin.version>
<surefire-plugin.version>3.5.5</surefire-plugin.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>

<!-- DI -->
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>${jda.version}</version>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>

<!-- Health -->
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>slf4j-tinylog</artifactId>
<version>${tinylog.version}</version>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-health</artifactId>
</dependency>

<!-- JDA -->
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-api</artifactId>
<version>${tinylog.version}</version>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>${jda.version}</version>
</dependency>

<!-- Annotations -->
<dependency>
<groupId>org.tinylog</groupId>
<artifactId>tinylog-impl</artifactId>
<version>${tinylog.version}</version>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-java</artifactId>
<version>${dotenv.version}</version>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>${jetbrains.annotations.version}</version>
</dependency>

<!-- Other -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
Expand All @@ -79,49 +100,22 @@
<version>${papertrail.sdk.version}</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<finalName>${project.artifactId}</finalName>

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>${maven.assembly.plugin.version}</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${app.main.class}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>assemble-all</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<version>${compiler-plugin.version}</version>
<configuration>
<parameters>true</parameters>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
Expand All @@ -131,7 +125,54 @@
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<argLine>@{argLine}</argLine>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<argLine>@{argLine}</argLine>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.artifactId}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<quarkus.package.jar.enabled>false</quarkus.package.jar.enabled>
<skipITs>false</skipITs>
<quarkus.native.enabled>true</quarkus.native.enabled>
</properties>
</profile>
</profiles>
</project>

Loading
Loading