Update documentation for API, configuration, and model

API.md:
- Add export formats (JSON, XML, EGF, FFG, CSV)
- Document /explain endpoint for pairing analysis
- Add PUT /standings for freezing
- Improve parameter documentation
- Fix typos (regitration -> registration, #tip -> #tid)

configuration.md:
- Add property loading hierarchy
- Document SSL/TLS configuration
- Add OAuth provider configuration
- Add ratings.path property
- Include example configurations

model.md:
- Complete entity diagram with Team, external IDs
- Document all tournament types (PAIRGO, RENGO, TEAM)
- Add TimeSystem types and parameters
- Document all pairing parameters
- List all 39 tiebreak criteria
- Add external database (AGA, EGF, FFG) documentation
This commit is contained in:
Claude Brisson
2025-11-29 08:05:53 +01:00
parent 8ca25ec421
commit 662f438cee
5 changed files with 827 additions and 134 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.claude
target
/docker/data
/.idea

160
CLAUDE.md Normal file
View File

@@ -0,0 +1,160 @@
# Pairgoth Project
## Purpose
**Pairgoth** is a modern Go tournament pairing engine - successor to OpenGotha. It manages tournaments using Swiss and MacMahon pairing systems, handling player registration, automatic pairing, results entry, and standings calculation.
**Version:** 0.20 | **License:** org.jeudego (French Go Association)
## Tech Stack
- **Backend:** Kotlin 2.1 + Maven + Jetty 10
- **Frontend:** Fomantic UI CSS 2.9.2 + Vanilla JavaScript (no jQuery/React)
- **Templates:** Apache Velocity 2.4
- **Storage:** File-based XML (no database required)
- **JDK:** 11+
## Project Structure
```
pairgoth/
├── pairgoth-common/ # Shared utilities (JSON, XML, crypto, logging)
├── api-webapp/ # REST API backend (port 8085)
│ └── model/ # Domain: Tournament, Player, Game, Pairing
│ └── pairing/ # Solvers: Swiss, MacMahon algorithms
│ └── store/ # Persistence: File/Memory storage
│ └── api/ # Handlers: Tournament, Player, Results, etc.
│ └── ext/ # OpenGotha import/export
├── view-webapp/ # Web UI frontend (port 8080)
│ └── webapp/js/ # Vanilla JS: domhelper, api, main, tour-*.inc
│ └── webapp/sass/ # Styles: main, tour, explain, index
│ └── templates/ # Velocity: index, tour, explain, login
│ └── kotlin/ # Servlets, OAuth, Ratings integration
├── webserver/ # Standalone Jetty launcher
├── application/ # Final JAR packaging
└── docker/ # Container deployment
```
## Architecture
### Dual-Webapp Pattern
```
[Browser] <--8080--> [view-webapp] <--8085--> [api-webapp]
│ │ │
Velocity HTML ApiClient.kt REST JSON
+ vanilla JS + FileStore
```
- **api-webapp** - Pure REST API, business logic, pairing engine
- **view-webapp** - Web UI, proxies API calls, handles auth/i18n/ratings
### Key Architectural Decisions
1. **No JS Framework** - 2200 lines of vanilla JS vs typical 50KB+ bundle
2. **Fomantic CSS Only** - Using CSS framework without its jQuery-dependent JS
3. **CSS @layer** - Clean cascade: `semantic` layer < `pairgoth` layer
4. **File Storage** - XML files for portability, no database setup needed
5. **Read/Write Locks** - Simple concurrency on API servlet
6. **SSE Events** - Real-time updates via Server-Sent Events
## Domain Model
```
Tournament (sealed class)
├── IndividualTournament
├── PairTournament
├── TeamTournament
└── RengoTournament
Player → Pairable (interface)
Game { white, black, result, handicap }
Pairing { Swiss | MacMahon }
TimeSystem { ByoYomi | SuddenDeath | Canadian | Fischer }
Rules { French | Japanese | AGA | Chinese }
```
## Pairing Engine
Location: `api-webapp/src/main/kotlin/org/jeudego/pairgoth/pairing/`
- **SwissSolver** - Swiss system pairing algorithm
- **MacMahonSolver** - MacMahon bands system
- **HistoryHelper** - Criteria: wins, SOS, SOSOS, colors, CUSS, etc.
- **PairingListener** - Progress callbacks for UI
## Key Files
| Purpose | Path |
|---------|------|
| DOM utilities | `view-webapp/.../js/domhelper.js` |
| API client | `view-webapp/.../js/api.js` |
| Core UI | `view-webapp/.../js/main.js` |
| Main styles | `view-webapp/.../sass/main.scss` |
| Tournament model | `api-webapp/.../model/Tournament.kt` |
| Swiss solver | `api-webapp/.../pairing/solver/SwissSolver.kt` |
| API router | `api-webapp/.../server/ApiServlet.kt` |
| App launcher | `webserver/.../application/Pairgoth.kt` |
## Build & Run
```bash
# Build
mvn clean package
# Run standalone (both webapps)
java -jar application/target/pairgoth-engine.jar
# Or separate:
# API: localhost:8085/api
# UI: localhost:8080/
```
## Configuration
File: `pairgoth.properties` (user) or `pairgoth.default.properties` (defaults)
```properties
webapp.port = 8080
api.port = 8085
store = file # file | memory
store.file.path = tournamentfiles
auth = none # none | oauth | sesame
```
## Frontend Patterns
### State via CSS Classes
- `.active` - tabs, accordions, visible elements
- `.shown` - modals/popups
- `.hidden` / `.disabled` / `.selected` / `.dimmed`
### Component Communication
```javascript
// Custom events
box.dispatchEvent(new CustomEvent('listitem-dblclk', { detail: id }));
// jQuery-like API (domhelper.js)
$('.item').addClass('active').on('click', handler);
```
### API Integration
```javascript
api.getJson('/tour/123/players')
.then(players => render(players))
.catch(err => error(err));
```
## External Integrations
- **Ratings:** FFG (French), EGF (European), AGA (Australian)
- **OAuth:** FFG, Google, Facebook, Twitter, Instagram
- **Import/Export:** OpenGotha XML format compatibility
## i18n
Translations in `view-webapp/.../WEB-INF/translations/`
- English (default)
- French (fr)
- German (de)
- Korean (ko)

View File

@@ -2,38 +2,73 @@
## General remarks
The API expects an `Accept` header of `application/json`, with no encoding or an `UTF-8` encoding. Exceptions are some export operations which can have different MIME types to specify the expected format.
The API expects an `Accept` header of `application/json`, with no encoding or an `UTF-8` encoding. Exceptions are some export operations which can have different MIME types to specify the expected format:
- `application/json` - JSON output (default)
- `application/xml` - OpenGotha XML export
- `application/egf` - EGF format
- `application/ffg` - FFG format
- `text/csv` - CSV format
GET requests return either an array or an object, as specified below.
POST, PUT and DELETE requests return either the 200 HTTP code with `{ "success": true }` (with an optional `"id"` field for some POST requests), or and invalid HTTP code and (for some errors) the body `{ "success": false, "error": <error message> }`.
POST, PUT and DELETE requests return either the 200 HTTP code with `{ "success": true }` (with an optional `"id"` field for some POST requests), or an invalid HTTP code and (for some errors) the body `{ "success": false, "error": <error message> }`.
All POST/PUT/DELETE requests use read/write locks for concurrency. GET requests use read locks.
When authentication is enabled, all requests require an `Authorization` header.
## Synopsis
+ /api/tour GET POST Tournaments handling
+ /api/tour/#tid GET PUT DELETE Tournaments handling
+ /api/tour/#tid/part GET POST Registration handling
+ /api/tour/#tid/part/#pid GET PUT DELETE Registration handling
+ /api/tour/#tid/team GET POST Team handling
+ /api/tour/#tid/team/#tid GET PUT DELETE Team handling
+ /api/tour/#tid/pair/#rn GET POST PUT DELETE Pairing
+ /api/tour/#tid/res/#rn GET PUT DELETE Results
+ /api/tour/#tid/standings GET Standings
+ /api/tour/#tid/stand/#rn GET Standings
+ /api/tour GET POST Tournaments handling
+ /api/tour/#tid GET PUT DELETE Tournaments handling
+ /api/tour/#tid/part GET POST Registration handling
+ /api/tour/#tid/part/#pid GET PUT DELETE Registration handling
+ /api/tour/#tid/team GET POST Team handling
+ /api/tour/#tid/team/#tid GET PUT DELETE Team handling
+ /api/tour/#tid/pair/#rn GET POST PUT DELETE Pairing
+ /api/tour/#tid/res/#rn GET PUT DELETE Results
+ /api/tour/#tid/standings GET PUT Standings
+ /api/tour/#tid/stand/#rn GET Standings
+ /api/tour/#tid/explain/#rn GET Pairing explanation
+ /api/token GET POST DELETE Authentication
## Tournament handling
+ `GET /api/tour` Get a list of known tournaments ids
*output* json map (id towards shortName) of known tournaments (subject to change)
*output* json map (id towards shortName) of known tournaments
+ `GET /api/tour/#tid` Get the details of tournament #tid
*output* json object for tournament #tid
Supports `Accept: application/xml` to get OpenGotha XML export.
+ `POST /api/tour` Create a new tournament
*input* json object for new tournament (see `Tournament.fromJson` in the sources)
*input* json object for new tournament, or OpenGotha XML with `Content-Type: application/xml`
Tournament JSON structure:
```json
{
"type": "INDIVIDUAL",
"name": "Tournament Name",
"shortName": "TN",
"startDate": "2024-01-15",
"endDate": "2024-01-16",
"country": "fr",
"location": "Paris",
"online": false,
"rounds": 5,
"gobanSize": 19,
"rules": "FRENCH",
"komi": 7.5,
"timeSystem": { ... },
"pairing": { ... }
}
```
Tournament types: `INDIVIDUAL`, `PAIRGO`, `RENGO2`, `RENGO3`, `TEAM2`, `TEAM3`, `TEAM4`, `TEAM5`
*output* `{ "success": true, "id": #tid }`
@@ -43,19 +78,40 @@ POST, PUT and DELETE requests return either the 200 HTTP code with `{ "success":
*output* `{ "success": true }`
+ `DELETE /api/tour/#tid` Delete a tournament
*output* `{ "success": true }`
## Players handling
+ `GET /api/tour/#tid/part` Get a list of registered players
*output* json array of known players
+ `GET /api/tour/#tid/part/#pid` Get regitration details for player #pid
+ `GET /api/tour/#tid/part/#pid` Get registration details for player #pid
*output* json object for player #pid
+ `POST /api/tour/#tid/part` Register a new player
*input* `{ "name":"..." , "firstname":"..." , "rating":<rating> , "rank":<rank> , "country":"XX" [ , "club":"Xxxx" ] [ , "final":true/false ] [ , "mmsCorrection":0 ] }`
*input*
```json
{
"name": "Lastname",
"firstname": "Firstname",
"rating": 1500,
"rank": -5,
"country": "FR",
"club": "Club Name",
"final": true,
"mmsCorrection": 0,
"egfId": "12345678",
"ffgId": "12345",
"agaId": "12345"
}
```
Rank values: -30 (30k) to 8 (9D). Rating in EGF-style (100 = 1 stone).
*output* `{ "success": true, "id": #pid }`
@@ -67,35 +123,41 @@ POST, PUT and DELETE requests return either the 200 HTTP code with `{ "success":
+ `DELETE /api/tour/#tid/part/#pid` Delete a player registration
*input* `{ "id": #pid }`
*output* `{ "success": true }`
## Teams handling
For team tournaments (PAIRGO, RENGO2, RENGO3, TEAM2-5).
+ `GET /api/tour/#tid/team` Get a list of registered teams
*output* json array of known teams
+ `GET /api/tour/#tid/team/#tid` Get regitration details for team #tid
+ `GET /api/tour/#tid/team/#teamid` Get registration details for team #teamid
*output* json object for team #tid
*output* json object for team #teamid
+ `POST /api/tour/#tid/team` Register a new team
*input* json object for new team
*input*
```json
{
"name": "Team Name",
"playerIds": [1, 2, 3],
"final": true,
"mmsCorrection": 0
}
```
*output* `{ "success": true, "id": #tid }`
*output* `{ "success": true, "id": #teamid }`
+ `PUT /api/tour/#tid/team/#tid` Modify a team registration
+ `PUT /api/tour/#tid/team/#teamid` Modify a team registration
*input* json object for updated registration (only id and updated fields required)
*output* `{ "success": true }`
+ `DELETE /api/tour/#tid/team/#tid` Delete a team registration
*input* `{ "id": #tid }`
+ `DELETE /api/tour/#tid/team/#teamid` Delete a team registration
*output* `{ "success": true }`
@@ -104,56 +166,121 @@ POST, PUT and DELETE requests return either the 200 HTTP code with `{ "success":
+ `GET /api/tour/#tid/pair/#rn` Get pairable players for round #rn
*output* `{ "games": [ games... ], "pairables:" [ #pid, ... of players not skipping and not playing the round ], "unpairables": [ #pid, ... of players skipping the round ] }`
*output*
```json
{
"games": [ { "id": 1, "t": 1, "w": 2, "b": 3, "h": 0 }, ... ],
"pairables": [ 4, 5, ... ],
"unpairables": [ 6, 7, ... ]
}
```
+ `POST /api/tour/#tip/pair/#n` Generate pairing for round #n and given players (or string "all") ; error if already generated for provided players
- `games`: existing pairings for the round
- `pairables`: player IDs available for pairing (not skipping, not already paired)
- `unpairables`: player IDs skipping the round
+ `POST /api/tour/#tid/pair/#rn` Generate pairing for round #rn
*input* `[ "all" ]` or `[ #pid, ... ]`
Optional query parameters:
- `legacy=true` - Use legacy pairing algorithm
- `weights_output=<file>` - Output weights to file for debugging
- `append=true` - Append to weights output file
*output* `[ { "id": #gid, "t": table, "w": #wpid, "b": #bpid, "h": handicap }, ... ]`
+ `PUT /api/tour/#tip/pair/#n` Manual pairing (with optional handicap)
+ `PUT /api/tour/#tid/pair/#rn` Manual pairing or table renumbering
For manual pairing:
*input* `{ "id": #gid, "w": #wpid, "b": #bpid, "h": <handicap> }`
For table renumbering:
*input* `{ "renumber": <game_id or null>, "orderBy": "mms" | "table" }`
*output* `{ "success": true }`
+ `DELETE /api/tour/#tip/pair/#n` Delete pairing for round #n and given players (or string "all") ; games with results entered are skipped
+ `DELETE /api/tour/#tid/pair/#rn` Delete pairing for round #rn
*input* `[ "all" ]` or `[ #gid, ... ]`
Games with results already entered are skipped unless `"all"` is specified.
*output* `{ "success": true }`
## Results
+ `GET /api/tour/#tip/res/#rn` Get results for round #rn
+ `GET /api/tour/#tid/res/#rn` Get results for round #rn
*output* `[ { "id": #gid, "res": <result> } ]` with `res` being one of: `"w"`, `"b"`, `"="` (jigo), `"x"` (cancelled),`"?"` (unknown), `"#"` (both win), or `"0"` (both loose).
*output* `[ { "id": #gid, "res": <result> }, ... ]`
+ `PUT /api/tour/#tip/res/#rn` Save a result (or put it back to unknown)
Result codes:
- `"w"` - White won
- `"b"` - Black won
- `"="` - Jigo (draw)
- `"X"` - Cancelled
- `"?"` - Unknown (not yet played)
- `"#"` - Both win (unusual)
- `"0"` - Both lose (unusual)
*input* `{ "id": #gid, "res": <result> }` with `res` being one of: `"w"`, `"b"`, `"="` (jigo), `"x"` (cancelled)
+ `PUT /api/tour/#tid/res/#rn` Save a result
*input* `{ "id": #gid, "res": <result> }`
*output* `{ "success": true }`
+ `DELETE /api/tour/#tip/res/#rn` Clear all results (put back all results to unknown)
+ `DELETE /api/tour/#tid/res/#rn` Clear all results for round
*input* none
*output* `{ "success": true }`
*output* `{ "success": true }`
## Standings
+ `GET /api/tour/#tid/stand/#rn` Get standings after round #rn (or initial standings for round '0')
+ `GET /api/tour/#tid/standings` Get standings after final round
*output* `[ { "id": #pid, "place": place, "<crit>": double }, ... ]`
where `<crit>` is the name of a criterium, among "score", "nbw", "mms", "sosm", "sososm", ...
*output* `[ { "id": #pid, "place": place, "<crit>": value }, ... ]`
Supports multiple output formats via Accept header:
- `application/json` - JSON (default)
- `application/egf` - EGF format
- `application/ffg` - FFG format
- `text/csv` - CSV format
Optional query parameters:
- `include_preliminary=true` - Include preliminary standings
- `individual_standings=true` - For team tournaments with individual scoring
+ `GET /api/tour/#tid/stand/#rn` Get standings after round #rn
Use round `0` for initial standings.
*output* `[ { "id": #pid, "place": place, "<crit>": value }, ... ]`
Criteria names include: `nbw`, `mms`, `sts`, `cps`, `sosw`, `sosm`, `sososw`, `sososm`, `sodosw`, `sodosm`, `cussw`, `cussm`, `dc`, `sdc`, `ext`, `exr`, etc.
+ `PUT /api/tour/#tid/standings` Freeze/lock standings
*output* `{ "success": true }`
## Pairing explanation
+ `GET /api/tour/#tid/explain/#rn` Get detailed pairing criteria weights for round #rn
*output* Detailed pairing weight analysis and criteria breakdown
Used for debugging and understanding pairing decisions.
## Authentication
+ `GET /api/token` Get the token of the currently logged user, or give an error.
+ `GET /api/token` Check authentication status
+ `POST /api/token` Create an access token. Expects an authentication json object.
*output* Token information for the currently logged user, or error if not authenticated.
+ `DELETE /api/token` Delete the token of the currently logged user.
+ `POST /api/token` Create an access token
*input* Authentication credentials (format depends on auth mode)
*output* `{ "success": true, "token": "..." }`
+ `DELETE /api/token` Logout / revoke token
*output* `{ "success": true }`

View File

@@ -2,39 +2,96 @@
Pairgoth general configuration is done using the `pairgoth.properties` file in the installation folder.
## environment
Properties are loaded in this order (later overrides earlier):
Controls the running environment: `dev` for development, `prod` for distributed instances.
1. Default properties embedded in WAR/JAR
2. User properties file (`./pairgoth.properties`) in current working directory
3. System properties prefixed with `pairgoth.` (command-line: `-Dpairgoth.key=value`)
## Environment
Controls the running environment.
```
env = prod
```
## mode
Values:
- `dev` - Development mode: enables CORS headers and additional logging
- `prod` - Production: for distributed instances
Running mode: `standalone`, `client` or `server`.
## Mode
Running mode for the application.
```
mode = standalone
```
## authentication
Values:
- `standalone` - Both web and API in a single process (default for jar execution)
- `server` - API only
- `client` - Web UI only (connects to remote API)
Authentication: `none`, `sesame` for a shared unique password, `oauth` for email and/or oauth accounts.
## Authentication
Authentication method for the application.
```
auth = none
```
When running in client or server mode, if `auth` is not `none`, the following extra property is needed:
Values:
- `none` - No authentication required
- `sesame` - Shared unique password
- `oauth` - Email and/or OAuth accounts
### Shared secret
When running in client or server mode with authentication enabled:
```
auth.shared_secret = <16 ascii characters string>
```
## webapp connector
This secret is shared between API and View webapps. Auto-generated in standalone mode.
Pairgoth webapp connector configuration.
### Sesame password
When using sesame authentication:
```
auth.sesame = <password>
```
## OAuth configuration
When using OAuth authentication:
```
oauth.providers = ffg,google,facebook
```
Comma-separated list of enabled providers: `ffg`, `facebook`, `google`, `instagram`, `twitter`
For each enabled provider, configure credentials:
```
oauth.<provider>.client_id = <client_id>
oauth.<provider>.secret = <client_secret>
```
Example:
```
oauth.ffg.client_id = your-ffg-client-id
oauth.ffg.secret = your-ffg-client-secret
oauth.google.client_id = your-google-client-id
oauth.google.secret = your-google-client-secret
```
## Webapp connector
Pairgoth webapp (UI) connector configuration.
```
webapp.protocol = http
@@ -44,7 +101,10 @@ webapp.context = /
webapp.external.url = http://localhost:8080
```
## api connector
- `webapp.host` (or `webapp.interface`) - Hostname/interface to bind to
- `webapp.external.url` - External URL for OAuth redirects and client configuration
## API connector
Pairgoth API connector configuration.
@@ -56,28 +116,91 @@ api.context = /api
api.external.url = http://localhost:8085/api
```
## store
Note: In standalone mode, API port defaults to 8080 and context to `/api/tour`.
Persistent storage for tournaments, `memory` (mainly used for tests) or `file`.
## SSL/TLS configuration
For HTTPS connections:
```
webapp.ssl.key = path/to/localhost.key
webapp.ssl.cert = path/to/localhost.crt
webapp.ssl.pass = <key passphrase>
```
Supports `jar:` URLs for embedded resources.
## Store
Persistent storage for tournaments.
```
store = file
store.file.path = tournamentfiles
```
## smtp
Values for `store`:
- `file` - Persistent XML files (default)
- `memory` - RAM-based (mainly for tests)
SMTP configuration. Not yet functional.
The `store.file.path` is relative to the current working directory.
## Ratings
### Ratings directory
```
smtp.sender =
smtp.host =
ratings.path = ratings
```
Directory for caching downloaded ratings files.
### Rating sources
For each rating source (`aga`, `egf`, `ffg`):
```
ratings.<source> = <url or file path>
```
If not set, ratings are auto-downloaded from the default URL. Set to a local file path to freeze ratings at a specific date.
Example to freeze EGF ratings:
```
ratings.egf = ratings/EGF-20240115.json
```
### Enable/disable ratings
```
ratings.<source>.enable = true | false
```
Whether to display the rating source button in the Add Player popup.
```
ratings.<source>.show = true | false
```
Whether to show player IDs from this rating source on the registration page.
Defaults:
- For tournaments in France: FFG enabled and shown by default
- Otherwise: all disabled by default
## SMTP
SMTP configuration for email notifications. Not yet functional.
```
smtp.sender = sender@example.com
smtp.host = smtp.example.com
smtp.port = 587
smtp.user =
smtp.password =
smtp.user = username
smtp.password = password
```
## logging
## Logging
Logging configuration.
@@ -86,34 +209,48 @@ logger.level = info
logger.format = [%level] %ip [%logger] %message
```
## ratings
Log levels: `trace`, `debug`, `info`, `warn`, `error`
Ratings configuration. `<ratings>` stands for `egf` or `ffg` in the following.
Format placeholders: `%level`, `%ip`, `%logger`, `%message`
### freeze ratings date
## Example configurations
If the following property is given:
### Standalone development
```
ratings.<ratings>.file = ...
```properties
env = dev
mode = standalone
auth = none
store = file
store.file.path = tournamentfiles
logger.level = trace
```
then the given ratings file will be used (it must use the Pairgoth ratings json format). If not, the corresponding ratings will be automatically downloaded and stored into `ratings/EGF-yyyymmdd.json` or `ratings/FFG-yyyymmdd.json`.
### Client-server deployment
The typical use case, for a big tournament lasting several days or a congress, is to let Pairgoth download the latest expected ratings, then to add this property to freeze the ratings at a specific date.
### enable or disable ratings
Whether to display the EGF or FFG ratings button in the Add Player popup:
```
ratings.<ratings>.enable = true | false
**Server (API):**
```properties
env = prod
mode = server
auth = oauth
auth.shared_secret = 1234567890abcdef
api.port = 8085
store = file
store.file.path = /var/tournaments
logger.level = info
```
Whether to show the ratings player IDs on the registration page:
**Client (Web UI):**
```properties
env = prod
mode = client
auth = oauth
auth.shared_secret = 1234567890abcdef
oauth.providers = ffg,google
oauth.ffg.client_id = your-ffg-id
oauth.ffg.secret = your-ffg-secret
oauth.google.client_id = your-google-id
oauth.google.secret = your-google-secret
webapp.port = 8080
api.external.url = http://api-server:8085/api
```
ratings.<ratings>.show = true | false
```
For a tournament in France, both are true for `ffg` by default, false otherwise.

View File

@@ -1,9 +1,7 @@
# PairGoth model
# Pairgoth Model
## Entity Relationship Diagram
For simplicity, teams (pairgo, rengo) and teams of individuals (clubs championships) are not included.
```mermaid
erDiagram
@@ -11,22 +9,23 @@ erDiagram
Tournament {
int id
string type
Type type
string name
string shortName
date startDate
date endDate
string director
string country
string location
bool isOnline
bool online
int rounds
int gobanSize
string rules
int komi
Rules rules
double komi
}
TimeSystem {
string type
TimeSystemType type
int mainTime
int increment
int maxTime
@@ -37,18 +36,17 @@ erDiagram
Pairing {
PairingType type
BaseParams base
MainParams main
SecondaryParams secondary
GeographicalParams geo
HandicapParams handicap
PlacementParams place
PairingParams pairingParams
PlacementParams placementParams
}
Game {
int id
int table
int handicap
string result
Result result
int drawnUpDown
bool forcedTable
}
Player {
@@ -58,13 +56,26 @@ erDiagram
string country
string club
int rating
string rank
int rank
bool final
array skip
int mmsCorrection
set skip
map externalIds
}
Team {
int id
string name
set playerIds
int rating
int rank
bool final
int mmsCorrection
set skip
}
Standings {
array criteria
list criteria
}
%% relationships
@@ -72,9 +83,266 @@ erDiagram
Tournament ||--|{ TimeSystem: "time system"
Tournament ||--|{ Pairing: "pairing"
Tournament ||--|{ Game: "round"
Tournament }o--|{ Player: "participate(round)"
Tournament }o--|{ Player: "players"
Tournament }o--|{ Team: "teams"
Team }o--|{ Player: "members"
Game ||--|| Player: "black"
Game ||--|| Player: "white"
Player }|--|| Standings: "position"
```
## Tournament
Sealed class hierarchy for different tournament formats.
| Field | Type | Description |
|-------|------|-------------|
| id | int | Tournament identifier |
| type | Type | Tournament format |
| name | string | Full tournament name |
| shortName | string | Abbreviated name |
| startDate | date | Start date |
| endDate | date | End date |
| director | string | Tournament director |
| country | string | Country code (default: "fr") |
| location | string | Venue location |
| online | bool | Is online tournament |
| rounds | int | Total number of rounds |
| gobanSize | int | Board size (default: 19) |
| rules | Rules | Scoring rules |
| komi | double | Komi value (default: 7.5) |
| timeSystem | TimeSystem | Time control |
| pairing | Pairing | Pairing system |
| tablesExclusion | list | Table exclusion rules per round |
### Tournament Types
| Type | Players/Team | Description |
|------|--------------|-------------|
| INDIVIDUAL | 1 | Individual players |
| PAIRGO | 2 | Pair Go (alternating) |
| RENGO2 | 2 | Rengo with 2 players |
| RENGO3 | 3 | Rengo with 3 players |
| TEAM2 | 2 | Team with 2 boards |
| TEAM3 | 3 | Team with 3 boards |
| TEAM4 | 4 | Team with 4 boards |
| TEAM5 | 5 | Team with 5 boards |
### Rules
- `AGA` - American Go Association
- `FRENCH` - French Go Association
- `JAPANESE` - Japanese rules
- `CHINESE` - Chinese rules
## Player
Individual tournament participant.
| Field | Type | Description |
|-------|------|-------------|
| id | int | Player identifier |
| name | string | Last name |
| firstname | string | First name |
| country | string | Country code |
| club | string | Club affiliation |
| rating | int | EGF-style rating |
| rank | int | Rank (-30=30k to 8=9D) |
| final | bool | Is registration confirmed |
| mmsCorrection | int | MacMahon score correction |
| skip | set | Skipped round numbers |
| externalIds | map | External IDs (AGA, EGF, FFG) |
## Team
Team participant (for team tournaments).
| Field | Type | Description |
|-------|------|-------------|
| id | int | Team identifier |
| name | string | Team name |
| playerIds | set | Member player IDs |
| rating | int | Computed from members |
| rank | int | Computed from members |
| final | bool | Is registration confirmed |
| mmsCorrection | int | MacMahon score correction |
| skip | set | Skipped round numbers |
## Game
Single game in a round.
| Field | Type | Description |
|-------|------|-------------|
| id | int | Game identifier |
| table | int | Table number (0 = unpaired) |
| white | int | White player ID (0 = bye) |
| black | int | Black player ID (0 = bye) |
| handicap | int | Handicap stones |
| result | Result | Game outcome |
| drawnUpDown | int | DUDD value |
| forcedTable | bool | Is table manually assigned |
### Result
| Code | Description |
|------|-------------|
| ? | Unknown (not yet played) |
| w | White won |
| b | Black won |
| = | Jigo (draw) |
| X | Cancelled |
| # | Both win (unusual) |
| 0 | Both lose (unusual) |
## TimeSystem
Time control configuration.
| Field | Type | Description |
|-------|------|-------------|
| type | TimeSystemType | System type |
| mainTime | int | Main time in seconds |
| increment | int | Fischer increment |
| maxTime | int | Fischer max time |
| byoyomi | int | Byoyomi time per period |
| periods | int | Number of byoyomi periods |
| stones | int | Stones per period (Canadian) |
### TimeSystemType
| Type | Description |
|------|-------------|
| CANADIAN | Canadian byoyomi |
| JAPANESE | Japanese byoyomi |
| FISCHER | Fischer increment |
| SUDDEN_DEATH | No overtime |
## Pairing
Pairing system configuration.
### Pairing Types
| Type | Description |
|------|-------------|
| SWISS | Swiss system |
| MAC_MAHON | MacMahon system |
| ROUND_ROBIN | Round robin (not implemented) |
### MacMahon-specific
| Field | Type | Description |
|-------|------|-------------|
| mmFloor | int | MacMahon floor (default: -20 = 20k) |
| mmBar | int | MacMahon bar (default: 0 = 1D) |
### Base Parameters
| Parameter | Description |
|-----------|-------------|
| nx1 | Concavity curve factor (0.0-1.0) |
| dupWeight | Duplicate game avoidance weight |
| random | Randomization factor |
| deterministic | Deterministic pairing |
| colorBalanceWeight | Color balance importance |
| byeWeight | Bye assignment weight |
### Main Parameters
| Parameter | Description |
|-----------|-------------|
| categoriesWeight | Avoid mixing categories |
| scoreWeight | Minimize score differences |
| drawUpDownWeight | Draw-up/draw-down weighting |
| compensateDrawUpDown | Enable DUDD compensation |
| drawUpDownUpperMode | TOP, MIDDLE, or BOTTOM |
| drawUpDownLowerMode | TOP, MIDDLE, or BOTTOM |
| seedingWeight | Seeding importance |
| lastRoundForSeedSystem1 | Round cutoff for system 1 |
| seedSystem1 | First seeding method |
| seedSystem2 | Second seeding method |
| mmsValueAbsent | MMS for absent players |
| roundDownScore | Floor vs round scores |
### Seed Methods
- `SPLIT_AND_FOLD`
- `SPLIT_AND_RANDOM`
- `SPLIT_AND_SLIP`
### Secondary Parameters
| Parameter | Description |
|-----------|-------------|
| barThresholdActive | Don't apply below bar |
| rankSecThreshold | Rank limit for criteria |
| nbWinsThresholdActive | Score threshold |
| defSecCrit | Secondary criteria weight |
### Geographical Parameters
| Parameter | Description |
|-----------|-------------|
| avoidSameGeo | Avoid same region |
| preferMMSDiffRatherThanSameCountry | Country preference |
| preferMMSDiffRatherThanSameClubsGroup | Club group preference |
| preferMMSDiffRatherThanSameClub | Club preference |
### Handicap Parameters
| Parameter | Description |
|-----------|-------------|
| weight | Handicap minimization weight |
| useMMS | Use MMS vs rank |
| rankThreshold | Rank threshold |
| correction | Handicap reduction |
| ceiling | Max handicap stones |
## Placement Criteria
Tiebreak criteria for standings, in order of priority.
### Score-based
| Criterion | Description |
|-----------|-------------|
| NBW | Number of wins |
| MMS | MacMahon score |
| STS | Strasbourg score |
| CPS | Cup score |
| SCOREX | Congress score |
### Opponent-based (W = wins, M = MMS)
| Criterion | Description |
|-----------|-------------|
| SOSW / SOSM | Sum of opponent scores |
| SOSWM1 / SOSMM1 | SOS minus worst |
| SOSWM2 / SOSMM2 | SOS minus two worst |
| SODOSW / SODOSM | Sum of defeated opponent scores |
| SOSOSW / SOSOSM | Sum of opponent SOS |
| CUSSW / CUSSM | Cumulative score sum |
### Other
| Criterion | Description |
|-----------|-------------|
| CATEGORY | Player category |
| RANK | Player rank |
| RATING | Player rating |
| DC | Direct confrontation |
| SDC | Simplified direct confrontation |
| EXT | Exploits attempted |
| EXR | Exploits successful |
## External Databases
Player IDs can be linked to external rating databases:
| Database | Description |
|----------|-------------|
| AGA | American Go Association |
| EGF | European Go Federation |
| FFG | French Go Association |