# 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)
