Initial project setup with Gradle

This commit is contained in:
Loki 2025-12-19 12:07:40 +01:00
commit 0a7b382cdb
6 changed files with 622 additions and 0 deletions

View file

@ -0,0 +1,319 @@
# Design Document: lorep Report Plugin
## Overview
Плагин lorep — система репортов для Paper 1.21, написанная на Java 21. Использует Gradle для сборки, SQLite для хранения данных и интегрируется с Discord через webhooks.
**Технологический стек:**
- Java 21
- Paper API 1.21
- Gradle (Kotlin DSL)
- SQLite (встроенная БД) или PostgreSQL (внешняя БД)
- HikariCP (connection pool для PostgreSQL)
- OkHttp (HTTP клиент для webhooks)
**Git репозиторий:** https://git.lokili.xyz/loki/lorep.git
## Architecture
```mermaid
graph TB
subgraph Plugin
Main[LorepPlugin]
CMD[CommandManager]
GUI[GuiManager]
DB[DatabaseManager]
WH[WebhookService]
CFG[ConfigManager]
end
subgraph External
Discord[Discord Webhook]
SQLite[(SQLite DB)]
end
Main --> CMD
Main --> GUI
Main --> DB
Main --> WH
Main --> CFG
CMD --> DB
CMD --> WH
GUI --> DB
WH --> Discord
DB --> SQLite
CFG --> Main
```
### Структура проекта
```
lorep/
├── .gitignore
├── build.gradle.kts
├── settings.gradle.kts
├── src/
│ └── main/
│ ├── java/
│ │ └── dev/
│ │ └── loki/
│ │ └── lorep/
│ │ ├── LorepPlugin.java
│ │ ├── command/
│ │ │ ├── ReportCommand.java
│ │ │ ├── ReportGuiCommand.java
│ │ │ └── ReportStatsCommand.java
│ │ ├── database/
│ │ │ ├── DatabaseManager.java
│ │ │ ├── SQLiteDatabaseManager.java
│ │ │ ├── PostgreSQLDatabaseManager.java
│ │ │ └── Report.java
│ │ ├── gui/
│ │ │ ├── ReportGui.java
│ │ │ └── GuiClickListener.java
│ │ ├── webhook/
│ │ │ └── DiscordWebhook.java
│ │ ├── config/
│ │ │ └── ConfigManager.java
│ │ └── util/
│ │ ├── TimeUtil.java
│ │ └── MessageUtil.java
│ └── resources/
│ ├── plugin.yml
│ └── config.yml
└── src/
└── test/
└── java/
└── dev/
└── loki/
└── lorep/
├── database/
│ └── DatabaseManagerTest.java
└── util/
└── TimeUtilTest.java
```
## Components and Interfaces
### 1. LorepPlugin (Main Class)
```java
public final class LorepPlugin extends JavaPlugin {
private DatabaseManager databaseManager;
private ConfigManager configManager;
private DiscordWebhook discordWebhook;
@Override
public void onEnable();
@Override
public void onDisable();
// Getters for managers
}
```
### 2. Report (Data Model)
```java
public record Report(
int id,
UUID reporterUuid,
String reporterName,
UUID targetUuid,
String targetName,
String reason,
Instant createdAt
) {}
```
### 3. DatabaseManager
```java
public interface DatabaseManager {
void initialize();
void close();
void saveReport(Report report);
List<Report> getReportsForTarget(UUID targetUuid);
List<Report> getAllReports();
int getReportCount(UUID targetUuid);
boolean hasReported(UUID reporterUuid, UUID targetUuid);
List<Report> getReportsPaginated(int page, int pageSize);
}
// Реализации:
public class SQLiteDatabaseManager implements DatabaseManager { }
public class PostgreSQLDatabaseManager implements DatabaseManager { }
```
### 4. DiscordWebhook
```java
public class DiscordWebhook {
public DiscordWebhook(String webhookUrl);
public void sendReport(Report report);
}
```
### 5. ConfigManager
```java
public class ConfigManager {
public String getWebhookUrl();
public String getDatabasePath();
public String getMessage(String key);
}
```
### 6. ReportGui
```java
public class ReportGui {
public void open(Player player, int page);
public ItemStack createReportItem(Report report, int totalReports);
}
```
## Data Models
### Report Entity
| Field | Type | Description |
|-------|------|-------------|
| id | INTEGER | Primary key, auto-increment |
| reporter_uuid | TEXT | UUID репортера |
| reporter_name | TEXT | Имя репортера |
| target_uuid | TEXT | UUID цели |
| target_name | TEXT | Имя цели |
| reason | TEXT | Причина репорта |
| created_at | INTEGER | Unix timestamp создания |
### SQL Schema
```sql
CREATE TABLE IF NOT EXISTS reports (
id INTEGER PRIMARY KEY AUTOINCREMENT,
reporter_uuid TEXT NOT NULL,
reporter_name TEXT NOT NULL,
target_uuid TEXT NOT NULL,
target_name TEXT NOT NULL,
reason TEXT NOT NULL,
created_at INTEGER NOT NULL
);
CREATE INDEX idx_target_uuid ON reports(target_uuid);
CREATE INDEX idx_reporter_target ON reports(reporter_uuid, target_uuid);
```
### Configuration (config.yml)
```yaml
# Discord Webhook URL
webhook-url: ""
# Database settings
database:
# Type: sqlite or postgresql
type: "sqlite"
# SQLite settings
sqlite:
file: "reports.db"
# PostgreSQL settings
postgresql:
host: "localhost"
port: 5432
database: "lorep"
username: "lorep"
password: "password"
pool-size: 10
# Messages
messages:
report-sent: "&aРепорт успешно отправлен!"
already-reported: "&cВы уже отправляли репорт на этого игрока!"
self-report: "&cВы не можете отправить репорт на себя!"
player-not-found: "&cИгрок не найден!"
no-permission: "&cУ вас нет прав на эту команду!"
usage: "&eИспользование: /report <ник> <причина>"
```
## Correctness Properties
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
### Property 1: Report Creation Integrity
*For any* valid reporter UUID, target UUID, and reason string, creating a report and then querying reports for that target SHALL return a list containing the created report with matching fields.
**Validates: Requirements 1.1, 2.1**
### Property 2: Duplicate Report Prevention
*For any* reporter-target pair, if a report already exists from that reporter to that target, attempting to create another report SHALL be rejected.
**Validates: Requirements 1.2**
### Property 3: Report Persistence Round-Trip
*For any* set of reports saved to the database, reloading the database SHALL return the same reports with identical data.
**Validates: Requirements 2.2**
### Property 4: Report Ordering
*For any* collection of reports with different timestamps, querying all reports SHALL return them sorted by creation timestamp in descending order (newest first).
**Validates: Requirements 2.3**
### Property 5: Webhook Payload Completeness
*For any* report sent to the webhook, the payload SHALL contain reporter name, target name, reason, and formatted timestamp.
**Validates: Requirements 3.1**
### Property 6: Pagination Correctness
*For any* list of N reports and page size P, requesting page K SHALL return at most P reports starting from index K*P, and the total page count SHALL equal ceil(N/P).
**Validates: Requirements 4.4**
### Property 7: Report Count Accuracy
*For any* target UUID, the report count returned by getReportCount SHALL equal the actual number of reports in the database for that target.
**Validates: Requirements 5.1**
### Property 8: Permission Enforcement
*For any* command execution, if the player lacks the required permission, the command SHALL be denied and return false.
**Validates: Requirements 6.1, 6.2, 6.3**
### Property 9: Configuration Parsing
*For any* valid config.yml file, parsing SHALL correctly extract webhook URL and database path values.
**Validates: Requirements 7.1, 7.3, 7.4**
## Error Handling
| Scenario | Handling |
|----------|----------|
| Database connection failure | Log error, disable plugin gracefully |
| Webhook request failure | Log warning, continue operation |
| Invalid player name | Return error message to player |
| Missing config values | Use default values |
| SQL exceptions | Log error, return empty result |
## Testing Strategy
### Property-Based Testing Library
- **JQwik** — библиотека для property-based тестирования в Java
- Минимум 100 итераций на каждый property test
### Unit Tests
- DatabaseManager: CRUD операции, pagination
- TimeUtil: форматирование времени
- ConfigManager: парсинг конфигурации
### Property-Based Tests
Каждый property test должен быть аннотирован:
```java
// **Feature: lorep-report-plugin, Property 1: Report Creation Integrity**
@Property(tries = 100)
void reportCreationIntegrity(@ForAll UUID reporter, @ForAll UUID target, @ForAll String reason) {
// test implementation
}
```
### Integration Tests
- Полный цикл создания репорта
- GUI открытие и навигация
- Webhook отправка (с mock сервером)