Remove deprecated classes and static singleton-based architecture
This commit is contained in:
1 parent
54a27883d1
commit
b8786c8dc9
133 files changed
+4984
-1038
No files matched your search
@@ -0,0 +1,128 @@
|
||||
# Persistence & Database
|
||||
|
||||
**Packages:** `me.bobert.netneutrality.platform.persistence` (session/migration),
|
||||
`me.bobert.netneutrality.db` (entities, repositories, services).
|
||||
**Resources:** `hibernate.cfg.xml`, `db/migration/V1__initial_schema.sql`.
|
||||
|
||||
## Stack
|
||||
|
||||
| Concern | Technology |
|
||||
|---|---|
|
||||
| ORM | Hibernate 7.1.9 (Jakarta JPA) |
|
||||
| Engine | MariaDB 11 (per `docker-compose.yml`), MySQL Connector/J 9.7.0 driver, InnoDB |
|
||||
| Pooling | HikariCP (via `hibernate-hikaricp`) |
|
||||
| Migrations | Flyway 11.20.3 (`flyway-core` + `flyway-mysql`) |
|
||||
|
||||
Configuration is externalized via `Settings` (env vars / `bot.properties`):
|
||||
`MYSQL_HOST`, `MYSQL_PORT`, `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_DATABASE`.
|
||||
|
||||
## Session & migration lifecycle
|
||||
|
||||
Both are wired in at [startup](architecture.md#startup-lifecycle):
|
||||
|
||||
1. **`SessionManager.getSessionFactory()`** — lazily builds the Hibernate `SessionFactory`. It reads
|
||||
the static config from `hibernate.cfg.xml` (dialect `MySQLDialect`, driver
|
||||
`com.mysql.cj.jdbc.Driver`, the Hikari connection provider, and the mapped entity list) and
|
||||
overrides the JDBC url/user/password from environment variables:
|
||||
|
||||
```java
|
||||
settings.put(Environment.JAKARTA_JDBC_URL,
|
||||
String.format("jdbc:mysql://%s:%s/%s", dbHost, dbPort, dbName));
|
||||
settings.put(Environment.JAKARTA_JDBC_USER, dbUser);
|
||||
settings.put(Environment.JAKARTA_JDBC_PASSWORD, dbPass);
|
||||
```
|
||||
|
||||
2. **`DatabaseMigration.migrate()`** — runs `flyway.migrate()` against the same database, applying the
|
||||
versioned scripts under `src/main/resources/db/migration/` (starting with
|
||||
`V1__initial_schema.sql`). The Flyway Maven plugin (`flyway-dev.sh`/`.ps1`) is available for local
|
||||
development, using `FLYWAY_URL` / `FLYWAY_USER` / `FLYWAY_PASSWORD`.
|
||||
|
||||
3. **`SessionManager.shutdown()`** — destroys the service registry / releases the pool on shutdown.
|
||||
|
||||
Repositories obtain sessions through the factory; transactional access uses helpers in
|
||||
[`JpaUtils`](utilities-and-bootstrap.md) (open session, run in a transaction, close).
|
||||
|
||||
## Entity catalog
|
||||
|
||||
Entities live in `me.bobert.netneutrality.data.entity` and are prefixed with `O`. `OGuild` is the hub
|
||||
of a star-shaped model; most other tables reference `guild_id` with `ON DELETE CASCADE`.
|
||||
|
||||
| Entity | Table | Key | Relationships / notes |
|
||||
|---|---|---|---|
|
||||
| `OGuild` | `guilds` | `guild_id` (String) | Central entity; one-to-many with settings, blacklist, log messages, logging. |
|
||||
| `OGuildSetting` | `guild_settings` | `id` (auto int) | Many-to-one `OGuild`; key/value guild settings. |
|
||||
| `OBlacklist` | `blacklist` | `id` (auto int) | Many-to-one `OGuild`; blacklisted words. |
|
||||
| `OLogging` | `logging` | `OLoggingId` (composite) | Composite key `guild_id` + `channel_id`; `@MapsId` to `OGuild`; debug/error log channel config. |
|
||||
| `OLoggingId` | — (embeddable) | — | `@Embeddable`/`@IdClass` for the composite key. |
|
||||
| `OLogMessage` | `log_message` | `id` (auto int) | Many-to-one `OGuild`; message logging history. |
|
||||
| `OTask` | `tasks` | `id` (auto int) | [Persistable task](tasks.md#31-persistable-tasks) state; unique `task_id`, class name, JSON `payload`. |
|
||||
| `OWebUser` | `web_users` | `id` (String) | Web dashboard user (tokens/expiry). *Present in schema & code but not listed in `hibernate.cfg.xml`.* |
|
||||
|
||||
### ER overview
|
||||
|
||||
```
|
||||
┌───────────────┐
|
||||
│ OGuild │ (guilds.guild_id)
|
||||
└───────┬───────┘
|
||||
┌───────────┬───────┼────────────┬─────────────┐
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
OGuildSetting OBlacklist OLogging OLogMessage (…)
|
||||
guild_settings blacklist logging log_message
|
||||
(FK guild) (FK guild) (PK guild+ (FK guild)
|
||||
channel)
|
||||
|
||||
OTask (tasks) OWebUser (web_users) ── standalone
|
||||
```
|
||||
|
||||
`OTask` and `OWebUser` are not tied to the guild graph.
|
||||
|
||||
## Repository layer
|
||||
|
||||
A lightweight generic repository pattern is used.
|
||||
|
||||
- **`Repository<O>`** (interface) — generic CRUD: `findAll()`, `findById(String)`, `save(O)` (via
|
||||
`session.merge()`), `deleteBy(String)`.
|
||||
- **`BlacklistRepository`** — find-by-guild and case-insensitive word lookups.
|
||||
- **`GuildRepository`** — CRUD for guilds.
|
||||
- **`GuildSettingRepository`** — set/get setting values; removes rows that equal the default value.
|
||||
- **`MessageRepository`** — message logging / edit history.
|
||||
- **`TaskRepository`** — CRUD for `OTask` rows (used by the task persistence flow).
|
||||
|
||||
## Service layer
|
||||
|
||||
Services wrap repositories with business logic and **caching**.
|
||||
|
||||
- **`GuildService`** — gateway for guild operations; caches one `GuildService` per guild id
|
||||
(`ConcurrentHashMap`); `findOrCreate` guarantees a guild row exists; `deleteGuild()` on leave;
|
||||
`isDebugEnabled()` / debug-channel helpers used by [`EventsHandler`](events.md) and
|
||||
[`LogHandler`](utilities-and-bootstrap.md#loghandler).
|
||||
- **`BlacklistService`** — maintains a `blacklistCache` (guild id → set of words) for fast message
|
||||
filtering.
|
||||
- **`GuildSettingService`** — reads/writes guild settings backed by [`GSettings`](#gsettings); caches
|
||||
values in `settingsCache` and reloads on change; used by the
|
||||
[web API settings endpoints](web-api.md).
|
||||
- **`TaskService`** — serializes [`PersistableTask`](tasks.md#31-persistable-tasks) instances to JSON
|
||||
for the `tasks` table and reconstructs them at startup via
|
||||
[`TaskRegistry`/`TaskFactory`](tasks.md#31-persistable-tasks).
|
||||
|
||||
## GSettings
|
||||
|
||||
`GSettings` is an **enum** of the available per-guild configuration keys and their defaults:
|
||||
|
||||
| Setting | Default |
|
||||
|---|---|
|
||||
| `MUSIC_ROLE` | (none) |
|
||||
| `MUSIC_CHANNEL` | (none) |
|
||||
| `MUSIC_VOLUME` | `30` |
|
||||
| `MUSIC_MAXPLAYLISTSIZE` | `20` |
|
||||
|
||||
`GuildSettingService` looks up an `OGuildSetting` row by the enum `name()`; if no row exists for a
|
||||
guild/setting, the enum's `defaultValue` is used. This is how `MusicCommand` obtains the guild's music
|
||||
role/channel and how `ConfigureCommand` persists changes.
|
||||
|
||||
## Schema (`V1__initial_schema.sql`)
|
||||
|
||||
The initial migration creates the tables backing the entities above (`guilds`, `guild_settings`,
|
||||
`blacklist`, `logging`, `log_message`, `tasks`, `web_users`), with `guild_id` foreign keys and
|
||||
`ON DELETE CASCADE` from the guild-scoped tables to `guilds`. Subsequent schema changes should be
|
||||
added as new `V2__…`, `V3__…` Flyway scripts in the same directory.
|
||||
Reference in new issue
Block a user