# archon
Tournament management
## Development install
This project uses [npm](https://docs.npmjs.com), that you can install with [nvm](https://github.com/nvm-sh/nvm).
It also uses [Python](https://docs.python.org/3/) on the backend side, so install Python version >= `3.11`.
Do not forget to install the required certifi certificates for Python (follow the installer instructions).
Finally, you'll need [GNU Make](https://www.gnu.org/software/make/manual/make.html)
for simple targets and processes defined in a [Makefile](Makefile).
Four options **if you are on Windows**:
- Use [Chocolatey](https://chocolatey.org) as package manager and `choco install make`
- Use the [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/) feature
- Just install the [GNU make binary for Windows](https://gnuwin32.sourceforge.net/packages/make.htm)
- Don't use `make` at all. The [Makefile](Makefile) is just a shortcut,
you can open it and copy/paste the commands in your Powershell.
```bash
nvm install node
nvm use node
python -m virtualenv .venv
source .venv/bin/activate
make update
```
### Using Homebrew on OSX
You can use [Homebrew](https://brew.sh/) on Linux or OSX to install Python and its dependencies.
Don't forget to update the CA certificates from time to time.
```bash
brew reinstall ca-certificates openssl
```
### Updating the development environment
To update Node.js and NPM versions, run:
```bash
nvm install --latest-npm
nvm use node
npm install -g npm@latest
npm install --include=dev
```
To update Python version, install the new Python binary (OS-dependant),
then remove and regenerate the virtualenv with the new Python binary:
```bash
rm -rf ".venv"
python3.13 -m virtualenv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install --upgrade ".[dev]"
```
### Tools & Frameworks
We are using a couple of very standard tools and frameworks, that `make update` will install and update for you:
- [Typescript](https://www.typescriptlang.org/docs/) our frontend language
- [Bootstrap](https://getbootstrap.com/docs) and its [icons](https://icons.getbootstrap.com), for basic styling & responsiveness
- [Parcel](https://parceljs.org/docs/) as our build framework for frontend
- [FastAPI](https://fastapi.tiangolo.com/learn/) as our backend server framework,
with [Jinja2](https://jinja.palletsprojects.com/en/stable/) for HTML templating,
its [i18n extension](https://jinja.palletsprojects.com/en/stable/extensions/#i18n-extension) for potential future translations,
and [pyJWT](https://pyjwt.readthedocs.io/en/stable/) for generating [OAuth 2.0](https://oauth.net/2/) [JWT (RFC 7519)](https://datatracker.ietf.org/doc/html/rfc7519) tokens.
- [PostgreSQL](https://www.postgresql.org/docs/current/index.html) for database,
with [psycopg3](https://www.psycopg.org/psycopg3/docs/) as our library to instrument it
- [AIOHTTP](https://docs.aiohttp.org) for web queries
- [Black](https://black.readthedocs.io/en/stable/) and [Ruff](https://docs.astral.sh/ruff/) for python formatting and linting, respectively
- [Twine](https://twine.readthedocs.io/en/stable/) to publish our Python package to the public [PYPI](https://pypi.org) repository.
- [PM2](https://pm2.keymetrics.io/docs/usage/quick-start/) to run our hot reload development services (front & back)
- [Geonames](https://www.geonames.org) for countries and cities names and IDs
- [Typer](https://typer.tiangolo.com) for the [`archon` Command-Line Interface (CLI)](#cli)
## Make targets
- `make geodata` downlad and refresh the geographical data in [geodata](src/archon/geodata)
- `make test` runs the tests, formatting and linting checks
- `make serve` runs a dev server with watchers for auto-reload when changes are made to the source files
- `make clean` cleans the repository from all transient build files
- `make build` builds the python package
- `make release` creates and pushes a git tag for this version and publishes the package on [PYPI](https://pypi.org)
## CLI
The `archon` CLI gives access to useful DB-related commands when developing in local.
```bash
> archon --help
Usage: archon [OPTIONS] COMMAND [ARGS]...
╭─ Options ───────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy it or customize the installation. │
│ --help Show this message and exit. │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ──────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ reset-db ⚠️ Reset the database ⚠️ Removes all data │
│ list List tournaments │
│ sync-members Update members from the vekn.net website │
│ sync-events Update historical tournaments from the vekn.net website │
│ purge Purge deprecated historical data │
│ add-client Add an authorized client to the platform │
│ recompute-ratings Recompute all tournament ratings │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
## Development database
You need a running [PostgreSQL](https://www.postgresql.org/docs/current/index.html) server, with an `archon` superuser,
an `archondb` database owned by that superuser, with no password.
You can use the `DB_USER` and `DB_PWD` environment variables to use other values. The database name is not configurable.
## Development server
Make sure you have set up all the required [setting](#settings).
Simply use `make serve` to run the front and back services.
They constantly watch your files and rebuild the project automatically when there is any change.
Use `pm2 logs` to keep an eye on what's going on and `pm2 kill` to stop the services.
You can also use `pm2 ps` to check if the services are up and running.
For more, see the [PM2 documentation](https://pm2.keymetrics.io/docs/usage/quick-start/).
### Bootstrapping
To bootstrap the app with a full VEKN sync, you need to run it once out of debug mode:
```
PYTHONOPTIMIZE=1 make serve
```
Alternatively, you can run the necessary sync from the command line directly:
```
archon sync-members
archon sync-events
archon recompute-ratings
```
## Settings
This software requires some environment settings for multiple functionalities:
### VEKN credentials
Used to collect the VEKN members list, and publish events and their result.
```bash
export VEKN_LOGIN="<vekn_login>"
export VEKN_PASSWORD="<vekn_password>"
```
### VEKN API
For now, this app uses the [VEKN API](https://bitbucket.org/vekn/vekn-api/src/master/)
to declare and report events. There is an [online documentation](https://www.vekn.net/API/readme.txt).
### Discord credentials
Used for the Discord social login. You need to register a
[Discord Application](https://discord.com/developers/applications).
```bash
export DISCORD_CLIENT_ID="<discord_client_id>"
export DISCORD_CLIENT_SECRET="<discord_client_secret>"
```
### Application secrets
Secrets for various security features.
Make sure you use different secure random secrets for different environments.
```bash
SESSION_KEY="<sign_session_cookie>"
TOKEN_SECRET="<sign_access_token>"
HASH_KEY="<hash_user_passwords>"
```
You can use `openssl` to generate each of these secrets:
```bash
openssl rand -hex 32
```
### Email (SMTP) parameters
Used to send the "password reset" email necessary for the basic email login feature.
Note that if you're using GMail, you probably need to generate an
[Application Password](https://myaccount.google.com/apppasswords) for this application.
```bash
export MAIL_SERVER="smtp.gmail.com"
export MAIL_PORT="587"
export MAIL_USERNAME="codex.of.the.damned@gmail.com"
export MAIL_PASSWORD="<app_password>"
export MAIL_FROM="codex.of.the.damned@gmail.com"
export MAIL_FROM_NAME="Archon"
```
## Design
### Offline mode and Source of Truth (SoT)
While it is desirable to have a clear unique source of truth (SoT) for a tournament state, it has also deemed important
to be able to use this website in offline mode. Therefore, offline mode is activated _while online_ and changes the
source of truth (SoT) from the remote server to the local browser instance. This locks the remote server instance,
so noone else can interact with the server anymore.
Features deactivated in offline mode:
- Self registration for players
- Self check-in for players
- Score reporting for players
- Dynamic seating computation
Offline mode can be deactivated by any judge, so there are two "ways" out of it:
- Upload back online from the local instance that had been designated Source of Truth (SoT)
- Revert back to online from any other device and drop all changes from local Source of Truth (SoT)
### Journal and state
To facilitate reconciliation and avoid concurrency issues between multiple clients, the tournament state is maintained
and computed by the SoT. All instances (any browser, device, etc.) maintains a journal of events.
These events have unique IDs. On active interactions, an instance will:
- Send the event to the server, together with the last recorded event ID on the instance
- Receive an updated tournament state, together with a list of events since the last recorded event ID
- replay the listed events to modify the interface
In offline mode (being the SoT), it will simply:
- Play the events as they arrive
- Upon returning online, sent the updated state with all events
Online clients can either:
- Simply rebuild their whole interface any time they get a tournament state update after sending an event
- Apply all returned events in order to their interface to avoid a global reload
In the future, this design will allow clients to use websockets for live updates very easily.
### Events list
#### Register
Neither VEKN nor UID is mandatory. To register a new player who has no VEKN account, provide a new UUID4.
If you do not provide one, a new UUID4 will be generated and an account created for that person.
```json
{
"type": "Register",
"name": "John Doe",
"vekn": "12300001",
"player_uid": "24AAC87E-DE63-46DF-9784-AB06B2F37A24",
"country": "France",
"city": "Paris"
}
```
#### OpenCheckin
Check a player in, signaling they are present and ready to play the next round.
You should perform the check-in just before the round starts to limit the number of players
who do not show up to their table.
```json
{
"type": "OpenCheckin"
}
```
#### CheckIn
Mark a player as ready to play. Players can self-check-in.
```json
{
"type": "CheckIn",
"player_uid": "238CD960-7E54-4A38-A676-8288A5700FC8"
}
```
#### CheckOut
Move a player back to registration.
```json
{
"type": "CheckOut",
"player_uid": "238CD960-7E54-4A38-A676-8288A5700FC8"
}
```
#### RoundStart
Start the next round. The provided seating must list players UID forming the tables.
Each UID must match a VEKN member UID.
```json
{
"type": "RoundStart",
"seating": [
["238CD960-7E54-4A38-A676-8288A5700FC8",
"796CD3CE-BC2B-4505-B448-1C2D42E9F140",
"80E9FD37-AD8C-40AA-A42D-138065530F10",
"586616DC-3FEA-4DAF-A222-1E77A2CBD809",
"8F28E4C2-1953-473E-A1C5-C281957072D1"
],[
"BD570AA9-B70C-43CA-AD05-3B4C7DADC28C",
"AB6F75B3-ED60-45CA-BDFF-1BF8DD5F02C4",
"1CB1E9A7-576B-4065-8A9C-F7920AAF977D",
"8907BE41-91A7-4395-AF91-54D94C489A36"
]
]
}
```
#### RoundAlter
Change a round's seating. Note recorded VPs, if any, stay assigned to the player even if they move.
```json
{
"type": "RoundAlter",
"round": 1,
"seating": [
["238CD960-7E54-4A38-A676-8288A5700FC8",
"796CD3CE-BC2B-4505-B448-1C2D42E9F140",
"80E9FD37-AD8C-40AA-A42D-138065530F10",
"586616DC-3FEA-4DAF-A222-1E77A2CBD809",
"8F28E4C2-1953-473E-A1C5-C281957072D1"
],[
"BD570AA9-B70C-43CA-AD05-3B4C7DADC28C",
"AB6F75B3-ED60-45CA-BDFF-1BF8DD5F02C4",
"1CB1E9A7-576B-4065-8A9C-F7920AAF977D",
"8907BE41-91A7-4395-AF91-54D94C489A36"
]
]
}
```
#### RoundFinish
Finish the current round.
```json
{
"type": "RoundFinish"
}
```
#### SetResult
Set a player's result. Players can set their and their table result for the current round.
Only VPs are provided, the GW and TP computations are done by the engine.
```json
{
"type": "SetResult",
"player_uid": "238CD960-7E54-4A38-A676-8288A5700FC8",
"round": 1,
"vps": 2.5
}
```
#### SetDeck
Set a player's deck list. Players can set their own decklist, each round if it is a multideck tournament.
Accepts plain text decklist (any usual format) or decklists URL (VDB, Amaranth, VTESDecks).
```json
{
"type": "SetDeck",
"player_uid": "238CD960-7E54-4A38-A676-8288A5700FC8",
"deck": "https://vdb.im/decks/11906"
}
```
The `round` parameter is facultative and can only be used by a Judge for corrective action in multideck tournaments.
```json
{
"type": "SetDeck",
"player_uid": "238CD960-7E54-4A38-A676-8288A5700FC8",
"round": 1,
"deck": "https://vdb.im/decks/11906"
}
```
#### Drop
Drop a player from the tournament. A player can drop by themselves.
A Judge can drop a player if they note they have juse left.
To **disqualify** a player, use the [Sanction](#sanction) event.
```json
{
"type": "Drop",
"player_uid": "238CD960-7E54-4A38-A676-8288A5700FC8"
}
```
#### Sanction
Sanction (punish) a player.
The sanction levels are: `CAUTION`, `WARNING` and `DISQUALIFICATION`.
Cautions are just informative. Warnings are recorded (accessible to organizers, even in future events).
Disqualifications are recorded and remove the player from the tournament.
Sanction also have an optional category, one of:
- `DECK_PROBLEM`
- `PROCEDURAL_ERRORS`
- `CARD_DRAWING`
- `MARKED_CARDS`
- `SLOW_PLAY`
- `UNSPORTSMANLIKE_CONDUCT`
- `CHEATING`
```json
{
"type": "Sanction",
"level": "WARNING",
"player_uid": "238CD960-7E54-4A38-A676-8288A5700FC8",
"comment": "Free comment",
"category": "PROCEDURAL_ERRORS"
}
```
#### Unsanction
Remove all sanctions of given level for a player.
```json
{
"type": "Unsanction",
"level": "WARNING",
"player_uid": "238CD960-7E54-4A38-A676-8288A5700FC8"
}
```
#### Override
Judges can validated an odd table score.
For example, if they disqualify a player but do not award VPs to their predator,
the final table score will not appear valid until it's overriden.
Rounds and tables are counted starting from 1.
```json
{
"type": "Override",
"round": 1,
"table": 1,
"comment": "Free form comment"
}
```
#### SeedFinals
A finals is "seeded" first before players elect their seat in seed order.
```json
{
"type": "SeedFinals",
"seeds": ["238CD960-7E54-4A38-A676-8288A5700FC8",
"796CD3CE-BC2B-4505-B448-1C2D42E9F140",
"80E9FD37-AD8C-40AA-A42D-138065530F10",
"586616DC-3FEA-4DAF-A222-1E77A2CBD809",
"8F28E4C2-1953-473E-A1C5-C281957072D1"
]
}
```
#### SeatFinals
Note what seating position finalists have elected.
```json
{
"type": "SeatFinals",
"seating": ["238CD960-7E54-4A38-A676-8288A5700FC8",
"796CD3CE-BC2B-4505-B448-1C2D42E9F140",
"80E9FD37-AD8C-40AA-A42D-138065530F10",
"586616DC-3FEA-4DAF-A222-1E77A2CBD809",
"8F28E4C2-1953-473E-A1C5-C281957072D1"
]
}
```
#### Finish
Finish the tournament. This closes up the tournament. The winner, if finals results have been recorded,
is automatically computed.
```json
{
"type": "Finish",
}
```
Raw data
{
"_id": null,
"home_page": null,
"name": "vtes-archon",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "vtes, Vampire: The Eternal Struggle, CCG, Tournament",
"author": "VEKN",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/15/26/6e1cd553abdceca009ad1b5de12384285603b6524868fae8fadd1dcd7a71/vtes_archon-0.30.tar.gz",
"platform": null,
"description": "# archon\n\nTournament management\n\n## Development install\n\nThis project uses [npm](https://docs.npmjs.com), that you can install with [nvm](https://github.com/nvm-sh/nvm).\nIt also uses [Python](https://docs.python.org/3/) on the backend side, so install Python version >= `3.11`.\nDo not forget to install the required certifi certificates for Python (follow the installer instructions).\n\nFinally, you'll need [GNU Make](https://www.gnu.org/software/make/manual/make.html) \nfor simple targets and processes defined in a [Makefile](Makefile).\nFour options **if you are on Windows**:\n\n- Use [Chocolatey](https://chocolatey.org) as package manager and `choco install make`\n- Use the [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/) feature\n- Just install the [GNU make binary for Windows](https://gnuwin32.sourceforge.net/packages/make.htm)\n- Don't use `make` at all. The [Makefile](Makefile) is just a shortcut, \n you can open it and copy/paste the commands in your Powershell.\n\n```bash\nnvm install node\nnvm use node\npython -m virtualenv .venv\nsource .venv/bin/activate\nmake update\n```\n\n### Using Homebrew on OSX\n\nYou can use [Homebrew](https://brew.sh/) on Linux or OSX to install Python and its dependencies.\nDon't forget to update the CA certificates from time to time.\n\n```bash\nbrew reinstall ca-certificates openssl\n```\n\n### Updating the development environment\n\nTo update Node.js and NPM versions, run:\n\n```bash\nnvm install --latest-npm\nnvm use node\nnpm install -g npm@latest\nnpm install --include=dev\n```\n\nTo update Python version, install the new Python binary (OS-dependant), \nthen remove and regenerate the virtualenv with the new Python binary:\n\n```bash\nrm -rf \".venv\"\npython3.13 -m virtualenv .venv\nsource .venv/bin/activate\npip install --upgrade pip\npip install --upgrade \".[dev]\"\n```\n\n### Tools & Frameworks\n\nWe are using a couple of very standard tools and frameworks, that `make update` will install and update for you:\n\n- [Typescript](https://www.typescriptlang.org/docs/) our frontend language\n\n- [Bootstrap](https://getbootstrap.com/docs) and its [icons](https://icons.getbootstrap.com), for basic styling & responsiveness \n\n- [Parcel](https://parceljs.org/docs/) as our build framework for frontend\n\n- [FastAPI](https://fastapi.tiangolo.com/learn/) as our backend server framework,\n with [Jinja2](https://jinja.palletsprojects.com/en/stable/) for HTML templating,\n its [i18n extension](https://jinja.palletsprojects.com/en/stable/extensions/#i18n-extension) for potential future translations,\n and [pyJWT](https://pyjwt.readthedocs.io/en/stable/) for generating [OAuth 2.0](https://oauth.net/2/) [JWT (RFC 7519)](https://datatracker.ietf.org/doc/html/rfc7519) tokens.\n\n- [PostgreSQL](https://www.postgresql.org/docs/current/index.html) for database,\n with [psycopg3](https://www.psycopg.org/psycopg3/docs/) as our library to instrument it\n\n- [AIOHTTP](https://docs.aiohttp.org) for web queries\n\n- [Black](https://black.readthedocs.io/en/stable/) and [Ruff](https://docs.astral.sh/ruff/) for python formatting and linting, respectively\n\n- [Twine](https://twine.readthedocs.io/en/stable/) to publish our Python package to the public [PYPI](https://pypi.org) repository.\n\n- [PM2](https://pm2.keymetrics.io/docs/usage/quick-start/) to run our hot reload development services (front & back)\n\n- [Geonames](https://www.geonames.org) for countries and cities names and IDs\n\n- [Typer](https://typer.tiangolo.com) for the [`archon` Command-Line Interface (CLI)](#cli)\n\n## Make targets\n\n- `make geodata` downlad and refresh the geographical data in [geodata](src/archon/geodata)\n- `make test` runs the tests, formatting and linting checks\n- `make serve` runs a dev server with watchers for auto-reload when changes are made to the source files\n- `make clean` cleans the repository from all transient build files\n- `make build` builds the python package\n- `make release` creates and pushes a git tag for this version and publishes the package on [PYPI](https://pypi.org)\n\n## CLI\n\nThe `archon` CLI gives access to useful DB-related commands when developing in local.\n\n```bash\n> archon --help\n\n Usage: archon [OPTIONS] COMMAND [ARGS]...\n\u256d\u2500 Options \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 --install-completion Install completion for the current shell. \u2502\n\u2502 --show-completion Show completion for the current shell, to copy it or customize the installation. \u2502\n\u2502 --help Show this message and exit. \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n\u256d\u2500 Commands \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e\n\u2502 reset-db \u26a0\ufe0f Reset the database \u26a0\ufe0f Removes all data \u2502\n\u2502 list List tournaments \u2502\n\u2502 sync-members Update members from the vekn.net website \u2502\n\u2502 sync-events Update historical tournaments from the vekn.net website \u2502\n\u2502 purge Purge deprecated historical data \u2502\n\u2502 add-client Add an authorized client to the platform \u2502\n\u2502 recompute-ratings Recompute all tournament ratings \u2502\n\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\n```\n\n## Development database\n\nYou need a running [PostgreSQL](https://www.postgresql.org/docs/current/index.html) server, with an `archon` superuser,\nan `archondb` database owned by that superuser, with no password.\nYou can use the `DB_USER` and `DB_PWD` environment variables to use other values. The database name is not configurable.\n\n## Development server\n\nMake sure you have set up all the required [setting](#settings).\nSimply use `make serve` to run the front and back services.\nThey constantly watch your files and rebuild the project automatically when there is any change.\nUse `pm2 logs` to keep an eye on what's going on and `pm2 kill` to stop the services.\nYou can also use `pm2 ps` to check if the services are up and running.\nFor more, see the [PM2 documentation](https://pm2.keymetrics.io/docs/usage/quick-start/).\n\n### Bootstrapping\n\nTo bootstrap the app with a full VEKN sync, you need to run it once out of debug mode:\n\n```\nPYTHONOPTIMIZE=1 make serve\n```\n\nAlternatively, you can run the necessary sync from the command line directly:\n\n```\narchon sync-members\narchon sync-events\narchon recompute-ratings\n```\n\n## Settings\n\nThis software requires some environment settings for multiple functionalities:\n\n### VEKN credentials\n\nUsed to collect the VEKN members list, and publish events and their result.\n\n```bash\nexport VEKN_LOGIN=\"<vekn_login>\"\nexport VEKN_PASSWORD=\"<vekn_password>\"\n```\n\n### VEKN API\n\nFor now, this app uses the [VEKN API](https://bitbucket.org/vekn/vekn-api/src/master/) \nto declare and report events. There is an [online documentation](https://www.vekn.net/API/readme.txt).\n\n### Discord credentials\n\nUsed for the Discord social login. You need to register a\n[Discord Application](https://discord.com/developers/applications).\n\n```bash\nexport DISCORD_CLIENT_ID=\"<discord_client_id>\"\nexport DISCORD_CLIENT_SECRET=\"<discord_client_secret>\"\n```\n\n### Application secrets\n\nSecrets for various security features.\nMake sure you use different secure random secrets for different environments.\n\n```bash\nSESSION_KEY=\"<sign_session_cookie>\"\nTOKEN_SECRET=\"<sign_access_token>\"\nHASH_KEY=\"<hash_user_passwords>\"\n```\n\nYou can use `openssl` to generate each of these secrets:\n\n```bash\nopenssl rand -hex 32\n```\n\n### Email (SMTP) parameters\n\nUsed to send the \"password reset\" email necessary for the basic email login feature.\nNote that if you're using GMail, you probably need to generate an\n[Application Password](https://myaccount.google.com/apppasswords) for this application.\n\n```bash\nexport MAIL_SERVER=\"smtp.gmail.com\"\nexport MAIL_PORT=\"587\"\nexport MAIL_USERNAME=\"codex.of.the.damned@gmail.com\"\nexport MAIL_PASSWORD=\"<app_password>\"\nexport MAIL_FROM=\"codex.of.the.damned@gmail.com\"\nexport MAIL_FROM_NAME=\"Archon\"\n```\n\n## Design \n\n### Offline mode and Source of Truth (SoT)\n\nWhile it is desirable to have a clear unique source of truth (SoT) for a tournament state, it has also deemed important\nto be able to use this website in offline mode. Therefore, offline mode is activated _while online_ and changes the\nsource of truth (SoT) from the remote server to the local browser instance. This locks the remote server instance,\nso noone else can interact with the server anymore.\n\nFeatures deactivated in offline mode:\n\n- Self registration for players\n- Self check-in for players\n- Score reporting for players\n- Dynamic seating computation\n\nOffline mode can be deactivated by any judge, so there are two \"ways\" out of it:\n\n- Upload back online from the local instance that had been designated Source of Truth (SoT)\n- Revert back to online from any other device and drop all changes from local Source of Truth (SoT)\n\n### Journal and state\n\nTo facilitate reconciliation and avoid concurrency issues between multiple clients, the tournament state is maintained\nand computed by the SoT. All instances (any browser, device, etc.) maintains a journal of events.\nThese events have unique IDs. On active interactions, an instance will:\n\n- Send the event to the server, together with the last recorded event ID on the instance\n- Receive an updated tournament state, together with a list of events since the last recorded event ID\n- replay the listed events to modify the interface\n\nIn offline mode (being the SoT), it will simply:\n\n- Play the events as they arrive\n- Upon returning online, sent the updated state with all events \n\nOnline clients can either:\n\n- Simply rebuild their whole interface any time they get a tournament state update after sending an event\n- Apply all returned events in order to their interface to avoid a global reload\n\nIn the future, this design will allow clients to use websockets for live updates very easily.\n\n### Events list\n\n#### Register\n\nNeither VEKN nor UID is mandatory. To register a new player who has no VEKN account, provide a new UUID4.\nIf you do not provide one, a new UUID4 will be generated and an account created for that person.\n\n```json\n{\n \"type\": \"Register\",\n \"name\": \"John Doe\",\n \"vekn\": \"12300001\",\n \"player_uid\": \"24AAC87E-DE63-46DF-9784-AB06B2F37A24\",\n \"country\": \"France\",\n \"city\": \"Paris\"\n}\n```\n\n#### OpenCheckin\n\nCheck a player in, signaling they are present and ready to play the next round.\nYou should perform the check-in just before the round starts to limit the number of players\nwho do not show up to their table.\n\n```json\n{\n \"type\": \"OpenCheckin\"\n}\n```\n\n#### CheckIn\n\nMark a player as ready to play. Players can self-check-in. \n\n```json\n{\n \"type\": \"CheckIn\",\n \"player_uid\": \"238CD960-7E54-4A38-A676-8288A5700FC8\"\n}\n```\n\n#### CheckOut\n\nMove a player back to registration.\n\n```json\n{\n \"type\": \"CheckOut\",\n \"player_uid\": \"238CD960-7E54-4A38-A676-8288A5700FC8\"\n}\n```\n\n#### RoundStart\n\nStart the next round. The provided seating must list players UID forming the tables.\nEach UID must match a VEKN member UID.\n\n```json\n{\n \"type\": \"RoundStart\",\n \"seating\": [\n [\"238CD960-7E54-4A38-A676-8288A5700FC8\",\n \"796CD3CE-BC2B-4505-B448-1C2D42E9F140\",\n \"80E9FD37-AD8C-40AA-A42D-138065530F10\",\n \"586616DC-3FEA-4DAF-A222-1E77A2CBD809\",\n \"8F28E4C2-1953-473E-A1C5-C281957072D1\"\n ],[\n \"BD570AA9-B70C-43CA-AD05-3B4C7DADC28C\",\n \"AB6F75B3-ED60-45CA-BDFF-1BF8DD5F02C4\",\n \"1CB1E9A7-576B-4065-8A9C-F7920AAF977D\",\n \"8907BE41-91A7-4395-AF91-54D94C489A36\"\n ]\n ]\n}\n```\n\n\n#### RoundAlter\n\nChange a round's seating. Note recorded VPs, if any, stay assigned to the player even if they move.\n\n```json\n{\n \"type\": \"RoundAlter\",\n \"round\": 1,\n \"seating\": [\n [\"238CD960-7E54-4A38-A676-8288A5700FC8\",\n \"796CD3CE-BC2B-4505-B448-1C2D42E9F140\",\n \"80E9FD37-AD8C-40AA-A42D-138065530F10\",\n \"586616DC-3FEA-4DAF-A222-1E77A2CBD809\",\n \"8F28E4C2-1953-473E-A1C5-C281957072D1\"\n ],[\n \"BD570AA9-B70C-43CA-AD05-3B4C7DADC28C\",\n \"AB6F75B3-ED60-45CA-BDFF-1BF8DD5F02C4\",\n \"1CB1E9A7-576B-4065-8A9C-F7920AAF977D\",\n \"8907BE41-91A7-4395-AF91-54D94C489A36\"\n ]\n ]\n}\n```\n\n#### RoundFinish\n\nFinish the current round.\n\n```json\n{\n \"type\": \"RoundFinish\"\n}\n```\n\n#### SetResult\n\nSet a player's result. Players can set their and their table result for the current round.\nOnly VPs are provided, the GW and TP computations are done by the engine.\n\n```json\n{\n \"type\": \"SetResult\",\n \"player_uid\": \"238CD960-7E54-4A38-A676-8288A5700FC8\",\n \"round\": 1,\n \"vps\": 2.5\n}\n```\n\n#### SetDeck\n\nSet a player's deck list. Players can set their own decklist, each round if it is a multideck tournament.\nAccepts plain text decklist (any usual format) or decklists URL (VDB, Amaranth, VTESDecks).\n\n```json\n{\n \"type\": \"SetDeck\",\n \"player_uid\": \"238CD960-7E54-4A38-A676-8288A5700FC8\",\n \"deck\": \"https://vdb.im/decks/11906\"\n}\n```\n\nThe `round` parameter is facultative and can only be used by a Judge for corrective action in multideck tournaments.\n\n```json\n{\n \"type\": \"SetDeck\",\n \"player_uid\": \"238CD960-7E54-4A38-A676-8288A5700FC8\",\n \"round\": 1,\n \"deck\": \"https://vdb.im/decks/11906\"\n}\n```\n\n#### Drop\n\nDrop a player from the tournament. A player can drop by themselves.\nA Judge can drop a player if they note they have juse left.\nTo **disqualify** a player, use the [Sanction](#sanction) event.\n\n```json\n{\n \"type\": \"Drop\",\n \"player_uid\": \"238CD960-7E54-4A38-A676-8288A5700FC8\"\n}\n```\n\n#### Sanction\n\nSanction (punish) a player.\nThe sanction levels are: `CAUTION`, `WARNING` and `DISQUALIFICATION`.\nCautions are just informative. Warnings are recorded (accessible to organizers, even in future events).\nDisqualifications are recorded and remove the player from the tournament.\n\nSanction also have an optional category, one of:\n\n- `DECK_PROBLEM`\n- `PROCEDURAL_ERRORS`\n- `CARD_DRAWING`\n- `MARKED_CARDS`\n- `SLOW_PLAY`\n- `UNSPORTSMANLIKE_CONDUCT`\n- `CHEATING`\n\n```json\n{\n \"type\": \"Sanction\",\n \"level\": \"WARNING\",\n \"player_uid\": \"238CD960-7E54-4A38-A676-8288A5700FC8\",\n \"comment\": \"Free comment\",\n \"category\": \"PROCEDURAL_ERRORS\"\n}\n```\n \n#### Unsanction\n\nRemove all sanctions of given level for a player.\n\n```json\n{\n \"type\": \"Unsanction\",\n \"level\": \"WARNING\",\n \"player_uid\": \"238CD960-7E54-4A38-A676-8288A5700FC8\"\n}\n```\n\n#### Override\nJudges can validated an odd table score.\nFor example, if they disqualify a player but do not award VPs to their predator,\nthe final table score will not appear valid until it's overriden.\n\nRounds and tables are counted starting from 1.\n\n```json\n{\n \"type\": \"Override\",\n \"round\": 1,\n \"table\": 1,\n \"comment\": \"Free form comment\"\n}\n```\n\n#### SeedFinals\n\nA finals is \"seeded\" first before players elect their seat in seed order.\n\n```json\n{\n \"type\": \"SeedFinals\",\n \"seeds\": [\"238CD960-7E54-4A38-A676-8288A5700FC8\",\n \"796CD3CE-BC2B-4505-B448-1C2D42E9F140\",\n \"80E9FD37-AD8C-40AA-A42D-138065530F10\",\n \"586616DC-3FEA-4DAF-A222-1E77A2CBD809\",\n \"8F28E4C2-1953-473E-A1C5-C281957072D1\"\n ]\n}\n```\n \n#### SeatFinals\n\nNote what seating position finalists have elected.\n\n```json\n{\n \"type\": \"SeatFinals\",\n \"seating\": [\"238CD960-7E54-4A38-A676-8288A5700FC8\",\n \"796CD3CE-BC2B-4505-B448-1C2D42E9F140\",\n \"80E9FD37-AD8C-40AA-A42D-138065530F10\",\n \"586616DC-3FEA-4DAF-A222-1E77A2CBD809\",\n \"8F28E4C2-1953-473E-A1C5-C281957072D1\"\n ]\n}\n```\n\n#### Finish\n\nFinish the tournament. This closes up the tournament. The winner, if finals results have been recorded,\nis automatically computed.\n\n```json\n{\n \"type\": \"Finish\",\n}\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "VTES tournament management",
"version": "0.30",
"project_urls": {
"Repository": "https://github.com/vtes-biased/archon"
},
"split_keywords": [
"vtes",
" vampire: the eternal struggle",
" ccg",
" tournament"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "9bd914f2d0e89dafaae1ff81195a11531600695d042c508a555e8bb17cddb927",
"md5": "5a23dd409e4f35f45e34cd8df5746809",
"sha256": "6fb3f3ab4e2fd04e2bdf813c730a66b808cf470636e614d4343614f7b78b272b"
},
"downloads": -1,
"filename": "vtes_archon-0.30-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5a23dd409e4f35f45e34cd8df5746809",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 10144624,
"upload_time": "2025-04-20T23:29:21",
"upload_time_iso_8601": "2025-04-20T23:29:21.490037Z",
"url": "https://files.pythonhosted.org/packages/9b/d9/14f2d0e89dafaae1ff81195a11531600695d042c508a555e8bb17cddb927/vtes_archon-0.30-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "15266e1cd553abdceca009ad1b5de12384285603b6524868fae8fadd1dcd7a71",
"md5": "ffabdfbd9bfafe3872d077a8777ae403",
"sha256": "6a7cca515d62b42c79d7deb0c6ae660c1debd78aeb8fafdc6ab9d7fa4b6c4031"
},
"downloads": -1,
"filename": "vtes_archon-0.30.tar.gz",
"has_sig": false,
"md5_digest": "ffabdfbd9bfafe3872d077a8777ae403",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 9947329,
"upload_time": "2025-04-20T23:29:24",
"upload_time_iso_8601": "2025-04-20T23:29:24.827469Z",
"url": "https://files.pythonhosted.org/packages/15/26/6e1cd553abdceca009ad1b5de12384285603b6524868fae8fadd1dcd7a71/vtes_archon-0.30.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-04-20 23:29:24",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "vtes-biased",
"github_project": "archon",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "vtes-archon"
}