Files
court-pilot/docs/architecture.md
T

120 lines
5.0 KiB
Markdown

# 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/`?