You should be a comfortable with the command line.
Mac and Linux operating systems work best for development. Using Windows is not recommended (utilizing the Windows Subsystem for Linux is an option however).
Recommended: IntelliJ IDEA Community Version. JetBrains is sponsoring ultimate licenses for core contributors of the project.
Java is required to build the backend and execute any Gradle tasks. The minimum required version is found in the build.gradle file (search for "JavaVersion"). Use sdkman to install and manage it.
Installing Gradle is optional, as the project has the gradle wrapper available. The currently used version can be found in the gradle-wrapper.properties file. Use sdkman to install and manage it.
NodeJS/NPM a prerequisite for using Yarn. The currently used version can be found in the versions.gradle file. Get it from the official website.
Yarn is used to develop the web frontend / dashboard. The currently used version can be found in the versions.gradle file. Get it from the official website.
Docker is required to build the project, as it uses testcontainers to start a real database to be used during tests.
Docker Compose is handy to run containers with required services during development.
This project uses the PostgreSQL relational database to store and query important data.
The currently used version can be found in the poggres repo.
Installing it is optional, running the development docker compose
is recommended instead:
docker compose -f docker/dev/docker-compose.yaml up -d
This project uses the Redis in-memory key-value database to store expiring data and caches.
The currently used version can be found in the dev docker compose file.
Installing it is optional, running the development docker compose
is recommended instead:
docker compose -f docker/dev/docker-compose.yaml up -d
The project comes with an .editorconfig file. Please use an IDE that respects it. Currently there is no autoformatter set up for the Java sources. If you know a decent one, please suggest it.
For the frontend, an eslint configuration is provided. Ideally, you should set up your IDE to run eslint on file changes or on save. You can run eslint manually like this:
cd frontend
yarn run lint
Branches should be shortlived. Work should be merged into the master branch as often as possible.
There are several reasons to do so:
- Splitting up large tasks into smaller individual chunks helps focussing on what needs to be done, step by step
- Short living branches result in fewer merge conflicts. Noone likes solving merge conflicts.
- Code is deployed daily. This opportunity should be used to see it in action as fast a possible.
- Reviewing large Pull Requests is hard and takes a lot of time until feedback is ready.
- Getting feedback early and often is important for everyones happyness. Dropping a 2k lines of code pull request that, after review, needs to be done from scratch does not create any positive feelings.
The web frontend uses the Vue.js framework including Vue router and Vuex.
We also use the Bulma CSS framework, together with a Bulmaswatch theme.
PostgreSQL is the main database. We deploy a customized Docker image that contains init scripts to set up required database extensions as well as backup scripts to back up the data to Backblaze B2.
Database schema migrations are handled by Flyway.
jOOQ is used for database querying.
During build time, Docker, Flyway and jOOQ are using to run migrations against a temporary database container and generate code from the resulting database schema.
The Spring Framework via Spring Boot is the main framework used in the backend code base.
Spring provides annotation based dependency injection, an important pillar of SOLID software.
We make use of the Spring Eventsystem to decouple our components where necessary. For example, the
DiscordEventListenerPublisher
class publishes all Discord events. Across the codebase, there are then multiple
@EventListener
s processing these events.
We use Spring's web server abstraction to serve various endpoints for the frontend, receiving webhooks, or allowing metrics collection from other parts of the infrastructure.
The Spring Application Context is populated with Components. Roughly, there are three types (or layers) to the various Spring Components:
- Controllers & Commands aka C&C
- Services
- Repositories
There are also Components that do not belong to any of the layers, for example some of our components parse and execute Commands, and some Components are necessary to interact with datasources like the database for example.
Controllers receive user input from the web. Commands receive user input from Discord.
Both of them make sure that the input has an expected format, identify the user,
and make sure they are allowed to do what they are trying to do.
C&C should only talk to services, not other C&Cs or Repositories.
Controllers can be identified by the @RestController
annotation in the code.
Commands can be identified by the @Command
annotation in the code.
Services are what happens in between C&C and Repositories. They are the largest layer.
There isn't a hard-and-fast rule what services actually are, it is easier to think of them as not being C&C and not
being Repositories. They usually contain the actual logic of an application.
Services may talk to other Services, or Repositories.
Services can be identified by the @Service
annotation in the code.
Repositories handle storing and fetching data from various sources, mostly our database.
Repositories can be identified by the @Repository
annotation in the code.
Repositories should not talk to anything else except the components directly necessary to interact with their data
source.
- file layout
- grouping by features
- feature flags
- sonar
- testing
- oauth2
- metrics/prometheus/grafana/sentry
- command system
- JSON-RPC
- game engine (haha yeah it barely even exists)
- rendering discord responses
- DTOs/VOs etc
- spring profiles
- nullability
- .gitignore
- secrets file
- listings