chore: add project guidance and agent workflows

This commit is contained in:
tothbt committed 2026-10-23 20:08:38 +02:00
1 parent 349662a055
commit 326575e55d
14 files changed
+963 -6

No files matched your search

+119
View File
@@ -0,0 +1,119 @@
# Architecture
This document describes behavior confirmed from the current repository. Proposed changes should be labeled as proposals rather than added here as existing behavior.
## System overview
Court Pilot is a local-first Angular/Ionic application packaged as a Tauri desktop application. There is no backend API in the repository. Domain data is persisted in IndexedDB through Dexie.
```mermaid
flowchart TD
Pages[Angular and Ionic pages] --> Services[Domain and persistence services]
Pages --> I18n[Translation service and pipe]
Services --> Dexie[Dexie]
Dexie --> IndexedDB[IndexedDB in browser or webview]
Tauri[Tauri desktop shell] --> WebApp[Built Angular application]
Tauri --> Updates[OS, process, and updater plugins]
WebApp --> Pages
```
## Frontend structure
The root route lazy-loads the tab routes. The three primary routes are:
| Route | Source | Responsibility |
|---|---|---|
| `/tabs/pilot` | `src/app/tab1/` | Waiting queues, court assignments, drag and drop, and rotation actions |
| `/tabs/umpires` | `src/app/tab2/` | Court-official roster management |
| `/tabs/settings` | `src/app/tab3/` | Court count, service-judge mode, alerts, and language |
Pages are standalone Angular components and directly import the Ionic standalone components they use. Services are root-provided and injected with Angular's `inject()` function.
## Reactive state
Persistence services use Dexie's `liveQuery()` and Angular's `toSignal()` to expose reactive data. Pages derive lookup maps, ID sets, filtered lists, and other display state with `computed()`.
`Tab1Page` currently coordinates multi-service operations such as moving officials between waiting queues and courts. These operations span multiple Dexie tables but are not currently wrapped in database transactions.
## Persistence model
`db.ts` declares a `CourtPilot` Dexie database at schema version 1.
```mermaid
erDiagram
UMPIRE ||--o{ COURT_UMPIRE : assigned_as
UMPIRE ||--o{ COURT_SERVICE_JUDGE : assigned_as
UMPIRE ||--o{ WAITING_UMPIRE : queued_as
UMPIRE ||--o{ WAITING_SERVICE_JUDGE : queued_as
UMPIRE {
number id PK
string firstName
string lastName
string country
string gender
number courtNo
}
COURT_UMPIRE {
number id PK
number umpireId
number courtNo
}
COURT_SERVICE_JUDGE {
number id PK
number umpireId
number courtNo
}
WAITING_UMPIRE {
number id PK
number umpireId
number order
}
WAITING_SERVICE_JUDGE {
number id PK
number serviceJudgeId
number order
}
```
Settings use a singleton row with ID `1`. Defaults are five courts, service judges enabled, and confirmation alerts enabled.
### Schema-change policy
Once data may exist in released clients, do not modify schema version 1 in place. Add a new `db.version(n)` declaration and define upgrade behavior when existing records need transformation.
## Localization
`src/app/i18n/translations.ts` defines the translation catalog and derives TypeScript types from it. English is the fallback language; Hungarian is also supported. The selected language is stored in `localStorage` under `language`.
Templates use `TranslatePipe`. Imperative UI such as Ionic alerts uses `TranslationService`.
## Desktop integration
The Tauri shell loads the Angular build from `www/`. Its Rust layer registers:
- OS plugin
- process plugin
- updater plugin
- debug-only logging plugin
At application startup, the Angular root component checks for desktop updates when running under Tauri. It skips the in-app updater on Linux because Snap manages Linux updates.
Windows and macOS updater artifacts are distributed through CrabNebula. Linux is packaged and published as a strict-confinement Snap.
## Supported platforms
The supported targets are browser/web, Windows, macOS, and Linux Snap. Android and iOS are not supported or planned at this stage. `capacitor.config.ts` remains as possible future scaffolding, but agents must not treat mobile builds as active.
Tauri development intentionally expects the Ionic frontend on port `8103`. The command used by `beforeDevCommand` must explicitly or otherwise reliably start the frontend on that port.
## Domain invariants affecting architecture
Each court official must be represented in exactly one operational state: not on duty, one waiting queue, or one court assignment. The two role queues are FIFO by numeric `order`. When service judges rotate off a court, the officials swap role queues. Reducing the court count removes assignments from eliminated courts and leaves those officials not on duty.
Operations that move an official between states should preserve exclusivity even when multiple Dexie tables are involved.
## Known architectural questions
- Should moves spanning multiple tables use Dexie transactions to prevent partial updates?
- Should domain entities and database setup remain in root-level `db.ts`, or move under `src/app/`?
+173
View File
@@ -0,0 +1,173 @@
# Development Guide
## Prerequisites
### Web development
- NVM
- Node.js `lts/jod` (Node.js 22), matching `.nvmrc` and the release workflow
- npm
- Ionic CLI available as `ionic`
Select the project Node.js version before running any npm command:
```sh
nvm install
nvm use
```
Run `nvm use` again in every new shell and after switching versions for another project. Agent terminal commands start separate shell processes, so they must activate Jod in the same command invocation as the npm command when shell state is not retained.
Install exact project dependencies with:
```sh
nvm use lts/jod
npm ci
```
If needed, install Ionic CLI globally:
```sh
npm install --global @ionic/cli
```
The committed `.nvmrc` uses the named `lts/jod` alias. Do not replace it with another Node release or add `.tool-versions` unless the team intentionally changes version-management tools.
### Desktop development
Install Rust stable and the Tauri 2 prerequisites for your operating system. `src-tauri/Cargo.toml` declares Rust 1.77.2 as the minimum supported Rust version.
## Web workflow
Start the Ionic development server:
```sh
npm start
```
Build the Angular application:
```sh
npm run build
```
The production web output is generated under `www/`. Do not edit that directory manually.
## Code formatting
Use an editor Prettier plugin for files you change. The root `.prettierrc` is the repository's shared formatting configuration and is discovered automatically by compatible plugins.
Its main rules are:
- 80-character print width
- two spaces, not tabs
- semicolons
- single quotes
- no trailing commas
- opening brackets kept on the same line where supported
For VS Code, install the recommended `esbenp.prettier-vscode` extension, select Prettier as the formatter, and use **Format Document** or format-on-save. Do not introduce personal overrides that conflict with `.prettierrc`, and do not reformat unrelated files during a focused change.
Prettier is currently an editor workflow; the repository does not declare a Prettier npm dependency or formatting script. Do not claim a CLI formatting check exists unless one is added later.
## Tauri workflow
Run Tauri commands through the npm script:
```sh
npm run tauri dev
npm run tauri build
```
Tauri development intentionally expects the frontend at `http://localhost:8103`. `devUrl` only tells Tauri where to connect; the Ionic command must also listen on port `8103`. The current `npm start` script does not explicitly select that port, so verify the complete development flow when changing Tauri or serve configuration.
The desktop wrapper is under `src-tauri/`. Do not edit generated `src-tauri/target/` or `src-tauri/gen/` content.
## Data storage
Court Pilot has no backend API. It stores domain data in IndexedDB using Dexie. The database and schema are declared in root-level `db.ts`.
Changing an interface in `db.ts` may require a database migration for existing users. Follow `.agents/skills/database-change/SKILL.md` for schema work.
The selected UI language is stored separately in browser local storage under the `language` key.
## Localization workflow
English and Hungarian are both required for user-facing text.
1. Add the same translation key to `en` and `hu` in `src/app/i18n/translations.ts`.
2. Preserve identical placeholder names, such as `{courtNo}`, in both translations.
3. Use `TranslatePipe` in templates.
4. Use `TranslationService` for alerts or other strings created in TypeScript.
5. Build the application so strict translation-key and template typing is checked.
## Manual release versioning
Court Pilot uses one application version across its JavaScript, Rust, Tauri, and Snap packages. Releases are updated manually; there is no version synchronization script.
### Select the next version
Before changing files, review commits since the latest release tag and recommend a Semantic Versioning bump:
- Breaking change (`!` or `BREAKING CHANGE:`) → major
- Backward-compatible `feat` → minor
- Backward-compatible `fix` or `perf` → patch
- Documentation, tests, refactoring, build, CI, chores, and style changes normally do not require a bump by themselves
Use the highest applicable bump. Because older repository commits do not consistently follow Conventional Commits, inspect the implementation and configuration diff since the latest tag whenever the messages are ambiguous. Base the recommendation on shipped behavior, data compatibility, packaging, and supported platforms—not only commit wording.
Show the current version, latest tag, recommendation, bump type, and reasoning to the developer. The developer may accept the recommendation or enter a different semantic version. Do not update files until the developer confirms the final version. Warn before using a version that is not greater than the current release or before using a prerelease identifier.
### Synchronize the selected version
After confirmation, set the same semantic version in:
1. `package.json` — top-level `version`
2. `package-lock.json` — root package `version`
3. `src-tauri/tauri.conf.json` — top-level `version`
4. `src-tauri/Cargo.toml` — `[package].version`
5. `src-tauri/Cargo.lock` — the `court-pilot` package entry, normally refreshed by Cargo
6. `snap/snapcraft.yaml` — top-level `version`
7. The version displayed by `src/app/tab3/tab3.page.html`
The current Settings page contains a hardcoded version. Until it is changed to consume build metadata, it must be updated manually for every release.
After editing `Cargo.toml`, run from `src-tauri/`:
```sh
cargo check
```
This validates the Rust package and refreshes its lockfile metadata when needed.
Then verify that all version declarations match and run the checks in `docs/testing.md`.
### Create the release tag
The synchronized version changes must be committed before tagging. Git tags point to commits and do not include uncommitted working-tree changes. Verify that the intended release commit contains every version update and that the tracked working tree is clean.
Release tags are lightweight tags, matching the repository's existing convention. Confirm the tag does not already exist, then create it with the selected version prefixed by `v`:
```sh
GIT_EDITOR=true git tag v1.2.0
```
Replace `1.2.0` with the confirmed release version and verify the tag points to the intended commit. Do not overwrite or move an existing release tag.
Creating the tag is local. Pushing it starts `.github/workflows/release.yml`, which builds Windows and macOS artifacts for CrabNebula and builds/publishes the Linux Snap. Push only after explicit confirmation:
```sh
git push origin v1.2.0
```
## Generated and local directories
Do not manually edit or commit generated/dependency content unless a workflow explicitly requires an artifact:
- `node_modules/`
- `.angular/`
- `www/`
- `coverage/`
- `src-tauri/target/`
- `src-tauri/gen/`
- generated `snap-root/`
+61
View File
@@ -0,0 +1,61 @@
# Domain Glossary
This document records confirmed Court Pilot terminology and business rules. Agents must preserve these invariants and ask before defining additional rotation behavior.
## Confirmed terms
### Court official
A person maintained in the application roster. The persistence type is currently named `Umpire`, while parts of the UI use the broader label “Court Official.” A record contains first name, last name, country, and gender.
### Umpire
The primary official assigned to a court. An official can wait in the umpire queue, be assigned to a court as umpire, or be off duty.
### Service judge
An optional second role on a court. Service-judge behavior can be enabled or disabled globally in settings. The same official records are used for both umpire and service-judge roles.
### Court
A numbered play area. Courts are generated from `1` through the configured `numberOfCourts`; the default is five.
### Waiting queue
An ordered FIFO list of officials awaiting assignment. Umpires and service judges have separate queues and numeric order values. The lowest `order` value is assigned next. Officials may be reordered with drag and drop.
### Not on duty / rest
An official who is not found in either waiting queue or in either kind of court assignment. The code derives this state rather than persisting it separately.
### Send to court
Assign the first eligible waiting official or officials to a selected court. With service judges enabled, one official is taken from each role-specific queue.
### Remove from court
Remove assigned officials from a court and return them to waiting duty. With service judges enabled, roles intentionally swap when re-queuing: the prior service judge enters the umpire queue and the prior umpire enters the service-judge queue.
## Domain invariants
- “Court official” is the umbrella term; “umpire” and “service judge” are roles.
- Every official must be in exactly one state: not on duty, one waiting queue, or one active court role.
- An official must never occupy multiple queues or assignments at the same time.
- Queue assignment is FIFO by numeric `order`; the lowest value is next.
- Removing a court assignment with service judges enabled swaps the officials' role queues.
- Reducing `numberOfCourts` removes assignments above the new court count. Those officials become not on duty; they are not automatically added to a waiting queue.
## Current settings
- `numberOfCourts` — number of numbered courts shown
- `withServiceJudge` — whether service-judge assignments are active
- `showAlert` — whether quick court actions require confirmation
- language — stored separately in local storage; currently English or Hungarian
## Still-undecided behavior
Ask the maintainer before a task depends on any of these questions:
1. How should malformed queue data—duplicate or conflicting order values—be repaired?
2. Are gender and country free-form values, fixed choices, or governed by tournament data?
3. Will Court Pilot continue to manage one tournament/session at a time, or support multiple events later?
+70
View File
@@ -0,0 +1,70 @@
# Testing and Validation
## Test stack
Angular unit tests use Jasmine and Karma. Test files are colocated with their subjects as `*.spec.ts`. Karma launches Chrome by default and keeps running in watch mode for local development.
## Local test commands
Run the interactive test suite:
```sh
npm test
```
Run the configured non-watching CI test mode:
```sh
npm test -- --configuration=ci
```
The test environment requires an available Chrome installation. Test coverage output, when enabled by the test runner, is written under `coverage/app/`.
## Lint and build
Lint TypeScript and Angular templates:
```sh
npm run lint
```
Build the production Angular application:
```sh
npm run build
```
Check Rust changes from the Tauri directory:
```sh
cargo check
```
## What to validate
Choose checks based on the changed area:
| Change | Expected validation |
|---|---|
| Documentation only | Markdown/editor diagnostics and `git diff --check` |
| Angular TypeScript or template | Related tests, `npm run lint`, and `npm run build` |
| Service or domain behavior | Behavior-focused service/page tests, lint, and build |
| Dexie schema or migration | Migration tests where practical, lint, and build |
| Styles only | Build and visual verification at relevant viewport sizes |
| Rust code | `cargo check` plus relevant Rust tests if introduced |
| Tauri/release configuration | Build/config checks available on the host; report untested platforms |
## Testing conventions
- Prefer behavior assertions over tests that only check whether a service or component was created.
- Cover domain invariants when changing court assignments or queues.
- Verify that an official cannot end up in multiple operational states.
- Verify FIFO ordering and contiguous queue order values after additions, removals, and moves.
- Verify the intentional umpire/service-judge role swap after rotation.
- Verify that reducing the court count removes assignments on eliminated courts and leaves those officials not on duty.
- For localization changes, exercise both English and Hungarian catalogs when practical.
- Do not hide existing failures by weakening unrelated assertions.
## Reporting validation
At task completion, list commands actually run and whether they passed. If a check cannot run—for example, Chrome is unavailable or a platform-specific desktop build cannot run on the host—state that explicitly. Distinguish pre-existing failures from failures introduced by the change.