Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 225c2285b7 | |||
| c5661de4a0 | |||
| 3b6c5297f6 | |||
| a24924c230 | |||
| 11826356c1 | |||
| e18b1df744 | |||
| 595c172900 | |||
| cf225826c0 | |||
| 25c05bc2d8 | |||
| 4ec6295d1d | |||
| 2d18478110 | |||
| 8b95f10c65 | |||
| f3d96fd700 | |||
| 4762f6c0c3 | |||
| 7117a93376 | |||
| 085e34f062 | |||
| 32c388760b | |||
| 98b0bba398 | |||
| 9836e87392 | |||
| 2579539084 | |||
| bc500e3e94 | |||
| 2dbb1d0b67 | |||
| 252851de1c | |||
| a253fa78df | |||
| ae3ef766e8 | |||
| 487711628f | |||
| 008d72d826 | |||
| 576e3fea9b | |||
| 1f66b7bde7 | |||
| 381161f003 | |||
| d0150fdfa4 | |||
| 29072efbfb | |||
| dcc5ce1195 | |||
| 354db11972 | |||
| 9296db88b7 | |||
| ec22a9585e | |||
| 411eed2453 | |||
| af6b0ed8b7 | |||
| bcd8257db2 | |||
| d61fe97b4c | |||
| 959bb53335 | |||
| b610678005 | |||
| d0552b08b5 | |||
| 87f29a7204 | |||
| cb44f491bd | |||
| f5614c3582 | |||
| 9d960d3ee5 | |||
| a9f4606b40 | |||
| 32a12737e3 | |||
| b4c75e2a0f | |||
| 9bf995f47d | |||
| 8df418627c | |||
| 6dbe1e62ac | |||
| 6311d8fd00 | |||
| 5205468534 | |||
| 4ec5b931de | |||
| ebba729af3 | |||
| 5619c8223a | |||
| 2d76c001fe | |||
| b58bbbc782 | |||
| 1a02f9e186 | |||
| 255f43ddda | |||
| f109fe3860 | |||
| a07bf89fae | |||
| b47ad7ef89 | |||
| 2e4ba43597 | |||
| b0d27d2de2 | |||
| 8f9eb12f66 |
@@ -0,0 +1,88 @@
|
||||
# Create Defect in YouTrack
|
||||
|
||||
Automated defect creation workflow. Topic/hint: `$ARGUMENTS`
|
||||
|
||||
## Step 1 — Gather Context
|
||||
|
||||
Use `AskUserQuestion` tool to ask the user (max 4 questions at once):
|
||||
|
||||
1. **Component** — Where does the bug occur? (e.g. move generation, FEN parsing, castling, UI, API)
|
||||
2. **What breaks** — What is the actual (broken) behavior?
|
||||
3. **Expected** — What should happen instead?
|
||||
4. **Reproducibility** — Is it always reproducible? Any known trigger conditions?
|
||||
|
||||
If `$ARGUMENTS` already answers some of these, skip those questions.
|
||||
|
||||
## Step 2 — Research (if needed)
|
||||
|
||||
If the bug involves domain logic or rules:
|
||||
- Search repo for relevant code (`Grep`/`Bash`).
|
||||
- Check test files for existing coverage of the broken area.
|
||||
- Do NOT guess at root cause. Surface findings before drafting.
|
||||
|
||||
## Step 3 — Draft Defect
|
||||
|
||||
Compose the full defect report using this template:
|
||||
|
||||
```
|
||||
Summary
|
||||
|
||||
[One-sentence description of what is broken.]
|
||||
|
||||
|
||||
Steps to Reproduce
|
||||
|
||||
1. Step one
|
||||
2. Step two
|
||||
3. Step three
|
||||
|
||||
|
||||
Expected Behavior
|
||||
|
||||
[What should happen.]
|
||||
|
||||
|
||||
Actual Behavior
|
||||
|
||||
[What actually happens.]
|
||||
|
||||
|
||||
Environment / Notes
|
||||
|
||||
[Any relevant context: FEN positions, game conditions, config, browser, OS — only if applicable.]
|
||||
```
|
||||
|
||||
Rules:
|
||||
- Steps must be minimal and reproducible.
|
||||
- Expected vs actual: concrete and unambiguous.
|
||||
- Omit "Environment / Notes" section if not relevant.
|
||||
|
||||
## Step 4 — Clarify
|
||||
|
||||
Show the draft to the user.
|
||||
**Use `AskUserQuestion` tool to ask:**
|
||||
- Are steps to reproduce complete and accurate?
|
||||
- Severity: Blocker / Critical / Major / Minor / Trivial?
|
||||
- Any related tickets or recent changes to link?
|
||||
|
||||
Incorporate feedback. Repeat until user approves.
|
||||
|
||||
## Step 5 — Determine Project
|
||||
|
||||
- Frontend / UI / UX → project: `NCWF`
|
||||
- Backend / coordinator / systems / bot / engine → project: `NCS`
|
||||
|
||||
If ambiguous, ask the user.
|
||||
|
||||
## Step 6 — Create Issue
|
||||
|
||||
Call `mcp__youtrack__create_issue` with:
|
||||
- `project`: determined in Step 5
|
||||
- `summary`: concise title describing what is broken (≤72 chars, sentence case)
|
||||
- `description`: full formatted defect report from Step 3 (Markdown)
|
||||
- `type`: `Bug`
|
||||
|
||||
## Step 7 — Report
|
||||
|
||||
Display the created issue ID and URL.
|
||||
Ask if a linked investigation or fix task is needed.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Create User Story in YouTrack
|
||||
|
||||
Automated user-story creation workflow. Topic/hint: `$ARGUMENTS`
|
||||
|
||||
## Step 1 — Gather Context
|
||||
|
||||
Use `AskUserQuestion` tool to ask the user (max 4 questions at once):
|
||||
|
||||
1. **Domain** — Is this frontend (UI/UX) or backend/coordinator/systems work?
|
||||
2. **User type** — Who is the actor? (e.g. player, admin, bot, system)
|
||||
3. **Action** — What should the user be able to do?
|
||||
4. **Goal/value** — Why? What outcome does it enable?
|
||||
|
||||
If `$ARGUMENTS` already answers some of these, skip those questions.
|
||||
|
||||
## Step 2 — Research (if needed)
|
||||
|
||||
If the topic involves unfamiliar domain logic, game rules, or technical constraints:
|
||||
- Search the repo for relevant code (use `Grep`/`Bash` to find related files).
|
||||
- Use `WebSearch` if the topic involves external standards or protocols.
|
||||
- Do NOT guess. Surface findings before drafting.
|
||||
|
||||
## Step 3 — Draft Story
|
||||
|
||||
Compose the full story using this template:
|
||||
|
||||
```
|
||||
As a [type of user]
|
||||
I want to [perform an action]
|
||||
So that [achieve a goal or value]
|
||||
|
||||
|
||||
Description
|
||||
|
||||
[Additional context or business logic for this story.]
|
||||
|
||||
|
||||
Acceptance Criteria
|
||||
|
||||
[List the specific, measurable criteria that define when this story is done:]
|
||||
|
||||
- Criterion 1
|
||||
- Criterion 2
|
||||
- Criterion 3
|
||||
|
||||
|
||||
Implementation Notes
|
||||
|
||||
[Technical notes, design references, or constraints.]
|
||||
```
|
||||
|
||||
Rules:
|
||||
- User story line: plain English, present tense, from user's perspective.
|
||||
- Acceptance criteria: testable, unambiguous, one condition each.
|
||||
- Implementation notes: optional — only include if there are known constraints, related tickets, or design refs.
|
||||
|
||||
## Step 4 — Clarify Acceptance Criteria
|
||||
|
||||
Show the draft to the user.
|
||||
**Use `AskUserQuestion` tool to ask:**
|
||||
- Are the acceptance criteria complete and correct?
|
||||
- Any implementation constraints to add?
|
||||
- Priority (if known)?
|
||||
|
||||
Incorporate feedback. Repeat until user approves.
|
||||
|
||||
## Step 5 — Determine Project
|
||||
|
||||
> **Project routing rules (always apply these):**
|
||||
> - Backend code (game engine, bots, API, services, coordinator) → `NCS`
|
||||
> - Frontend code (UI, UX, web app) → `NCWF`
|
||||
> - Infrastructure (Kubernetes, pipelines, CI/CD, DB setup, cloud infra) → `NCI`
|
||||
> - If ambiguous, ask the user.
|
||||
|
||||
- Frontend / UI / UX → project: `NCWF`
|
||||
- Backend / coordinator / systems / bot / engine → project: `NCS`
|
||||
- Kubernetes, pipelines, CI/CD, DB setup, infrastructure → project: `NCI`
|
||||
|
||||
If still ambiguous, ask the user.
|
||||
|
||||
## Step 6 — Create Issue
|
||||
|
||||
Call `mcp__youtrack__create_issue` with:
|
||||
- `project`: determined in Step 5
|
||||
- `summary`: concise title derived from the "I want to" clause (≤72 chars, sentence case)
|
||||
- `description`: full formatted story from Step 3 (Markdown)
|
||||
- `type`: `Feature` (or `Task` if purely technical with no user-facing value)
|
||||
|
||||
## Step 7 — Link Issues
|
||||
|
||||
After creation, **automatically** ask the user (use `AskUserQuestion` if interactive, otherwise infer from context):
|
||||
|
||||
> Are there related issues to link? (skip if none)
|
||||
|
||||
Collect any issue IDs the user mentions. For each, determine the correct relation and call `mcp__youtrack__link_issues`:
|
||||
|
||||
| Situation | Relation to use |
|
||||
|-----------|----------------|
|
||||
| This story must be done before another | `blocks` |
|
||||
| Another story must be done before this | `is blocked by` |
|
||||
| Stories share domain or are related | `relates to` |
|
||||
| This is a child of an epic/story | `subtask of` |
|
||||
| This is a parent grouping subtasks | `parent for` |
|
||||
| This depends on another ticket's output | `depends on` |
|
||||
|
||||
If the user mentions an issue in the story description or implementation notes (e.g. "see NCS-42", "after NCS-12 is done"), auto-detect and suggest linking it — confirm before creating the link.
|
||||
|
||||
## Step 8 — Report
|
||||
|
||||
Display the created issue ID and URL.
|
||||
List any links created (relation type + linked issue ID).
|
||||
Ask if a linked sub-task or implementation ticket is needed.
|
||||
@@ -0,0 +1,90 @@
|
||||
# Estimate Issue Time in YouTrack
|
||||
|
||||
Sprint planning time estimator. Issue ID or empty for full current sprint: `$ARGUMENTS`
|
||||
|
||||
## Step 1 — Determine Scope
|
||||
|
||||
**Single-issue mode** (`$ARGUMENTS` set):
|
||||
- Call `mcp__youtrack__get_issue` on `$ARGUMENTS`.
|
||||
- Proceed with that issue only.
|
||||
|
||||
**Sprint mode** (`$ARGUMENTS` empty):
|
||||
- Call `mcp__youtrack__search_issues` with query `project: NCS Sprints: {current sprint} #Unresolved`.
|
||||
- If query returns 0 results, use `AskUserQuestion` to ask for the sprint name, then retry with `project: NCS Sprints: {name}`.
|
||||
- Collect all returned issues.
|
||||
|
||||
## Step 2 — Build Issue Tree
|
||||
|
||||
For each top-level issue from Step 1:
|
||||
1. Fetch full details via `mcp__youtrack__get_issue`: summary, description, acceptance criteria, Type, existing `Zeitschätzung`, linked issues.
|
||||
2. Identify subtasks from links with relation `subtask of` (i.e. issues where the fetched issue is the parent).
|
||||
3. Recursively fetch subtasks until all leaves are known.
|
||||
4. Group into tree: Epic → Story → Task/Subtask.
|
||||
|
||||
**Leaf node** = issue with no subtask children.
|
||||
**Parent node** = issue that has at least one subtask child.
|
||||
|
||||
## Step 3 — Estimate Leaf Nodes
|
||||
|
||||
For each leaf node:
|
||||
1. Read: summary, description, acceptance criteria, implementation notes.
|
||||
2. If scope is unclear, search codebase (`Grep`/`Bash`) for related files to gauge complexity.
|
||||
3. Assign estimate using this scale:
|
||||
|
||||
| Size | Criteria | Estimate |
|
||||
|------|----------|----------|
|
||||
| Trivial | Config change, rename, 1-file tweak | 30m |
|
||||
| Small | 1–3 files, clear scope, no unknowns | 1h–2h |
|
||||
| Medium | 3–6 files, some design needed | 3h–5h |
|
||||
| Large | 6+ files, cross-module, non-trivial design | 1d–2d |
|
||||
| XL | New subsystem, research spike, major refactor | 3d–5d |
|
||||
|
||||
4. Record: estimate + one-line reasoning.
|
||||
5. Skip leaf if it already has `Zeitschätzung` set — note it as pre-estimated.
|
||||
|
||||
## Step 4 — Roll Up for Display
|
||||
|
||||
YouTrack auto-sums `Zeitschätzung` from subtasks up to parents — **do not write estimates to parent nodes**.
|
||||
|
||||
Compute display-only rolled-up totals:
|
||||
- Parent total = sum of all descendant leaf estimates (including pre-estimated ones).
|
||||
- Flag any branch where some leaves are missing estimates (partial roll-up).
|
||||
|
||||
## Step 5 — Show Summary + Confirm
|
||||
|
||||
Display full tree with estimates. Format:
|
||||
|
||||
```
|
||||
Epic NCS-10: Castling overhaul [4h 30m] ← rolled up
|
||||
Story NCS-11: Validate castling rights [2h 30m] ← rolled up
|
||||
Task NCS-12: Fix RuleSet check 1h 30m ← leaf (new)
|
||||
Task NCS-13: Add regression tests 1h ← leaf (new)
|
||||
Story NCS-14: UI feedback for castling [2h] ← rolled up
|
||||
Task NCS-15: Highlight invalid squares 2h ← leaf (pre-set, skipped)
|
||||
```
|
||||
|
||||
Legend: `[X]` = display-only roll-up (not written). Plain = will be written to YouTrack.
|
||||
|
||||
If sprint mode, show grand total at bottom:
|
||||
```
|
||||
Sprint total: Xd Yh Zm (N issues, M leaves to update)
|
||||
```
|
||||
|
||||
**Use `AskUserQuestion` tool:**
|
||||
- Does the breakdown look right?
|
||||
- Any estimates to adjust before writing to YouTrack?
|
||||
|
||||
Incorporate all feedback before proceeding.
|
||||
|
||||
## Step 6 — Write Estimates
|
||||
|
||||
On user approval, write estimates **only to leaf nodes** (bottom-up order):
|
||||
- For each leaf with a new estimate, call `mcp__youtrack__update_issue` with field `Zeitschätzung` = approved estimate.
|
||||
- YouTrack period format: `"30m"`, `"1h 30m"`, `"1d"`, `"2d 4h"`.
|
||||
- Skip leaves already pre-estimated.
|
||||
|
||||
## Step 7 — Report
|
||||
|
||||
List all updated issues with set estimates.
|
||||
Show final rolled-up totals per Epic/Story (read back from YouTrack via `mcp__youtrack__get_issue` if needed).
|
||||
In sprint mode, show total sprint estimate.
|
||||
@@ -0,0 +1,140 @@
|
||||
# Fix Defect from YouTrack
|
||||
|
||||
Automated defect-fix workflow. Ticket ID: `$ARGUMENTS`
|
||||
|
||||
## Step 1 — Fetch Ticket
|
||||
|
||||
Call `mcp__youtrack__get_issue` with ID `$ARGUMENTS`.
|
||||
Extract and display: summary, description, steps to reproduce, Priority, Subsystem.
|
||||
|
||||
## Step 2 — Create Worktree
|
||||
|
||||
Derive branch name from ticket:
|
||||
- `type` from YouTrack issue type: `bug` → `fix`, `feature`/`task` → `feat`, `refactor` → `refactor`, else `chore`
|
||||
- `scope` from affected module/component (kebab-case, omit if unclear)
|
||||
- `description` from ticket summary: lowercase, kebab-case, max 40 chars, drop articles
|
||||
|
||||
Branch format: `<type>/<ticket-id>-<description>`
|
||||
Example: `fix/NOW-123-castling-validation-failure`
|
||||
|
||||
Call `EnterWorktree` with that branch name.
|
||||
All subsequent file work happens inside this worktree.
|
||||
|
||||
## Step 3 — Identify Root Cause (read-only)
|
||||
|
||||
1. Run `./compile` — capture all errors and warnings.
|
||||
2. Run `./test` — capture all failures.
|
||||
3. Spawn `cavecrew-investigator` with: ticket description + compile/test output → locate root cause (files, line numbers, what's wrong).
|
||||
4. **If anything is ambiguous (reproduction unclear, scope uncertain, conflicting signals), use `AskUserQuestion` tool to ask — max 4 questions at once.**
|
||||
5. **Report findings to user. No file writes yet. Wait for acknowledgement before continuing.**
|
||||
|
||||
## Step 3b — Complexity Assessment + Subtasks
|
||||
|
||||
After root cause confirmed, assess scope:
|
||||
|
||||
**Simple** (1–2 files, single concern, < 1 hour estimated): proceed directly to Step 4.
|
||||
|
||||
**Complex** (3+ files, multiple concerns, or estimated > 1 hour): create subtasks before coding.
|
||||
|
||||
To create subtasks:
|
||||
1. Break fix into discrete, independently-completable tasks (e.g. "Fix validation in RuleSet", "Add regression test for castling edge case", "Update FenParser to handle X").
|
||||
2. For each subtask call `mcp__youtrack__create_issue` with:
|
||||
- `project`: based on subtask content — do **not** inherit from parent. Backend code → `NCS`; frontend/UI → `NCWF`; Kubernetes/pipelines/CI-CD/DB setup/infrastructure → `NCI`. If ambiguous, ask user.
|
||||
- `summary`: concise action-oriented title
|
||||
- `type`: `Task`
|
||||
- `description`: what to do and why
|
||||
3. Call `mcp__youtrack__link_issues` to link each subtask to `$ARGUMENTS` with relation `subtask of`.
|
||||
4. Check if the ticket description or comments mention other issue IDs. For each mentioned ID, suggest a link and confirm with user:
|
||||
- Fix depends on another fix finishing first → `is blocked by`
|
||||
- This fix blocks another ticket → `blocks`
|
||||
- Logically related but independent → `relates to`
|
||||
5. List created subtask IDs and any additional links to user.
|
||||
|
||||
Then proceed to Step 4, implementing subtasks in order.
|
||||
|
||||
## Step 4 — Fix
|
||||
|
||||
1. Implement fix (use `scala-implementer` agent for non-trivial changes; inline edits for small ones).
|
||||
2. Run `./compile` — must be green.
|
||||
3. Run `./test` — must be green.
|
||||
4. Run `./gradlew spotlessScalaApply` — **blocking, foreground only**. Wait for completion before continuing.
|
||||
5. Run `./lint` — **blocking, foreground only** (never `run_in_background`). Wait for exit code 0. Must be green.
|
||||
- If lint fails, fix all issues and re-run until exit code 0.
|
||||
- **Do NOT proceed to Step 5 until `./lint` has completed and returned exit code 0.**
|
||||
If any step fails, iterate until all pass.
|
||||
|
||||
## Step 5 — Review
|
||||
|
||||
Spawn `cavecrew-reviewer` on the full diff.
|
||||
Display findings grouped by severity.
|
||||
|
||||
## Step 5b — Apply Review Findings
|
||||
|
||||
If the review produced any findings (any severity):
|
||||
1. Implement all agreed fixes.
|
||||
2. Run `./compile` — must be green.
|
||||
3. Run `./test` — must be green.
|
||||
4. Run `./gradlew spotlessScalaApply` — **blocking, foreground only**. Wait for completion.
|
||||
5. Run `./lint` — **blocking, foreground only**. Wait for exit code 0.
|
||||
- If lint fails, fix all issues and re-run until exit code 0.
|
||||
6. Re-spawn `cavecrew-reviewer` on the updated diff to confirm all findings are resolved.
|
||||
|
||||
Repeat until review is clean or user explicitly accepts remaining findings.
|
||||
|
||||
## Step 6 — Confirm + Push
|
||||
|
||||
Show summary: ticket, branch, files changed, review findings.
|
||||
**Use `AskUserQuestion` tool to ask for explicit approval before pushing.** Include any open questions about commit message scope or body if unclear.
|
||||
|
||||
On approval, commit following Conventional Commits:
|
||||
|
||||
```
|
||||
<type>(<scope>): <short description, imperative, ≤50 chars>
|
||||
|
||||
<optional body: what changed and why, wrap at 72 chars>
|
||||
|
||||
Closes $ARGUMENTS
|
||||
https://knockoutwhist.youtrack.cloud/issue/$ARGUMENTS
|
||||
```
|
||||
|
||||
- `type`: same as branch type (`fix`, `feat`, `refactor`, `chore`, etc.)
|
||||
- `scope`: affected module (`core`, `rule`, `api`, `bot`, `io`)
|
||||
- Subject: imperative mood, no period, lowercase
|
||||
- Footer `Closes $ARGUMENTS` and ticket URL always present
|
||||
|
||||
Push branch to remote.
|
||||
|
||||
## Step 7 — Comment on Ticket
|
||||
|
||||
After successful push, call `mcp__youtrack__add_issue_comment` on `$ARGUMENTS` with:
|
||||
|
||||
```
|
||||
Branch `<branch-name>` pushed.
|
||||
|
||||
<one-sentence summary of what was changed and why>
|
||||
|
||||
Files changed:
|
||||
- <file1>
|
||||
- <file2>
|
||||
```
|
||||
|
||||
## Step 7b — Additional Links
|
||||
|
||||
After commenting, ask the user if `$ARGUMENTS` should be linked to any other issues not already linked:
|
||||
|
||||
| Situation | Relation |
|
||||
|-----------|---------|
|
||||
| This fix blocks another open ticket | `blocks` |
|
||||
| Another ticket must ship first | `is blocked by` |
|
||||
| Related defect or story | `relates to` |
|
||||
| Duplicate of another defect | `duplicates` |
|
||||
|
||||
Scan the ticket description and comments for any issue IDs that were mentioned but not yet linked. Suggest those automatically.
|
||||
|
||||
Call `mcp__youtrack__link_issues` for each confirmed link.
|
||||
|
||||
## Step 8 — Cleanup
|
||||
|
||||
Call `ExitWorktree` with `discard_changes: true` to delete the worktree.
|
||||
(Branch was pushed in step 6 — commits are safe on remote; `discard_changes: true` bypasses the local-ahead guard.)
|
||||
Report: branch pushed, ticket commented, links created, worktree deleted, done.
|
||||
@@ -0,0 +1,101 @@
|
||||
# Implement Feature from YouTrack
|
||||
|
||||
Automated feature-implementation workflow. Ticket ID: `$ARGUMENTS`
|
||||
|
||||
## Step 1 — Fetch Ticket
|
||||
|
||||
Call `mcp__youtrack__get_issue` with ID `$ARGUMENTS`.
|
||||
Extract and display: summary, description, acceptance criteria, Priority, Subsystem.
|
||||
|
||||
## Step 2 — Create Worktree
|
||||
|
||||
Derive branch name from ticket:
|
||||
- `type` from YouTrack issue type: `feature`/`task` → `feat`, `refactor` → `refactor`, `bug` → `fix`, else `chore`
|
||||
- `scope` from affected module/component (kebab-case, omit if unclear)
|
||||
- `description` from ticket summary: lowercase, kebab-case, max 40 chars, drop articles
|
||||
|
||||
Branch format: `<type>/<ticket-id>-<description>`
|
||||
Example: `feat/NOW-456-add-bot-difficulty-slider`
|
||||
|
||||
Call `EnterWorktree` with that branch name.
|
||||
All subsequent file work happens inside this worktree.
|
||||
|
||||
## Step 3 — Understand Requirements (read-only)
|
||||
|
||||
1. Run `./compile` — confirm baseline is green.
|
||||
2. Run `./test` — confirm baseline is green.
|
||||
3. Spawn `cavecrew-investigator` with: ticket description + acceptance criteria → locate affected files, relevant types/interfaces, entry points, integration touch-points.
|
||||
4. **If anything is ambiguous (scope unclear, acceptance criteria missing, design decisions needed), use `AskUserQuestion` tool to ask — max 4 questions at once.**
|
||||
5. **Report plan to user: what will be added/changed, which files, which modules. No file writes yet. Wait for acknowledgement before continuing.**
|
||||
|
||||
## Step 4 — Implement
|
||||
|
||||
1. Implement feature (use `scala-implementer` agent for non-trivial changes; inline edits for small ones).
|
||||
2. Run `./compile` — must be green.
|
||||
3. Run `./test` — must be green (add new tests for new behaviour; do not modify existing tests unless requirements changed).
|
||||
4. Run `./gradlew spotlessScalaApply` — **blocking, foreground only**. Wait for completion before continuing.
|
||||
5. Run `./lint` — **blocking, foreground only** (never `run_in_background`). Wait for exit code 0. Must be green.
|
||||
- If lint fails, fix all issues and re-run until exit code 0.
|
||||
- **Do NOT proceed to Step 5 until `./lint` has completed and returned exit code 0.**
|
||||
If any step fails, iterate until all pass.
|
||||
|
||||
## Step 5 — Review
|
||||
|
||||
Spawn `cavecrew-reviewer` on the full diff.
|
||||
Display findings grouped by severity.
|
||||
|
||||
## Step 5b — Apply Review Findings
|
||||
|
||||
If the review produced any findings (any severity):
|
||||
1. Implement all agreed fixes.
|
||||
2. Run `./compile` — must be green.
|
||||
3. Run `./test` — must be green.
|
||||
4. Run `./gradlew spotlessScalaApply` — **blocking, foreground only**. Wait for completion.
|
||||
5. Run `./lint` — **blocking, foreground only**. Wait for exit code 0.
|
||||
- If lint fails, fix all issues and re-run until exit code 0.
|
||||
6. Re-spawn `cavecrew-reviewer` on the updated diff to confirm all findings are resolved.
|
||||
|
||||
Repeat until review is clean or user explicitly accepts remaining findings.
|
||||
|
||||
## Step 6 — Confirm + Push
|
||||
|
||||
Show summary: ticket, branch, files changed, review findings.
|
||||
**Use `AskUserQuestion` tool to ask for explicit approval before pushing.** Include any open questions about commit message scope or body if unclear.
|
||||
|
||||
On approval, commit following Conventional Commits:
|
||||
|
||||
```
|
||||
<type>(<scope>): <short description, imperative, ≤50 chars>
|
||||
|
||||
<optional body: what changed and why, wrap at 72 chars>
|
||||
|
||||
Closes $ARGUMENTS
|
||||
https://knockoutwhist.youtrack.cloud/issue/$ARGUMENTS
|
||||
```
|
||||
|
||||
- `type`: same as branch type (`feat`, `refactor`, `chore`, etc.)
|
||||
- `scope`: affected module (`core`, `rule`, `api`, `bot`, `io`)
|
||||
- Subject: imperative mood, no period, lowercase
|
||||
- Footer `Closes $ARGUMENTS` and ticket URL always present
|
||||
|
||||
Push branch to remote.
|
||||
|
||||
## Step 7 — Comment on Ticket
|
||||
|
||||
After successful push, call `mcp__youtrack__add_issue_comment` on `$ARGUMENTS` with:
|
||||
|
||||
```
|
||||
Branch `<branch-name>` pushed.
|
||||
|
||||
<one-sentence summary of what was added and why>
|
||||
|
||||
Files changed:
|
||||
- <file1>
|
||||
- <file2>
|
||||
```
|
||||
|
||||
## Step 8 — Cleanup
|
||||
|
||||
Call `ExitWorktree` with `discard_changes: true` to delete the worktree.
|
||||
(Branch was pushed in step 6 — commits are safe on remote; `discard_changes: true` bypasses the local-ahead guard.)
|
||||
Report: branch pushed, ticket commented, worktree deleted, done.
|
||||
@@ -0,0 +1,109 @@
|
||||
# Split Story into Subtasks in YouTrack
|
||||
|
||||
Split a user story into smaller, implementable subtasks. Story ID: `$ARGUMENTS`
|
||||
|
||||
## Step 1 — Fetch Story
|
||||
|
||||
Call `mcp__youtrack__get_issue` with ID `$ARGUMENTS`.
|
||||
Extract and display: summary, description, acceptance criteria, implementation notes.
|
||||
|
||||
## Step 2 — Research (if needed)
|
||||
|
||||
If the story involves unfamiliar domain logic or technical constraints:
|
||||
- Search repo for relevant code (`Grep`/`Bash`).
|
||||
- Use `WebSearch` for external standards or protocols.
|
||||
- Do NOT guess. Surface findings before proposing splits.
|
||||
|
||||
## Step 3 — Propose Split
|
||||
|
||||
Analyse the story and propose a set of subtasks. Rules:
|
||||
- Each subtask = one unit of work, completable independently or in sequence.
|
||||
- No subtask should exceed ~2 days of work.
|
||||
- Name subtasks in imperative mood (e.g. "Implement move validation endpoint").
|
||||
- Cover the full scope of the parent story — no gaps.
|
||||
|
||||
Show proposed subtask list to user (titles only) and ask:
|
||||
**Use `AskUserQuestion` tool:**
|
||||
- Does the split look right?
|
||||
- Any subtasks to add, remove, or merge?
|
||||
- Should any subtask be assigned to a specific person?
|
||||
|
||||
Incorporate feedback. Repeat until user approves the list.
|
||||
|
||||
## Step 4 — Draft Each Subtask
|
||||
|
||||
For each approved subtask, compose description using this template:
|
||||
|
||||
```
|
||||
[Brief description of what needs to be done for this subtask.]
|
||||
|
||||
|
||||
Steps / Tasks
|
||||
|
||||
- Task 1
|
||||
- Task 2
|
||||
- Task 3
|
||||
|
||||
|
||||
Definition of Done
|
||||
|
||||
What must be true for this subtask to be considered complete:
|
||||
|
||||
- Code implemented
|
||||
- Tests passed
|
||||
- Reviewed and merged
|
||||
```
|
||||
|
||||
Rules:
|
||||
- Steps/Tasks: concrete, ordered where order matters.
|
||||
- Definition of Done: adjust per subtask — not all subtasks need the same criteria (e.g. a research spike has different DoD than an implementation task).
|
||||
- Keep description short — one paragraph max.
|
||||
|
||||
## Step 5 — Determine Project per Subtask
|
||||
|
||||
Assign each subtask's project based on its content — do **not** inherit blindly from parent:
|
||||
|
||||
- Backend code (game engine, bots, API, services, coordinator) → `NCS`
|
||||
- Frontend code (UI, UX, web app) → `NCWF`
|
||||
- Kubernetes, pipelines, CI/CD, DB setup, infrastructure → `NCI`
|
||||
|
||||
If a subtask's project is ambiguous, ask the user before creating it.
|
||||
|
||||
## Step 6 — Create Subtasks
|
||||
|
||||
For each subtask call `mcp__youtrack__create_issue` with:
|
||||
- `project`: from Step 5
|
||||
- `summary`: subtask title (≤72 chars, sentence case)
|
||||
- `description`: full formatted description from Step 4 (Markdown)
|
||||
- `type`: `Task`
|
||||
|
||||
Then call `mcp__youtrack__link_issues` to link each created subtask to `$ARGUMENTS` with relation `subtask of`.
|
||||
|
||||
## Step 6b — Inter-Subtask Links
|
||||
|
||||
If subtasks must be done in sequence (one depends on output of another), add ordering links:
|
||||
- For each dependency pair call `mcp__youtrack__link_issues` with relation `is blocked by` (subtask B is blocked by subtask A).
|
||||
|
||||
Ask the user to confirm sequencing before adding these links:
|
||||
|
||||
> Do any subtasks have ordering dependencies? (e.g. "Implement X must come before Add tests for X")
|
||||
|
||||
## Step 6c — External Links
|
||||
|
||||
Scan `$ARGUMENTS` description and implementation notes for any referenced issue IDs not already linked. For each:
|
||||
|
||||
| Situation | Relation |
|
||||
|-----------|---------|
|
||||
| Parent story blocks another epic/story | `blocks` |
|
||||
| Story depends on another epic completing | `is blocked by` |
|
||||
| Related story in same domain | `relates to` |
|
||||
| This story duplicates or supersedes | `duplicates` |
|
||||
|
||||
Suggest links to the user and call `mcp__youtrack__link_issues` on confirmation.
|
||||
|
||||
## Step 7 — Report
|
||||
|
||||
List all created subtask IDs and summaries.
|
||||
List all links created (subtask-of, blocking chains, external).
|
||||
Display parent story link.
|
||||
Ask if any subtask needs further splitting.
|
||||
@@ -57,6 +57,13 @@ jobs:
|
||||
- rule
|
||||
- store
|
||||
- ws
|
||||
arch:
|
||||
- name: default
|
||||
march_flag: ""
|
||||
tag_suffix: ""
|
||||
- name: x86_v2
|
||||
march_flag: "-march=x86-64-v2"
|
||||
tag_suffix: "-x86_v2"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -66,12 +73,12 @@ jobs:
|
||||
run: |
|
||||
if [ -f "modules/${{ matrix.module }}/versions.env" ]; then
|
||||
source modules/${{ matrix.module }}/versions.env
|
||||
VERSION="${MAJOR}.${MINOR}.${PATCH}"
|
||||
echo "[${{ matrix.module }}] Version: ${VERSION}"
|
||||
VERSION="${MAJOR}.${MINOR}.${PATCH}${{ matrix.arch.tag_suffix }}"
|
||||
echo "[${{ matrix.module }}/${{ matrix.arch.name }}] Version: ${VERSION}"
|
||||
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "[${{ matrix.module }}] No versions.env found — using 'latest'"
|
||||
echo "version=latest" >> "$GITHUB_OUTPUT"
|
||||
echo "[${{ matrix.module }}/${{ matrix.arch.name }}] No versions.env found — using 'latest${{ matrix.arch.tag_suffix }}'"
|
||||
echo "version=latest${{ matrix.arch.tag_suffix }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Check if image exists in GHCR
|
||||
@@ -83,12 +90,12 @@ jobs:
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
EXISTING_TAGS=$(gh api "orgs/now-chess/packages/container/${PACKAGE}/versions" \
|
||||
--jq '.[].metadata.container.tags[]' 2>/dev/null || echo "")
|
||||
echo "[${{ matrix.module }}] Existing tags: $(echo "${EXISTING_TAGS}" | tr '\n' ' ' | xargs)"
|
||||
echo "[${{ matrix.module }}/${{ matrix.arch.name }}] Existing tags: $(echo "${EXISTING_TAGS}" | tr '\n' ' ' | xargs)"
|
||||
if echo "${EXISTING_TAGS}" | grep -qx "${VERSION}"; then
|
||||
echo "[${{ matrix.module }}] Image ${VERSION} already exists — skipping build"
|
||||
echo "[${{ matrix.module }}/${{ matrix.arch.name }}] Image ${VERSION} already exists — skipping build"
|
||||
echo "exists=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "[${{ matrix.module }}] Image ${VERSION} not found — will build"
|
||||
echo "[${{ matrix.module }}/${{ matrix.arch.name }}] Image ${VERSION} not found — will build"
|
||||
echo "exists=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
@@ -112,7 +119,13 @@ jobs:
|
||||
|
||||
- name: Build native binary
|
||||
if: steps.image-check.outputs.exists == 'false'
|
||||
run: ./gradlew :modules:${{ matrix.module }}:build -x test -Dquarkus.native.enabled=true -Dquarkus.package.jar.enabled=false -Dquarkus.profile=deployed --no-daemon
|
||||
run: |
|
||||
MARCH="${{ matrix.arch.march_flag }}"
|
||||
MARCH_ARG=""
|
||||
if [ -n "$MARCH" ]; then
|
||||
MARCH_ARG="-Dquarkus.native.additional-build-args=$MARCH"
|
||||
fi
|
||||
./gradlew :modules:${{ matrix.module }}:build -x test -Dquarkus.native.enabled=true -Dquarkus.package.jar.enabled=false -Dquarkus.profile=deployed $MARCH_ARG --no-daemon
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: steps.image-check.outputs.exists == 'false'
|
||||
@@ -134,7 +147,7 @@ jobs:
|
||||
images: ghcr.io/now-chess/now-chess-systems/${{ matrix.module }}
|
||||
tags: |
|
||||
type=raw,value=${{ steps.version.outputs.version }}
|
||||
type=raw,value=latest
|
||||
type=raw,value=latest${{ matrix.arch.tag_suffix }}
|
||||
|
||||
- name: Build and push
|
||||
if: steps.image-check.outputs.exists == 'false'
|
||||
@@ -145,5 +158,5 @@ jobs:
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha,scope=${{ matrix.module }}
|
||||
cache-to: type=gha,mode=max,scope=${{ matrix.module }}
|
||||
cache-from: type=gha,scope=${{ matrix.module }}-${{ matrix.arch.name }}
|
||||
cache-to: type=gha,mode=max,scope=${{ matrix.module }}-${{ matrix.arch.name }}
|
||||
|
||||
@@ -48,3 +48,9 @@ graphify-out/
|
||||
.DS_Store
|
||||
/jacoco-reporter/.venv/
|
||||
/.claude/settings.local.json
|
||||
/.claude/worktrees/
|
||||
modules/tournament/src/main/resources/keys/dev-public.pem
|
||||
modules/account/src/main/resources/keys/dev-private.pem
|
||||
modules/account/src/main/resources/keys/dev-public.pem
|
||||
modules/core/src/main/resources/keys/dev-public.pem
|
||||
*.hprof
|
||||
|
||||
Generated
-19
@@ -5,25 +5,6 @@
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="ms-21" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/modules" />
|
||||
<option value="$PROJECT_DIR$/modules/account" />
|
||||
<option value="$PROJECT_DIR$/modules/api" />
|
||||
<option value="$PROJECT_DIR$/modules/bot-platform" />
|
||||
<option value="$PROJECT_DIR$/modules/coordinator" />
|
||||
<option value="$PROJECT_DIR$/modules/core" />
|
||||
<option value="$PROJECT_DIR$/modules/io" />
|
||||
<option value="$PROJECT_DIR$/modules/json" />
|
||||
<option value="$PROJECT_DIR$/modules/official-bots" />
|
||||
<option value="$PROJECT_DIR$/modules/rule" />
|
||||
<option value="$PROJECT_DIR$/modules/security" />
|
||||
<option value="$PROJECT_DIR$/modules/store" />
|
||||
<option value="$PROJECT_DIR$/modules/ws" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
Generated
-1
@@ -1,4 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
|
||||
Generated
-6
@@ -1,11 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CommitMessageInspectionProfile">
|
||||
<profile version="1.0">
|
||||
<inspection_tool class="CommitFormat" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="CommitNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
<component name="IssueNavigationConfiguration">
|
||||
<option name="links">
|
||||
<list>
|
||||
|
||||
@@ -57,6 +57,14 @@ Use consistently.
|
||||
- **Tests are the spec.** Don't modify to pass. Fix requirements/code. Update only if requirements change.
|
||||
- Never read build folders. Ask permission if needed.
|
||||
- Keep file current with decisions + conventions.
|
||||
- **NativeReflectionConfig (mandatory):** Every new type (class, case class, enum, sealed trait — anything serialized) must be registered in the `NativeReflectionConfig` of **every module that interacts with it**. Configs live at:
|
||||
- `modules/account/src/main/scala/de/nowchess/account/config/NativeReflectionConfig.scala`
|
||||
- `modules/coordinator/src/main/scala/de/nowchess/coordinator/config/NativeReflectionConfig.scala`
|
||||
- `modules/core/src/main/scala/de/nowchess/chess/config/NativeReflectionConfig.scala`
|
||||
- `modules/io/src/main/scala/de/nowchess/io/service/config/NativeReflectionConfig.scala`
|
||||
- `modules/rule/src/main/scala/de/nowchess/rules/config/NativeReflectionConfig.scala`
|
||||
- `modules/store/src/main/scala/de/nowchess/store/config/NativeReflectionConfig.scala`
|
||||
- `modules/ws/src/main/scala/de/nowchess/ws/config/NativeReflectionConfig.scala`
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -10,11 +10,6 @@ post {
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
|
||||
headers {
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
@@ -22,9 +17,20 @@ headers {
|
||||
|
||||
body:json {
|
||||
{
|
||||
"color": "random",
|
||||
"timeControl": {
|
||||
"limitSeconds": 600,
|
||||
"incrementSeconds": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars:pre-request {
|
||||
username: bdc
|
||||
token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJub3djaGVzcyIsInN1YiI6ImY3MGQxNDIwLTdhZmEtNGVjMy05Mzg1LWViYWU0N2U3NGY4OCIsInVzZXJuYW1lIjoicGxheWVyMSIsImlhdCI6MTc3OTE5MjkwOCwiZXhwIjoxNzc5MTkzMjA4LCJqdGkiOiJkMDhlZmRhMi01ZjliLTQyNjgtOGM3MC1iNDA2OTViNDhiMTUifQ.q68R2bUdRQ5QwEIfcP0d2g_Wac94qd4K6BzP-PC94x-tDpT3leUY8ZpqY6YzoNv-ywp5sm47-WC539DyUqdzDgPVLLSmOMjRxG-HpaNdXwsXlp8_C7KGlgkK_XSMa3Gq6S4AfUbaXbRhPg5NZz2MRosu0BY2ed0ISvmEfX5XEdBRlKgD14BIKAsEFv3tHtarFS1RGpcSoHV2oeIk_m-VHUC78N-ciNHmBH6mZna_fVHgMocOIrEsTZuUms0Zacmebvh2tAcf36xux1Bm2awJff19zReD-A2o9jucrKcM3Im5BJ6JtuWAsHEae9KLmuol6S2pldvNOmUn3egFUYz0yQ
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
|
||||
@@ -0,0 +1,623 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: NowChess Tournament API
|
||||
description: |
|
||||
Swiss-system bot tournaments, modelled after the Lichess API style.
|
||||
|
||||
Game moves flow through the existing board and bot endpoints — this module
|
||||
handles pairings, standings, and lifecycle only.
|
||||
|
||||
## Streaming
|
||||
Endpoints marked **NDJSON** return newline-delimited JSON objects
|
||||
(`application/x-ndjson`). Each line is one complete JSON object. The
|
||||
connection stays open until the tournament or round ends.
|
||||
|
||||
## Bot flow
|
||||
```
|
||||
POST /api/tournament # create
|
||||
POST /api/tournament/{id}/join # each bot joins
|
||||
POST /api/tournament/{id}/start # director starts
|
||||
|
||||
GET /api/tournament/{id}/stream (NDJSON) # open before start
|
||||
|
||||
-- per round --
|
||||
receive gameStart { gameId, color }
|
||||
GET /bot/stream/game/{gameId} (existing, NDJSON)
|
||||
POST /bot/game/{gameId}/move/{uci} (existing)
|
||||
-- repeat --
|
||||
|
||||
GET /api/tournament/{id}/results (NDJSON) # final standings
|
||||
```
|
||||
version: 1.0.0
|
||||
|
||||
servers:
|
||||
- url: https://st.nowchess.janis-eccarius.de
|
||||
description: Staging
|
||||
- url: https://nowchess.janis-eccarius.de
|
||||
description: Production
|
||||
- url: http://localhost:8086
|
||||
description: Local
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
|
||||
tags:
|
||||
- name: Tournament
|
||||
description: Tournament lifecycle
|
||||
- name: Participation
|
||||
description: Join and withdraw
|
||||
- name: Results
|
||||
description: Standings, pairings, and game export
|
||||
- name: Stream
|
||||
description: NDJSON event streams
|
||||
|
||||
paths:
|
||||
|
||||
/api/tournament:
|
||||
get:
|
||||
tags: [Tournament]
|
||||
summary: Get current tournaments
|
||||
description: Returns tournaments grouped by status. No auth required.
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
description: Tournaments by status
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
created:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/TournamentInfo"
|
||||
started:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/TournamentInfo"
|
||||
finished:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/TournamentInfo"
|
||||
|
||||
post:
|
||||
tags: [Tournament]
|
||||
summary: Create a new tournament
|
||||
description: The authenticated user becomes the tournament director.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CreateTournamentForm"
|
||||
responses:
|
||||
"201":
|
||||
description: Tournament created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Tournament"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
|
||||
/api/tournament/{id}:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/id"
|
||||
|
||||
get:
|
||||
tags: [Tournament]
|
||||
summary: Get a tournament
|
||||
description: Includes the first page of standings in the `standing` field.
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
description: Tournament with embedded standings
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Tournament"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
delete:
|
||||
tags: [Tournament]
|
||||
summary: Terminate a tournament
|
||||
description: Only the director may terminate. Only allowed while status is `created`.
|
||||
responses:
|
||||
"204":
|
||||
description: Terminated
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
"409":
|
||||
$ref: "#/components/responses/Conflict"
|
||||
|
||||
/api/tournament/{id}/start:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/id"
|
||||
|
||||
post:
|
||||
tags: [Tournament]
|
||||
summary: Start the tournament
|
||||
description: |
|
||||
Only the director may start. Requires at least 2 joined bots.
|
||||
Computes round 1 pairings and creates games via `POST /api/board/game`.
|
||||
responses:
|
||||
"200":
|
||||
description: Tournament started
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Tournament"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
"409":
|
||||
$ref: "#/components/responses/Conflict"
|
||||
|
||||
/api/tournament/{id}/join:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/id"
|
||||
|
||||
post:
|
||||
tags: [Participation]
|
||||
summary: Join a tournament
|
||||
description: |
|
||||
Register the authenticated bot for the tournament. Only allowed while
|
||||
status is `created`. The token subject must be a bot account.
|
||||
responses:
|
||||
"200":
|
||||
description: Ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Ok"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
"409":
|
||||
$ref: "#/components/responses/Conflict"
|
||||
|
||||
/api/tournament/{id}/withdraw:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/id"
|
||||
|
||||
post:
|
||||
tags: [Participation]
|
||||
summary: Withdraw from a tournament
|
||||
description: Only allowed while status is `created`.
|
||||
responses:
|
||||
"200":
|
||||
description: Ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Ok"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"403":
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
"409":
|
||||
$ref: "#/components/responses/Conflict"
|
||||
|
||||
/api/tournament/{id}/results:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/id"
|
||||
|
||||
get:
|
||||
tags: [Results]
|
||||
summary: Get results as NDJSON stream
|
||||
description: |
|
||||
Streams one `Result` object per line, sorted by rank ascending.
|
||||
Available at any point during or after the tournament.
|
||||
security: []
|
||||
parameters:
|
||||
- name: nb
|
||||
in: query
|
||||
description: Max number of results to stream (default all)
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
responses:
|
||||
"200":
|
||||
description: NDJSON stream of results
|
||||
content:
|
||||
application/x-ndjson:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Result"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
/api/tournament/{id}/round/{round}:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/id"
|
||||
- name: round
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
|
||||
get:
|
||||
tags: [Results]
|
||||
summary: Get pairings for a round
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
description: Pairings for the specified round
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
round:
|
||||
type: integer
|
||||
example: 2
|
||||
pairings:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Pairing"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
/api/tournament/{id}/export/games:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/id"
|
||||
|
||||
get:
|
||||
tags: [Results]
|
||||
summary: Export all games
|
||||
description: |
|
||||
Returns all games of the tournament. Accepts both PGN and NDJSON via
|
||||
the `Accept` header.
|
||||
security: []
|
||||
parameters:
|
||||
- name: Accept
|
||||
in: header
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- application/x-chess-pgn
|
||||
- application/x-ndjson
|
||||
default: application/x-chess-pgn
|
||||
responses:
|
||||
"200":
|
||||
description: Games in the requested format
|
||||
content:
|
||||
application/x-chess-pgn:
|
||||
schema:
|
||||
type: string
|
||||
description: Standard PGN, one game per block
|
||||
application/x-ndjson:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GameExport"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
/api/tournament/{id}/stream:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/id"
|
||||
|
||||
get:
|
||||
tags: [Stream]
|
||||
summary: Stream tournament events
|
||||
description: |
|
||||
NDJSON stream scoped to one tournament. Keep this connection open for
|
||||
the full tournament lifetime.
|
||||
|
||||
On `gameStart` the bot connects to the existing bot endpoints:
|
||||
- `GET /bot/stream/game/{gameId}` — stream game state (existing)
|
||||
- `POST /bot/game/{gameId}/move/{uci}` — submit moves (existing)
|
||||
responses:
|
||||
"200":
|
||||
description: NDJSON event stream
|
||||
content:
|
||||
application/x-ndjson:
|
||||
schema:
|
||||
$ref: "#/components/schemas/TournamentEvent"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
components:
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
|
||||
parameters:
|
||||
id:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
example: t7kXq2
|
||||
|
||||
schemas:
|
||||
|
||||
Clock:
|
||||
type: object
|
||||
required: [limit, increment]
|
||||
properties:
|
||||
limit:
|
||||
type: integer
|
||||
description: Base time in seconds
|
||||
example: 300
|
||||
increment:
|
||||
type: integer
|
||||
description: Increment per move in seconds
|
||||
example: 3
|
||||
|
||||
Variant:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
example: standard
|
||||
name:
|
||||
type: string
|
||||
example: Standard
|
||||
|
||||
BotRef:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
example: bot_abc
|
||||
name:
|
||||
type: string
|
||||
example: StockfishClone
|
||||
|
||||
Standing:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
example: 1
|
||||
players:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Result"
|
||||
|
||||
TournamentInfo:
|
||||
description: Lightweight tournament summary used in list responses.
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
example: t7kXq2
|
||||
fullName:
|
||||
type: string
|
||||
example: Friday Night Bots Swiss
|
||||
clock:
|
||||
$ref: "#/components/schemas/Clock"
|
||||
variant:
|
||||
$ref: "#/components/schemas/Variant"
|
||||
rated:
|
||||
type: boolean
|
||||
example: true
|
||||
nbPlayers:
|
||||
type: integer
|
||||
example: 8
|
||||
nbRounds:
|
||||
type: integer
|
||||
example: 5
|
||||
createdBy:
|
||||
type: string
|
||||
example: userId
|
||||
startsAt:
|
||||
type: string
|
||||
format: date-time
|
||||
|
||||
Tournament:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/TournamentInfo"
|
||||
- type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
enum: [created, started, finished]
|
||||
example: started
|
||||
round:
|
||||
type: integer
|
||||
description: Current round number
|
||||
example: 2
|
||||
standing:
|
||||
$ref: "#/components/schemas/Standing"
|
||||
winner:
|
||||
description: Present only when status is `finished`
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/BotRef"
|
||||
nullable: true
|
||||
|
||||
CreateTournamentForm:
|
||||
type: object
|
||||
required: [name, nbRounds, clockLimit, clockIncrement]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: Friday Night Bots
|
||||
nbRounds:
|
||||
type: integer
|
||||
minimum: 1
|
||||
example: 5
|
||||
clockLimit:
|
||||
type: integer
|
||||
description: Base time in seconds
|
||||
example: 300
|
||||
clockIncrement:
|
||||
type: integer
|
||||
description: Increment per move in seconds
|
||||
example: 3
|
||||
rated:
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
Result:
|
||||
type: object
|
||||
properties:
|
||||
rank:
|
||||
type: integer
|
||||
example: 1
|
||||
points:
|
||||
type: number
|
||||
format: double
|
||||
example: 3.5
|
||||
tieBreak:
|
||||
type: number
|
||||
format: double
|
||||
description: Buchholz score (sum of opponents' points)
|
||||
example: 9.0
|
||||
bot:
|
||||
$ref: "#/components/schemas/BotRef"
|
||||
nbGames:
|
||||
type: integer
|
||||
example: 4
|
||||
wins:
|
||||
type: integer
|
||||
example: 3
|
||||
draws:
|
||||
type: integer
|
||||
example: 1
|
||||
losses:
|
||||
type: integer
|
||||
example: 0
|
||||
|
||||
Pairing:
|
||||
type: object
|
||||
properties:
|
||||
round:
|
||||
type: integer
|
||||
example: 2
|
||||
white:
|
||||
$ref: "#/components/schemas/BotRef"
|
||||
black:
|
||||
$ref: "#/components/schemas/BotRef"
|
||||
gameId:
|
||||
type: string
|
||||
example: j0nPtcjl
|
||||
winner:
|
||||
type: string
|
||||
enum: [white, black, draw]
|
||||
nullable: true
|
||||
description: Null while the game is ongoing
|
||||
|
||||
GameExport:
|
||||
description: One game object per NDJSON line.
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
example: j0nPtcjl
|
||||
round:
|
||||
type: integer
|
||||
example: 2
|
||||
white:
|
||||
$ref: "#/components/schemas/BotRef"
|
||||
black:
|
||||
$ref: "#/components/schemas/BotRef"
|
||||
winner:
|
||||
type: string
|
||||
enum: [white, black, draw]
|
||||
nullable: true
|
||||
moves:
|
||||
type: string
|
||||
description: Space-separated UCI moves
|
||||
example: e2e4 e7e5 g1f3
|
||||
|
||||
TournamentEvent:
|
||||
description: |
|
||||
One JSON object per NDJSON line. Discriminate on `type`.
|
||||
|
||||
| type | extra fields |
|
||||
|------|-------------|
|
||||
| `tournamentStarted` | — |
|
||||
| `roundStarted` | `round` |
|
||||
| `gameStart` | `round`, `gameId`, `color` |
|
||||
| `roundFinished` | `round` |
|
||||
| `tournamentFinished` | `winner` |
|
||||
type: object
|
||||
required: [type]
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- tournamentStarted
|
||||
- roundStarted
|
||||
- gameStart
|
||||
- roundFinished
|
||||
- tournamentFinished
|
||||
round:
|
||||
type: integer
|
||||
example: 2
|
||||
gameId:
|
||||
type: string
|
||||
example: j0nPtcjl
|
||||
color:
|
||||
type: string
|
||||
enum: [white, black]
|
||||
winner:
|
||||
$ref: "#/components/schemas/BotRef"
|
||||
|
||||
Ok:
|
||||
type: object
|
||||
properties:
|
||||
ok:
|
||||
type: boolean
|
||||
example: true
|
||||
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
example: tournament already started
|
||||
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Invalid request body or parameters
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
Unauthorized:
|
||||
description: Missing or invalid JWT
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
Forbidden:
|
||||
description: Action not permitted for this user or bot
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
NotFound:
|
||||
description: Tournament not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
Conflict:
|
||||
description: Conflicting state (e.g. already started, bot already joined)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
@@ -283,3 +283,210 @@
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-05-19)
|
||||
|
||||
### Features
|
||||
|
||||
* **account:** implement token pair handling for login and refresh endpoints ([9296db8](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/9296db88b7131bbda9b9b0da65c327ef9063ee31))
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add H2 database configuration for testing environment ([39c9e49](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/39c9e492cef2515368c074da9406f95e9c0c9e64))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** add InternalClientHeadersFactory for custom client headers management ([e279c39](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e279c39246470156bf11e745ee72204018d4229d))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* **tests:** update token path to accessToken in ChallengeResourceTest ([354db11](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/354db11972342c47a1034303c11bccfb92e60109))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-05-21)
|
||||
|
||||
### Features
|
||||
|
||||
* **account:** implement token pair handling for login and refresh endpoints ([9296db8](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/9296db88b7131bbda9b9b0da65c327ef9063ee31))
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add H2 database configuration for testing environment ([39c9e49](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/39c9e492cef2515368c074da9406f95e9c0c9e64))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **account:** configure JDBC connection pool size to prevent exhaustion under load ([29072ef](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/29072efbfb1cfa1c3b1a85b4c1a587c971d245f9))
|
||||
* **auth:** add InternalClientHeadersFactory for custom client headers management ([e279c39](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e279c39246470156bf11e745ee72204018d4229d))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* **tests:** update token path to accessToken in ChallengeResourceTest ([354db11](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/354db11972342c47a1034303c11bccfb92e60109))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-03)
|
||||
|
||||
### Features
|
||||
|
||||
* **account:** implement token pair handling for login and refresh endpoints ([9296db8](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/9296db88b7131bbda9b9b0da65c327ef9063ee31))
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add H2 database configuration for testing environment ([39c9e49](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/39c9e492cef2515368c074da9406f95e9c0c9e64))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **account:** configure JDBC connection pool size to prevent exhaustion under load ([29072ef](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/29072efbfb1cfa1c3b1a85b4c1a587c971d245f9))
|
||||
* **auth:** add InternalClientHeadersFactory for custom client headers management ([e279c39](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e279c39246470156bf11e745ee72204018d4229d))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **official-bots:** NCS-70-auto-register official bots with account service ([#59](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/59)) ([7117a93](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7117a93376272094d0b1a6abf2121254ce396684))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* **tests:** update token path to accessToken in ChallengeResourceTest ([354db11](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/354db11972342c47a1034303c11bccfb92e60109))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **account:** implement token pair handling for login and refresh endpoints ([9296db8](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/9296db88b7131bbda9b9b0da65c327ef9063ee31))
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **api:** define shared EventEnvelope and EventType for Redis EventBus ([#61](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/61)) ([595c172](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/595c172900da99de367c274488c3ccbeaef55882))
|
||||
* **config:** add H2 database configuration for testing environment ([39c9e49](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/39c9e492cef2515368c074da9406f95e9c0c9e64))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **account:** configure JDBC connection pool size to prevent exhaustion under load ([29072ef](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/29072efbfb1cfa1c3b1a85b4c1a587c971d245f9))
|
||||
* **auth:** add InternalClientHeadersFactory for custom client headers management ([e279c39](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e279c39246470156bf11e745ee72204018d4229d))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **official-bots:** NCS-70-auto-register official bots with account service ([#59](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/59)) ([7117a93](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7117a93376272094d0b1a6abf2121254ce396684))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* **tests:** update token path to accessToken in ChallengeResourceTest ([354db11](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/354db11972342c47a1034303c11bccfb92e60109))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **account:** implement token pair handling for login and refresh endpoints ([9296db8](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/9296db88b7131bbda9b9b0da65c327ef9063ee31))
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **api:** define shared EventEnvelope and EventType for Redis EventBus ([#61](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/61)) ([595c172](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/595c172900da99de367c274488c3ccbeaef55882))
|
||||
* **config:** add H2 database configuration for testing environment ([39c9e49](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/39c9e492cef2515368c074da9406f95e9c0c9e64))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **events:** migrate game-creation and bot flows to Redis Streams NCS-89 ([#62](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/62)) ([a24924c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a24924c23057db3d700a75dbc4333557789cd991))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **account:** configure JDBC connection pool size to prevent exhaustion under load ([29072ef](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/29072efbfb1cfa1c3b1a85b4c1a587c971d245f9))
|
||||
* **auth:** add InternalClientHeadersFactory for custom client headers management ([e279c39](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e279c39246470156bf11e745ee72204018d4229d))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **official-bots:** NCS-70-auto-register official bots with account service ([#59](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/59)) ([7117a93](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7117a93376272094d0b1a6abf2121254ce396684))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* **tests:** update token path to accessToken in ChallengeResourceTest ([354db11](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/354db11972342c47a1034303c11bccfb92e60109))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **account:** implement token pair handling for login and refresh endpoints ([9296db8](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/9296db88b7131bbda9b9b0da65c327ef9063ee31))
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **api:** define shared EventEnvelope and EventType for Redis EventBus ([#61](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/61)) ([595c172](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/595c172900da99de367c274488c3ccbeaef55882))
|
||||
* **config:** add H2 database configuration for testing environment ([39c9e49](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/39c9e492cef2515368c074da9406f95e9c0c9e64))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **events:** migrate game-creation and bot flows to Redis Streams NCS-89 ([#62](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/62)) ([a24924c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a24924c23057db3d700a75dbc4333557789cd991))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* NCS-82 add Swiss-system tournament module ([#55](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/55)) ([c5661de](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c5661de4a0ebf4b33211f5a391840dcf744656b7))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **account:** configure JDBC connection pool size to prevent exhaustion under load ([29072ef](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/29072efbfb1cfa1c3b1a85b4c1a587c971d245f9))
|
||||
* **auth:** add InternalClientHeadersFactory for custom client headers management ([e279c39](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e279c39246470156bf11e745ee72204018d4229d))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **official-bots:** NCS-70-auto-register official bots with account service ([#59](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/59)) ([7117a93](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7117a93376272094d0b1a6abf2121254ce396684))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* **tests:** update token path to accessToken in ChallengeResourceTest ([354db11](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/354db11972342c47a1034303c11bccfb92e60109))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
|
||||
@@ -45,6 +45,7 @@ dependencies {
|
||||
}
|
||||
}
|
||||
|
||||
implementation(project(":modules:api"))
|
||||
implementation(project(":modules:security"))
|
||||
|
||||
implementation(platform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}"))
|
||||
|
||||
@@ -76,6 +76,9 @@ nowchess:
|
||||
password: ${DB_PASSWORD}
|
||||
jdbc:
|
||||
url: ${DB_URL}
|
||||
min-size: 10
|
||||
max-size: 50
|
||||
acquisition-timeout: 30
|
||||
hibernate-orm:
|
||||
schema-management:
|
||||
strategy: update
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package de.nowchess.account.client
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.nowchess.account.config.RedisConfig
|
||||
import de.nowchess.api.dto.{GameCreationRequestDto, GameCreationResponseDto, PlayerInfoDto, TimeControlDto}
|
||||
import de.nowchess.api.game.GameMode
|
||||
import de.nowchess.api.player.PlayerType
|
||||
import de.nowchess.api.event.{EventEnvelope, EventType}
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import io.quarkus.redis.datasource.stream.{StreamMessage, XAddArgs, XGroupCreateArgs, XReadGroupArgs}
|
||||
import io.quarkus.runtime.StartupEvent
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.enterprise.event.Observes
|
||||
import jakarta.inject.Inject
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty
|
||||
import org.eclipse.microprofile.context.ManagedExecutor
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.{Failure, Success, Try}
|
||||
import java.time.Duration
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.{CompletableFuture, ConcurrentHashMap, TimeUnit}
|
||||
|
||||
@ApplicationScoped
|
||||
class GameCreationStreamClient:
|
||||
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Inject var redis: RedisDataSource = uninitialized
|
||||
@Inject var redisConfig: RedisConfig = uninitialized
|
||||
@Inject var objectMapper: ObjectMapper = uninitialized
|
||||
@Inject var executor: ManagedExecutor = uninitialized
|
||||
@ConfigProperty(name = "nowchess.game-creation-stream.enabled", defaultValue = "true")
|
||||
private var streamEnabled: Boolean = true
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private val log = Logger.getLogger(classOf[GameCreationStreamClient])
|
||||
private val instanceId = UUID.randomUUID().toString
|
||||
private val groupName = s"account-game-creation-$instanceId"
|
||||
private val consumerId = instanceId
|
||||
private val maxStreamLen = 1000L
|
||||
private val timeout = Duration.ofSeconds(10)
|
||||
|
||||
private val pending = new ConcurrentHashMap[String, CompletableFuture[GameCreationResponseDto]]()
|
||||
|
||||
private def requestStream: String = s"${redisConfig.prefix}:game-creation"
|
||||
private def responseStream: String = s"${redisConfig.prefix}:game-creation-response"
|
||||
|
||||
def start(@Observes _ev: StartupEvent): Unit =
|
||||
if streamEnabled then
|
||||
createGroupIfAbsent()
|
||||
executor.submit(
|
||||
new Runnable:
|
||||
def run(): Unit = pollLoop(),
|
||||
)
|
||||
log.infof("Game-creation response listener started (consumer=%s)", consumerId)
|
||||
|
||||
def createGame(req: CoreCreateGameRequest): GameCreationResponseDto =
|
||||
val correlationId = UUID.randomUUID().toString
|
||||
val future = new CompletableFuture[GameCreationResponseDto]()
|
||||
pending.put(correlationId, future)
|
||||
Try {
|
||||
val payload = objectMapper.valueToTree[com.fasterxml.jackson.databind.JsonNode](toDto(req))
|
||||
val envelope = EventEnvelope.of(EventType.GameCreationRequest, payload, Some(correlationId))
|
||||
publish(requestStream, envelope)
|
||||
future.get(timeout.toMillis, TimeUnit.MILLISECONDS)
|
||||
} match
|
||||
case Success(resp) =>
|
||||
pending.remove(correlationId)
|
||||
resp
|
||||
case Failure(ex) =>
|
||||
pending.remove(correlationId)
|
||||
log.errorf(ex, "Game creation request %s failed", correlationId)
|
||||
GameCreationResponseDto(None, Some("Game creation request timed out or failed"))
|
||||
|
||||
private def toDto(req: CoreCreateGameRequest): GameCreationRequestDto =
|
||||
GameCreationRequestDto(
|
||||
white = req.white.map(p => PlayerInfoDto(p.id, p.displayName, PlayerType.Human)),
|
||||
black = req.black.map(p => PlayerInfoDto(p.id, p.displayName, PlayerType.Human)),
|
||||
timeControl = req.timeControl.map(t => TimeControlDto(t.limitSeconds, t.incrementSeconds, t.daysPerMove)),
|
||||
mode = req.mode.map(_ => GameMode.Authenticated),
|
||||
)
|
||||
|
||||
private def createGroupIfAbsent(): Unit =
|
||||
Try(
|
||||
redis
|
||||
.stream(classOf[String])
|
||||
.xgroupCreate(responseStream, groupName, "0", new XGroupCreateArgs().mkstream()),
|
||||
) match
|
||||
case Failure(ex) if Option(ex.getMessage).exists(_.contains("BUSYGROUP")) => ()
|
||||
case Failure(ex) => log.warnf(ex, "Failed to create response consumer group")
|
||||
case Success(_) => ()
|
||||
|
||||
private def pollLoop(): Unit =
|
||||
while true do
|
||||
Try {
|
||||
val messages = redis
|
||||
.stream(classOf[String])
|
||||
.xreadgroup(
|
||||
groupName,
|
||||
consumerId,
|
||||
responseStream,
|
||||
">",
|
||||
new XReadGroupArgs().count(10).block(Duration.ofSeconds(2)),
|
||||
)
|
||||
Option(messages).foreach(_.forEach(handleResponse))
|
||||
} match
|
||||
case Failure(ex) => log.warnf(ex, "Error in game-creation response poll loop")
|
||||
case Success(_) => ()
|
||||
|
||||
private def handleResponse(msg: StreamMessage[String, String, String]): Unit =
|
||||
val json = msg.payload().get("data")
|
||||
Try(objectMapper.readValue(json, classOf[EventEnvelope])) match
|
||||
case Success(envelope) =>
|
||||
envelope.correlationId.flatMap(id => Option(pending.remove(id))).foreach { future =>
|
||||
Try(objectMapper.treeToValue(envelope.payload, classOf[GameCreationResponseDto])) match
|
||||
case Success(resp) => future.complete(resp)
|
||||
case Failure(ex) => future.completeExceptionally(ex)
|
||||
}
|
||||
case Failure(ex) => log.warnf(ex, "Unparseable game-creation response: %s", json)
|
||||
ack(msg.id())
|
||||
|
||||
private def ack(id: String): Unit =
|
||||
Try(redis.stream(classOf[String]).xack(responseStream, groupName, id)) match
|
||||
case Failure(ex) => log.warnf(ex, "Failed to ack response %s", id)
|
||||
case Success(_) => ()
|
||||
|
||||
private def publish(key: String, envelope: EventEnvelope): Unit =
|
||||
val json = objectMapper.writeValueAsString(envelope)
|
||||
redis
|
||||
.stream(classOf[String])
|
||||
.xadd(key, new XAddArgs().maxlen(maxStreamLen).nearlyExactTrimming(), Map("data" -> json).asJava)
|
||||
()
|
||||
+15
-1
@@ -12,10 +12,19 @@ import de.nowchess.account.domain.{
|
||||
UserAccount,
|
||||
}
|
||||
import de.nowchess.account.dto.*
|
||||
import de.nowchess.api.dto.{
|
||||
GameCreationRequestDto,
|
||||
GameCreationResponseDto,
|
||||
PlayerInfoDto as ApiPlayerInfoDto,
|
||||
TimeControlDto as ApiTimeControlDto,
|
||||
}
|
||||
import de.nowchess.api.event.{EventEnvelope, EventType}
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection
|
||||
|
||||
@RegisterForReflection(
|
||||
targets = Array(
|
||||
classOf[EventEnvelope],
|
||||
classOf[EventType],
|
||||
classOf[UserAccount],
|
||||
classOf[BotAccount],
|
||||
classOf[OfficialBotAccount],
|
||||
@@ -25,7 +34,8 @@ import io.quarkus.runtime.annotations.RegisterForReflection
|
||||
classOf[DeclineReason],
|
||||
classOf[TimeControl],
|
||||
classOf[LoginRequest],
|
||||
classOf[TokenResponse],
|
||||
classOf[RefreshRequest],
|
||||
classOf[TokenPairResponse],
|
||||
classOf[PlayerInfo],
|
||||
classOf[PublicAccountDto],
|
||||
classOf[BotAccountDto],
|
||||
@@ -45,6 +55,10 @@ import io.quarkus.runtime.annotations.RegisterForReflection
|
||||
classOf[CoreCreateGameRequest],
|
||||
classOf[CoreGameResponse],
|
||||
classOf[OfficialChallengeResponse],
|
||||
classOf[GameCreationRequestDto],
|
||||
classOf[GameCreationResponseDto],
|
||||
classOf[ApiPlayerInfoDto],
|
||||
classOf[ApiTimeControlDto],
|
||||
),
|
||||
)
|
||||
class NativeReflectionConfig
|
||||
|
||||
@@ -6,7 +6,6 @@ import scala.compiletime.uninitialized
|
||||
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
import scala.Conversion
|
||||
|
||||
@Entity
|
||||
@Table(name = "challenges")
|
||||
@@ -34,13 +33,14 @@ class Challenge extends PanacheEntityBase:
|
||||
@Column(nullable = true, columnDefinition = "varchar(255)")
|
||||
var declineReason: DeclineReason = uninitialized
|
||||
|
||||
var timeControlType: String = uninitialized
|
||||
@Column(nullable = true)
|
||||
var limitSeconds: java.lang.Integer = uninitialized
|
||||
|
||||
@Column(nullable = true)
|
||||
var timeControlLimit: java.lang.Integer = uninitialized
|
||||
var incrementSeconds: java.lang.Integer = uninitialized
|
||||
|
||||
@Column(nullable = true)
|
||||
var timeControlIncrement: java.lang.Integer = uninitialized
|
||||
var daysPerMove: java.lang.Integer = uninitialized
|
||||
|
||||
var createdAt: Instant = uninitialized
|
||||
|
||||
@@ -52,5 +52,6 @@ class Challenge extends PanacheEntityBase:
|
||||
|
||||
def gameIdOpt: Option[String] = Option(gameId)
|
||||
def declineReasonOpt: Option[DeclineReason] = Option(declineReason)
|
||||
def timeControlLimitOpt: Option[Int] = Option(timeControlLimit).map(_.intValue())
|
||||
def timeControlIncrementOpt: Option[Int] = Option(timeControlIncrement).map(_.intValue())
|
||||
def limitSecondsOpt: Option[Int] = Option(limitSeconds).map(_.intValue())
|
||||
def incrementSecondsOpt: Option[Int] = Option(incrementSeconds).map(_.intValue())
|
||||
def daysPerMoveOpt: Option[Int] = Option(daysPerMove).map(_.intValue())
|
||||
|
||||
@@ -51,7 +51,7 @@ class BotAccount extends PanacheEntityBase:
|
||||
@JoinColumn(name = "owner_id", nullable = false)
|
||||
var owner: UserAccount = uninitialized
|
||||
|
||||
@Column(unique = true, nullable = false, length = 256)
|
||||
@Column(unique = true, nullable = false, length = 1024)
|
||||
var token: String = uninitialized
|
||||
|
||||
var rating: Int = 1500
|
||||
@@ -75,4 +75,7 @@ class OfficialBotAccount extends PanacheEntityBase:
|
||||
var rating: Int = 1500
|
||||
|
||||
var createdAt: Instant = uninitialized
|
||||
|
||||
@Column(length = 1024)
|
||||
var token: String = uninitialized
|
||||
// scalafix:on
|
||||
|
||||
@@ -4,13 +4,15 @@ case class RegisterRequest(username: String, email: String, password: String)
|
||||
|
||||
case class LoginRequest(username: String, password: String)
|
||||
|
||||
case class TokenResponse(token: String)
|
||||
case class RefreshRequest(refreshToken: String)
|
||||
|
||||
case class TokenPairResponse(accessToken: String, refreshToken: String)
|
||||
|
||||
case class PlayerInfo(id: String, name: String, rating: Int)
|
||||
|
||||
case class PublicAccountDto(id: String, username: String, rating: Int, createdAt: String)
|
||||
|
||||
case class TimeControlDto(`type`: String, limit: Option[Int], increment: Option[Int])
|
||||
case class TimeControlDto(limitSeconds: Option[Int], incrementSeconds: Option[Int], daysPerMove: Option[Int])
|
||||
|
||||
case class ChallengeRequest(color: String, timeControl: TimeControlDto)
|
||||
|
||||
@@ -44,6 +46,8 @@ case class BotAccountWithTokenDto(id: String, name: String, rating: Int, token:
|
||||
|
||||
case class RotatedTokenDto(token: String)
|
||||
|
||||
case class OfficialBotAccountDto(id: String, name: String, rating: Int, createdAt: String)
|
||||
case class OfficialBotAccountDto(id: String, name: String, rating: Int, createdAt: String, token: Option[String] = None)
|
||||
|
||||
case class OfficialChallengeResponse(gameId: String, botName: String, difficulty: Int)
|
||||
|
||||
case class SyncOfficialBotsRequest(bots: List[String])
|
||||
|
||||
@@ -4,6 +4,7 @@ enum AccountError:
|
||||
case UsernameTaken(username: String)
|
||||
case EmailAlreadyRegistered(email: String)
|
||||
case InvalidCredentials
|
||||
case InvalidRefreshToken
|
||||
case UserNotFound
|
||||
case BotNotFound
|
||||
case BotLimitExceeded
|
||||
@@ -15,6 +16,7 @@ enum AccountError:
|
||||
case UsernameTaken(u) => s"Username '$u' is already taken"
|
||||
case EmailAlreadyRegistered(e) => s"Email '$e' is already registered"
|
||||
case InvalidCredentials => "Invalid credentials"
|
||||
case InvalidRefreshToken => "Invalid or expired refresh token"
|
||||
case UserNotFound => "User not found"
|
||||
case BotNotFound => "Bot account not found"
|
||||
case BotLimitExceeded => "Maximum of 5 bot accounts per user exceeded"
|
||||
|
||||
@@ -89,6 +89,13 @@ class OfficialBotAccountRepository:
|
||||
def findAll(): List[OfficialBotAccount] =
|
||||
em.createQuery("FROM OfficialBotAccount", classOf[OfficialBotAccount]).getResultList.asScala.toList
|
||||
|
||||
def findByName(name: String): Option[OfficialBotAccount] =
|
||||
em.createQuery("FROM OfficialBotAccount WHERE name = :name", classOf[OfficialBotAccount])
|
||||
.setParameter("name", name)
|
||||
.getResultList
|
||||
.asScala
|
||||
.headOption
|
||||
|
||||
def persist(bot: OfficialBotAccount): OfficialBotAccount =
|
||||
em.persist(bot)
|
||||
bot
|
||||
|
||||
@@ -4,6 +4,7 @@ import de.nowchess.account.domain.{BotAccount, OfficialBotAccount, UserAccount}
|
||||
import de.nowchess.account.dto.*
|
||||
import de.nowchess.account.error.AccountError
|
||||
import de.nowchess.account.service.AccountService
|
||||
import de.nowchess.security.InternalOnly
|
||||
import jakarta.annotation.security.RolesAllowed
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
@@ -40,8 +41,19 @@ class AccountResource:
|
||||
@Path("/login")
|
||||
def login(req: LoginRequest): Response =
|
||||
accountService.login(req) match
|
||||
case Right(token) =>
|
||||
Response.ok(TokenResponse(token)).build()
|
||||
case Right((accessToken, refreshToken)) =>
|
||||
Response.ok(TokenPairResponse(accessToken, refreshToken)).build()
|
||||
case Left(AccountError.UserBanned) =>
|
||||
Response.status(Response.Status.FORBIDDEN).entity(ErrorDto(AccountError.UserBanned.message)).build()
|
||||
case Left(error) =>
|
||||
Response.status(Response.Status.UNAUTHORIZED).entity(ErrorDto(error.message)).build()
|
||||
|
||||
@POST
|
||||
@Path("/refresh")
|
||||
def refresh(req: RefreshRequest): Response =
|
||||
accountService.refresh(req.refreshToken) match
|
||||
case Right((accessToken, refreshToken)) =>
|
||||
Response.ok(TokenPairResponse(accessToken, refreshToken)).build()
|
||||
case Left(AccountError.UserBanned) =>
|
||||
Response.status(Response.Status.FORBIDDEN).entity(ErrorDto(AccountError.UserBanned.message)).build()
|
||||
case Left(error) =>
|
||||
@@ -168,6 +180,13 @@ class AccountResource:
|
||||
createdAt = bot.createdAt.toString,
|
||||
)
|
||||
|
||||
@POST
|
||||
@Path("/official-bots/sync")
|
||||
@InternalOnly
|
||||
def syncOfficialBots(req: SyncOfficialBotsRequest): Response =
|
||||
accountService.syncOfficialBots(req.bots)
|
||||
Response.noContent().build()
|
||||
|
||||
@GET
|
||||
@Path("/official-bots")
|
||||
def getOfficialBots: Response =
|
||||
@@ -180,7 +199,7 @@ class AccountResource:
|
||||
def createOfficialBot(req: CreateBotAccountRequest): Response =
|
||||
accountService.createOfficialBotAccount(req.name) match
|
||||
case Right(bot) =>
|
||||
Response.status(Response.Status.CREATED).entity(toOfficialBotDto(bot)).build()
|
||||
Response.status(Response.Status.CREATED).entity(toOfficialBotDtoWithToken(bot)).build()
|
||||
case Left(error) =>
|
||||
Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ErrorDto(error.message)).build()
|
||||
|
||||
@@ -200,3 +219,12 @@ class AccountResource:
|
||||
rating = bot.rating,
|
||||
createdAt = bot.createdAt.toString,
|
||||
)
|
||||
|
||||
private def toOfficialBotDtoWithToken(bot: OfficialBotAccount): OfficialBotAccountDto =
|
||||
OfficialBotAccountDto(
|
||||
id = bot.id.toString,
|
||||
name = bot.name,
|
||||
rating = bot.rating,
|
||||
createdAt = bot.createdAt.toString,
|
||||
token = Some(bot.token),
|
||||
)
|
||||
|
||||
+3
-5
@@ -1,6 +1,6 @@
|
||||
package de.nowchess.account.resource
|
||||
|
||||
import de.nowchess.account.client.{CoreCreateGameRequest, CoreGameClient, CorePlayerInfo}
|
||||
import de.nowchess.account.client.{CoreCreateGameRequest, CorePlayerInfo, GameCreationStreamClient}
|
||||
import de.nowchess.account.dto.{ErrorDto, OfficialChallengeResponse}
|
||||
import de.nowchess.account.service.{AccountService, EventPublisher}
|
||||
import jakarta.annotation.security.RolesAllowed
|
||||
@@ -9,7 +9,6 @@ import jakarta.inject.Inject
|
||||
import jakarta.ws.rs.*
|
||||
import jakarta.ws.rs.core.{MediaType, Response}
|
||||
import org.eclipse.microprofile.jwt.JsonWebToken
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
|
||||
@@ -29,8 +28,7 @@ class OfficialChallengeResource:
|
||||
@Inject var botEventPublisher: EventPublisher = uninitialized
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
var coreGameClient: CoreGameClient = uninitialized
|
||||
var gameCreationClient: GameCreationStreamClient = uninitialized
|
||||
// scalafix:on
|
||||
|
||||
private val log = Logger.getLogger(classOf[OfficialChallengeResource])
|
||||
@@ -72,7 +70,7 @@ class OfficialChallengeResource:
|
||||
(CorePlayerInfo(bot.id.toString, bot.name), CorePlayerInfo(user.id.toString, user.username), "white")
|
||||
val req = CoreCreateGameRequest(Some(white), Some(black), None, Some("Authenticated"))
|
||||
val gameId =
|
||||
try Right(coreGameClient.createGame(req).gameId)
|
||||
try gameCreationClient.createGame(req).gameId.toRight("Failed to create game")
|
||||
catch case _ => Left("Failed to create game")
|
||||
gameId match
|
||||
case Left(err) =>
|
||||
|
||||
@@ -6,6 +6,7 @@ import de.nowchess.account.error.AccountError
|
||||
import de.nowchess.account.repository.{BotAccountRepository, OfficialBotAccountRepository, UserAccountRepository}
|
||||
import io.micrometer.core.instrument.MeterRegistry
|
||||
import io.quarkus.elytron.security.common.BcryptUtil
|
||||
import io.smallrye.jwt.auth.principal.JWTParser
|
||||
import io.smallrye.jwt.build.Jwt
|
||||
import jakarta.annotation.PostConstruct
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
@@ -34,6 +35,9 @@ class AccountService:
|
||||
|
||||
@Inject
|
||||
var meterRegistry: MeterRegistry = uninitialized
|
||||
|
||||
@Inject
|
||||
var jwtParser: JWTParser = uninitialized
|
||||
// scalafix:on
|
||||
|
||||
@PostConstruct
|
||||
@@ -66,7 +70,7 @@ class AccountService:
|
||||
log.infof("User %s registered successfully", req.username)
|
||||
Right(account)
|
||||
|
||||
def login(req: LoginRequest): Either[AccountError, String] =
|
||||
def login(req: LoginRequest): Either[AccountError, (String, String)] =
|
||||
val result = authenticateUser(req)
|
||||
result match
|
||||
case Right(_) => meterRegistry.counter("nowchess.auth.logins", "result", "success").increment()
|
||||
@@ -75,7 +79,7 @@ class AccountService:
|
||||
meterRegistry.counter("nowchess.auth.login.failures", "reason", loginFailureReason(error)).increment()
|
||||
result
|
||||
|
||||
private def authenticateUser(req: LoginRequest): Either[AccountError, String] =
|
||||
private def authenticateUser(req: LoginRequest): Either[AccountError, (String, String)] =
|
||||
userAccountRepository.findByUsername(req.username) match
|
||||
case None =>
|
||||
log.warnf("Login failed for unknown user %s", req.username)
|
||||
@@ -89,16 +93,39 @@ class AccountService:
|
||||
Left(AccountError.UserBanned)
|
||||
else
|
||||
log.infof("User %s logged in successfully", req.username)
|
||||
Right(
|
||||
Jwt
|
||||
.issuer("nowchess")
|
||||
.subject(account.id.toString)
|
||||
.claim("username", account.username)
|
||||
.sign(),
|
||||
)
|
||||
Right((generateAccessToken(account), generateRefreshToken(account.id)))
|
||||
|
||||
def refresh(refreshToken: String): Either[AccountError, (String, String)] =
|
||||
try
|
||||
val parsed = jwtParser.parse(refreshToken)
|
||||
if parsed.getClaim[String]("type") != "refresh" then Left(AccountError.InvalidRefreshToken)
|
||||
else
|
||||
val userId = UUID.fromString(parsed.getSubject)
|
||||
userAccountRepository.findById(userId) match
|
||||
case None => Left(AccountError.UserNotFound)
|
||||
case Some(u) if u.banned => Left(AccountError.UserBanned)
|
||||
case Some(u) => Right((generateAccessToken(u), generateRefreshToken(u.id)))
|
||||
catch case _: Throwable => Left(AccountError.InvalidRefreshToken)
|
||||
|
||||
private def generateAccessToken(account: UserAccount): String =
|
||||
Jwt
|
||||
.issuer("nowchess")
|
||||
.subject(account.id.toString)
|
||||
.claim("username", account.username)
|
||||
.expiresIn(3600)
|
||||
.sign()
|
||||
|
||||
private def generateRefreshToken(userId: UUID): String =
|
||||
Jwt
|
||||
.issuer("nowchess")
|
||||
.subject(userId.toString)
|
||||
.claim("type", "refresh")
|
||||
.expiresIn(30L * 24 * 3600)
|
||||
.sign()
|
||||
|
||||
private def loginFailureReason(error: AccountError): String = error match
|
||||
case AccountError.InvalidCredentials => "invalid_credentials"
|
||||
case AccountError.InvalidRefreshToken => "invalid_refresh_token"
|
||||
case AccountError.UserBanned => "user_banned"
|
||||
case AccountError.UsernameTaken(_) => "username_taken"
|
||||
case AccountError.EmailAlreadyRegistered(_) => "email_registered"
|
||||
@@ -126,9 +153,10 @@ class AccountService:
|
||||
val bot = new BotAccount()
|
||||
bot.name = botName
|
||||
bot.owner = owner
|
||||
bot.token = generateBotToken(bot.id)
|
||||
bot.token = UUID.randomUUID().toString
|
||||
bot.createdAt = Instant.now()
|
||||
botAccountRepository.persist(bot)
|
||||
bot.token = generateBotToken(bot.id, bot.name)
|
||||
log.infof("Bot account %s created for owner %s", botName, ownerId.toString)
|
||||
Right(bot)
|
||||
|
||||
@@ -167,7 +195,7 @@ class AccountService:
|
||||
case Some(bot) =>
|
||||
if bot.owner.id != ownerId then Left(AccountError.NotAuthorized)
|
||||
else
|
||||
bot.token = generateBotToken(botId)
|
||||
bot.token = generateBotToken(botId, bot.name)
|
||||
botAccountRepository.persist(bot)
|
||||
Right(bot)
|
||||
|
||||
@@ -177,8 +205,23 @@ class AccountService:
|
||||
bot.name = botName
|
||||
bot.createdAt = Instant.now()
|
||||
officialBotAccountRepository.persist(bot)
|
||||
bot.token = generateBotToken(bot.id, bot.name)
|
||||
officialBotAccountRepository.persist(bot)
|
||||
Right(bot)
|
||||
|
||||
@Transactional
|
||||
def syncOfficialBots(botNames: List[String]): Unit =
|
||||
botNames.foreach { name =>
|
||||
if officialBotAccountRepository.findByName(name).isEmpty then
|
||||
val bot = new OfficialBotAccount()
|
||||
bot.name = name
|
||||
bot.createdAt = Instant.now()
|
||||
officialBotAccountRepository.persist(bot)
|
||||
bot.token = generateBotToken(bot.id, bot.name)
|
||||
officialBotAccountRepository.persist(bot)
|
||||
log.infof("Auto-registered official bot: %s", name)
|
||||
}
|
||||
|
||||
def getOfficialBotAccounts(): List[OfficialBotAccount] =
|
||||
officialBotAccountRepository.findAll()
|
||||
|
||||
@@ -190,12 +233,13 @@ class AccountService:
|
||||
officialBotAccountRepository.delete(botId)
|
||||
Right(())
|
||||
|
||||
private def generateBotToken(botId: UUID): String =
|
||||
private def generateBotToken(botId: UUID, botName: String): String =
|
||||
Jwt
|
||||
.issuer("nowchess")
|
||||
.subject(botId.toString)
|
||||
.expiresAt(Long.MaxValue)
|
||||
.claim("type", "bot")
|
||||
.claim("name", botName)
|
||||
.sign()
|
||||
|
||||
@Transactional
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
package de.nowchess.account.service
|
||||
|
||||
import de.nowchess.account.client.{
|
||||
CoreCreateGameRequest,
|
||||
CoreGameClient,
|
||||
CoreGameResponse,
|
||||
CorePlayerInfo,
|
||||
CoreTimeControl,
|
||||
}
|
||||
import de.nowchess.account.client.{CoreCreateGameRequest, CorePlayerInfo, CoreTimeControl, GameCreationStreamClient}
|
||||
import de.nowchess.account.domain.{Challenge, ChallengeColor, ChallengeStatus, DeclineReason}
|
||||
import de.nowchess.account.dto.{
|
||||
ChallengeDto,
|
||||
@@ -23,7 +17,6 @@ import jakarta.annotation.PostConstruct
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import jakarta.transaction.Transactional
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
|
||||
@@ -45,8 +38,7 @@ class ChallengeService:
|
||||
var challengeRepository: ChallengeRepository = uninitialized
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
var coreGameClient: CoreGameClient = uninitialized
|
||||
var gameCreationClient: GameCreationStreamClient = uninitialized
|
||||
|
||||
@Inject
|
||||
var eventPublisher: EventPublisher = uninitialized
|
||||
@@ -88,9 +80,9 @@ class ChallengeService:
|
||||
challenge.destUser = destUser
|
||||
challenge.color = color
|
||||
challenge.status = ChallengeStatus.Created
|
||||
challenge.timeControlType = req.timeControl.`type`
|
||||
challenge.timeControlLimit = req.timeControl.limit.map(java.lang.Integer.valueOf).orNull
|
||||
challenge.timeControlIncrement = req.timeControl.increment.map(java.lang.Integer.valueOf).orNull
|
||||
challenge.limitSeconds = req.timeControl.limitSeconds.map(java.lang.Integer.valueOf).orNull
|
||||
challenge.incrementSeconds = req.timeControl.incrementSeconds.map(java.lang.Integer.valueOf).orNull
|
||||
challenge.daysPerMove = req.timeControl.daysPerMove.map(java.lang.Integer.valueOf).orNull
|
||||
challenge.createdAt = Instant.now()
|
||||
challenge.expiresAt = Instant.now().plus(24, ChronoUnit.HOURS)
|
||||
challengeRepository.persist(challenge)
|
||||
@@ -187,7 +179,7 @@ class ChallengeService:
|
||||
val (white, black) = assignColors(challenge)
|
||||
val tc = buildTimeControl(challenge)
|
||||
val req = CoreCreateGameRequest(Some(white), Some(black), tc, Some("Authenticated"))
|
||||
Right(coreGameClient.createGame(req).gameId)
|
||||
gameCreationClient.createGame(req).gameId.toRight(ChallengeError.GameCreationFailed)
|
||||
catch case _ => Left(ChallengeError.GameCreationFailed)
|
||||
|
||||
private def assignColors(challenge: Challenge): (CorePlayerInfo, CorePlayerInfo) =
|
||||
@@ -200,10 +192,9 @@ class ChallengeService:
|
||||
if ThreadLocalRandom.current().nextBoolean() then (challenger, destUser) else (destUser, challenger)
|
||||
|
||||
private def buildTimeControl(challenge: Challenge): Option[CoreTimeControl] =
|
||||
challenge.timeControlType match
|
||||
case "unlimited" => None
|
||||
case "correspondence" => Some(CoreTimeControl(None, None, challenge.timeControlLimitOpt))
|
||||
case _ => Some(CoreTimeControl(challenge.timeControlLimitOpt, challenge.timeControlIncrementOpt, None))
|
||||
if challenge.limitSecondsOpt.isEmpty && challenge.incrementSecondsOpt.isEmpty && challenge.daysPerMoveOpt.isEmpty
|
||||
then None
|
||||
else Some(CoreTimeControl(challenge.limitSecondsOpt, challenge.incrementSecondsOpt, challenge.daysPerMoveOpt))
|
||||
|
||||
private def parseColor(raw: String): Either[ChallengeError, ChallengeColor] =
|
||||
raw.toLowerCase match
|
||||
@@ -227,7 +218,7 @@ class ChallengeService:
|
||||
destUser = PlayerInfo(c.destUser.id.toString, c.destUser.username, c.destUser.rating),
|
||||
variant = "standard",
|
||||
color = c.color.toString.toLowerCase,
|
||||
timeControl = TimeControlDto(c.timeControlType, c.timeControlLimitOpt, c.timeControlIncrementOpt),
|
||||
timeControl = TimeControlDto(c.limitSecondsOpt, c.incrementSecondsOpt, c.daysPerMoveOpt),
|
||||
status = c.status.toString.toLowerCase,
|
||||
declineReason = c.declineReasonOpt.map(_.toString.toLowerCase),
|
||||
gameId = c.gameIdOpt,
|
||||
|
||||
@@ -1,31 +1,61 @@
|
||||
package de.nowchess.account.service
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.nowchess.account.config.RedisConfig
|
||||
import de.nowchess.api.event.{EventEnvelope, EventType}
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import io.quarkus.redis.datasource.stream.XAddArgs
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.jdk.CollectionConverters.*
|
||||
|
||||
@ApplicationScoped
|
||||
class EventPublisher:
|
||||
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Inject var redis: RedisDataSource = uninitialized
|
||||
@Inject var redisConfig: RedisConfig = uninitialized
|
||||
@Inject var redis: RedisDataSource = uninitialized
|
||||
@Inject var redisConfig: RedisConfig = uninitialized
|
||||
@Inject var objectMapper: ObjectMapper = uninitialized
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private val maxStreamLen = 1000L
|
||||
|
||||
def publishGameStart(botId: String, gameId: String, playingAs: String, difficulty: Int, botAccountId: String): Unit =
|
||||
val event =
|
||||
s"""{"type":"gameStart","gameId":"$gameId","playingAs":"$playingAs","difficulty":$difficulty,"botAccountId":"$botAccountId"}"""
|
||||
redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:bot:$botId:events", event)
|
||||
val payload = objectMapper.createObjectNode()
|
||||
payload.put("gameId", gameId)
|
||||
payload.put("playingAs", playingAs)
|
||||
payload.put("difficulty", difficulty)
|
||||
payload.put("botAccountId", botAccountId)
|
||||
val envelope = EventEnvelope.of(EventType.BotGameStart, payload)
|
||||
val json = objectMapper.writeValueAsString(envelope)
|
||||
redis
|
||||
.stream(classOf[String])
|
||||
.xadd(
|
||||
s"${redisConfig.prefix}:bot:$botId:events:stream",
|
||||
new XAddArgs().maxlen(maxStreamLen).nearlyExactTrimming(),
|
||||
Map("data" -> json).asJava,
|
||||
)
|
||||
redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:bot:$botId:events", json)
|
||||
()
|
||||
|
||||
def publishChallengeCreated(destUserId: String, challengeId: String, challengerName: String): Unit =
|
||||
val event = s"""{"type":"challengeCreated","challengeId":"$challengeId","challengerName":"$challengerName"}"""
|
||||
redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:user:$destUserId:events", event)
|
||||
()
|
||||
val payload = objectMapper.createObjectNode()
|
||||
payload.put("challengeId", challengeId)
|
||||
payload.put("challengerName", challengerName)
|
||||
publish(s"${redisConfig.prefix}:user:$destUserId:events", EventType.ChallengeCreated, payload)
|
||||
|
||||
def publishChallengeAccepted(challengerId: String, challengeId: String, gameId: String): Unit =
|
||||
val event = s"""{"type":"challengeAccepted","challengeId":"$challengeId","gameId":"$gameId"}"""
|
||||
redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:user:$challengerId:events", event)
|
||||
val payload = objectMapper.createObjectNode()
|
||||
payload.put("challengeId", challengeId)
|
||||
payload.put("gameId", gameId)
|
||||
publish(s"${redisConfig.prefix}:user:$challengerId:events", EventType.ChallengeAccepted, payload)
|
||||
|
||||
private def publish(
|
||||
channel: String,
|
||||
eventType: EventType,
|
||||
payload: com.fasterxml.jackson.databind.node.ObjectNode,
|
||||
): Unit =
|
||||
val envelope = EventEnvelope.of(eventType, payload)
|
||||
redis.pubsub(classOf[String]).publish(channel, objectMapper.writeValueAsString(envelope))
|
||||
()
|
||||
|
||||
@@ -34,3 +34,5 @@ nowchess:
|
||||
secret: test-secret
|
||||
auth:
|
||||
enabled: false
|
||||
game-creation-stream:
|
||||
enabled: false
|
||||
|
||||
+84
-3
@@ -32,7 +32,24 @@ class AccountResourceTest:
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.path[String]("token")
|
||||
.path[String]("accessToken")
|
||||
|
||||
private def registerAndLoginPair(username: String): (String, String) =
|
||||
givenRequest()
|
||||
.body(registerBody(username))
|
||||
.when()
|
||||
.post("/api/account")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
val resp = givenRequest()
|
||||
.body(loginBody(username))
|
||||
.when()
|
||||
.post("/api/account/login")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.response()
|
||||
(resp.path[String]("accessToken"), resp.path[String]("refreshToken"))
|
||||
|
||||
@Test
|
||||
def registerReturns200(): Unit =
|
||||
@@ -57,7 +74,7 @@ class AccountResourceTest:
|
||||
.body("error", containsString("bob"))
|
||||
|
||||
@Test
|
||||
def loginReturns200WithToken(): Unit =
|
||||
def loginReturns200WithTokenPair(): Unit =
|
||||
givenRequest().body(registerBody("charlie")).when().post("/api/account")
|
||||
givenRequest()
|
||||
.body(loginBody("charlie"))
|
||||
@@ -65,7 +82,8 @@ class AccountResourceTest:
|
||||
.post("/api/account/login")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("token", notNullValue())
|
||||
.body("accessToken", notNullValue())
|
||||
.body("refreshToken", notNullValue())
|
||||
|
||||
@Test
|
||||
def loginUnauthorizedOnWrongPassword(): Unit =
|
||||
@@ -105,3 +123,66 @@ class AccountResourceTest:
|
||||
.get("/api/account/doesnotexist")
|
||||
.`then`()
|
||||
.statusCode(404)
|
||||
|
||||
@Test
|
||||
def refreshReturnsNewTokenPair(): Unit =
|
||||
val (_, refreshToken) = registerAndLoginPair("refresh_user")
|
||||
givenRequest()
|
||||
.body(s"""{"refreshToken":"$refreshToken"}""")
|
||||
.when()
|
||||
.post("/api/account/refresh")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("accessToken", notNullValue())
|
||||
.body("refreshToken", notNullValue())
|
||||
|
||||
@Test
|
||||
def refreshWithInvalidTokenReturns401(): Unit =
|
||||
givenRequest()
|
||||
.body("""{"refreshToken":"invalid.token.value"}""")
|
||||
.when()
|
||||
.post("/api/account/refresh")
|
||||
.`then`()
|
||||
.statusCode(401)
|
||||
|
||||
@Test
|
||||
def refreshWithAccessTokenReturns401(): Unit =
|
||||
val accessToken = registerAndLogin("refresh_bad_type")
|
||||
givenRequest()
|
||||
.body(s"""{"refreshToken":"$accessToken"}""")
|
||||
.when()
|
||||
.post("/api/account/refresh")
|
||||
.`then`()
|
||||
.statusCode(401)
|
||||
|
||||
@Test
|
||||
def syncOfficialBotsCreatesNewBots(): Unit =
|
||||
givenRequest()
|
||||
.body("""{"bots":["sync-easy","sync-hard"]}""")
|
||||
.when()
|
||||
.post("/api/account/official-bots/sync")
|
||||
.`then`()
|
||||
.statusCode(204)
|
||||
RestAssured
|
||||
.`given`()
|
||||
.when()
|
||||
.get("/api/account/official-bots")
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.body("name", hasItems("sync-easy", "sync-hard"))
|
||||
|
||||
@Test
|
||||
def syncOfficialBotsIsIdempotent(): Unit =
|
||||
val body = """{"bots":["idempotent-bot"]}"""
|
||||
givenRequest()
|
||||
.body(body)
|
||||
.when()
|
||||
.post("/api/account/official-bots/sync")
|
||||
.`then`()
|
||||
.statusCode(204)
|
||||
givenRequest()
|
||||
.body(body)
|
||||
.when()
|
||||
.post("/api/account/official-bots/sync")
|
||||
.`then`()
|
||||
.statusCode(204)
|
||||
|
||||
+8
-7
@@ -1,11 +1,11 @@
|
||||
package de.nowchess.account.resource
|
||||
|
||||
import de.nowchess.account.client.{CoreGameClient, CoreGameResponse}
|
||||
import de.nowchess.account.client.GameCreationStreamClient
|
||||
import de.nowchess.api.dto.GameCreationResponseDto
|
||||
import io.quarkus.test.InjectMock
|
||||
import io.quarkus.test.junit.QuarkusTest
|
||||
import io.restassured.RestAssured
|
||||
import io.restassured.http.ContentType
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient
|
||||
import org.hamcrest.Matchers.*
|
||||
import org.junit.jupiter.api.{BeforeEach, Test}
|
||||
import org.mockito.{ArgumentMatchers, Mockito}
|
||||
@@ -14,14 +14,15 @@ import org.mockito.{ArgumentMatchers, Mockito}
|
||||
class ChallengeResourceTest:
|
||||
|
||||
@InjectMock
|
||||
@RestClient
|
||||
// scalafix:off DisableSyntax.var
|
||||
var coreGameClient: CoreGameClient = scala.compiletime.uninitialized
|
||||
var gameCreationClient: GameCreationStreamClient = scala.compiletime.uninitialized
|
||||
// scalafix:on
|
||||
|
||||
@BeforeEach
|
||||
def setup(): Unit =
|
||||
Mockito.when(coreGameClient.createGame(ArgumentMatchers.any())).thenReturn(CoreGameResponse("test-game-id"))
|
||||
Mockito
|
||||
.when(gameCreationClient.createGame(ArgumentMatchers.any()))
|
||||
.thenReturn(GameCreationResponseDto(Some("test-game-id")))
|
||||
|
||||
private def givenRequest() = RestAssured.`given`().contentType(ContentType.JSON)
|
||||
|
||||
@@ -41,10 +42,10 @@ class ChallengeResourceTest:
|
||||
.`then`()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.path[String]("token")
|
||||
.path[String]("accessToken")
|
||||
|
||||
private val clockBody =
|
||||
"""{"color":"random","timeControl":{"type":"clock","limit":300,"increment":5}}"""
|
||||
"""{"color":"random","timeControl":{"limitSeconds":300,"incrementSeconds":5}}"""
|
||||
|
||||
private def authed(token: String) =
|
||||
givenRequest().header("Authorization", s"Bearer $token")
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=16
|
||||
MINOR=22
|
||||
PATCH=0
|
||||
|
||||
@@ -109,3 +109,78 @@
|
||||
### Bug Fixes
|
||||
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
## (2026-05-22)
|
||||
|
||||
### Features
|
||||
|
||||
* **dto:** update GameWritebackEventDto for JSON deserialization and remove unused mixin ([576e3fe](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/576e3fea9bf1082549ea53efd3288474c42be93d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dependencies:** correct Jackson databind dependency group ID ([008d72d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/008d72d826707c04205bac7de25170fae5fed861))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
## (2026-05-31)
|
||||
|
||||
### Features
|
||||
|
||||
* **dto:** update GameWritebackEventDto for JSON deserialization and remove unused mixin ([576e3fe](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/576e3fea9bf1082549ea53efd3288474c42be93d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dependencies:** correct Jackson databind dependency group ID ([008d72d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/008d72d826707c04205bac7de25170fae5fed861))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
## (2026-06-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** define shared EventEnvelope and EventType for Redis EventBus ([#61](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/61)) ([595c172](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/595c172900da99de367c274488c3ccbeaef55882))
|
||||
* **dto:** update GameWritebackEventDto for JSON deserialization and remove unused mixin ([576e3fe](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/576e3fea9bf1082549ea53efd3288474c42be93d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dependencies:** correct Jackson databind dependency group ID ([008d72d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/008d72d826707c04205bac7de25170fae5fed861))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
## (2026-06-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** define shared EventEnvelope and EventType for Redis EventBus ([#61](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/61)) ([595c172](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/595c172900da99de367c274488c3ccbeaef55882))
|
||||
* **dto:** update GameWritebackEventDto for JSON deserialization and remove unused mixin ([576e3fe](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/576e3fea9bf1082549ea53efd3288474c42be93d))
|
||||
* **events:** migrate game-creation and bot flows to Redis Streams NCS-89 ([#62](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/62)) ([a24924c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a24924c23057db3d700a75dbc4333557789cd991))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dependencies:** correct Jackson databind dependency group ID ([008d72d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/008d72d826707c04205bac7de25170fae5fed861))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
|
||||
@@ -49,6 +49,9 @@ dependencies {
|
||||
strictly(versions["SCALA_LIBRARY"]!!)
|
||||
}
|
||||
}
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind:${versions["JACKSON"]!!}")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-scala_3:${versions["JACKSON_SCALA"]!!}")
|
||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${versions["JACKSON"]!!}")
|
||||
|
||||
testImplementation(platform("org.junit:junit-bom:5.13.4"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.nowchess.api.dto
|
||||
|
||||
import de.nowchess.api.game.GameMode
|
||||
|
||||
final case class GameCreationRequestDto(
|
||||
white: Option[PlayerInfoDto],
|
||||
black: Option[PlayerInfoDto],
|
||||
timeControl: Option[TimeControlDto],
|
||||
mode: Option[GameMode] = None,
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
package de.nowchess.api.dto
|
||||
|
||||
final case class GameCreationResponseDto(
|
||||
gameId: Option[String],
|
||||
error: Option[String] = None,
|
||||
)
|
||||
@@ -1,5 +1,7 @@
|
||||
package de.nowchess.api.dto
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
|
||||
case class GameWritebackEventDto(
|
||||
gameId: String,
|
||||
fen: String,
|
||||
@@ -14,11 +16,11 @@ case class GameWritebackEventDto(
|
||||
limitSeconds: Option[Int],
|
||||
incrementSeconds: Option[Int],
|
||||
daysPerMove: Option[Int],
|
||||
whiteRemainingMs: Option[Long],
|
||||
blackRemainingMs: Option[Long],
|
||||
incrementMs: Option[Long],
|
||||
clockLastTickAt: Option[Long],
|
||||
clockMoveDeadline: Option[Long],
|
||||
@JsonDeserialize(contentAs = classOf[java.lang.Long]) whiteRemainingMs: Option[Long],
|
||||
@JsonDeserialize(contentAs = classOf[java.lang.Long]) blackRemainingMs: Option[Long],
|
||||
@JsonDeserialize(contentAs = classOf[java.lang.Long]) incrementMs: Option[Long],
|
||||
@JsonDeserialize(contentAs = classOf[java.lang.Long]) clockLastTickAt: Option[Long],
|
||||
@JsonDeserialize(contentAs = classOf[java.lang.Long]) clockMoveDeadline: Option[Long],
|
||||
clockActiveColor: Option[String],
|
||||
pendingDrawOffer: Option[String],
|
||||
result: Option[String] = None,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package de.nowchess.api.event
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
final case class EventEnvelope(
|
||||
eventId: UUID,
|
||||
`type`: EventType,
|
||||
payload: JsonNode,
|
||||
timestamp: Instant,
|
||||
correlationId: Option[String],
|
||||
)
|
||||
|
||||
object EventEnvelope:
|
||||
def of(
|
||||
`type`: EventType,
|
||||
payload: JsonNode,
|
||||
correlationId: Option[String] = None,
|
||||
): EventEnvelope =
|
||||
EventEnvelope(
|
||||
eventId = UUID.randomUUID(),
|
||||
`type` = `type`,
|
||||
payload = payload,
|
||||
timestamp = Instant.now(),
|
||||
correlationId = correlationId,
|
||||
)
|
||||
@@ -0,0 +1,4 @@
|
||||
package de.nowchess.api.event
|
||||
|
||||
enum EventType:
|
||||
case GameStart, GameCreationRequest, GameCreationResponse, BotGameStart, ChallengeCreated, ChallengeAccepted
|
||||
@@ -0,0 +1,50 @@
|
||||
package de.nowchess.api.event
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.scala.DefaultScalaModule
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
||||
class EventEnvelopeTest extends AnyFunSuite with Matchers:
|
||||
|
||||
private val mapper =
|
||||
val m = new ObjectMapper()
|
||||
m.registerModule(DefaultScalaModule)
|
||||
m.findAndRegisterModules()
|
||||
m
|
||||
|
||||
test("EventEnvelope round-trips through JSON") {
|
||||
val payload = mapper.createObjectNode()
|
||||
payload.put("gameId", "game-123")
|
||||
payload.put("difficulty", 3)
|
||||
|
||||
val original = EventEnvelope.of(EventType.GameStart, payload, Some("corr-abc"))
|
||||
|
||||
val json = mapper.writeValueAsString(original)
|
||||
val decoded = mapper.readValue(json, classOf[EventEnvelope])
|
||||
|
||||
decoded.eventId shouldBe original.eventId
|
||||
decoded.`type` shouldBe original.`type`
|
||||
decoded.payload shouldBe original.payload
|
||||
decoded.timestamp shouldBe original.timestamp
|
||||
decoded.correlationId shouldBe Some("corr-abc")
|
||||
}
|
||||
|
||||
test("EventEnvelope serializes without correlationId") {
|
||||
val payload = mapper.createObjectNode()
|
||||
payload.put("challengeId", "ch-1")
|
||||
|
||||
val envelope = EventEnvelope.of(EventType.ChallengeCreated, payload)
|
||||
val json = mapper.writeValueAsString(envelope)
|
||||
val decoded = mapper.readValue(json, classOf[EventEnvelope])
|
||||
|
||||
decoded.`type` shouldBe EventType.ChallengeCreated
|
||||
decoded.correlationId shouldBe None
|
||||
}
|
||||
|
||||
test("EventEnvelope.of generates unique eventIds") {
|
||||
val payload = mapper.createObjectNode()
|
||||
val e1 = EventEnvelope.of(EventType.BotGameStart, payload)
|
||||
val e2 = EventEnvelope.of(EventType.BotGameStart, payload)
|
||||
e1.eventId should not equal e2.eventId
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=12
|
||||
MINOR=16
|
||||
PATCH=0
|
||||
|
||||
@@ -569,3 +569,413 @@
|
||||
* streamline logging for evicted instances in InstanceRegistry ([10937e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10937e756a56e0e8fcf939decfdcaa4394506cc0))
|
||||
* update grpcServer variable to use Instance wrapper and add optional access method ([d5c8da2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d5c8da20f8805199e920ea5afbd9cdb39a078e40))
|
||||
* update HealthMonitor to evict instances without associated pods ([0f41f13](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0f41f13ce68b76846684bab67241a122250dfaf9))
|
||||
## (2026-05-16)
|
||||
|
||||
### Features
|
||||
|
||||
* add coordinator startup validation and K8s pod watch ([81b045d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/81b045d01bb054a4bc9dc9e02fc30f814e756205))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* add periodic health check to evict dead instances ([380a2cc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/380a2cceeb5873bf93ff17a1e87d62408ef8e178))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* scale up on high CPU load, not just subscription count ([255e2da](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/255e2da33c37e186ed14f2862f2d2e1b4adc59bf))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add instance-dead-timeout configuration and update HealthMonitor to use it for stale instance eviction ([be0b710](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/be0b710543b542da5c301efef7d2d587d0ba758a))
|
||||
* clean up code formatting and improve error handling in gRPC server and failover service ([ad9495a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ad9495afa3e93593b57154a187346c9b01393911))
|
||||
* coordinator auto-scaling, cache eviction, rebalancing, and grpc timeouts ([d0c7169](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d0c71693bb6f55fafdce5bcea0d5f38b9bb505ef))
|
||||
* **coordinator:** refine type casting in rolloutSpec method ([#45](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/45)) ([d522f7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d522f7f6edf9c985f03dd16816439d4184f1a589))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#43](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/43)) ([fa3c6b2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fa3c6b2886dc59c14c5dad834acc9b41e42023bb))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#44](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/44)) ([82d0b75](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/82d0b754be1075084944b466858672d944f9f7d8))
|
||||
* **dependencies:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
|
||||
* don't block event loop during scale-down drain ([1d121c7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1d121c727cbd4df477827cf64d065b7356a56e59))
|
||||
* don't trigger scale-down if already at min replicas ([4b3b5e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4b3b5e7c4ed9b3cd4fe2490e9f268f2e3a0d9e85))
|
||||
* enhance AutoScaler and InstanceRegistry for replica management and stale instance eviction ([b4920d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4920d3817e58bda94d7764e608b856ce9a909f7))
|
||||
* force-delete hanging pods and remove failed instances from registry ([960a419](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/960a419792e1161fb7241e465b7349efe4a10137))
|
||||
* linter formatting and improve code readability ([4a36096](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4a36096a5586e3f321d9c34c53e60d02bcc02c55))
|
||||
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove corrupted instances immediately and evict dead instances ([43184d2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43184d296da5a6a7b760ac90c2b739220d86bce3))
|
||||
* replace null checks with Option in coordinator ([2b04d7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2b04d7fa713e06662bff5afe3fb3f9d04541ce51))
|
||||
* scalafix violations in metrics check and health monitor ([b991878](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b99187821489b296d66da5a5a13f5d545b6045c6))
|
||||
* scale up immediately when instance is lost ([43525d4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43525d41a3884c00f1db26bf3c8c4cd9a607c260))
|
||||
* streamline logging for evicted instances in InstanceRegistry ([10937e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10937e756a56e0e8fcf939decfdcaa4394506cc0))
|
||||
* update grpcServer variable to use Instance wrapper and add optional access method ([d5c8da2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d5c8da20f8805199e920ea5afbd9cdb39a078e40))
|
||||
* update HealthMonitor to evict instances without associated pods ([0f41f13](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0f41f13ce68b76846684bab67241a122250dfaf9))
|
||||
## (2026-05-16)
|
||||
|
||||
### Features
|
||||
|
||||
* add coordinator startup validation and K8s pod watch ([81b045d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/81b045d01bb054a4bc9dc9e02fc30f814e756205))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* add periodic health check to evict dead instances ([380a2cc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/380a2cceeb5873bf93ff17a1e87d62408ef8e178))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement clock expiry scanning and handling for game records ([#54](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/54)) ([2e4ba43](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2e4ba435978ef415b4ee2d7d2fc4af3b4e834b3d))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* scale up on high CPU load, not just subscription count ([255e2da](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/255e2da33c37e186ed14f2862f2d2e1b4adc59bf))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add instance-dead-timeout configuration and update HealthMonitor to use it for stale instance eviction ([be0b710](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/be0b710543b542da5c301efef7d2d587d0ba758a))
|
||||
* clean up code formatting and improve error handling in gRPC server and failover service ([ad9495a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ad9495afa3e93593b57154a187346c9b01393911))
|
||||
* coordinator auto-scaling, cache eviction, rebalancing, and grpc timeouts ([d0c7169](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d0c71693bb6f55fafdce5bcea0d5f38b9bb505ef))
|
||||
* **coordinator:** refine type casting in rolloutSpec method ([#45](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/45)) ([d522f7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d522f7f6edf9c985f03dd16816439d4184f1a589))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#43](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/43)) ([fa3c6b2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fa3c6b2886dc59c14c5dad834acc9b41e42023bb))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#44](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/44)) ([82d0b75](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/82d0b754be1075084944b466858672d944f9f7d8))
|
||||
* **dependencies:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
|
||||
* don't block event loop during scale-down drain ([1d121c7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1d121c727cbd4df477827cf64d065b7356a56e59))
|
||||
* don't trigger scale-down if already at min replicas ([4b3b5e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4b3b5e7c4ed9b3cd4fe2490e9f268f2e3a0d9e85))
|
||||
* enhance AutoScaler and InstanceRegistry for replica management and stale instance eviction ([b4920d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4920d3817e58bda94d7764e608b856ce9a909f7))
|
||||
* force-delete hanging pods and remove failed instances from registry ([960a419](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/960a419792e1161fb7241e465b7349efe4a10137))
|
||||
* linter formatting and improve code readability ([4a36096](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4a36096a5586e3f321d9c34c53e60d02bcc02c55))
|
||||
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove corrupted instances immediately and evict dead instances ([43184d2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43184d296da5a6a7b760ac90c2b739220d86bce3))
|
||||
* replace null checks with Option in coordinator ([2b04d7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2b04d7fa713e06662bff5afe3fb3f9d04541ce51))
|
||||
* scalafix violations in metrics check and health monitor ([b991878](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b99187821489b296d66da5a5a13f5d545b6045c6))
|
||||
* scale up immediately when instance is lost ([43525d4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43525d41a3884c00f1db26bf3c8c4cd9a607c260))
|
||||
* streamline logging for evicted instances in InstanceRegistry ([10937e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10937e756a56e0e8fcf939decfdcaa4394506cc0))
|
||||
* update grpcServer variable to use Instance wrapper and add optional access method ([d5c8da2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d5c8da20f8805199e920ea5afbd9cdb39a078e40))
|
||||
* update HealthMonitor to evict instances without associated pods ([0f41f13](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0f41f13ce68b76846684bab67241a122250dfaf9))
|
||||
## (2026-05-16)
|
||||
|
||||
### Features
|
||||
|
||||
* add configurable CPU and memory scaling thresholds for auto-scaling ([a07bf89](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a07bf89fae43e3ef5fdd30aed0429742a95f8bbe))
|
||||
* add coordinator startup validation and K8s pod watch ([81b045d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/81b045d01bb054a4bc9dc9e02fc30f814e756205))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* add periodic health check to evict dead instances ([380a2cc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/380a2cceeb5873bf93ff17a1e87d62408ef8e178))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement clock expiry scanning and handling for game records ([#54](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/54)) ([2e4ba43](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2e4ba435978ef415b4ee2d7d2fc4af3b4e834b3d))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* scale up on high CPU load, not just subscription count ([255e2da](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/255e2da33c37e186ed14f2862f2d2e1b4adc59bf))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add instance-dead-timeout configuration and update HealthMonitor to use it for stale instance eviction ([be0b710](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/be0b710543b542da5c301efef7d2d587d0ba758a))
|
||||
* clean up code formatting and improve error handling in gRPC server and failover service ([ad9495a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ad9495afa3e93593b57154a187346c9b01393911))
|
||||
* coordinator auto-scaling, cache eviction, rebalancing, and grpc timeouts ([d0c7169](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d0c71693bb6f55fafdce5bcea0d5f38b9bb505ef))
|
||||
* **coordinator:** refine type casting in rolloutSpec method ([#45](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/45)) ([d522f7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d522f7f6edf9c985f03dd16816439d4184f1a589))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#43](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/43)) ([fa3c6b2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fa3c6b2886dc59c14c5dad834acc9b41e42023bb))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#44](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/44)) ([82d0b75](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/82d0b754be1075084944b466858672d944f9f7d8))
|
||||
* **dependencies:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
|
||||
* don't block event loop during scale-down drain ([1d121c7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1d121c727cbd4df477827cf64d065b7356a56e59))
|
||||
* don't trigger scale-down if already at min replicas ([4b3b5e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4b3b5e7c4ed9b3cd4fe2490e9f268f2e3a0d9e85))
|
||||
* enhance AutoScaler and InstanceRegistry for replica management and stale instance eviction ([b4920d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4920d3817e58bda94d7764e608b856ce9a909f7))
|
||||
* force-delete hanging pods and remove failed instances from registry ([960a419](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/960a419792e1161fb7241e465b7349efe4a10137))
|
||||
* improve pod instance ID matching logic in AutoScaler and HealthMonitor ([f109fe3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f109fe3860371dd0be3434b10a721936dc258b16))
|
||||
* linter formatting and improve code readability ([4a36096](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4a36096a5586e3f321d9c34c53e60d02bcc02c55))
|
||||
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove corrupted instances immediately and evict dead instances ([43184d2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43184d296da5a6a7b760ac90c2b739220d86bce3))
|
||||
* replace null checks with Option in coordinator ([2b04d7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2b04d7fa713e06662bff5afe3fb3f9d04541ce51))
|
||||
* scalafix violations in metrics check and health monitor ([b991878](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b99187821489b296d66da5a5a13f5d545b6045c6))
|
||||
* scale up immediately when instance is lost ([43525d4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43525d41a3884c00f1db26bf3c8c4cd9a607c260))
|
||||
* streamline logging for evicted instances in InstanceRegistry ([10937e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10937e756a56e0e8fcf939decfdcaa4394506cc0))
|
||||
* update grpcServer variable to use Instance wrapper and add optional access method ([d5c8da2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d5c8da20f8805199e920ea5afbd9cdb39a078e40))
|
||||
* update HealthMonitor to evict instances without associated pods ([0f41f13](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0f41f13ce68b76846684bab67241a122250dfaf9))
|
||||
## (2026-05-17)
|
||||
|
||||
### Features
|
||||
|
||||
* add configurable CPU and memory scaling thresholds for auto-scaling ([a07bf89](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a07bf89fae43e3ef5fdd30aed0429742a95f8bbe))
|
||||
* add coordinator startup validation and K8s pod watch ([81b045d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/81b045d01bb054a4bc9dc9e02fc30f814e756205))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* add periodic health check to evict dead instances ([380a2cc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/380a2cceeb5873bf93ff17a1e87d62408ef8e178))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement clock expiry scanning and handling for game records ([#54](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/54)) ([2e4ba43](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2e4ba435978ef415b4ee2d7d2fc4af3b4e834b3d))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* scale up on high CPU load, not just subscription count ([255e2da](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/255e2da33c37e186ed14f2862f2d2e1b4adc59bf))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add instance-dead-timeout configuration and update HealthMonitor to use it for stale instance eviction ([be0b710](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/be0b710543b542da5c301efef7d2d587d0ba758a))
|
||||
* clean up code formatting and improve error handling in gRPC server and failover service ([ad9495a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ad9495afa3e93593b57154a187346c9b01393911))
|
||||
* coordinator auto-scaling, cache eviction, rebalancing, and grpc timeouts ([d0c7169](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d0c71693bb6f55fafdce5bcea0d5f38b9bb505ef))
|
||||
* **coordinator:** refine type casting in rolloutSpec method ([#45](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/45)) ([d522f7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d522f7f6edf9c985f03dd16816439d4184f1a589))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#43](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/43)) ([fa3c6b2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fa3c6b2886dc59c14c5dad834acc9b41e42023bb))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#44](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/44)) ([82d0b75](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/82d0b754be1075084944b466858672d944f9f7d8))
|
||||
* **dependencies:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
|
||||
* don't block event loop during scale-down drain ([1d121c7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1d121c727cbd4df477827cf64d065b7356a56e59))
|
||||
* don't trigger scale-down if already at min replicas ([4b3b5e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4b3b5e7c4ed9b3cd4fe2490e9f268f2e3a0d9e85))
|
||||
* enhance AutoScaler and InstanceRegistry for replica management and stale instance eviction ([b4920d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4920d3817e58bda94d7764e608b856ce9a909f7))
|
||||
* force-delete hanging pods and remove failed instances from registry ([960a419](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/960a419792e1161fb7241e465b7349efe4a10137))
|
||||
* improve pod instance ID matching logic in AutoScaler and HealthMonitor ([f109fe3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f109fe3860371dd0be3434b10a721936dc258b16))
|
||||
* linter formatting and improve code readability ([4a36096](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4a36096a5586e3f321d9c34c53e60d02bcc02c55))
|
||||
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove corrupted instances immediately and evict dead instances ([43184d2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43184d296da5a6a7b760ac90c2b739220d86bce3))
|
||||
* remove unused clearDrainingByPodName method and update HealthMonitor to clear draining instances ([1a02f9e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1a02f9e18673d0038e9a307fee5ea5219dc76af8))
|
||||
* replace null checks with Option in coordinator ([2b04d7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2b04d7fa713e06662bff5afe3fb3f9d04541ce51))
|
||||
* scalafix violations in metrics check and health monitor ([b991878](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b99187821489b296d66da5a5a13f5d545b6045c6))
|
||||
* scale up immediately when instance is lost ([43525d4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43525d41a3884c00f1db26bf3c8c4cd9a607c260))
|
||||
* streamline logging for evicted instances in InstanceRegistry ([10937e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10937e756a56e0e8fcf939decfdcaa4394506cc0))
|
||||
* update grpcServer variable to use Instance wrapper and add optional access method ([d5c8da2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d5c8da20f8805199e920ea5afbd9cdb39a078e40))
|
||||
* update HealthMonitor to evict instances without associated pods ([0f41f13](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0f41f13ce68b76846684bab67241a122250dfaf9))
|
||||
## (2026-05-17)
|
||||
|
||||
### Features
|
||||
|
||||
* add configurable CPU and memory scaling thresholds for auto-scaling ([a07bf89](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a07bf89fae43e3ef5fdd30aed0429742a95f8bbe))
|
||||
* add coordinator startup validation and K8s pod watch ([81b045d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/81b045d01bb054a4bc9dc9e02fc30f814e756205))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* add periodic health check to evict dead instances ([380a2cc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/380a2cceeb5873bf93ff17a1e87d62408ef8e178))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement clock expiry scanning and handling for game records ([#54](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/54)) ([2e4ba43](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2e4ba435978ef415b4ee2d7d2fc4af3b4e834b3d))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* scale up on high CPU load, not just subscription count ([255e2da](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/255e2da33c37e186ed14f2862f2d2e1b4adc59bf))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add instance-dead-timeout configuration and update HealthMonitor to use it for stale instance eviction ([be0b710](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/be0b710543b542da5c301efef7d2d587d0ba758a))
|
||||
* clean up code formatting and improve error handling in gRPC server and failover service ([ad9495a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ad9495afa3e93593b57154a187346c9b01393911))
|
||||
* coordinator auto-scaling, cache eviction, rebalancing, and grpc timeouts ([d0c7169](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d0c71693bb6f55fafdce5bcea0d5f38b9bb505ef))
|
||||
* **coordinator:** refine type casting in rolloutSpec method ([#45](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/45)) ([d522f7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d522f7f6edf9c985f03dd16816439d4184f1a589))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#43](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/43)) ([fa3c6b2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fa3c6b2886dc59c14c5dad834acc9b41e42023bb))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#44](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/44)) ([82d0b75](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/82d0b754be1075084944b466858672d944f9f7d8))
|
||||
* **dependencies:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
|
||||
* don't block event loop during scale-down drain ([1d121c7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1d121c727cbd4df477827cf64d065b7356a56e59))
|
||||
* don't trigger scale-down if already at min replicas ([4b3b5e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4b3b5e7c4ed9b3cd4fe2490e9f268f2e3a0d9e85))
|
||||
* enhance AutoScaler and InstanceRegistry for replica management and stale instance eviction ([b4920d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4920d3817e58bda94d7764e608b856ce9a909f7))
|
||||
* force-delete hanging pods and remove failed instances from registry ([960a419](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/960a419792e1161fb7241e465b7349efe4a10137))
|
||||
* improve pod instance ID matching logic in AutoScaler and HealthMonitor ([f109fe3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f109fe3860371dd0be3434b10a721936dc258b16))
|
||||
* linter formatting and improve code readability ([4a36096](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4a36096a5586e3f321d9c34c53e60d02bcc02c55))
|
||||
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* refresh Redis TTL on instance heartbeat to prevent false DEAD marking ([2d76c00](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2d76c001fe22868190a546f1794cf0ade36bb9a9))
|
||||
* remove corrupted instances immediately and evict dead instances ([43184d2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43184d296da5a6a7b760ac90c2b739220d86bce3))
|
||||
* remove redundant line break in LoadBalancer.scala for improved readability ([5205468](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/520546853447e0e0992b258c264272f8f7b8b438))
|
||||
* remove unused clearDrainingByPodName method and update HealthMonitor to clear draining instances ([1a02f9e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1a02f9e18673d0038e9a307fee5ea5219dc76af8))
|
||||
* replace null checks with Option in coordinator ([2b04d7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2b04d7fa713e06662bff5afe3fb3f9d04541ce51))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* scalafix violations in metrics check and health monitor ([b991878](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b99187821489b296d66da5a5a13f5d545b6045c6))
|
||||
* scale up immediately when instance is lost ([43525d4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43525d41a3884c00f1db26bf3c8c4cd9a607c260))
|
||||
* streamline logging for evicted instances in InstanceRegistry ([10937e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10937e756a56e0e8fcf939decfdcaa4394506cc0))
|
||||
* update grpcServer variable to use Instance wrapper and add optional access method ([d5c8da2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d5c8da20f8805199e920ea5afbd9cdb39a078e40))
|
||||
* update HealthMonitor to evict instances without associated pods ([0f41f13](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0f41f13ce68b76846684bab67241a122250dfaf9))
|
||||
## (2026-05-17)
|
||||
|
||||
### Features
|
||||
|
||||
* add configurable CPU and memory scaling thresholds for auto-scaling ([a07bf89](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a07bf89fae43e3ef5fdd30aed0429742a95f8bbe))
|
||||
* add coordinator startup validation and K8s pod watch ([81b045d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/81b045d01bb054a4bc9dc9e02fc30f814e756205))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* add periodic health check to evict dead instances ([380a2cc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/380a2cceeb5873bf93ff17a1e87d62408ef8e178))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement clock expiry scanning and handling for game records ([#54](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/54)) ([2e4ba43](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2e4ba435978ef415b4ee2d7d2fc4af3b4e834b3d))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* scale up on high CPU load, not just subscription count ([255e2da](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/255e2da33c37e186ed14f2862f2d2e1b4adc59bf))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add instance-dead-timeout configuration and update HealthMonitor to use it for stale instance eviction ([be0b710](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/be0b710543b542da5c301efef7d2d587d0ba758a))
|
||||
* clean up code formatting and improve error handling in gRPC server and failover service ([ad9495a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ad9495afa3e93593b57154a187346c9b01393911))
|
||||
* coordinator auto-scaling, cache eviction, rebalancing, and grpc timeouts ([d0c7169](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d0c71693bb6f55fafdce5bcea0d5f38b9bb505ef))
|
||||
* **coordinator:** refine type casting in rolloutSpec method ([#45](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/45)) ([d522f7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d522f7f6edf9c985f03dd16816439d4184f1a589))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#43](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/43)) ([fa3c6b2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fa3c6b2886dc59c14c5dad834acc9b41e42023bb))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#44](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/44)) ([82d0b75](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/82d0b754be1075084944b466858672d944f9f7d8))
|
||||
* correct pod matching logic from endsWith to contains ([6dbe1e6](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6dbe1e62ac74f4ddbf03049b20184f7fac793f81))
|
||||
* **dependencies:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
|
||||
* don't block event loop during scale-down drain ([1d121c7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1d121c727cbd4df477827cf64d065b7356a56e59))
|
||||
* don't trigger scale-down if already at min replicas ([4b3b5e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4b3b5e7c4ed9b3cd4fe2490e9f268f2e3a0d9e85))
|
||||
* enhance AutoScaler and InstanceRegistry for replica management and stale instance eviction ([b4920d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4920d3817e58bda94d7764e608b856ce9a909f7))
|
||||
* force-delete hanging pods and remove failed instances from registry ([960a419](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/960a419792e1161fb7241e465b7349efe4a10137))
|
||||
* improve pod instance ID matching logic in AutoScaler and HealthMonitor ([f109fe3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f109fe3860371dd0be3434b10a721936dc258b16))
|
||||
* linter formatting and improve code readability ([4a36096](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4a36096a5586e3f321d9c34c53e60d02bcc02c55))
|
||||
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* refresh Redis TTL on instance heartbeat to prevent false DEAD marking ([2d76c00](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2d76c001fe22868190a546f1794cf0ade36bb9a9))
|
||||
* remove corrupted instances immediately and evict dead instances ([43184d2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43184d296da5a6a7b760ac90c2b739220d86bce3))
|
||||
* remove redundant line break in LoadBalancer.scala for improved readability ([5205468](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/520546853447e0e0992b258c264272f8f7b8b438))
|
||||
* remove unused clearDrainingByPodName method and update HealthMonitor to clear draining instances ([1a02f9e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1a02f9e18673d0038e9a307fee5ea5219dc76af8))
|
||||
* replace null checks with Option in coordinator ([2b04d7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2b04d7fa713e06662bff5afe3fb3f9d04541ce51))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* scalafix violations in metrics check and health monitor ([b991878](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b99187821489b296d66da5a5a13f5d545b6045c6))
|
||||
* scale up immediately when instance is lost ([43525d4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43525d41a3884c00f1db26bf3c8c4cd9a607c260))
|
||||
* streamline logging for evicted instances in InstanceRegistry ([10937e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10937e756a56e0e8fcf939decfdcaa4394506cc0))
|
||||
* update grpcServer variable to use Instance wrapper and add optional access method ([d5c8da2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d5c8da20f8805199e920ea5afbd9cdb39a078e40))
|
||||
* update HealthMonitor to evict instances without associated pods ([0f41f13](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0f41f13ce68b76846684bab67241a122250dfaf9))
|
||||
## (2026-05-17)
|
||||
|
||||
### Features
|
||||
|
||||
* add configurable CPU and memory scaling thresholds for auto-scaling ([a07bf89](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a07bf89fae43e3ef5fdd30aed0429742a95f8bbe))
|
||||
* add coordinator startup validation and K8s pod watch ([81b045d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/81b045d01bb054a4bc9dc9e02fc30f814e756205))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* add periodic health check to evict dead instances ([380a2cc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/380a2cceeb5873bf93ff17a1e87d62408ef8e178))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement clock expiry scanning and handling for game records ([#54](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/54)) ([2e4ba43](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2e4ba435978ef415b4ee2d7d2fc4af3b4e834b3d))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* scale up on high CPU load, not just subscription count ([255e2da](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/255e2da33c37e186ed14f2862f2d2e1b4adc59bf))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add instance-dead-timeout configuration and update HealthMonitor to use it for stale instance eviction ([be0b710](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/be0b710543b542da5c301efef7d2d587d0ba758a))
|
||||
* clean up code formatting and improve error handling in gRPC server and failover service ([ad9495a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ad9495afa3e93593b57154a187346c9b01393911))
|
||||
* coordinator auto-scaling, cache eviction, rebalancing, and grpc timeouts ([d0c7169](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d0c71693bb6f55fafdce5bcea0d5f38b9bb505ef))
|
||||
* **coordinator:** refine type casting in rolloutSpec method ([#45](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/45)) ([d522f7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d522f7f6edf9c985f03dd16816439d4184f1a589))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#43](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/43)) ([fa3c6b2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fa3c6b2886dc59c14c5dad834acc9b41e42023bb))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#44](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/44)) ([82d0b75](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/82d0b754be1075084944b466858672d944f9f7d8))
|
||||
* correct pod matching logic from endsWith to contains ([6dbe1e6](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6dbe1e62ac74f4ddbf03049b20184f7fac793f81))
|
||||
* **dependencies:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
|
||||
* don't block event loop during scale-down drain ([1d121c7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1d121c727cbd4df477827cf64d065b7356a56e59))
|
||||
* don't trigger scale-down if already at min replicas ([4b3b5e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4b3b5e7c4ed9b3cd4fe2490e9f268f2e3a0d9e85))
|
||||
* enhance AutoScaler and InstanceRegistry for replica management and stale instance eviction ([b4920d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4920d3817e58bda94d7764e608b856ce9a909f7))
|
||||
* force-delete hanging pods and remove failed instances from registry ([960a419](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/960a419792e1161fb7241e465b7349efe4a10137))
|
||||
* improve pod instance ID matching logic in AutoScaler and HealthMonitor ([f109fe3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f109fe3860371dd0be3434b10a721936dc258b16))
|
||||
* linter formatting and improve code readability ([4a36096](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4a36096a5586e3f321d9c34c53e60d02bcc02c55))
|
||||
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* refresh Redis TTL on instance heartbeat to prevent false DEAD marking ([2d76c00](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2d76c001fe22868190a546f1794cf0ade36bb9a9))
|
||||
* remove corrupted instances immediately and evict dead instances ([43184d2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43184d296da5a6a7b760ac90c2b739220d86bce3))
|
||||
* remove redundant line break in LoadBalancer.scala for improved readability ([5205468](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/520546853447e0e0992b258c264272f8f7b8b438))
|
||||
* remove unused clearDrainingByPodName method and update HealthMonitor to clear draining instances ([1a02f9e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1a02f9e18673d0038e9a307fee5ea5219dc76af8))
|
||||
* replace null checks with Option in coordinator ([2b04d7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2b04d7fa713e06662bff5afe3fb3f9d04541ce51))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* revert pod matching to original logic instanceId.contains(podName) ([9bf995f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/9bf995f47d4dec19dd62ce2f7d52286ec2aa575f))
|
||||
* scalafix violations in metrics check and health monitor ([b991878](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b99187821489b296d66da5a5a13f5d545b6045c6))
|
||||
* scale up immediately when instance is lost ([43525d4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43525d41a3884c00f1db26bf3c8c4cd9a607c260))
|
||||
* streamline logging for evicted instances in InstanceRegistry ([10937e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10937e756a56e0e8fcf939decfdcaa4394506cc0))
|
||||
* update grpcServer variable to use Instance wrapper and add optional access method ([d5c8da2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d5c8da20f8805199e920ea5afbd9cdb39a078e40))
|
||||
* update HealthMonitor to evict instances without associated pods ([0f41f13](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0f41f13ce68b76846684bab67241a122250dfaf9))
|
||||
## (2026-05-18)
|
||||
|
||||
### Features
|
||||
|
||||
* add configurable CPU and memory scaling thresholds for auto-scaling ([a07bf89](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a07bf89fae43e3ef5fdd30aed0429742a95f8bbe))
|
||||
* add coordinator startup validation and K8s pod watch ([81b045d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/81b045d01bb054a4bc9dc9e02fc30f814e756205))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* add periodic health check to evict dead instances ([380a2cc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/380a2cceeb5873bf93ff17a1e87d62408ef8e178))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* force delete pod immediately on heartbeat loss ([a9f4606](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a9f4606b40fcaf9ec59fc2503a40054264bcbccf))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement clock expiry scanning and handling for game records ([#54](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/54)) ([2e4ba43](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2e4ba435978ef415b4ee2d7d2fc4af3b4e834b3d))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* scale up on high CPU load, not just subscription count ([255e2da](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/255e2da33c37e186ed14f2862f2d2e1b4adc59bf))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add instance-dead-timeout configuration and update HealthMonitor to use it for stale instance eviction ([be0b710](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/be0b710543b542da5c301efef7d2d587d0ba758a))
|
||||
* clean up code formatting and improve error handling in gRPC server and failover service ([ad9495a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ad9495afa3e93593b57154a187346c9b01393911))
|
||||
* coordinator auto-scaling, cache eviction, rebalancing, and grpc timeouts ([d0c7169](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d0c71693bb6f55fafdce5bcea0d5f38b9bb505ef))
|
||||
* **coordinator:** refine type casting in rolloutSpec method ([#45](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/45)) ([d522f7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d522f7f6edf9c985f03dd16816439d4184f1a589))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#43](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/43)) ([fa3c6b2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fa3c6b2886dc59c14c5dad834acc9b41e42023bb))
|
||||
* **coordinator:** use genericKubernetesResources API for Argo Rollout scaling ([#44](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/44)) ([82d0b75](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/82d0b754be1075084944b466858672d944f9f7d8))
|
||||
* correct pod matching logic from endsWith to contains ([6dbe1e6](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6dbe1e62ac74f4ddbf03049b20184f7fac793f81))
|
||||
* **dependencies:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
|
||||
* don't block event loop during scale-down drain ([1d121c7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1d121c727cbd4df477827cf64d065b7356a56e59))
|
||||
* don't trigger scale-down if already at min replicas ([4b3b5e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4b3b5e7c4ed9b3cd4fe2490e9f268f2e3a0d9e85))
|
||||
* enhance AutoScaler and InstanceRegistry for replica management and stale instance eviction ([b4920d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4920d3817e58bda94d7764e608b856ce9a909f7))
|
||||
* force-delete hanging pods and remove failed instances from registry ([960a419](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/960a419792e1161fb7241e465b7349efe4a10137))
|
||||
* improve pod instance ID matching logic in AutoScaler and HealthMonitor ([f109fe3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f109fe3860371dd0be3434b10a721936dc258b16))
|
||||
* linter formatting and improve code readability ([4a36096](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4a36096a5586e3f321d9c34c53e60d02bcc02c55))
|
||||
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* refresh Redis TTL on instance heartbeat to prevent false DEAD marking ([2d76c00](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2d76c001fe22868190a546f1794cf0ade36bb9a9))
|
||||
* remove corrupted instances immediately and evict dead instances ([43184d2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43184d296da5a6a7b760ac90c2b739220d86bce3))
|
||||
* remove redundant line break in LoadBalancer.scala for improved readability ([5205468](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/520546853447e0e0992b258c264272f8f7b8b438))
|
||||
* remove unused clearDrainingByPodName method and update HealthMonitor to clear draining instances ([1a02f9e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1a02f9e18673d0038e9a307fee5ea5219dc76af8))
|
||||
* replace null checks with Option in coordinator ([2b04d7f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2b04d7fa713e06662bff5afe3fb3f9d04541ce51))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* revert pod matching to original logic instanceId.contains(podName) ([9bf995f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/9bf995f47d4dec19dd62ce2f7d52286ec2aa575f))
|
||||
* scalafix violations in metrics check and health monitor ([b991878](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b99187821489b296d66da5a5a13f5d545b6045c6))
|
||||
* scale up immediately when instance is lost ([43525d4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/43525d41a3884c00f1db26bf3c8c4cd9a607c260))
|
||||
* streamline logging for evicted instances in InstanceRegistry ([10937e7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/10937e756a56e0e8fcf939decfdcaa4394506cc0))
|
||||
* update grpcServer variable to use Instance wrapper and add optional access method ([d5c8da2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d5c8da20f8805199e920ea5afbd9cdb39a078e40))
|
||||
* update HealthMonitor to evict instances without associated pods ([0f41f13](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0f41f13ce68b76846684bab67241a122250dfaf9))
|
||||
|
||||
@@ -47,6 +47,8 @@ nowchess:
|
||||
k8s-rollout-label-selector: "app=nowchess-core"
|
||||
startup-validation-timeout: 15s
|
||||
failover-wait-timeout: 30s
|
||||
scale-cpu-threshold-percent: 0.8
|
||||
scale-memory-threshold-percent: 0.8
|
||||
|
||||
---
|
||||
# dev profile
|
||||
|
||||
+6
@@ -62,3 +62,9 @@ trait CoordinatorConfig:
|
||||
|
||||
@WithName("failover-wait-timeout")
|
||||
def failoverWaitTimeout: Duration
|
||||
|
||||
@WithName("scale-cpu-threshold-percent")
|
||||
def scaleCpuThresholdPercent: Double
|
||||
|
||||
@WithName("scale-memory-threshold-percent")
|
||||
def scaleMemoryThresholdPercent: Double
|
||||
|
||||
+183
-103
@@ -10,9 +10,11 @@ import io.fabric8.kubernetes.client.KubernetesClient
|
||||
import io.micrometer.core.instrument.{Gauge, MeterRegistry}
|
||||
import io.quarkus.scheduler.Scheduled
|
||||
import org.jboss.logging.Logger
|
||||
import io.fabric8.kubernetes.client.KubernetesClientException
|
||||
import scala.jdk.CollectionConverters.*
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import scala.compiletime.uninitialized
|
||||
|
||||
@ApplicationScoped
|
||||
@@ -37,9 +39,16 @@ class AutoScaler:
|
||||
private var meterRegistry: MeterRegistry = uninitialized
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private val log = Logger.getLogger(classOf[AutoScaler])
|
||||
private val lastScaleTime = new java.util.concurrent.atomic.AtomicLong(0L)
|
||||
private val avgLoadRef = new AtomicReference[Double](0.0)
|
||||
private val log = Logger.getLogger(classOf[AutoScaler])
|
||||
private val lastScaleTime = new java.util.concurrent.atomic.AtomicLong(0L)
|
||||
private val avgLoadRef = new AtomicReference[Double](0.0)
|
||||
private val drainingForScaleDown = ConcurrentHashMap.newKeySet[String]()
|
||||
|
||||
def isDrainingForScaleDown(instanceId: String): Boolean =
|
||||
drainingForScaleDown.contains(instanceId)
|
||||
|
||||
def clearDraining(instanceId: String): Unit =
|
||||
drainingForScaleDown.remove(instanceId)
|
||||
|
||||
private def kubeClientOpt: Option[KubernetesClient] =
|
||||
if kubeClientInstance.isUnsatisfied then None
|
||||
@@ -72,33 +81,81 @@ class AutoScaler:
|
||||
}
|
||||
// scalafix:on DisableSyntax.asInstanceOf
|
||||
|
||||
private def parseMillicores(s: String): Long =
|
||||
if s.endsWith("n") then s.dropRight(1).toLongOption.map(_ / 1000000).getOrElse(0L)
|
||||
else if s.endsWith("m") then s.dropRight(1).toLongOption.getOrElse(0L)
|
||||
else s.toLongOption.map(_ * 1000).getOrElse(0L)
|
||||
|
||||
private def parseBytes(s: String): Long =
|
||||
if s.endsWith("Ki") then s.dropRight(2).toLongOption.map(_ * 1024L).getOrElse(0L)
|
||||
else if s.endsWith("Mi") then s.dropRight(2).toLongOption.map(_ * 1024L * 1024L).getOrElse(0L)
|
||||
else if s.endsWith("Gi") then s.dropRight(2).toLongOption.map(_ * 1024L * 1024L * 1024L).getOrElse(0L)
|
||||
else if s.endsWith("K") then s.dropRight(1).toLongOption.map(_ * 1000L).getOrElse(0L)
|
||||
else if s.endsWith("M") then s.dropRight(1).toLongOption.map(_ * 1000L * 1000L).getOrElse(0L)
|
||||
else if s.endsWith("G") then s.dropRight(1).toLongOption.map(_ * 1000L * 1000L * 1000L).getOrElse(0L)
|
||||
else s.toLongOption.getOrElse(0L)
|
||||
|
||||
private def exceedsRatio(
|
||||
used: Long,
|
||||
request: Long,
|
||||
threshold: Double,
|
||||
resource: String,
|
||||
instanceId: String,
|
||||
): Boolean =
|
||||
if request <= 0 then false
|
||||
else
|
||||
val ratio = used.toDouble / request.toDouble
|
||||
log.debugf(
|
||||
"Instance %s %s: %d used / %d requested = %.0f%%",
|
||||
instanceId,
|
||||
resource,
|
||||
used,
|
||||
request,
|
||||
ratio * 100,
|
||||
)
|
||||
ratio > threshold
|
||||
|
||||
// scalafix:off DisableSyntax.asInstanceOf
|
||||
private def isResourceConstrained(instanceId: String): Boolean =
|
||||
kubeClientOpt.fold(false) { kube =>
|
||||
try
|
||||
val pods =
|
||||
kube.pods().inNamespace(config.k8sNamespace).withLabel(config.k8sRolloutLabelSelector).list().getItems.asScala
|
||||
pods.find(_.getMetadata.getName.contains(instanceId)).exists { pod =>
|
||||
pods.find(pod => instanceId.contains(pod.getMetadata.getName)).exists { pod =>
|
||||
try
|
||||
val metricsRes = kube
|
||||
.genericKubernetesResources(metricsApiVersion, "PodMetrics")
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.withName(pod.getMetadata.getName)
|
||||
.get()
|
||||
val metricsMap = metricsRes.asInstanceOf[java.util.Map[String, AnyRef]]
|
||||
Option(metricsMap.get("metrics"))
|
||||
.map(_.asInstanceOf[java.util.Map[String, AnyRef]])
|
||||
.flatMap(m => Option(m.get("containers")).map(_.asInstanceOf[java.util.List[AnyRef]]))
|
||||
.filter(!_.isEmpty)
|
||||
.map(_.get(0).asInstanceOf[java.util.Map[String, AnyRef]])
|
||||
.flatMap(c => Option(c.get("usage")).map(_.asInstanceOf[java.util.Map[String, AnyRef]]))
|
||||
.flatMap(u => Option(u.get("cpu")))
|
||||
.map(_.toString)
|
||||
.exists { cpuStr =>
|
||||
val cpuMillis =
|
||||
if cpuStr.endsWith("m") then cpuStr.dropRight(1).toLongOption.getOrElse(0L)
|
||||
else cpuStr.toLongOption.map(_ * 1000).getOrElse(0L)
|
||||
cpuMillis > 800
|
||||
val requests = Option(pod.getSpec)
|
||||
.flatMap(s => Option(s.getContainers))
|
||||
.flatMap(cs => if cs.isEmpty then None else Option(cs.get(0)))
|
||||
.flatMap(c => Option(c.getResources))
|
||||
.flatMap(r => Option(r.getRequests))
|
||||
|
||||
val cpuRequestMillis =
|
||||
requests.flatMap(m => Option(m.get("cpu"))).map(q => parseMillicores(q.toString)).getOrElse(0L)
|
||||
val memRequestBytes =
|
||||
requests.flatMap(m => Option(m.get("memory"))).map(q => parseBytes(q.toString)).getOrElse(0L)
|
||||
|
||||
if cpuRequestMillis <= 0 && memRequestBytes <= 0 then
|
||||
log.debugf("No resource requests found for instance %s, skipping resource check", instanceId)
|
||||
false
|
||||
else
|
||||
val metricsRes = kube
|
||||
.genericKubernetesResources(metricsApiVersion, "PodMetrics")
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.withName(pod.getMetadata.getName)
|
||||
.get()
|
||||
val metricsMap = metricsRes.asInstanceOf[java.util.Map[String, AnyRef]]
|
||||
val usageOpt = Option(metricsMap.get("metrics"))
|
||||
.map(_.asInstanceOf[java.util.Map[String, AnyRef]])
|
||||
.flatMap(m => Option(m.get("containers")).map(_.asInstanceOf[java.util.List[AnyRef]]))
|
||||
.filter(!_.isEmpty)
|
||||
.map(_.get(0).asInstanceOf[java.util.Map[String, AnyRef]])
|
||||
.flatMap(c => Option(c.get("usage")).map(_.asInstanceOf[java.util.Map[String, AnyRef]]))
|
||||
|
||||
usageOpt.exists { usage =>
|
||||
val cpuUsed = Option(usage.get("cpu")).map(v => parseMillicores(v.toString)).getOrElse(0L)
|
||||
val memUsed = Option(usage.get("memory")).map(v => parseBytes(v.toString)).getOrElse(0L)
|
||||
exceedsRatio(cpuUsed, cpuRequestMillis, config.scaleCpuThresholdPercent, "CPU", instanceId) ||
|
||||
exceedsRatio(memUsed, memRequestBytes, config.scaleMemoryThresholdPercent, "memory", instanceId)
|
||||
}
|
||||
catch case _: Exception => false
|
||||
}
|
||||
@@ -116,58 +173,88 @@ class AutoScaler:
|
||||
if now - last >= 120000 && lastScaleTime.compareAndSet(last, now) then
|
||||
val instances = instanceRegistry.getAllInstances.filter(_.state == "HEALTHY")
|
||||
if instances.nonEmpty then
|
||||
val avgLoad = instances.map(_.subscriptionCount).sum.toDouble / instances.size
|
||||
val avgLoad = instances.map(_.subscriptionCount).sum.toDouble / instances.size
|
||||
val scaleUpLoad = config.scaleUpThreshold * config.maxGamesPerCore
|
||||
val scaleDownLoad = config.scaleDownThreshold * config.maxGamesPerCore
|
||||
avgLoadRef.set(avgLoad)
|
||||
|
||||
val hasHighCpuOrMemory = instances.exists(inst => isResourceConstrained(inst.instanceId))
|
||||
val constrainedInstance = instances.find(inst => isResourceConstrained(inst.instanceId))
|
||||
val hasHighCpuOrMemory = constrainedInstance.isDefined
|
||||
|
||||
if avgLoad > config.scaleUpThreshold * config.maxGamesPerCore || hasHighCpuOrMemory then scaleUp()
|
||||
else if avgLoad < config.scaleDownThreshold * config.maxGamesPerCore && instances.size > config.scaleMinReplicas
|
||||
log.infof(
|
||||
"Scale check: instances=%d avgLoad=%.1f resourceConstrained=%s",
|
||||
instances.size,
|
||||
avgLoad,
|
||||
constrainedInstance.map(_.instanceId).getOrElse("none"),
|
||||
)
|
||||
|
||||
if hasHighCpuOrMemory then scaleUp()
|
||||
if !hasHighCpuOrMemory && avgLoad < scaleDownLoad && instances.size > config.scaleMinReplicas
|
||||
then scaleDown()
|
||||
|
||||
private def patchRolloutReplicas(
|
||||
kube: KubernetesClient,
|
||||
direction: String,
|
||||
delta: Int,
|
||||
canScale: Int => Boolean,
|
||||
atLimit: Int => Unit,
|
||||
onSuccess: (Int, Int) => Unit,
|
||||
maxRetries: Int = 3,
|
||||
): Unit =
|
||||
def attempt(retries: Int): Unit =
|
||||
try
|
||||
Option(
|
||||
kube
|
||||
.genericKubernetesResources(argoApiVersion, argoKind)
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.withName(config.k8sRolloutName)
|
||||
.get(),
|
||||
).foreach { rollout =>
|
||||
rolloutSpec(rollout).foreach { spec =>
|
||||
spec.get("replicas") match
|
||||
case current: Integer =>
|
||||
val n = current.intValue()
|
||||
if !canScale(n) then atLimit(n)
|
||||
else
|
||||
spec.put("replicas", Integer.valueOf(n + delta))
|
||||
kube
|
||||
.genericKubernetesResources(argoApiVersion, argoKind)
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.resource(rollout)
|
||||
.update()
|
||||
meterRegistry.counter("nowchess.coordinator.scale.events", "direction", direction).increment()
|
||||
onSuccess(n, n + delta)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
catch
|
||||
case ex: KubernetesClientException if ex.getCode == 409 =>
|
||||
if retries > 0 then
|
||||
log.debugf("Conflict scaling %s %s, retrying (%d left)", direction, config.k8sRolloutName, retries - 1)
|
||||
attempt(retries - 1)
|
||||
else
|
||||
meterRegistry.counter("nowchess.coordinator.scale.failures", "direction", direction).increment()
|
||||
log.errorf(ex, "Failed to scale %s %s after conflict retries", direction, config.k8sRolloutName)
|
||||
case ex: Exception =>
|
||||
meterRegistry.counter("nowchess.coordinator.scale.failures", "direction", direction).increment()
|
||||
log.errorf(ex, "Failed to scale %s %s", direction, config.k8sRolloutName)
|
||||
attempt(maxRetries)
|
||||
|
||||
def scaleUp(): Unit =
|
||||
log.info("Scaling up Argo Rollout")
|
||||
kubeClientOpt match
|
||||
case None =>
|
||||
log.warn("Kubernetes client not available, cannot scale")
|
||||
case None => log.warn("Kubernetes client not available, cannot scale")
|
||||
case Some(kube) =>
|
||||
try
|
||||
Option(
|
||||
kube
|
||||
.genericKubernetesResources(argoApiVersion, argoKind)
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.withName(config.k8sRolloutName)
|
||||
.get(),
|
||||
).foreach { rollout =>
|
||||
rolloutSpec(rollout).foreach { spec =>
|
||||
spec.get("replicas") match
|
||||
case replicas: Integer =>
|
||||
val currentReplicas = replicas.intValue()
|
||||
val maxReplicas = config.scaleMaxReplicas
|
||||
|
||||
if currentReplicas < maxReplicas then
|
||||
spec.put("replicas", Integer.valueOf(currentReplicas + 1))
|
||||
kube
|
||||
.genericKubernetesResources(argoApiVersion, argoKind)
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.resource(rollout)
|
||||
.update()
|
||||
meterRegistry.counter("nowchess.coordinator.scale.events", "direction", "up").increment()
|
||||
log.infof(
|
||||
"Scaled up %s from %d to %d replicas",
|
||||
config.k8sRolloutName,
|
||||
currentReplicas,
|
||||
currentReplicas + 1,
|
||||
)
|
||||
loadBalancer.rebalance
|
||||
else log.infof("Already at max replicas %d for %s", maxReplicas, config.k8sRolloutName)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
catch
|
||||
case ex: Exception =>
|
||||
meterRegistry.counter("nowchess.coordinator.scale.failures", "direction", "up").increment()
|
||||
log.errorf(ex, "Failed to scale up %s", config.k8sRolloutName)
|
||||
patchRolloutReplicas(
|
||||
kube,
|
||||
direction = "up",
|
||||
delta = 1,
|
||||
canScale = _ < config.scaleMaxReplicas,
|
||||
atLimit = n => log.infof("Already at max replicas %d for %s", n, config.k8sRolloutName),
|
||||
onSuccess = (from, to) =>
|
||||
log.infof("Scaled up %s from %d to %d replicas", config.k8sRolloutName, from, to)
|
||||
loadBalancer.rebalance,
|
||||
)
|
||||
|
||||
def scaleDown(): Unit =
|
||||
log.info("Scaling down Argo Rollout")
|
||||
@@ -177,6 +264,7 @@ class AutoScaler:
|
||||
|
||||
underloadedInstance.foreach { inst =>
|
||||
log.infof("Marking instance %s for drain before scale-down", inst.instanceId)
|
||||
drainingForScaleDown.add(inst.instanceId)
|
||||
failoverService
|
||||
.onInstanceStreamDropped(inst.instanceId)
|
||||
.subscribe()
|
||||
@@ -187,42 +275,34 @@ class AutoScaler:
|
||||
}
|
||||
|
||||
kubeClientOpt match
|
||||
case None =>
|
||||
log.warn("Kubernetes client not available, cannot scale")
|
||||
case None => log.warn("Kubernetes client not available, cannot scale")
|
||||
case Some(kube) =>
|
||||
try
|
||||
Option(
|
||||
kube
|
||||
.genericKubernetesResources(argoApiVersion, argoKind)
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.withName(config.k8sRolloutName)
|
||||
.get(),
|
||||
).foreach { rollout =>
|
||||
rolloutSpec(rollout).foreach { spec =>
|
||||
spec.get("replicas") match
|
||||
case replicas: Integer =>
|
||||
val currentReplicas = replicas.intValue()
|
||||
val minReplicas = config.scaleMinReplicas
|
||||
patchRolloutReplicas(
|
||||
kube,
|
||||
direction = "down",
|
||||
delta = -1,
|
||||
canScale = _ > config.scaleMinReplicas,
|
||||
atLimit = n => log.infof("Already at min replicas %d for %s", n, config.k8sRolloutName),
|
||||
onSuccess = (from, to) =>
|
||||
log.infof("Scaled down %s from %d to %d replicas", config.k8sRolloutName, from, to)
|
||||
underloadedInstance.foreach(inst => forceDeletePod(inst.instanceId, kube)),
|
||||
)
|
||||
|
||||
if currentReplicas > minReplicas then
|
||||
spec.put("replicas", Integer.valueOf(currentReplicas - 1))
|
||||
kube
|
||||
.genericKubernetesResources(argoApiVersion, argoKind)
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.resource(rollout)
|
||||
.update()
|
||||
meterRegistry.counter("nowchess.coordinator.scale.events", "direction", "down").increment()
|
||||
log.infof(
|
||||
"Scaled down %s from %d to %d replicas",
|
||||
config.k8sRolloutName,
|
||||
currentReplicas,
|
||||
currentReplicas - 1,
|
||||
)
|
||||
else log.infof("Already at min replicas %d for %s", minReplicas, config.k8sRolloutName)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
catch
|
||||
case ex: Exception =>
|
||||
meterRegistry.counter("nowchess.coordinator.scale.failures", "direction", "down").increment()
|
||||
log.errorf(ex, "Failed to scale down %s", config.k8sRolloutName)
|
||||
private def forceDeletePod(instanceId: String, kube: KubernetesClient): Unit =
|
||||
try
|
||||
val pods = kube
|
||||
.pods()
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.withLabel(config.k8sRolloutLabelSelector)
|
||||
.list()
|
||||
.getItems
|
||||
.asScala
|
||||
pods.find(pod => instanceId.contains(pod.getMetadata.getName)) match
|
||||
case Some(pod) =>
|
||||
kube.pods().inNamespace(config.k8sNamespace).withName(pod.getMetadata.getName).withGracePeriod(0L).delete()
|
||||
log.infof("Force-deleted pod for drained instance %s", instanceId)
|
||||
case None =>
|
||||
log.debugf("No pod found for drained instance %s, skipping deletion", instanceId)
|
||||
catch
|
||||
case ex: Exception =>
|
||||
log.warnf(ex, "Failed to force-delete pod for drained instance %s", instanceId)
|
||||
|
||||
+9
-7
@@ -75,6 +75,7 @@ class CacheEvictionManager:
|
||||
try
|
||||
coreGrpcClient.evictGames(instance.hostname, instance.grpcPort, List(gameId))
|
||||
redis.key(classOf[String]).del(key)
|
||||
redis.key(classOf[String]).del(s"$redisPrefix:game:$gameId:instance")
|
||||
meterRegistry.counter("nowchess.coordinator.cache.evictions").increment()
|
||||
log.infof("Evicted idle game %s from %s", gameId, instance.instanceId)
|
||||
count + 1
|
||||
@@ -96,17 +97,18 @@ class CacheEvictionManager:
|
||||
private def extractLastUpdatedTimestamp(json: String): Long =
|
||||
Try {
|
||||
val parsed = objectMapper.readTree(json)
|
||||
Option(parsed.get("lastHeartbeat"))
|
||||
.filter(_.isTextual)
|
||||
.fold(0L)(lh => Instant.parse(lh.asText()).toEpochMilli)
|
||||
Option(parsed.get("lastUpdatedMs"))
|
||||
.filter(_.isNumber)
|
||||
.fold(0L)(_.asLong())
|
||||
}.getOrElse(0L)
|
||||
|
||||
private def findInstanceWithGame(gameId: String): Option[de.nowchess.coordinator.dto.InstanceMetadata] =
|
||||
try
|
||||
instanceRegistry.getAllInstances.find { instance =>
|
||||
val setKey = s"$redisPrefix:instance:${instance.instanceId}:games"
|
||||
redis.set(classOf[String]).sismember(setKey, gameId)
|
||||
}
|
||||
val mapKey = s"$redisPrefix:game:$gameId:instance"
|
||||
Option(redis.value(classOf[String]).get(mapKey))
|
||||
.flatMap { instanceId =>
|
||||
instanceRegistry.getInstance(instanceId)
|
||||
}
|
||||
catch
|
||||
case ex: Exception =>
|
||||
log.debugf(ex, "Failed to find instance for game %s", gameId)
|
||||
|
||||
+48
@@ -1,6 +1,7 @@
|
||||
package de.nowchess.coordinator.service
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.enterprise.inject.Instance
|
||||
import jakarta.inject.Inject
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import scala.jdk.CollectionConverters.*
|
||||
@@ -9,6 +10,7 @@ import org.jboss.logging.Logger
|
||||
import de.nowchess.coordinator.dto.InstanceMetadata
|
||||
import de.nowchess.coordinator.grpc.CoreGrpcClient
|
||||
import de.nowchess.coordinator.config.CoordinatorConfig
|
||||
import io.fabric8.kubernetes.client.KubernetesClient
|
||||
import io.smallrye.mutiny.Uni
|
||||
import java.time.Duration
|
||||
|
||||
@@ -27,10 +29,17 @@ class FailoverService:
|
||||
@Inject
|
||||
private var config: CoordinatorConfig = uninitialized
|
||||
|
||||
@Inject
|
||||
private var kubeClientInstance: Instance[KubernetesClient] = uninitialized
|
||||
|
||||
private val log = Logger.getLogger(classOf[FailoverService])
|
||||
private var redisPrefix = "nowchess"
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private def kubeClientOpt: Option[KubernetesClient] =
|
||||
if kubeClientInstance.isUnsatisfied then None
|
||||
else Some(kubeClientInstance.get())
|
||||
|
||||
def setRedisPrefix(prefix: String): Unit =
|
||||
redisPrefix = prefix
|
||||
|
||||
@@ -39,6 +48,7 @@ class FailoverService:
|
||||
|
||||
val startTime = System.currentTimeMillis()
|
||||
instanceRegistry.markInstanceDead(instanceId)
|
||||
deleteK8sPod(instanceId)
|
||||
|
||||
val gameIds = getOrphanedGames(instanceId)
|
||||
log.infof("Found %d orphaned games for instance %s", gameIds.size, instanceId)
|
||||
@@ -107,6 +117,7 @@ class FailoverService:
|
||||
try
|
||||
val subscribed = coreGrpcClient.batchResubscribeGames(target.hostname, target.grpcPort, batch)
|
||||
if subscribed > 0 then
|
||||
updateGameInstanceMappings(batch, deadId, target.instanceId)
|
||||
log.infof("Migrated %d games from %s to %s", subscribed, deadId, target.instanceId)
|
||||
true
|
||||
else false
|
||||
@@ -116,6 +127,43 @@ class FailoverService:
|
||||
false
|
||||
if success then true else tryMigrateBatch(batch, batchIdx, instances, deadId, attempt + 1)
|
||||
|
||||
private def updateGameInstanceMappings(gameIds: List[String], deadId: String, targetId: String): Unit =
|
||||
try
|
||||
val fromKey = s"$redisPrefix:instance:$deadId:games"
|
||||
val toKey = s"$redisPrefix:instance:$targetId:games"
|
||||
gameIds.foreach { gameId =>
|
||||
redis.set(classOf[String]).sadd(toKey, gameId)
|
||||
redis.value(classOf[String]).set(s"$redisPrefix:game:$gameId:instance", targetId)
|
||||
}
|
||||
catch
|
||||
case ex: Exception =>
|
||||
log.errorf(ex, "Failed to update game instance mappings")
|
||||
|
||||
private def deleteK8sPod(instanceId: String): Unit =
|
||||
kubeClientOpt match
|
||||
case None =>
|
||||
log.debugf("Kubernetes client not available, skipping pod deletion for %s", instanceId)
|
||||
case Some(kube) =>
|
||||
try
|
||||
val pods = kube
|
||||
.pods()
|
||||
.inNamespace(config.k8sNamespace)
|
||||
.withLabel(config.k8sRolloutLabelSelector)
|
||||
.list()
|
||||
.getItems
|
||||
.asScala
|
||||
|
||||
pods.find(pod => instanceId.contains(pod.getMetadata.getName)) match
|
||||
case Some(pod) =>
|
||||
val podName = pod.getMetadata.getName
|
||||
kube.pods().inNamespace(config.k8sNamespace).withName(podName).withGracePeriod(0L).delete()
|
||||
log.infof("Force-deleted pod %s for dead instance %s", podName, instanceId)
|
||||
case None =>
|
||||
log.debugf("No pod found for instance %s, skipping deletion", instanceId)
|
||||
catch
|
||||
case ex: Exception =>
|
||||
log.errorf(ex, "Failed to delete pod for instance %s", instanceId)
|
||||
|
||||
private def cleanupDeadInstance(instanceId: String): Unit =
|
||||
val setKey = s"$redisPrefix:instance:$instanceId:games"
|
||||
redis.key(classOf[String]).del(setKey)
|
||||
|
||||
+6
-10
@@ -88,7 +88,7 @@ class HealthMonitor:
|
||||
if evicted.nonEmpty then
|
||||
log.warnf("Evicted %d stale instances: %s", evicted.size, evicted.mkString(", "))
|
||||
evicted.foreach(deleteK8sPod)
|
||||
autoScaler.scaleUp()
|
||||
evicted.foreach(autoScaler.clearDraining)
|
||||
val instances = instanceRegistry.getAllInstances
|
||||
val failed = instances.collect { inst =>
|
||||
val isHealthy = checkHealth(inst.instanceId)
|
||||
@@ -99,7 +99,6 @@ class HealthMonitor:
|
||||
Some(inst.instanceId)
|
||||
else None
|
||||
}.flatten
|
||||
if failed.nonEmpty then autoScaler.scaleUp()
|
||||
|
||||
private def checkHealth(instanceId: String): Boolean =
|
||||
val redisHealthy = checkRedisHeartbeat(instanceId)
|
||||
@@ -128,7 +127,7 @@ class HealthMonitor:
|
||||
|
||||
pods.exists { pod =>
|
||||
val podName = pod.getMetadata.getName
|
||||
podName.contains(instanceId) && isPodReady(pod)
|
||||
instanceId.contains(podName) && isPodReady(pod)
|
||||
}
|
||||
catch
|
||||
case ex: Exception =>
|
||||
@@ -182,7 +181,7 @@ class HealthMonitor:
|
||||
.getItems
|
||||
.asScala
|
||||
|
||||
pods.find(pod => pod.getMetadata.getName.contains(instanceId)) match
|
||||
pods.find(pod => instanceId.contains(pod.getMetadata.getName)) match
|
||||
case Some(pod) =>
|
||||
val podName = pod.getMetadata.getName
|
||||
kube.pods().inNamespace(config.k8sNamespace).withName(podName).withGracePeriod(0L).delete()
|
||||
@@ -227,12 +226,9 @@ class HealthMonitor:
|
||||
}
|
||||
|
||||
private def handlePodGone(pod: Pod): Unit =
|
||||
val podName = pod.getMetadata.getName
|
||||
findRegisteredInstance(pod).foreach { inst =>
|
||||
log.warnf(
|
||||
"Pod %s deleted — triggering failover for %s",
|
||||
pod.getMetadata.getName,
|
||||
inst.instanceId,
|
||||
)
|
||||
log.warnf("Pod %s deleted — triggering failover for %s", podName, inst.instanceId)
|
||||
failoverService
|
||||
.onInstanceStreamDropped(inst.instanceId)
|
||||
.subscribe()
|
||||
@@ -244,4 +240,4 @@ class HealthMonitor:
|
||||
|
||||
private def findRegisteredInstance(pod: Pod): Option[InstanceMetadata] =
|
||||
val podName = pod.getMetadata.getName
|
||||
instanceRegistry.getAllInstances.find(inst => podName.contains(inst.instanceId))
|
||||
instanceRegistry.getAllInstances.find(inst => inst.instanceId.contains(podName))
|
||||
|
||||
+11
-1
@@ -9,6 +9,7 @@ import scala.jdk.CollectionConverters.*
|
||||
import scala.compiletime.uninitialized
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.nowchess.coordinator.dto.InstanceMetadata
|
||||
import de.nowchess.coordinator.config.CoordinatorConfig
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.time.{Duration, Instant}
|
||||
import io.micrometer.core.instrument.{Gauge, MeterRegistry}
|
||||
@@ -27,6 +28,9 @@ class InstanceRegistry:
|
||||
|
||||
@Inject
|
||||
private var meterRegistry: MeterRegistry = uninitialized
|
||||
|
||||
@Inject
|
||||
private var config: CoordinatorConfig = uninitialized
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private val log = Logger.getLogger(classOf[InstanceRegistry])
|
||||
@@ -95,7 +99,13 @@ class InstanceRegistry:
|
||||
metadata.subscriptionCount,
|
||||
metadata.state,
|
||||
)
|
||||
Uni.createFrom().item(())
|
||||
val ttlMs = config.heartbeatTtl.toMillis
|
||||
redis
|
||||
.key(classOf[String])
|
||||
.pexpire(key, ttlMs)
|
||||
.map(_ => ())
|
||||
.onFailure()
|
||||
.recoverWithItem(())
|
||||
}
|
||||
catch
|
||||
case ex: Exception =>
|
||||
|
||||
+6
-6
@@ -69,7 +69,7 @@ class LoadBalancer:
|
||||
|
||||
val overloaded = instances
|
||||
.filter(_.subscriptionCount > config.maxGamesPerCore)
|
||||
.sortBy[Int](_.subscriptionCount)
|
||||
.sortBy(_.subscriptionCount)
|
||||
.reverse
|
||||
val underloaded = instances
|
||||
.filter(_.subscriptionCount < avgLoad * 0.8)
|
||||
@@ -108,7 +108,9 @@ class LoadBalancer:
|
||||
private def getGamesToMove(instanceId: String, count: Int): List[String] =
|
||||
try
|
||||
val setKey = s"$redisPrefix:instance:$instanceId:games"
|
||||
redis.set(classOf[String]).smembers(setKey).asScala.toList.take(count)
|
||||
val result = scala.collection.mutable.ListBuffer[String]()
|
||||
for _ <- 0 until count do Option(redis.set(classOf[String]).spop(setKey)).foreach(result += _)
|
||||
result.toList
|
||||
catch
|
||||
case ex: Exception =>
|
||||
log.debugf(ex, "Failed to get games for %s", instanceId)
|
||||
@@ -116,12 +118,10 @@ class LoadBalancer:
|
||||
|
||||
private def updateRedisGameSets(fromInstanceId: String, toInstanceId: String, gameIds: List[String]): Unit =
|
||||
try
|
||||
val fromKey = s"$redisPrefix:instance:$fromInstanceId:games"
|
||||
val toKey = s"$redisPrefix:instance:$toInstanceId:games"
|
||||
|
||||
val toKey = s"$redisPrefix:instance:$toInstanceId:games"
|
||||
gameIds.foreach { gameId =>
|
||||
redis.set(classOf[String]).srem(fromKey, gameId)
|
||||
redis.set(classOf[String]).sadd(toKey, gameId)
|
||||
redis.value(classOf[String]).set(s"$redisPrefix:game:$gameId:instance", toInstanceId)
|
||||
}
|
||||
catch
|
||||
case ex: Exception =>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=24
|
||||
MINOR=32
|
||||
PATCH=0
|
||||
|
||||
@@ -1434,3 +1434,535 @@
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-05-16)
|
||||
|
||||
### Features
|
||||
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add CORS configuration and reorder JWT settings in application.yml ([a49f9be](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a49f9be146f04c14561c305d980846a92f8c12b2))
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-40 Rework Draw System ([#34](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/34)) ([33e785d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e785d22af87724839b62ae91dfe74a05b398c3))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* NCS-53 changed IO to MicroService for easier scaling ([#37](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/37)) ([b5a2966](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b5a2966adafa9650f0f7d601bdeb8fdd13710327))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-78 Add Traceability to the Applications ([#48](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/48)) ([c96a09b](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c96a09bb5cee59fc23205bb63baa8b217a7e1b00))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* **auth:** change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation ([c08d530](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c08d5303eb9e70d36c8eebf6a061ccb71e118fe5))
|
||||
* **auth:** update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration ([6e0fd95](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6e0fd9523e001756ce7109e639ebb54be4fcdabf))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* **heartbeat:** inject ObjectMapper into InstanceHeartbeatService ([#42](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/42)) ([0c98151](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0c981517da1f94cd10ae396e47bde2b35d0b3ba0))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
* Lints ([dc224ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dc224abe26acf5361c56956006e1cc51b75b0b7e))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
|
||||
* **redis:** enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling ([0eb752d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0eb752d4935377f75aab710b7f4eda4b29098e6a))
|
||||
* **redis:** prevent concurrent Redis heartbeat refreshes using AtomicBoolean ([847b132](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/847b13202cb909d18ca3304c27ebe17ce2312b8e))
|
||||
* **redis:** simplify refreshRedisHeartbeat logic and ensure proper error handling ([1813ea1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1813ea1d2d5d093f7925f87371b5e29820bf1136))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* update documentation to reflect new functions in CoordinatorGrpcServer and InstanceRegistry ([f7ce4df](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f7ce4df595cbdc2ef84122781f4851ff140c0f44))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-05-17)
|
||||
|
||||
### Features
|
||||
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add CORS configuration and reorder JWT settings in application.yml ([a49f9be](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a49f9be146f04c14561c305d980846a92f8c12b2))
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-40 Rework Draw System ([#34](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/34)) ([33e785d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e785d22af87724839b62ae91dfe74a05b398c3))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* NCS-53 changed IO to MicroService for easier scaling ([#37](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/37)) ([b5a2966](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b5a2966adafa9650f0f7d601bdeb8fdd13710327))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-78 Add Traceability to the Applications ([#48](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/48)) ([c96a09b](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c96a09bb5cee59fc23205bb63baa8b217a7e1b00))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* **auth:** change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation ([c08d530](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c08d5303eb9e70d36c8eebf6a061ccb71e118fe5))
|
||||
* **auth:** update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration ([6e0fd95](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6e0fd9523e001756ce7109e639ebb54be4fcdabf))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* **heartbeat:** inject ObjectMapper into InstanceHeartbeatService ([#42](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/42)) ([0c98151](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0c981517da1f94cd10ae396e47bde2b35d0b3ba0))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
* Lints ([dc224ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dc224abe26acf5361c56956006e1cc51b75b0b7e))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
|
||||
* **redis:** enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling ([0eb752d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0eb752d4935377f75aab710b7f4eda4b29098e6a))
|
||||
* **redis:** prevent concurrent Redis heartbeat refreshes using AtomicBoolean ([847b132](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/847b13202cb909d18ca3304c27ebe17ce2312b8e))
|
||||
* **redis:** simplify refreshRedisHeartbeat logic and ensure proper error handling ([1813ea1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1813ea1d2d5d093f7925f87371b5e29820bf1136))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* update documentation to reflect new functions in CoordinatorGrpcServer and InstanceRegistry ([f7ce4df](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f7ce4df595cbdc2ef84122781f4851ff140c0f44))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-05-18)
|
||||
|
||||
### Features
|
||||
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add CORS configuration and reorder JWT settings in application.yml ([a49f9be](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a49f9be146f04c14561c305d980846a92f8c12b2))
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-40 Rework Draw System ([#34](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/34)) ([33e785d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e785d22af87724839b62ae91dfe74a05b398c3))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* NCS-53 changed IO to MicroService for easier scaling ([#37](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/37)) ([b5a2966](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b5a2966adafa9650f0f7d601bdeb8fdd13710327))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-78 Add Traceability to the Applications ([#48](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/48)) ([c96a09b](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c96a09bb5cee59fc23205bb63baa8b217a7e1b00))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* **auth:** change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation ([c08d530](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c08d5303eb9e70d36c8eebf6a061ccb71e118fe5))
|
||||
* **auth:** update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration ([6e0fd95](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6e0fd9523e001756ce7109e639ebb54be4fcdabf))
|
||||
* **core:** add logs to trace subscribeGame call in createGame ([f5614c3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f5614c358255598ba1230e42a56b22934d79183c))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* **heartbeat:** inject ObjectMapper into InstanceHeartbeatService ([#42](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/42)) ([0c98151](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0c981517da1f94cd10ae396e47bde2b35d0b3ba0))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
* Lints ([dc224ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dc224abe26acf5361c56956006e1cc51b75b0b7e))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
|
||||
* **redis:** enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling ([0eb752d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0eb752d4935377f75aab710b7f4eda4b29098e6a))
|
||||
* **redis:** prevent concurrent Redis heartbeat refreshes using AtomicBoolean ([847b132](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/847b13202cb909d18ca3304c27ebe17ce2312b8e))
|
||||
* **redis:** simplify refreshRedisHeartbeat logic and ensure proper error handling ([1813ea1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1813ea1d2d5d093f7925f87371b5e29820bf1136))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* update documentation to reflect new functions in CoordinatorGrpcServer and InstanceRegistry ([f7ce4df](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f7ce4df595cbdc2ef84122781f4851ff140c0f44))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-05-19)
|
||||
|
||||
### Features
|
||||
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add CORS configuration and reorder JWT settings in application.yml ([a49f9be](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a49f9be146f04c14561c305d980846a92f8c12b2))
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add GameWritebackEventDto to reflection targets ([87f29a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87f29a720422f538ef70699533500e060337b8ea))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-40 Rework Draw System ([#34](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/34)) ([33e785d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e785d22af87724839b62ae91dfe74a05b398c3))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* NCS-53 changed IO to MicroService for easier scaling ([#37](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/37)) ([b5a2966](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b5a2966adafa9650f0f7d601bdeb8fdd13710327))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-78 Add Traceability to the Applications ([#48](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/48)) ([c96a09b](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c96a09bb5cee59fc23205bb63baa8b217a7e1b00))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* **auth:** change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation ([c08d530](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c08d5303eb9e70d36c8eebf6a061ccb71e118fe5))
|
||||
* **auth:** update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration ([6e0fd95](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6e0fd9523e001756ce7109e639ebb54be4fcdabf))
|
||||
* **core:** add logs to trace subscribeGame call in createGame ([f5614c3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f5614c358255598ba1230e42a56b22934d79183c))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* **heartbeat:** inject ObjectMapper into InstanceHeartbeatService ([#42](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/42)) ([0c98151](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0c981517da1f94cd10ae396e47bde2b35d0b3ba0))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
* Lints ([dc224ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dc224abe26acf5361c56956006e1cc51b75b0b7e))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
|
||||
* **redis:** enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling ([0eb752d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0eb752d4935377f75aab710b7f4eda4b29098e6a))
|
||||
* **redis:** prevent concurrent Redis heartbeat refreshes using AtomicBoolean ([847b132](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/847b13202cb909d18ca3304c27ebe17ce2312b8e))
|
||||
* **redis:** simplify refreshRedisHeartbeat logic and ensure proper error handling ([1813ea1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1813ea1d2d5d093f7925f87371b5e29820bf1136))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* update documentation to reflect new functions in CoordinatorGrpcServer and InstanceRegistry ([f7ce4df](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f7ce4df595cbdc2ef84122781f4851ff140c0f44))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-05-31)
|
||||
|
||||
### Features
|
||||
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add CORS configuration and reorder JWT settings in application.yml ([a49f9be](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a49f9be146f04c14561c305d980846a92f8c12b2))
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add GameWritebackEventDto to reflection targets ([87f29a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87f29a720422f538ef70699533500e060337b8ea))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-40 Rework Draw System ([#34](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/34)) ([33e785d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e785d22af87724839b62ae91dfe74a05b398c3))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* NCS-53 changed IO to MicroService for easier scaling ([#37](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/37)) ([b5a2966](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b5a2966adafa9650f0f7d601bdeb8fdd13710327))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-78 Add Traceability to the Applications ([#48](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/48)) ([c96a09b](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c96a09bb5cee59fc23205bb63baa8b217a7e1b00))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* **redis:** implement game writeback stream processing with error handling and retries ([ae3ef76](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ae3ef766e8b7596a09e466cd4fb386119f17ca5c))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* **auth:** change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation ([c08d530](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c08d5303eb9e70d36c8eebf6a061ccb71e118fe5))
|
||||
* **auth:** update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration ([6e0fd95](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6e0fd9523e001756ce7109e639ebb54be4fcdabf))
|
||||
* **core:** add logs to trace subscribeGame call in createGame ([f5614c3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f5614c358255598ba1230e42a56b22934d79183c))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* **heartbeat:** inject ObjectMapper into InstanceHeartbeatService ([#42](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/42)) ([0c98151](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0c981517da1f94cd10ae396e47bde2b35d0b3ba0))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
* Lints ([dc224ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dc224abe26acf5361c56956006e1cc51b75b0b7e))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
|
||||
* **redis:** enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling ([0eb752d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0eb752d4935377f75aab710b7f4eda4b29098e6a))
|
||||
* **redis:** prevent concurrent Redis heartbeat refreshes using AtomicBoolean ([847b132](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/847b13202cb909d18ca3304c27ebe17ce2312b8e))
|
||||
* **redis:** simplify refreshRedisHeartbeat logic and ensure proper error handling ([1813ea1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1813ea1d2d5d093f7925f87371b5e29820bf1136))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* update documentation to reflect new functions in CoordinatorGrpcServer and InstanceRegistry ([f7ce4df](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f7ce4df595cbdc2ef84122781f4851ff140c0f44))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-02)
|
||||
|
||||
### Features
|
||||
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add CORS configuration and reorder JWT settings in application.yml ([a49f9be](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a49f9be146f04c14561c305d980846a92f8c12b2))
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add GameWritebackEventDto to reflection targets ([87f29a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87f29a720422f538ef70699533500e060337b8ea))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-40 Rework Draw System ([#34](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/34)) ([33e785d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e785d22af87724839b62ae91dfe74a05b398c3))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* NCS-53 changed IO to MicroService for easier scaling ([#37](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/37)) ([b5a2966](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b5a2966adafa9650f0f7d601bdeb8fdd13710327))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-78 Add Traceability to the Applications ([#48](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/48)) ([c96a09b](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c96a09bb5cee59fc23205bb63baa8b217a7e1b00))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* **redis:** implement game writeback stream processing with error handling and retries ([ae3ef76](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ae3ef766e8b7596a09e466cd4fb386119f17ca5c))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* **auth:** change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation ([c08d530](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c08d5303eb9e70d36c8eebf6a061ccb71e118fe5))
|
||||
* **auth:** update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration ([6e0fd95](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6e0fd9523e001756ce7109e639ebb54be4fcdabf))
|
||||
* **core:** add logs to trace subscribeGame call in createGame ([f5614c3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f5614c358255598ba1230e42a56b22934d79183c))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* **heartbeat:** inject ObjectMapper into InstanceHeartbeatService ([#42](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/42)) ([0c98151](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0c981517da1f94cd10ae396e47bde2b35d0b3ba0))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
* Lints ([dc224ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dc224abe26acf5361c56956006e1cc51b75b0b7e))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **pgn:** add SAN disambiguation and check/checkmate suffixes [NCS-42] ([#56](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/56)) ([2579539](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2579539084152178f4482ddb7b84b7f1162f10da))
|
||||
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
|
||||
* **redis:** enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling ([0eb752d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0eb752d4935377f75aab710b7f4eda4b29098e6a))
|
||||
* **redis:** prevent concurrent Redis heartbeat refreshes using AtomicBoolean ([847b132](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/847b13202cb909d18ca3304c27ebe17ce2312b8e))
|
||||
* **redis:** simplify refreshRedisHeartbeat logic and ensure proper error handling ([1813ea1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1813ea1d2d5d093f7925f87371b5e29820bf1136))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* update documentation to reflect new functions in CoordinatorGrpcServer and InstanceRegistry ([f7ce4df](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f7ce4df595cbdc2ef84122781f4851ff140c0f44))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-09)
|
||||
|
||||
### Features
|
||||
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add CORS configuration and reorder JWT settings in application.yml ([a49f9be](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a49f9be146f04c14561c305d980846a92f8c12b2))
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add GameWritebackEventDto to reflection targets ([87f29a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87f29a720422f538ef70699533500e060337b8ea))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **events:** migrate game-creation and bot flows to Redis Streams NCS-89 ([#62](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/62)) ([a24924c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a24924c23057db3d700a75dbc4333557789cd991))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-40 Rework Draw System ([#34](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/34)) ([33e785d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e785d22af87724839b62ae91dfe74a05b398c3))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* NCS-53 changed IO to MicroService for easier scaling ([#37](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/37)) ([b5a2966](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b5a2966adafa9650f0f7d601bdeb8fdd13710327))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-78 Add Traceability to the Applications ([#48](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/48)) ([c96a09b](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c96a09bb5cee59fc23205bb63baa8b217a7e1b00))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* **redis:** implement game writeback stream processing with error handling and retries ([ae3ef76](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ae3ef766e8b7596a09e466cd4fb386119f17ca5c))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* **auth:** change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation ([c08d530](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c08d5303eb9e70d36c8eebf6a061ccb71e118fe5))
|
||||
* **auth:** update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration ([6e0fd95](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6e0fd9523e001756ce7109e639ebb54be4fcdabf))
|
||||
* **core:** add logs to trace subscribeGame call in createGame ([f5614c3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f5614c358255598ba1230e42a56b22934d79183c))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* **heartbeat:** inject ObjectMapper into InstanceHeartbeatService ([#42](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/42)) ([0c98151](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0c981517da1f94cd10ae396e47bde2b35d0b3ba0))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
* Lints ([dc224ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dc224abe26acf5361c56956006e1cc51b75b0b7e))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **pgn:** add SAN disambiguation and check/checkmate suffixes [NCS-42] ([#56](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/56)) ([2579539](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2579539084152178f4482ddb7b84b7f1162f10da))
|
||||
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
|
||||
* **redis:** enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling ([0eb752d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0eb752d4935377f75aab710b7f4eda4b29098e6a))
|
||||
* **redis:** prevent concurrent Redis heartbeat refreshes using AtomicBoolean ([847b132](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/847b13202cb909d18ca3304c27ebe17ce2312b8e))
|
||||
* **redis:** simplify refreshRedisHeartbeat logic and ensure proper error handling ([1813ea1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1813ea1d2d5d093f7925f87371b5e29820bf1136))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* update documentation to reflect new functions in CoordinatorGrpcServer and InstanceRegistry ([f7ce4df](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f7ce4df595cbdc2ef84122781f4851ff140c0f44))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-09)
|
||||
|
||||
### Features
|
||||
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add CORS configuration and reorder JWT settings in application.yml ([a49f9be](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a49f9be146f04c14561c305d980846a92f8c12b2))
|
||||
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add GameWritebackEventDto to reflection targets ([87f29a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87f29a720422f538ef70699533500e060337b8ea))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **events:** migrate game-creation and bot flows to Redis Streams NCS-89 ([#62](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/62)) ([a24924c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a24924c23057db3d700a75dbc4333557789cd991))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* implement GameRules with isInCheck, legalMoves, gameStatus ([94a02ff](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/94a02ff6849436d9496c70a0f16c21666dae8e4e))
|
||||
* implement legal castling ([#1](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/1)) ([00d326c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/00d326c1ba67711fbe180f04e1100c3f01dd0254))
|
||||
* implement periodic scaling checks and enhance instance management in AutoScaler ([3f12f69](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f12f695f132b92f634d98df2c037292498b6e86))
|
||||
* **logging:** add DEBUG/INFO/WARN logging across services (NCS-72) ([#41](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/41)) ([804a4bf](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/804a4bf179e3dfb19e2be4390e7e543caf5237c6))
|
||||
* NCS-10 Implement Pawn Promotion ([#12](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/12)) ([13bfc16](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/13bfc16cfe25db78ec607db523ca6d993c13430c))
|
||||
* NCS-11 50-move rule ([#9](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/9)) ([412ed98](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/412ed986a95703a3b282276540153480ceed229d))
|
||||
* NCS-13 Implement Threefold Repetition ([#31](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/31)) ([767d305](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/767d3051a76c266050b6335774d66e2db2273c16))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-16 Core Separation via Patterns ([#10](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/10)) ([1361dfc](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1361dfc89553b146864fb8ff3526cf12cf3f293a))
|
||||
* NCS-17 Implement basic ScalaFX UI ([#14](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/14)) ([3ff8031](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ff80318b4f16c59733a46498581a5c27f048287))
|
||||
* NCS-21 Write Scripts to automate certain tasks ([#15](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/15)) ([8051871](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/80518719d536a087d339fe02530825dc07f8b388))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-40 Rework Draw System ([#34](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/34)) ([33e785d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e785d22af87724839b62ae91dfe74a05b398c3))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* NCS-53 changed IO to MicroService for easier scaling ([#37](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/37)) ([b5a2966](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b5a2966adafa9650f0f7d601bdeb8fdd13710327))
|
||||
* NCS-6 Implementing FEN & PGN ([#7](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/7)) ([f28e69d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f28e69dc181416aa2f221fdc4b45c2cda5efbf07))
|
||||
* NCS-78 Add Traceability to the Applications ([#48](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/48)) ([c96a09b](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c96a09bb5cee59fc23205bb63baa8b217a7e1b00))
|
||||
* NCS-82 add Swiss-system tournament module ([#55](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/55)) ([c5661de](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c5661de4a0ebf4b33211f5a391840dcf744656b7))
|
||||
* NCS-9 En passant implementation ([#8](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/8)) ([919beb3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/919beb3b4bfa8caf2f90976a415fe9b19b7e9747))
|
||||
* **redis:** implement game writeback stream processing with error handling and retries ([ae3ef76](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ae3ef766e8b7596a09e466cd4fb386119f17ca5c))
|
||||
* **rule:** Rules as a microservice ([#39](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/39)) ([093134d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/093134d36c6844ba02a36a28d5d044f09291cd1d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
* wire check/checkmate/stalemate into processMove and gameLoop ([5264a22](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5264a225418b885c5e6ea6411b96f85e38837f6c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing kings to gameLoop capture test board ([aedd787](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/aedd787b77203c2af934751dba7b784eaf165032))
|
||||
* **auth:** change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation ([c08d530](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c08d5303eb9e70d36c8eebf6a061ccb71e118fe5))
|
||||
* **auth:** update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration ([6e0fd95](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6e0fd9523e001756ce7109e639ebb54be4fcdabf))
|
||||
* **core:** add logs to trace subscribeGame call in createGame ([f5614c3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f5614c358255598ba1230e42a56b22934d79183c))
|
||||
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
|
||||
* **heartbeat:** inject ObjectMapper into InstanceHeartbeatService ([#42](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/42)) ([0c98151](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0c981517da1f94cd10ae396e47bde2b35d0b3ba0))
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
* Lints ([dc224ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dc224abe26acf5361c56956006e1cc51b75b0b7e))
|
||||
* NCS-84 More Verbose Logging ([#51](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/51)) ([4ad92ab](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/4ad92ab23698267f8faa59c4e18388d4a0042cca))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **pgn:** add SAN disambiguation and check/checkmate suffixes [NCS-42] ([#56](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/56)) ([2579539](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2579539084152178f4482ddb7b84b7f1162f10da))
|
||||
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
|
||||
* **redis:** enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling ([0eb752d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0eb752d4935377f75aab710b7f4eda4b29098e6a))
|
||||
* **redis:** prevent concurrent Redis heartbeat refreshes using AtomicBoolean ([847b132](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/847b13202cb909d18ca3304c27ebe17ce2312b8e))
|
||||
* **redis:** simplify refreshRedisHeartbeat logic and ensure proper error handling ([1813ea1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/1813ea1d2d5d093f7925f87371b5e29820bf1136))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* resolve 6 coordinator bugs (cache eviction, rebalance race, pod matching, lookup inefficiency) ([5619c82](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5619c8223ad7091706909eda8c907a29d215fd30))
|
||||
* update documentation to reflect new functions in CoordinatorGrpcServer and InstanceRegistry ([f7ce4df](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f7ce4df595cbdc2ef84122781f4851ff140c0f44))
|
||||
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189))
|
||||
* update move validation to check for king safety ([#13](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/13)) ([e5e20c5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5e20c566e368b12ca1dc59680c34e9112bf6762))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
|
||||
@@ -138,6 +138,8 @@ tasks.withType(org.gradle.api.tasks.scala.ScalaCompile::class).configureEach {
|
||||
exclude("**/resource/GameDtoMapper.scala")
|
||||
exclude("**/resource/GameResource.scala")
|
||||
exclude("**/redis/GameRedis*.scala")
|
||||
exclude("**/redis/GameCreationStreamListener.scala")
|
||||
exclude("**/service/GameCreationService.scala")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.nowchess.chess.config
|
||||
|
||||
import de.nowchess.api.board.{CastlingRights, Color, File, Piece, PieceType, Rank, Square}
|
||||
import de.nowchess.api.dto.*
|
||||
import de.nowchess.api.event.{EventEnvelope, EventType}
|
||||
import de.nowchess.api.game.{DrawReason, GameContext, GameMode, GameResult}
|
||||
import de.nowchess.api.move.{Move, MoveType, PromotionPiece}
|
||||
import de.nowchess.chess.registry.GameCacheDto
|
||||
@@ -13,7 +14,12 @@ import io.quarkus.runtime.annotations.RegisterForReflection
|
||||
classOf[GameCacheDto],
|
||||
classOf[ClockDto],
|
||||
classOf[CreateGameRequestDto],
|
||||
classOf[GameCreationRequestDto],
|
||||
classOf[GameCreationResponseDto],
|
||||
classOf[EventEnvelope],
|
||||
classOf[EventType],
|
||||
classOf[ErrorEventDto],
|
||||
classOf[GameWritebackEventDto],
|
||||
classOf[GameFullDto],
|
||||
classOf[GameFullEventDto],
|
||||
classOf[GameStateDto],
|
||||
|
||||
@@ -418,7 +418,6 @@ class GameEngine(
|
||||
val contextBefore = currentContext
|
||||
val nextContext = ruleSet.applyMove(currentContext)(move)
|
||||
val captured = computeCaptured(currentContext, move)
|
||||
val notation = translateMoveToNotation(move, contextBefore.board)
|
||||
currentContext = nextContext
|
||||
|
||||
advanceClock(contextBefore.turn)
|
||||
@@ -463,13 +462,18 @@ class GameEngine(
|
||||
redoStack = Nil
|
||||
else if status.isCheck then notifyObservers(CheckDetectedEvent(currentContext))
|
||||
|
||||
private def translateMoveToNotation(move: Move, boardBefore: Board): String =
|
||||
move.moveType match
|
||||
private def translateMoveToNotation(move: Move, ctxBefore: GameContext, status: PostMoveStatus): String =
|
||||
val suffix =
|
||||
if status.isCheckmate then "#"
|
||||
else if status.isCheck then "+"
|
||||
else ""
|
||||
val base = move.moveType match
|
||||
case MoveType.CastleKingside => "O-O"
|
||||
case MoveType.CastleQueenside => "O-O-O"
|
||||
case MoveType.EnPassant => enPassantNotation(move)
|
||||
case MoveType.Promotion(pp) => promotionNotation(move, pp)
|
||||
case MoveType.Normal(isCapture) => normalMoveNotation(move, boardBefore, isCapture)
|
||||
case MoveType.Normal(isCapture) => normalMoveNotation(move, ctxBefore, isCapture)
|
||||
base + suffix
|
||||
|
||||
private def enPassantNotation(move: Move): String =
|
||||
s"${move.from.file.toString.toLowerCase}x${move.to}"
|
||||
@@ -482,16 +486,31 @@ class GameEngine(
|
||||
case PromotionPiece.Knight => "N"
|
||||
s"${move.to}=$ppChar"
|
||||
|
||||
private[engine] def normalMoveNotation(move: Move, boardBefore: Board, isCapture: Boolean): String =
|
||||
boardBefore.pieceAt(move.from).map(_.pieceType) match
|
||||
private[engine] def normalMoveNotation(move: Move, ctxBefore: GameContext, isCapture: Boolean): String =
|
||||
ctxBefore.board.pieceAt(move.from).map(_.pieceType) match
|
||||
case Some(PieceType.Pawn) =>
|
||||
if isCapture then s"${move.from.file.toString.toLowerCase}x${move.to}"
|
||||
else move.to.toString
|
||||
case Some(pt) =>
|
||||
val letter = pieceNotation(pt)
|
||||
if isCapture then s"${letter}x${move.to}" else s"$letter${move.to}"
|
||||
val d = disambiguatePiece(move.from, move.to, pt, ctxBefore)
|
||||
if isCapture then s"$letter${d}x${move.to}" else s"$letter$d${move.to}"
|
||||
case None => move.to.toString
|
||||
|
||||
private def disambiguatePiece(from: Square, to: Square, pieceType: PieceType, ctx: GameContext): String =
|
||||
if pieceType == PieceType.King then ""
|
||||
else
|
||||
val competitors = ruleSet
|
||||
.allLegalMoves(ctx)
|
||||
.filter(m => m.to == to && m.from != from && ctx.board.pieceAt(m.from).exists(_.pieceType == pieceType))
|
||||
if competitors.isEmpty then ""
|
||||
else
|
||||
val sameFile = competitors.exists(_.from.file == from.file)
|
||||
val sameRank = competitors.exists(_.from.rank == from.rank)
|
||||
if !sameFile then from.file.toString.toLowerCase
|
||||
else if !sameRank then (from.rank.ordinal + 1).toString
|
||||
else from.toString
|
||||
|
||||
private[engine] def pieceNotation(pieceType: PieceType): String =
|
||||
pieceType match
|
||||
case PieceType.Knight => "N"
|
||||
@@ -519,9 +538,10 @@ class GameEngine(
|
||||
if currentContext.moves.isEmpty then
|
||||
notifyObservers(InvalidMoveEvent(currentContext, InvalidMoveReason.NothingToUndo))
|
||||
else
|
||||
val lastMove = currentContext.moves.last
|
||||
val prevCtx = replayContextFromMoves(currentContext.moves.dropRight(1))
|
||||
val notation = translateMoveToNotation(lastMove, prevCtx.board)
|
||||
val lastMove = currentContext.moves.last
|
||||
val prevCtx = replayContextFromMoves(currentContext.moves.dropRight(1))
|
||||
val postStatus = ruleSet.postMoveStatus(currentContext)
|
||||
val notation = translateMoveToNotation(lastMove, prevCtx, postStatus)
|
||||
redoStack = lastMove :: redoStack
|
||||
currentContext = prevCtx
|
||||
notifyObservers(MoveUndoneEvent(currentContext, notation))
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package de.nowchess.chess.redis
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.nowchess.api.dto.{GameCreationRequestDto, GameCreationResponseDto}
|
||||
import de.nowchess.api.event.{EventEnvelope, EventType}
|
||||
import de.nowchess.chess.config.RedisConfig
|
||||
import de.nowchess.chess.service.GameCreationService
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import io.quarkus.redis.datasource.stream.{StreamMessage, XAddArgs, XGroupCreateArgs, XReadGroupArgs}
|
||||
import io.quarkus.runtime.StartupEvent
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.enterprise.event.Observes
|
||||
import jakarta.inject.Inject
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty
|
||||
import org.eclipse.microprofile.context.ManagedExecutor
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.{Failure, Success, Try}
|
||||
import java.time.Duration
|
||||
import java.util.UUID
|
||||
|
||||
@ApplicationScoped
|
||||
class GameCreationStreamListener:
|
||||
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Inject var redis: RedisDataSource = uninitialized
|
||||
@Inject var objectMapper: ObjectMapper = uninitialized
|
||||
@Inject var creationService: GameCreationService = uninitialized
|
||||
@Inject var executor: ManagedExecutor = uninitialized
|
||||
@Inject var redisConfig: RedisConfig = uninitialized
|
||||
@ConfigProperty(name = "nowchess.game-creation-stream.enabled", defaultValue = "true")
|
||||
private var streamEnabled: Boolean = true
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private val log = Logger.getLogger(classOf[GameCreationStreamListener])
|
||||
private val groupName = "core-game-creation"
|
||||
private val consumerId = UUID.randomUUID().toString
|
||||
private val maxRetries = 3
|
||||
private val maxStreamLen = 1000L
|
||||
|
||||
private def requestStream: String = s"${redisConfig.prefix}:game-creation"
|
||||
private def responseStream: String = s"${redisConfig.prefix}:game-creation-response"
|
||||
private def dlqStream: String = s"${redisConfig.prefix}:dlq"
|
||||
|
||||
def start(@Observes _ev: StartupEvent): Unit =
|
||||
if streamEnabled then
|
||||
createGroupIfAbsent()
|
||||
executor.submit(
|
||||
new Runnable:
|
||||
def run(): Unit = pollLoop(),
|
||||
)
|
||||
log.infof("Game-creation request listener started (consumer=%s)", consumerId)
|
||||
|
||||
private def createGroupIfAbsent(): Unit =
|
||||
Try(
|
||||
redis
|
||||
.stream(classOf[String])
|
||||
.xgroupCreate(requestStream, groupName, "0", new XGroupCreateArgs().mkstream()),
|
||||
) match
|
||||
case Failure(ex) if Option(ex.getMessage).exists(_.contains("BUSYGROUP")) => ()
|
||||
case Failure(ex) => log.warnf(ex, "Failed to create game-creation consumer group")
|
||||
case Success(_) => ()
|
||||
|
||||
private def pollLoop(): Unit =
|
||||
while true do
|
||||
Try {
|
||||
val messages = redis
|
||||
.stream(classOf[String])
|
||||
.xreadgroup(
|
||||
groupName,
|
||||
consumerId,
|
||||
requestStream,
|
||||
">",
|
||||
new XReadGroupArgs().count(10).block(Duration.ofSeconds(2)),
|
||||
)
|
||||
Option(messages).foreach(_.forEach(handleMessage))
|
||||
} match
|
||||
case Failure(ex) => log.warnf(ex, "Error in game-creation poll loop")
|
||||
case Success(_) => ()
|
||||
|
||||
private def handleMessage(msg: StreamMessage[String, String, String]): Unit =
|
||||
val json = msg.payload().get("data")
|
||||
val attempt = Option(msg.payload().get("attempt")).flatMap(_.toIntOption).getOrElse(0)
|
||||
Try(objectMapper.readValue(json, classOf[EventEnvelope])) match
|
||||
case Failure(ex) =>
|
||||
log.errorf(ex, "Unparseable game-creation event, sending to DLQ: %s", json)
|
||||
toDlq(EventType.GameCreationRequest.toString, json, ex, attempt)
|
||||
ack(msg.id())
|
||||
case Success(envelope) =>
|
||||
processEnvelope(msg, envelope, json, attempt)
|
||||
|
||||
private def processEnvelope(
|
||||
msg: StreamMessage[String, String, String],
|
||||
envelope: EventEnvelope,
|
||||
json: String,
|
||||
attempt: Int,
|
||||
): Unit =
|
||||
Try {
|
||||
val req = objectMapper.treeToValue(envelope.payload, classOf[GameCreationRequestDto])
|
||||
val entry = creationService.createGame(req)
|
||||
publishResponse(envelope.correlationId, GameCreationResponseDto(Some(entry.gameId)))
|
||||
} match
|
||||
case Success(_) => ack(msg.id())
|
||||
case Failure(ex) if attempt + 1 < maxRetries =>
|
||||
log.warnf(ex, "Game creation failed (attempt %d), retrying", attempt)
|
||||
retry(json, attempt + 1)
|
||||
ack(msg.id())
|
||||
case Failure(ex) =>
|
||||
log.errorf(ex, "Game creation failed after %d attempts, sending to DLQ", maxRetries)
|
||||
publishResponse(envelope.correlationId, GameCreationResponseDto(None, Some("Game creation failed")))
|
||||
toDlq(envelope.`type`.toString, json, ex, attempt)
|
||||
ack(msg.id())
|
||||
|
||||
private def publishResponse(correlationId: Option[String], resp: GameCreationResponseDto): Unit =
|
||||
val payload = objectMapper.valueToTree[com.fasterxml.jackson.databind.JsonNode](resp)
|
||||
val envelope = EventEnvelope.of(EventType.GameCreationResponse, payload, correlationId)
|
||||
xadd(responseStream, Map("data" -> objectMapper.writeValueAsString(envelope)))
|
||||
|
||||
private def retry(json: String, attempt: Int): Unit =
|
||||
xadd(requestStream, Map("data" -> json, "attempt" -> attempt.toString))
|
||||
|
||||
private def toDlq(eventType: String, json: String, error: Throwable, attempt: Int): Unit =
|
||||
xadd(
|
||||
dlqStream,
|
||||
Map(
|
||||
"data" -> json,
|
||||
"eventType" -> eventType,
|
||||
"error" -> Option(error.getMessage).getOrElse(error.getClass.getName),
|
||||
"attempt" -> (attempt + 1).toString,
|
||||
),
|
||||
)
|
||||
|
||||
private def ack(id: String): Unit =
|
||||
Try(redis.stream(classOf[String]).xack(requestStream, groupName, id)) match
|
||||
case Failure(ex) => log.warnf(ex, "Failed to ack message %s", id)
|
||||
case Success(_) => ()
|
||||
|
||||
private def xadd(key: String, fields: Map[String, String]): Unit =
|
||||
Try(
|
||||
redis
|
||||
.stream(classOf[String])
|
||||
.xadd(key, new XAddArgs().maxlen(maxStreamLen).nearlyExactTrimming(), fields.asJava),
|
||||
) match
|
||||
case Failure(ex) => log.errorf(ex, "Failed to publish to stream %s", key)
|
||||
case Success(_) => ()
|
||||
@@ -1,13 +1,12 @@
|
||||
package de.nowchess.chess.redis
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.nowchess.api.dto.{GameStateEventDto, GameWritebackEventDto}
|
||||
import de.nowchess.api.game.{CorrespondenceClockState, LiveClockState}
|
||||
import de.nowchess.chess.grpc.IoGrpcClientWrapper
|
||||
import de.nowchess.api.game.{DrawReason, GameResult, WinReason}
|
||||
import de.nowchess.api.dto.{GameStateDto, GameStateEventDto, GameWritebackEventDto}
|
||||
import de.nowchess.api.game.{CorrespondenceClockState, DrawReason, GameResult, LiveClockState, TimeControl, WinReason}
|
||||
import de.nowchess.api.board.Color
|
||||
import de.nowchess.chess.grpc.IoGrpcClientWrapper
|
||||
import de.nowchess.chess.observer.{GameEvent, Observer}
|
||||
import de.nowchess.chess.registry.GameRegistry
|
||||
import de.nowchess.chess.registry.{GameEntry, GameRegistry}
|
||||
import de.nowchess.chess.resource.GameDtoMapper
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import org.jboss.logging.Logger
|
||||
@@ -26,61 +25,69 @@ class GameRedisPublisher(
|
||||
onGameOver: String => Unit,
|
||||
) extends Observer:
|
||||
|
||||
def emitInitialWriteback(): Unit =
|
||||
try
|
||||
registry.get(gameId).foreach { entry =>
|
||||
val dto = GameDtoMapper.toGameStateDto(entry, ioClient)
|
||||
writebackEmit(objectMapper.writeValueAsString(buildWriteback(entry, dto)))
|
||||
}
|
||||
catch case ex: Exception => GameRedisPublisher.log.warnf(ex, "Failed to emit initial writeback for game %s", gameId)
|
||||
|
||||
def onGameEvent(event: GameEvent): Unit =
|
||||
try
|
||||
GameRedisPublisher.log.debugf("Publishing game event for game %s", gameId)
|
||||
registry.get(gameId).foreach { entry =>
|
||||
val dto = GameDtoMapper.toGameStateDto(entry, ioClient)
|
||||
val json = objectMapper.writeValueAsString(GameStateEventDto(dto))
|
||||
redis.pubsub(classOf[String]).publish(s2cTopicName, json)
|
||||
|
||||
val clock = entry.engine.currentClockState
|
||||
val wb = GameWritebackEventDto(
|
||||
gameId = gameId,
|
||||
fen = dto.fen,
|
||||
pgn = dto.pgn,
|
||||
moveCount = entry.engine.context.moves.size,
|
||||
whiteId = entry.white.id.value,
|
||||
whiteName = entry.white.displayName,
|
||||
blackId = entry.black.id.value,
|
||||
blackName = entry.black.displayName,
|
||||
mode = entry.mode.toString,
|
||||
resigned = entry.resigned,
|
||||
limitSeconds = entry.engine.timeControl match {
|
||||
case de.nowchess.api.game.TimeControl.Clock(l, _) => Some(l); case _ => None
|
||||
},
|
||||
incrementSeconds = entry.engine.timeControl match {
|
||||
case de.nowchess.api.game.TimeControl.Clock(_, i) => Some(i); case _ => None
|
||||
},
|
||||
daysPerMove = entry.engine.timeControl match {
|
||||
case de.nowchess.api.game.TimeControl.Correspondence(d) => Some(d); case _ => None
|
||||
},
|
||||
whiteRemainingMs = clock.collect { case c: LiveClockState => c.whiteRemainingMs },
|
||||
blackRemainingMs = clock.collect { case c: LiveClockState => c.blackRemainingMs },
|
||||
incrementMs = clock.collect { case c: LiveClockState => c.incrementMs },
|
||||
clockLastTickAt = clock.collect { case c: LiveClockState => c.lastTickAt.toEpochMilli },
|
||||
clockMoveDeadline = clock.collect { case c: CorrespondenceClockState => c.moveDeadline.toEpochMilli },
|
||||
clockActiveColor = clock.map(_.activeColor.label.toLowerCase),
|
||||
pendingDrawOffer = entry.engine.pendingDrawOfferBy.map(_.label.toLowerCase),
|
||||
result = entry.engine.context.result.map {
|
||||
case GameResult.Win(Color.White, _) => "white"
|
||||
case GameResult.Win(Color.Black, _) => "black"
|
||||
case GameResult.Draw(_) => "draw"
|
||||
},
|
||||
terminationReason = entry.engine.context.result.map {
|
||||
case GameResult.Win(_, WinReason.Checkmate) => "checkmate"
|
||||
case GameResult.Win(_, WinReason.Resignation) => "resignation"
|
||||
case GameResult.Win(_, WinReason.TimeControl) => "timeout"
|
||||
case GameResult.Draw(DrawReason.Stalemate) => "stalemate"
|
||||
case GameResult.Draw(DrawReason.InsufficientMaterial) => "insufficient_material"
|
||||
case GameResult.Draw(DrawReason.FiftyMoveRule) => "fifty_move"
|
||||
case GameResult.Draw(DrawReason.ThreefoldRepetition) => "repetition"
|
||||
case GameResult.Draw(DrawReason.Agreement) => "agreement"
|
||||
},
|
||||
redoStack = entry.engine.redoStackMoves.map(GameDtoMapper.moveToUci),
|
||||
pendingTakebackRequest = entry.engine.pendingTakebackRequestBy.map(_.label.toLowerCase),
|
||||
)
|
||||
writebackEmit(objectMapper.writeValueAsString(wb))
|
||||
val dto = GameDtoMapper.toGameStateDto(entry, ioClient)
|
||||
redis.pubsub(classOf[String]).publish(s2cTopicName, objectMapper.writeValueAsString(GameStateEventDto(dto)))
|
||||
writebackEmit(objectMapper.writeValueAsString(buildWriteback(entry, dto)))
|
||||
if entry.engine.context.result.isDefined then onGameOver(gameId)
|
||||
}
|
||||
catch case ex: Exception => GameRedisPublisher.log.warnf(ex, "Failed to publish game event for game %s", gameId)
|
||||
|
||||
private def buildWriteback(entry: GameEntry, dto: GameStateDto): GameWritebackEventDto =
|
||||
val clock = entry.engine.currentClockState
|
||||
GameWritebackEventDto(
|
||||
gameId = gameId,
|
||||
fen = dto.fen,
|
||||
pgn = dto.pgn,
|
||||
moveCount = entry.engine.context.moves.size,
|
||||
whiteId = entry.white.id.value,
|
||||
whiteName = entry.white.displayName,
|
||||
blackId = entry.black.id.value,
|
||||
blackName = entry.black.displayName,
|
||||
mode = entry.mode.toString,
|
||||
resigned = entry.resigned,
|
||||
limitSeconds = entry.engine.timeControl match {
|
||||
case TimeControl.Clock(l, _) => Some(l); case _ => None
|
||||
},
|
||||
incrementSeconds = entry.engine.timeControl match {
|
||||
case TimeControl.Clock(_, i) => Some(i); case _ => None
|
||||
},
|
||||
daysPerMove = entry.engine.timeControl match {
|
||||
case TimeControl.Correspondence(d) => Some(d); case _ => None
|
||||
},
|
||||
whiteRemainingMs = clock.collect { case c: LiveClockState => c.whiteRemainingMs },
|
||||
blackRemainingMs = clock.collect { case c: LiveClockState => c.blackRemainingMs },
|
||||
incrementMs = clock.collect { case c: LiveClockState => c.incrementMs },
|
||||
clockLastTickAt = clock.collect { case c: LiveClockState => c.lastTickAt.toEpochMilli },
|
||||
clockMoveDeadline = clock.collect { case c: CorrespondenceClockState => c.moveDeadline.toEpochMilli },
|
||||
clockActiveColor = clock.map(_.activeColor.label.toLowerCase),
|
||||
pendingDrawOffer = entry.engine.pendingDrawOfferBy.map(_.label.toLowerCase),
|
||||
result = entry.engine.context.result.map {
|
||||
case GameResult.Win(Color.White, _) => "white"
|
||||
case GameResult.Win(Color.Black, _) => "black"
|
||||
case GameResult.Draw(_) => "draw"
|
||||
},
|
||||
terminationReason = entry.engine.context.result.map {
|
||||
case GameResult.Win(_, WinReason.Checkmate) => "checkmate"
|
||||
case GameResult.Win(_, WinReason.Resignation) => "resignation"
|
||||
case GameResult.Win(_, WinReason.TimeControl) => "timeout"
|
||||
case GameResult.Draw(DrawReason.Stalemate) => "stalemate"
|
||||
case GameResult.Draw(DrawReason.InsufficientMaterial) => "insufficient_material"
|
||||
case GameResult.Draw(DrawReason.FiftyMoveRule) => "fifty_move"
|
||||
case GameResult.Draw(DrawReason.ThreefoldRepetition) => "repetition"
|
||||
case GameResult.Draw(DrawReason.Agreement) => "agreement"
|
||||
},
|
||||
redoStack = entry.engine.redoStackMoves.map(GameDtoMapper.moveToUci),
|
||||
pendingTakebackRequest = entry.engine.pendingTakebackRequestBy.map(_.label.toLowerCase),
|
||||
)
|
||||
|
||||
+55
-3
@@ -13,14 +13,16 @@ import de.nowchess.chess.service.InstanceHeartbeatService
|
||||
import io.quarkus.redis.datasource.ReactiveRedisDataSource
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import io.quarkus.redis.datasource.pubsub.ReactivePubSubCommands
|
||||
import jakarta.annotation.PostConstruct
|
||||
import jakarta.annotation.PreDestroy
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.enterprise.inject.Instance
|
||||
import jakarta.inject.Inject
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.Try
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.{ConcurrentHashMap, ExecutorService, Executors}
|
||||
import java.util.function.Consumer
|
||||
|
||||
@ApplicationScoped
|
||||
@@ -44,6 +46,34 @@ class GameRedisSubscriberManager:
|
||||
|
||||
private val c2sListeners = new ConcurrentHashMap[String, ReactivePubSubCommands.ReactiveRedisSubscriber]()
|
||||
private val s2cObservers = new ConcurrentHashMap[String, Observer]()
|
||||
// Per-game single-thread executor so c2s messages are handled off the Vert.x
|
||||
// event loop (handleConnected/handleMove make blocking gRPC + Redis calls) while
|
||||
// staying ordered per game.
|
||||
private val c2sExecutors = new ConcurrentHashMap[String, ExecutorService]()
|
||||
|
||||
// scalafix:off DisableSyntax.var
|
||||
private var clockExpireSubscriber: Option[ReactivePubSubCommands.ReactiveRedisSubscriber] = None
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private def clockExpireChannel: String = s"${redisConfig.prefix}:game:clock:expire"
|
||||
|
||||
@PostConstruct
|
||||
def subscribeClockExpiry(): Unit =
|
||||
val handler: Consumer[String] = gameId => handleClockExpiry(gameId)
|
||||
try
|
||||
val subscriber = reactiveRedis
|
||||
.pubsub(classOf[String])
|
||||
.subscribe(clockExpireChannel, handler)
|
||||
.await()
|
||||
.atMost(java.time.Duration.ofSeconds(5))
|
||||
clockExpireSubscriber = Some(subscriber)
|
||||
log.infof("Subscribed to clock expiry channel %s", clockExpireChannel)
|
||||
catch case ex: Exception => log.warnf(ex, "Failed to subscribe to clock expiry channel")
|
||||
|
||||
private def handleClockExpiry(gameId: String): Unit =
|
||||
if !s2cObservers.containsKey(gameId) then
|
||||
log.infof("Clock expired for game %s — loading engine to enforce timeout", gameId)
|
||||
subscribeGame(gameId)
|
||||
|
||||
private def c2sTopic(gameId: String): String =
|
||||
s"${redisConfig.prefix}:game:$gameId:c2s"
|
||||
@@ -52,7 +82,8 @@ class GameRedisSubscriberManager:
|
||||
s"${redisConfig.prefix}:game:$gameId:s2c"
|
||||
|
||||
def subscribeGame(gameId: String): Unit =
|
||||
val writebackFn: String => Unit = json => redis.pubsub(classOf[String]).publish("game-writeback", json)
|
||||
val writebackFn: String => Unit = json =>
|
||||
redis.stream(classOf[String]).xadd(s"${redisConfig.prefix}:game-writeback", Map("data" -> json).asJava)
|
||||
val obs = new GameRedisPublisher(
|
||||
gameId,
|
||||
registry,
|
||||
@@ -65,9 +96,17 @@ class GameRedisSubscriberManager:
|
||||
)
|
||||
s2cObservers.put(gameId, obs)
|
||||
registry.get(gameId).foreach(_.engine.subscribe(obs))
|
||||
obs.emitInitialWriteback()
|
||||
heartbeatServiceOpt.foreach(_.addGameSubscription(gameId))
|
||||
|
||||
val handler: Consumer[String] = msg => handleC2sMessage(gameId, msg)
|
||||
val executor = c2sExecutors.computeIfAbsent(gameId, _ => Executors.newSingleThreadExecutor())
|
||||
val handler: Consumer[String] = msg =>
|
||||
val task = new Runnable:
|
||||
def run(): Unit =
|
||||
try handleC2sMessage(gameId, msg)
|
||||
catch case ex: Exception => log.warnf(ex, "Error handling c2s message for game %s", gameId)
|
||||
Try(executor.execute(task))
|
||||
()
|
||||
try
|
||||
val subscriber = reactiveRedis
|
||||
.pubsub(classOf[String])
|
||||
@@ -78,6 +117,16 @@ class GameRedisSubscriberManager:
|
||||
log.debugf("Subscribed to game %s", gameId)
|
||||
catch case ex: Exception => log.warnf(ex, "Redis subscription failed for game %s", gameId)
|
||||
|
||||
// Notify the official-bots service to start playing a side of a game. Mirrors
|
||||
// the event the tournament service publishes; official-bots subscribes to
|
||||
// "<prefix>:bot:*:events".
|
||||
def publishBotGameStart(gameId: String, botId: String, playingAs: String): Unit =
|
||||
val channel = s"${redisConfig.prefix}:bot:$botId:events"
|
||||
val payload = s"""{"type":"gameStart","gameId":"$gameId","playingAs":"$playingAs","botAccountId":"$botId"}"""
|
||||
Try(redis.pubsub(classOf[String]).publish(channel, payload)) match
|
||||
case scala.util.Failure(ex) => log.warnf(ex, "Failed to publish bot gameStart for game %s", gameId)
|
||||
case scala.util.Success(_) => ()
|
||||
|
||||
def unsubscribeGame(gameId: String): Unit =
|
||||
Option(c2sListeners.remove(gameId)).foreach { subscriber =>
|
||||
subscriber.unsubscribe(c2sTopic(gameId)).subscribe().`with`(_ => (), _ => ())
|
||||
@@ -85,6 +134,7 @@ class GameRedisSubscriberManager:
|
||||
Option(s2cObservers.remove(gameId)).foreach { obs =>
|
||||
registry.get(gameId).foreach(_.engine.unsubscribe(obs))
|
||||
}
|
||||
Option(c2sExecutors.remove(gameId)).foreach(_.shutdownNow())
|
||||
|
||||
heartbeatServiceOpt.foreach(_.removeGameSubscription(gameId))
|
||||
log.debugf("Unsubscribed from game %s", gameId)
|
||||
@@ -156,5 +206,7 @@ class GameRedisSubscriberManager:
|
||||
|
||||
@PreDestroy
|
||||
def cleanup(): Unit =
|
||||
clockExpireSubscriber.foreach(_.unsubscribe(clockExpireChannel).await().indefinitely())
|
||||
c2sListeners.forEach((gameId, subscriber) => subscriber.unsubscribe(c2sTopic(gameId)).await().indefinitely())
|
||||
s2cObservers.forEach((gameId, obs) => registry.get(gameId).foreach(_.engine.unsubscribe(obs)))
|
||||
c2sExecutors.forEach((_, executor) => executor.shutdownNow())
|
||||
|
||||
@@ -22,4 +22,5 @@ case class GameCacheDto(
|
||||
pendingDrawOffer: Option[String],
|
||||
redoStack: List[String] = Nil,
|
||||
pendingTakebackRequest: Option[String] = None,
|
||||
lastUpdatedMs: Long = System.currentTimeMillis(),
|
||||
)
|
||||
|
||||
@@ -143,6 +143,7 @@ class RedisGameRegistry extends GameRegistry:
|
||||
clockMoveDeadline = Option(record.clockMoveDeadline).map(_.longValue),
|
||||
clockActiveColor = Option(record.clockActiveColor),
|
||||
pendingDrawOffer = Option(record.pendingDrawOffer),
|
||||
lastUpdatedMs = System.currentTimeMillis(),
|
||||
)
|
||||
(dto, reconstruct(dto))
|
||||
} match
|
||||
|
||||
@@ -25,6 +25,7 @@ import de.nowchess.chess.observer.*
|
||||
import de.nowchess.chess.redis.GameRedisSubscriberManager
|
||||
import de.nowchess.chess.registry.{GameEntry, GameRegistry}
|
||||
import de.nowchess.security.InternalOnly
|
||||
import jakarta.annotation.security.PermitAll
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import jakarta.ws.rs.*
|
||||
@@ -167,7 +168,9 @@ class GameResource:
|
||||
val mode = req.mode.getOrElse(GameMode.Open)
|
||||
val entry = newEntry(GameContext.initial, white, black, tc, mode)
|
||||
registry.store(entry)
|
||||
log.infof("About to subscribe game %s", entry.gameId)
|
||||
subscriberManager.subscribeGame(entry.gameId)
|
||||
log.infof("Subscribed game %s", entry.gameId)
|
||||
log.infof(
|
||||
"Game %s created — white=%s black=%s mode=%s",
|
||||
entry.gameId,
|
||||
@@ -177,6 +180,32 @@ class GameResource:
|
||||
)
|
||||
created(GameDtoMapper.toGameFullDto(entry, ioClient))
|
||||
|
||||
// Player-facing game creation for "play vs bot". Unlike createGame this is not
|
||||
// internal-only: a logged-in (or anonymous) player creates the game directly,
|
||||
// and core notifies the official-bots service to play the bot side.
|
||||
@POST
|
||||
@Path("/vs-bot")
|
||||
@PermitAll
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def createBotGame(body: CreateGameRequestDto): Response =
|
||||
val req = Option(body).getOrElse(CreateGameRequestDto(None, None, None, None))
|
||||
val white = playerInfoFrom(req.white, DefaultWhite)
|
||||
val black = playerInfoFrom(req.black, DefaultBlack)
|
||||
val tc = toTimeControl(req.timeControl)
|
||||
val entry = newEntry(GameContext.initial, white, black, tc, GameMode.Open)
|
||||
registry.store(entry)
|
||||
subscriberManager.subscribeGame(entry.gameId)
|
||||
notifyBotSide(entry)
|
||||
log.infof("Bot game %s created — white=%s black=%s", entry.gameId, white.displayName, black.displayName)
|
||||
created(GameDtoMapper.toGameFullDto(entry, ioClient))
|
||||
|
||||
private def notifyBotSide(entry: GameEntry): Unit =
|
||||
if entry.black.id.value.startsWith("bot-") then
|
||||
subscriberManager.publishBotGameStart(entry.gameId, entry.black.id.value, "black")
|
||||
else if entry.white.id.value.startsWith("bot-") then
|
||||
subscriberManager.publishBotGameStart(entry.gameId, entry.white.id.value, "white")
|
||||
|
||||
@GET
|
||||
@Path("/{gameId}")
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package de.nowchess.chess.service
|
||||
|
||||
import de.nowchess.api.dto.{GameCreationRequestDto, PlayerInfoDto, TimeControlDto}
|
||||
import de.nowchess.api.game.{GameContext, GameMode, TimeControl}
|
||||
import de.nowchess.api.player.{PlayerId, PlayerInfo}
|
||||
import de.nowchess.chess.engine.GameEngine
|
||||
import de.nowchess.chess.grpc.RuleSetGrpcAdapter
|
||||
import de.nowchess.chess.redis.GameRedisSubscriberManager
|
||||
import de.nowchess.chess.registry.{GameEntry, GameRegistry}
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
|
||||
@ApplicationScoped
|
||||
class GameCreationService:
|
||||
|
||||
private val log = Logger.getLogger(classOf[GameCreationService])
|
||||
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Inject var registry: GameRegistry = uninitialized
|
||||
@Inject var ruleSetAdapter: RuleSetGrpcAdapter = uninitialized
|
||||
@Inject var subscriberManager: GameRedisSubscriberManager = uninitialized
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private val DefaultWhite = PlayerInfo(PlayerId("p1"), "Player 1")
|
||||
private val DefaultBlack = PlayerInfo(PlayerId("p2"), "Player 2")
|
||||
|
||||
def createGame(req: GameCreationRequestDto): GameEntry =
|
||||
val white = playerInfoFrom(req.white, DefaultWhite)
|
||||
val black = playerInfoFrom(req.black, DefaultBlack)
|
||||
val tc = toTimeControl(req.timeControl)
|
||||
val mode = req.mode.getOrElse(GameMode.Open)
|
||||
val entry = newEntry(GameContext.initial, white, black, tc, mode)
|
||||
registry.store(entry)
|
||||
subscriberManager.subscribeGame(entry.gameId)
|
||||
log.infof(
|
||||
"Game %s created — white=%s black=%s mode=%s",
|
||||
entry.gameId,
|
||||
white.displayName,
|
||||
black.displayName,
|
||||
mode.toString,
|
||||
)
|
||||
entry
|
||||
|
||||
private def playerInfoFrom(dto: Option[PlayerInfoDto], default: PlayerInfo): PlayerInfo =
|
||||
dto.fold(default)(d => PlayerInfo(PlayerId(d.id), d.displayName))
|
||||
|
||||
private def toTimeControl(dto: Option[TimeControlDto]): TimeControl =
|
||||
dto match
|
||||
case None => TimeControl.Unlimited
|
||||
case Some(tc) =>
|
||||
tc.daysPerMove match
|
||||
case Some(d) => TimeControl.Correspondence(d)
|
||||
case None =>
|
||||
tc.limitSeconds.fold(TimeControl.Unlimited)(l => TimeControl.Clock(l, tc.incrementSeconds.getOrElse(0)))
|
||||
|
||||
private def newEntry(
|
||||
ctx: GameContext,
|
||||
white: PlayerInfo,
|
||||
black: PlayerInfo,
|
||||
tc: TimeControl,
|
||||
mode: GameMode,
|
||||
): GameEntry =
|
||||
GameEntry(
|
||||
registry.generateId(),
|
||||
GameEngine(initialContext = ctx, ruleSet = ruleSetAdapter, timeControl = tc),
|
||||
white,
|
||||
black,
|
||||
mode = mode,
|
||||
)
|
||||
@@ -18,6 +18,8 @@ nowchess:
|
||||
enabled: false
|
||||
coordinator:
|
||||
enabled: false
|
||||
game-creation-stream:
|
||||
enabled: false
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package de.nowchess.chess.engine
|
||||
|
||||
import de.nowchess.api.board.{Board, Color, File, PieceType, Rank, Square}
|
||||
import de.nowchess.api.board.{Color, File, PieceType, Rank, Square}
|
||||
import de.nowchess.api.game.GameContext
|
||||
import de.nowchess.api.move.{Move, MoveType, PromotionPiece}
|
||||
import de.nowchess.chess.observer.{GameEvent, InvalidMoveEvent, InvalidMoveReason, Observer}
|
||||
@@ -137,7 +137,7 @@ class GameEngineIntegrationTest extends AnyFunSuite with Matchers:
|
||||
|
||||
test("normalMoveNotation handles missing source piece"):
|
||||
val engine = new GameEngine(ruleSet = DefaultRules)
|
||||
val result = engine.normalMoveNotation(Move(sq("e3"), sq("e4")), Board.initial, isCapture = false)
|
||||
val result = engine.normalMoveNotation(Move(sq("e3"), sq("e4")), GameContext.initial, isCapture = false)
|
||||
|
||||
result shouldBe "e4"
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ class GameEngineNotationTest extends AnyFunSuite with Matchers:
|
||||
engine.undo()
|
||||
|
||||
val evt = events.collect { case e: MoveUndoneEvent => e }.head
|
||||
evt.pgnNotation shouldBe "e8=B"
|
||||
evt.pgnNotation shouldBe "e8=B+"
|
||||
|
||||
// ── King normal move notation (line 246) ───────────────────────────
|
||||
|
||||
@@ -134,3 +134,87 @@ class GameEngineNotationTest extends AnyFunSuite with Matchers:
|
||||
val evt = events.collect { case e: MoveUndoneEvent => e }.head
|
||||
evt.pgnNotation should startWith("K")
|
||||
evt.pgnNotation should include("f1")
|
||||
|
||||
// ── Disambiguation: two knights same rank (file suffix) ────────────
|
||||
|
||||
test("undo with two knights on same rank disambiguates by file"):
|
||||
// White knights on b1 and f3, black pawn on h7 prevents draw, both knights can reach d2
|
||||
val board = FenParser.parseBoard("k7/7p/8/8/8/5N2/8/1N5K").get
|
||||
val ctx = GameContext.initial
|
||||
.withBoard(board)
|
||||
.withTurn(Color.White)
|
||||
.withCastlingRights(de.nowchess.api.board.CastlingRights(false, false, false, false))
|
||||
|
||||
val engine = new GameEngine(ctx, DefaultRules)
|
||||
val events = captureEvents(engine)
|
||||
|
||||
// Knight on b1 moves to d2; notation must be "Nbd2" to disambiguate from Nf3
|
||||
engine.processUserInput("b1d2")
|
||||
events.clear()
|
||||
engine.undo()
|
||||
|
||||
val evt = events.collect { case e: MoveUndoneEvent => e }.head
|
||||
evt.pgnNotation should startWith("Nb")
|
||||
evt.pgnNotation should include("d2")
|
||||
|
||||
// ── Disambiguation: two knights same file (rank suffix) ────────────
|
||||
|
||||
test("undo with two knights on same file disambiguates by rank"):
|
||||
// White knights on b1 and b3, both can reach d2 or c5; use b1->d2
|
||||
val board = FenParser.parseBoard("k7/7p/8/8/8/1N6/8/1N5K").get
|
||||
val ctx = GameContext.initial
|
||||
.withBoard(board)
|
||||
.withTurn(Color.White)
|
||||
.withCastlingRights(de.nowchess.api.board.CastlingRights(false, false, false, false))
|
||||
|
||||
val engine = new GameEngine(ctx, DefaultRules)
|
||||
val events = captureEvents(engine)
|
||||
|
||||
// Knight on b1 moves to d2; notation must be "N1d2" to disambiguate from b3
|
||||
engine.processUserInput("b1d2")
|
||||
events.clear()
|
||||
engine.undo()
|
||||
|
||||
val evt = events.collect { case e: MoveUndoneEvent => e }.head
|
||||
evt.pgnNotation should include("1")
|
||||
evt.pgnNotation should include("d2")
|
||||
|
||||
// ── Check suffix (+) ───────────────────────────────────────────────
|
||||
|
||||
test("undo after move that gives check emits notation with + suffix"):
|
||||
// White rook a1, white king h1, black king e8; Ra1-e1 gives check on e-file
|
||||
val board = FenParser.parseBoard("4k3/8/8/8/8/8/8/R6K").get
|
||||
val ctx = GameContext.initial
|
||||
.withBoard(board)
|
||||
.withTurn(Color.White)
|
||||
.withCastlingRights(de.nowchess.api.board.CastlingRights(false, false, false, false))
|
||||
|
||||
val engine = new GameEngine(ctx, DefaultRules)
|
||||
val events = captureEvents(engine)
|
||||
|
||||
engine.processUserInput("a1e1")
|
||||
events.clear()
|
||||
engine.undo()
|
||||
|
||||
val evt = events.collect { case e: MoveUndoneEvent => e }.head
|
||||
evt.pgnNotation should endWith("+")
|
||||
|
||||
// ── Checkmate suffix (#) ──────────────────────────────────────────
|
||||
|
||||
test("undo after checkmate move emits notation with # suffix"):
|
||||
// Fool's mate setup (before final move): 1.f3 e5 2.g4 -- black plays Qd8-h4#
|
||||
val board = FenParser.parseBoard("rnbqkbnr/pppp1ppp/8/4p3/6P1/5P2/PPPPP2P/RNBQKBNR").get
|
||||
val ctx = GameContext.initial
|
||||
.withBoard(board)
|
||||
.withTurn(Color.Black)
|
||||
.withCastlingRights(de.nowchess.api.board.CastlingRights(true, true, true, true))
|
||||
|
||||
val engine = new GameEngine(ctx, DefaultRules)
|
||||
val events = captureEvents(engine)
|
||||
|
||||
engine.processUserInput("d8h4")
|
||||
events.clear()
|
||||
engine.undo()
|
||||
|
||||
val evt = events.collect { case e: MoveUndoneEvent => e }.head
|
||||
evt.pgnNotation should endWith("#")
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package de.nowchess.chess.service
|
||||
|
||||
import de.nowchess.api.dto.{GameCreationRequestDto, PlayerInfoDto, TimeControlDto}
|
||||
import de.nowchess.api.game.{GameMode, TimeControl}
|
||||
import de.nowchess.api.player.PlayerType
|
||||
import de.nowchess.chess.client.CombinedExportResponse
|
||||
import de.nowchess.chess.grpc.IoGrpcClientWrapper
|
||||
import de.nowchess.chess.redis.GameRedisSubscriberManager
|
||||
import io.quarkus.test.InjectMock
|
||||
import io.quarkus.test.junit.QuarkusTest
|
||||
import jakarta.inject.Inject
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.{BeforeEach, DisplayName, Test}
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.Mockito.{verify, when}
|
||||
import scala.compiletime.uninitialized
|
||||
|
||||
// scalafix:off
|
||||
@QuarkusTest
|
||||
@DisplayName("GameCreationService")
|
||||
class GameCreationServiceTest:
|
||||
|
||||
@Inject
|
||||
var service: GameCreationService = uninitialized
|
||||
|
||||
@InjectMock
|
||||
var subscriberManager: GameRedisSubscriberManager = uninitialized
|
||||
|
||||
@InjectMock
|
||||
var ioWrapper: IoGrpcClientWrapper = uninitialized
|
||||
|
||||
@BeforeEach
|
||||
def setup(): Unit =
|
||||
when(ioWrapper.exportCombined(any()))
|
||||
.thenReturn(CombinedExportResponse("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", ""))
|
||||
|
||||
private def player(id: String, name: String): PlayerInfoDto =
|
||||
PlayerInfoDto(id, name, PlayerType.Human)
|
||||
|
||||
@Test
|
||||
def createsGameAndSubscribes(): Unit =
|
||||
val req =
|
||||
GameCreationRequestDto(Some(player("w", "White")), Some(player("b", "Black")), None, Some(GameMode.Authenticated))
|
||||
val entry = service.createGame(req)
|
||||
assertNotNull(entry.gameId)
|
||||
assertEquals("White", entry.white.displayName)
|
||||
assertEquals("Black", entry.black.displayName)
|
||||
assertEquals(GameMode.Authenticated, entry.mode)
|
||||
verify(subscriberManager).subscribeGame(entry.gameId)
|
||||
|
||||
@Test
|
||||
def defaultsToOpenModeAndDefaultPlayers(): Unit =
|
||||
val entry = service.createGame(GameCreationRequestDto(None, None, None, None))
|
||||
assertEquals(GameMode.Open, entry.mode)
|
||||
assertEquals("Player 1", entry.white.displayName)
|
||||
assertEquals("Player 2", entry.black.displayName)
|
||||
|
||||
@Test
|
||||
def mapsClockTimeControl(): Unit =
|
||||
val tc = TimeControlDto(Some(300), Some(5), None)
|
||||
val entry = service.createGame(GameCreationRequestDto(None, None, Some(tc), None))
|
||||
assertEquals(TimeControl.Clock(300, 5), entry.engine.timeControl)
|
||||
|
||||
@Test
|
||||
def mapsCorrespondenceTimeControl(): Unit =
|
||||
val tc = TimeControlDto(None, None, Some(3))
|
||||
val entry = service.createGame(GameCreationRequestDto(None, None, Some(tc), None))
|
||||
assertEquals(TimeControl.Correspondence(3), entry.engine.timeControl)
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=41
|
||||
MINOR=49
|
||||
PATCH=0
|
||||
|
||||
@@ -296,3 +296,31 @@
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-02)
|
||||
|
||||
### Features
|
||||
|
||||
* add authentication permissions for metrics endpoints in application.yml ([04edd4d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/04edd4d6fd8a63196c36f6d67992832febc9bebb))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* NCS-14 implemented insufficient moves rule ([#30](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/30)) ([b0399a4](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b0399a4e489950083066c9538df9a84dcc7a4613))
|
||||
* NCS-25 Add linters to keep quality up ([#27](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/27)) ([fd4e67d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fd4e67d4f782a7e955822d90cb909d0a81676fb2))
|
||||
* NCS-29 JSON - Cherry Picked ([#28](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/28)) ([dbcafd2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/dbcafd286993e0604a6fa286c5543581a149439e))
|
||||
* NCS-30 FEN Parser using ParserCombinators ([#21](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/21)) ([b4bc72f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b4bc72f7e49f94d6e1bc805c68680e5fe8ef8e36))
|
||||
* NCS-31 FastParse FEN ([#22](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/22)) ([7a045d3](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7a045d31d757bbc5aa6f4bad2664ebe8b8519cac))
|
||||
* NCS-37 Quarkus integration ([#35](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/35)) ([f088c4e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f088c4e9ffcc498d3d1b6f01e8f50042d5830d55))
|
||||
* NCS-41 Bot Platform ([#33](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/33)) ([8744bee](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8744bee2dd20966dae90a09c21a43d5b06f59e00))
|
||||
* NCS-53 changed IO to MicroService for easier scaling ([#37](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/37)) ([b5a2966](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b5a2966adafa9650f0f7d601bdeb8fdd13710327))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
|
||||
* **pgn:** add SAN disambiguation and check/checkmate suffixes [NCS-42] ([#56](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/56)) ([2579539](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2579539084152178f4482ddb7b84b7f1162f10da))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat: add authentication permissions for metrics endpoints in application.yml" ([a298417](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a298417b9e4d68dc73bbf40be63d9484536e9f83))
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
|
||||
@@ -31,7 +31,9 @@ object PgnExporter extends GameContextExport:
|
||||
if moves.isEmpty then ""
|
||||
else
|
||||
val contexts = moves.scanLeft(GameContext.initial)((ctx, move) => DefaultRules.applyMove(ctx)(move))
|
||||
val sanMoves = moves.zip(contexts).map { case (move, ctx) => moveToAlgebraic(move, ctx.board) }
|
||||
val sanMoves = moves.zip(contexts).zip(contexts.tail).map { case ((move, ctxBefore), ctxAfter) =>
|
||||
moveToAlgebraic(move, ctxBefore, ctxAfter)
|
||||
}
|
||||
|
||||
val groupedMoves = sanMoves.zipWithIndex.groupBy(_._2 / 2)
|
||||
val moveLines = for (moveNumber, movePairs) <- groupedMoves.toList.sortBy(_._1) yield
|
||||
@@ -48,9 +50,24 @@ object PgnExporter extends GameContextExport:
|
||||
else if moveText.isEmpty then headerLines
|
||||
else s"$headerLines\n\n$moveText"
|
||||
|
||||
/** Convert a Move to Standard Algebraic Notation using the board state before the move. */
|
||||
private def moveToAlgebraic(move: Move, boardBefore: Board): String =
|
||||
move.moveType match
|
||||
private def disambiguate(from: Square, to: Square, pieceType: PieceType, ctx: GameContext): String =
|
||||
val competitors = DefaultRules
|
||||
.allLegalMoves(ctx)
|
||||
.filter(m => m.to == to && m.from != from && ctx.board.pieceAt(m.from).exists(_.pieceType == pieceType))
|
||||
if competitors.isEmpty then ""
|
||||
else
|
||||
val sameFile = competitors.exists(_.from.file == from.file)
|
||||
val sameRank = competitors.exists(_.from.rank == from.rank)
|
||||
if !sameFile then from.file.toString.toLowerCase
|
||||
else if !sameRank then (from.rank.ordinal + 1).toString
|
||||
else from.toString
|
||||
|
||||
private def moveToAlgebraic(move: Move, ctxBefore: GameContext, ctxAfter: GameContext): String =
|
||||
val suffix =
|
||||
if DefaultRules.isCheckmate(ctxAfter) then "#"
|
||||
else if DefaultRules.isCheck(ctxAfter) then "+"
|
||||
else ""
|
||||
val base = move.moveType match
|
||||
case MoveType.CastleKingside => "O-O"
|
||||
case MoveType.CastleQueenside => "O-O-O"
|
||||
case MoveType.EnPassant => s"${move.from.file.toString.toLowerCase}x${move.to}"
|
||||
@@ -60,18 +77,19 @@ object PgnExporter extends GameContextExport:
|
||||
case PromotionPiece.Rook => "=R"
|
||||
case PromotionPiece.Bishop => "=B"
|
||||
case PromotionPiece.Knight => "=N"
|
||||
val isCapture = boardBefore.pieceAt(move.to).isDefined
|
||||
val isCapture = ctxBefore.board.pieceAt(move.to).isDefined
|
||||
if isCapture then s"${move.from.file.toString.toLowerCase}x${move.to}$promSuffix"
|
||||
else s"${move.to}$promSuffix"
|
||||
case MoveType.Normal(isCapture) =>
|
||||
val dest = move.to.toString
|
||||
val capStr = if isCapture then "x" else ""
|
||||
boardBefore.pieceAt(move.from).map(_.pieceType).getOrElse(PieceType.Pawn) match
|
||||
ctxBefore.board.pieceAt(move.from).map(_.pieceType).getOrElse(PieceType.Pawn) match
|
||||
case PieceType.Pawn =>
|
||||
if isCapture then s"${move.from.file.toString.toLowerCase}x$dest"
|
||||
else dest
|
||||
case PieceType.Knight => s"N$capStr$dest"
|
||||
case PieceType.Bishop => s"B$capStr$dest"
|
||||
case PieceType.Rook => s"R$capStr$dest"
|
||||
case PieceType.Queen => s"Q$capStr$dest"
|
||||
case PieceType.Knight => s"N${disambiguate(move.from, move.to, PieceType.Knight, ctxBefore)}$capStr$dest"
|
||||
case PieceType.Bishop => s"B${disambiguate(move.from, move.to, PieceType.Bishop, ctxBefore)}$capStr$dest"
|
||||
case PieceType.Rook => s"R${disambiguate(move.from, move.to, PieceType.Rook, ctxBefore)}$capStr$dest"
|
||||
case PieceType.Queen => s"Q${disambiguate(move.from, move.to, PieceType.Queen, ctxBefore)}$capStr$dest"
|
||||
case PieceType.King => s"K$capStr$dest"
|
||||
base + suffix
|
||||
|
||||
@@ -112,3 +112,38 @@ class PgnExporterTest extends AnyFunSuite with Matchers:
|
||||
pgn should include("exf8=Q")
|
||||
pawnCapturePgn should include("exd3")
|
||||
quietPromotionPgn should include("e8=Q")
|
||||
|
||||
test("exportGame disambiguates when two knights can reach same square"):
|
||||
// 1.Nf3 a6 2.d3 a5 3.Nfd2: d3 clears d2 so both Nb1 and Nf3 can reach d2; must emit "Nfd2"
|
||||
val moves = List(
|
||||
Move(sq("g1"), sq("f3")),
|
||||
Move(sq("a7"), sq("a6")),
|
||||
Move(sq("d2"), sq("d3")),
|
||||
Move(sq("a6"), sq("a5")),
|
||||
Move(sq("f3"), sq("d2")),
|
||||
)
|
||||
val pgn = PgnExporter.exportGame(Map.empty, moves)
|
||||
pgn should include("Nfd2")
|
||||
|
||||
test("exportGame appends + after move that gives check"):
|
||||
// 1.e4 e5 2.Qh5 Nc6 3.Qxf7+ — queen captures f7, gives check to black king on e8
|
||||
val moves = List(
|
||||
Move(sq("e2"), sq("e4")),
|
||||
Move(sq("e7"), sq("e5")),
|
||||
Move(sq("d1"), sq("h5")),
|
||||
Move(sq("b8"), sq("c6")),
|
||||
Move(sq("h5"), sq("f7"), MoveType.Normal(isCapture = true)),
|
||||
)
|
||||
val pgn = PgnExporter.exportGame(Map.empty, moves)
|
||||
pgn should include("Qxf7+")
|
||||
|
||||
test("exportGame appends # after checkmate move"):
|
||||
// Fool's mate: 1.f3 e5 2.g4 Qh4#
|
||||
val moves = List(
|
||||
Move(sq("f2"), sq("f3")),
|
||||
Move(sq("e7"), sq("e5")),
|
||||
Move(sq("g2"), sq("g4")),
|
||||
Move(sq("d8"), sq("h4")),
|
||||
)
|
||||
val pgn = PgnExporter.exportGame(Map("Result" -> "*"), moves)
|
||||
pgn should include("Qh4#")
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=22
|
||||
MINOR=23
|
||||
PATCH=0
|
||||
|
||||
@@ -156,3 +156,75 @@
|
||||
### Reverts
|
||||
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-03)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **official-bots:** NCS-70-auto-register official bots with account service ([#59](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/59)) ([7117a93](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7117a93376272094d0b1a6abf2121254ce396684))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-09)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **events:** migrate game-creation and bot flows to Redis Streams NCS-89 ([#62](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/62)) ([a24924c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a24924c23057db3d700a75dbc4333557789cd991))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **official-bots:** NCS-70-auto-register official bots with account service ([#59](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/59)) ([7117a93](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7117a93376272094d0b1a6abf2121254ce396684))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
## (2026-06-09)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **events:** migrate game-creation and bot flows to Redis Streams NCS-89 ([#62](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/62)) ([a24924c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a24924c23057db3d700a75dbc4333557789cd991))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* NCS-82 add Swiss-system tournament module ([#55](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/55)) ([c5661de](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c5661de4a0ebf4b33211f5a391840dcf744656b7))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **official-bots:** NCS-70-auto-register official bots with account service ([#59](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/59)) ([7117a93](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7117a93376272094d0b1a6abf2121254ce396684))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "refactor: update metrics paths formatting in application.yml for clarity" ([3870566](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/38705663498d5f47c40dafe2f26198589ede8656))
|
||||
|
||||
@@ -77,6 +77,8 @@ dependencies {
|
||||
implementation(project(":modules:api"))
|
||||
implementation(project(":modules:io"))
|
||||
implementation(project(":modules:rule"))
|
||||
implementation(project(":modules:security"))
|
||||
implementation("io.quarkus:quarkus-rest-client-jackson")
|
||||
implementation("com.microsoft.onnxruntime:onnxruntime:${versions["ONNXRUNTIME"]!!}")
|
||||
implementation("io.quarkus:quarkus-redis-client")
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ quarkus:
|
||||
name: nowchess-official-bots
|
||||
redis:
|
||||
hosts: redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379}
|
||||
rest-client:
|
||||
account-service:
|
||||
url: http://localhost:8083
|
||||
smallrye-jwt:
|
||||
enabled: true
|
||||
log:
|
||||
@@ -15,6 +18,8 @@ nowchess:
|
||||
host: localhost
|
||||
port: 6379
|
||||
prefix: nowchess
|
||||
internal:
|
||||
secret: 123abc
|
||||
|
||||
"%deployed":
|
||||
quarkus:
|
||||
@@ -28,8 +33,13 @@ nowchess:
|
||||
exporter:
|
||||
otlp:
|
||||
endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4317}
|
||||
rest-client:
|
||||
account-service:
|
||||
url: ${ACCOUNT_SERVICE_URL}
|
||||
nowchess:
|
||||
redis:
|
||||
host: ${REDIS_HOST:localhost}
|
||||
port: ${REDIS_PORT:6379}
|
||||
prefix: ${REDIS_PREFIX:nowchess}
|
||||
internal:
|
||||
secret: ${INTERNAL_SECRET}
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package de.nowchess.bot.client
|
||||
|
||||
import de.nowchess.security.{InternalClientHeadersFactory, InternalSecretClientFilter}
|
||||
import jakarta.ws.rs.*
|
||||
import jakarta.ws.rs.core.MediaType
|
||||
import org.eclipse.microprofile.rest.client.annotation.{RegisterClientHeaders, RegisterProvider}
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient
|
||||
|
||||
case class SyncOfficialBotsRequest(bots: List[String])
|
||||
|
||||
@Path("/api/account/official-bots")
|
||||
@RegisterRestClient(configKey = "account-service")
|
||||
@RegisterProvider(classOf[InternalSecretClientFilter])
|
||||
@RegisterClientHeaders(classOf[InternalClientHeadersFactory])
|
||||
trait AccountServiceClient:
|
||||
|
||||
@POST
|
||||
@Path("/sync")
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
def syncBots(req: SyncOfficialBotsRequest): Unit
|
||||
+114
-14
@@ -1,36 +1,61 @@
|
||||
package de.nowchess.bot.service
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.nowchess.api.event.EventEnvelope
|
||||
import de.nowchess.api.move.{Move, MoveType, PromotionPiece}
|
||||
import de.nowchess.bot.BotController
|
||||
import de.nowchess.bot.BotDifficulty
|
||||
import de.nowchess.bot.client.{AccountServiceClient, SyncOfficialBotsRequest}
|
||||
import de.nowchess.bot.config.RedisConfig
|
||||
import de.nowchess.io.fen.FenParser
|
||||
import io.micrometer.core.instrument.MeterRegistry
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import io.quarkus.redis.datasource.stream.{StreamMessage, XAddArgs, XGroupCreateArgs, XReadGroupArgs}
|
||||
import io.quarkus.runtime.StartupEvent
|
||||
import jakarta.annotation.PostConstruct
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.enterprise.event.Observes
|
||||
import jakarta.inject.Inject
|
||||
import org.eclipse.microprofile.context.ManagedExecutor
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.{Failure, Success, Try}
|
||||
import java.time.Duration
|
||||
import java.util.UUID
|
||||
import java.util.function.Consumer
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@ApplicationScoped
|
||||
class OfficialBotService:
|
||||
|
||||
private val log = Logger.getLogger(classOf[OfficialBotService])
|
||||
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Inject var redis: RedisDataSource = uninitialized
|
||||
@Inject var redisConfig: RedisConfig = uninitialized
|
||||
@Inject var objectMapper: ObjectMapper = uninitialized
|
||||
@Inject var botController: BotController = uninitialized
|
||||
@Inject var meterRegistry: MeterRegistry = uninitialized
|
||||
@Inject var executor: ManagedExecutor = uninitialized
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
var accountServiceClient: AccountServiceClient = uninitialized
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private val terminalStatuses =
|
||||
Set("checkmate", "resign", "timeout", "stalemate", "insufficientMaterial", "draw")
|
||||
|
||||
private val groupName = "official-bot"
|
||||
private val consumerId = UUID.randomUUID().toString
|
||||
private val maxRetries = 3
|
||||
private val maxStreamLen = 1000L
|
||||
|
||||
private def eventStream(botName: String): String = s"${redisConfig.prefix}:bot:$botName:events:stream"
|
||||
private def dlqStream: String = s"${redisConfig.prefix}:dlq"
|
||||
|
||||
@PostConstruct
|
||||
def initializeMetrics(): Unit =
|
||||
BotController.listBots.foreach { bot =>
|
||||
@@ -39,23 +64,98 @@ class OfficialBotService:
|
||||
}
|
||||
|
||||
def onStart(@Observes event: StartupEvent): Unit =
|
||||
BotController.listBots.foreach(subscribeToEventChannel)
|
||||
val bots = BotController.listBots
|
||||
try accountServiceClient.syncBots(SyncOfficialBotsRequest(bots))
|
||||
catch case ex: Exception => log.errorf(ex, "Failed to auto-register official bots with account service")
|
||||
bots.foreach(subscribeToEventChannel)
|
||||
|
||||
private def subscribeToEventChannel(botName: String): Unit =
|
||||
val handler: Consumer[String] = msg => handleBotEvent(botName, msg)
|
||||
redis.pubsub(classOf[String]).subscribe(s"${redisConfig.prefix}:bot:$botName:events", handler)
|
||||
()
|
||||
createGroupIfAbsent(botName)
|
||||
executor.submit(
|
||||
new Runnable:
|
||||
def run(): Unit = pollLoop(botName),
|
||||
)
|
||||
log.infof("Listening to bot event stream for %s (consumer=%s)", botName, consumerId)
|
||||
|
||||
private def handleBotEvent(botName: String, msg: String): Unit =
|
||||
try
|
||||
val node = objectMapper.readTree(msg)
|
||||
if node.path("type").asText() == "gameStart" then
|
||||
val gameId = node.path("gameId").asText()
|
||||
val playingAs = node.path("playingAs").asText()
|
||||
val difficulty = node.path("difficulty").asInt(1400)
|
||||
val botAccountId = node.path("botAccountId").asText()
|
||||
watchGame(botName, gameId, playingAs, difficulty, botAccountId)
|
||||
catch case _: Exception => ()
|
||||
private def createGroupIfAbsent(botName: String): Unit =
|
||||
Try(
|
||||
redis
|
||||
.stream(classOf[String])
|
||||
.xgroupCreate(eventStream(botName), groupName, "0", new XGroupCreateArgs().mkstream()),
|
||||
) match
|
||||
case Failure(ex) if Option(ex.getMessage).exists(_.contains("BUSYGROUP")) => ()
|
||||
case Failure(ex) => log.warnf(ex, "Failed to create bot event consumer group for %s", botName)
|
||||
case Success(_) => ()
|
||||
|
||||
private def pollLoop(botName: String): Unit =
|
||||
while true do
|
||||
Try {
|
||||
val messages = redis
|
||||
.stream(classOf[String])
|
||||
.xreadgroup(
|
||||
groupName,
|
||||
consumerId,
|
||||
eventStream(botName),
|
||||
">",
|
||||
new XReadGroupArgs().count(10).block(Duration.ofSeconds(2)),
|
||||
)
|
||||
Option(messages).foreach(_.forEach(msg => handleStreamMessage(botName, msg)))
|
||||
} match
|
||||
case Failure(ex) => log.warnf(ex, "Error in bot event poll loop for %s", botName)
|
||||
case Success(_) => ()
|
||||
|
||||
private def handleStreamMessage(botName: String, msg: StreamMessage[String, String, String]): Unit =
|
||||
val json = msg.payload().get("data")
|
||||
val attempt = Option(msg.payload().get("attempt")).flatMap(_.toIntOption).getOrElse(0)
|
||||
Try {
|
||||
val envelope = objectMapper.readValue(json, classOf[EventEnvelope])
|
||||
handleBotEvent(botName, envelope)
|
||||
} match
|
||||
case Success(_) => ack(botName, msg.id())
|
||||
case Failure(ex) if attempt + 1 < maxRetries =>
|
||||
log.warnf(ex, "Bot event handling failed for %s (attempt %d), retrying", botName, attempt)
|
||||
retry(botName, json, attempt + 1)
|
||||
ack(botName, msg.id())
|
||||
case Failure(ex) =>
|
||||
log.errorf(ex, "Bot event handling failed for %s after %d attempts, sending to DLQ", botName, maxRetries)
|
||||
toDlq(json, ex, attempt)
|
||||
ack(botName, msg.id())
|
||||
|
||||
private def handleBotEvent(botName: String, envelope: EventEnvelope): Unit =
|
||||
val payload = envelope.payload
|
||||
val gameId = payload.path("gameId").asText()
|
||||
val playingAs = payload.path("playingAs").asText()
|
||||
val difficulty = payload.path("difficulty").asInt(1400)
|
||||
val botAccountId = payload.path("botAccountId").asText()
|
||||
watchGame(botName, gameId, playingAs, difficulty, botAccountId)
|
||||
|
||||
private def ack(botName: String, id: String): Unit =
|
||||
Try(redis.stream(classOf[String]).xack(eventStream(botName), groupName, id)) match
|
||||
case Failure(ex) => log.warnf(ex, "Failed to ack bot event %s", id)
|
||||
case Success(_) => ()
|
||||
|
||||
private def retry(botName: String, json: String, attempt: Int): Unit =
|
||||
xadd(eventStream(botName), Map("data" -> json, "attempt" -> attempt.toString))
|
||||
|
||||
private def toDlq(json: String, error: Throwable, attempt: Int): Unit =
|
||||
xadd(
|
||||
dlqStream,
|
||||
Map(
|
||||
"data" -> json,
|
||||
"eventType" -> "BotGameStart",
|
||||
"error" -> Option(error.getMessage).getOrElse(error.getClass.getName),
|
||||
"attempt" -> (attempt + 1).toString,
|
||||
),
|
||||
)
|
||||
|
||||
private def xadd(key: String, fields: Map[String, String]): Unit =
|
||||
Try(
|
||||
redis
|
||||
.stream(classOf[String])
|
||||
.xadd(key, new XAddArgs().maxlen(maxStreamLen).nearlyExactTrimming(), fields.asJava),
|
||||
) match
|
||||
case Failure(ex) => log.errorf(ex, "Failed to publish to stream %s", key)
|
||||
case Success(_) => ()
|
||||
|
||||
private def watchGame(
|
||||
botName: String,
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package de.nowchess.bot.service
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import scala.util.Try
|
||||
|
||||
final case class TournamentBotConfig(
|
||||
serverUrl: String,
|
||||
tournamentId: String,
|
||||
token: String,
|
||||
botId: String,
|
||||
difficulty: String,
|
||||
)
|
||||
|
||||
object TournamentBotConfig:
|
||||
|
||||
private val mapper = new ObjectMapper()
|
||||
|
||||
def fromEnv(env: Map[String, String]): Option[TournamentBotConfig] =
|
||||
for
|
||||
tournamentId <- env.get("TOURNAMENT_ID").filter(_.nonEmpty)
|
||||
token <- env.get("TOURNAMENT_BOT_TOKEN").filter(_.nonEmpty)
|
||||
botId <- jwtSubject(token)
|
||||
serverUrl = env.getOrElse("TOURNAMENT_SERVER_URL", "http://localhost:8089")
|
||||
difficulty = env.getOrElse("TOURNAMENT_BOT_DIFFICULTY", "medium")
|
||||
yield TournamentBotConfig(serverUrl, tournamentId, token, botId, difficulty)
|
||||
|
||||
def jwtSubject(token: String): Option[String] =
|
||||
Try {
|
||||
val parts = token.split("\\.")
|
||||
if parts.length >= 2 then
|
||||
val payload = new String(java.util.Base64.getUrlDecoder.decode(parts(1)))
|
||||
val sub = mapper.readTree(payload).path("sub").asText()
|
||||
Option(sub).filter(_.nonEmpty)
|
||||
else None
|
||||
}.toOption.flatten
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
package de.nowchess.bot.service
|
||||
|
||||
import com.fasterxml.jackson.databind.{JsonNode, ObjectMapper}
|
||||
import de.nowchess.api.move.{Move, MoveType, PromotionPiece}
|
||||
import de.nowchess.bot.{Bot, BotController}
|
||||
import de.nowchess.io.fen.FenParser
|
||||
import io.quarkus.runtime.Startup
|
||||
import jakarta.annotation.{PostConstruct, PreDestroy}
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import jakarta.ws.rs.client.{Client, ClientBuilder, Entity}
|
||||
import jakarta.ws.rs.core.MediaType
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.{Failure, Success, Try}
|
||||
import java.io.{BufferedReader, InputStream, InputStreamReader}
|
||||
import java.util.concurrent.{ConcurrentHashMap, ExecutorService, Executors}
|
||||
|
||||
@Startup
|
||||
@ApplicationScoped
|
||||
class TournamentBotGamePlayer:
|
||||
|
||||
private val log = Logger.getLogger(classOf[TournamentBotGamePlayer])
|
||||
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Inject var objectMapper: ObjectMapper = uninitialized
|
||||
@Inject var botController: BotController = uninitialized
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
private val client: Client = ClientBuilder.newClient()
|
||||
private val workers: ExecutorService = Executors.newCachedThreadPool()
|
||||
private val activeGames = ConcurrentHashMap.newKeySet[String]()
|
||||
|
||||
private val config = TournamentBotConfig.fromEnv(System.getenv().asScala.toMap)
|
||||
|
||||
// scalafix:off DisableSyntax.var
|
||||
@volatile private var running = true
|
||||
// scalafix:on DisableSyntax.var
|
||||
|
||||
@PostConstruct
|
||||
def initialize(): Unit =
|
||||
config match
|
||||
case None =>
|
||||
log.info("Tournament bot disabled — set TOURNAMENT_ID and TOURNAMENT_BOT_TOKEN to enable")
|
||||
case Some(cfg) =>
|
||||
log.infof("Tournament bot enabled — server=%s tournament=%s bot=%s", cfg.serverUrl, cfg.tournamentId, cfg.botId)
|
||||
val thread = new Thread(() => connect(cfg), s"TournamentBot-${cfg.tournamentId}")
|
||||
thread.setDaemon(true)
|
||||
thread.start()
|
||||
|
||||
@PreDestroy
|
||||
def cleanup(): Unit =
|
||||
running = false
|
||||
workers.shutdownNow()
|
||||
Try(client.close())
|
||||
log.info("Tournament bot stopped")
|
||||
|
||||
private def connect(cfg: TournamentBotConfig): Unit =
|
||||
if join(cfg) then
|
||||
while running do
|
||||
Try(streamEvents(cfg)) match
|
||||
case Failure(ex) => log.warnf(ex, "Tournament event stream dropped — reconnecting"); sleep(5000)
|
||||
case Success(_) => sleep(2000)
|
||||
|
||||
private def join(cfg: TournamentBotConfig): Boolean =
|
||||
Try {
|
||||
val response = authed(cfg, target(cfg).path("join"))
|
||||
.post(Entity.entity("", MediaType.APPLICATION_JSON))
|
||||
val ok = response.getStatus == 200
|
||||
if ok then log.infof("Joined tournament %s", cfg.tournamentId)
|
||||
else log.errorf("Failed to join tournament %s — status %d", cfg.tournamentId, response.getStatus)
|
||||
response.close()
|
||||
ok
|
||||
}.getOrElse { log.error("Join request failed"); false }
|
||||
|
||||
private def streamEvents(cfg: TournamentBotConfig): Unit =
|
||||
val response = authed(cfg, target(cfg).path("stream"))
|
||||
.header("Accept", "application/x-ndjson")
|
||||
.get()
|
||||
if response.getStatus != 200 then
|
||||
log.warnf("Tournament stream returned status %d", response.getStatus)
|
||||
response.close()
|
||||
sleep(5000)
|
||||
else
|
||||
log.infof("Listening to tournament %s event stream", cfg.tournamentId)
|
||||
forEachLine(response.readEntity(classOf[InputStream])): line =>
|
||||
parse(line).foreach: node =>
|
||||
if node.path("type").asText() == "gameStart" then onGameStart(cfg, node.path("gameId").asText())
|
||||
|
||||
private def onGameStart(cfg: TournamentBotConfig, gameId: String): Unit =
|
||||
if gameId.nonEmpty && activeGames.add(gameId) then
|
||||
workers.submit(new Runnable { def run(): Unit = playGame(cfg, gameId) })
|
||||
()
|
||||
|
||||
private def playGame(cfg: TournamentBotConfig, gameId: String): Unit =
|
||||
Try {
|
||||
colorFor(cfg, gameId) match
|
||||
case None =>
|
||||
log.debugf("Game %s is not ours — ignoring", gameId)
|
||||
activeGames.remove(gameId)
|
||||
case Some(color) =>
|
||||
log.infof("Playing game %s as %s", gameId, color)
|
||||
val stream = openGameStream(cfg, gameId)
|
||||
maybeMoveFromCurrentState(cfg, gameId, color)
|
||||
stream.foreach(consumeGameStream(cfg, gameId, color, _))
|
||||
activeGames.remove(gameId)
|
||||
} match
|
||||
case Failure(ex) => log.errorf(ex, "Game %s crashed", gameId); activeGames.remove(gameId)
|
||||
case Success(_) => ()
|
||||
|
||||
private def colorFor(cfg: TournamentBotConfig, gameId: String): Option[String] =
|
||||
fetchGame(cfg, gameId).flatMap: game =>
|
||||
val white = game.path("white").path("id").asText()
|
||||
val black = game.path("black").path("id").asText()
|
||||
if white == cfg.botId then Some("white")
|
||||
else if black == cfg.botId then Some("black")
|
||||
else None
|
||||
|
||||
private def maybeMoveFromCurrentState(cfg: TournamentBotConfig, gameId: String, color: String): Unit =
|
||||
fetchGame(cfg, gameId).foreach: game =>
|
||||
maybeMove(cfg, gameId, color, game.path("turn").asText(), game.path("status").asText(), game.path("fen").asText())
|
||||
|
||||
private def consumeGameStream(cfg: TournamentBotConfig, gameId: String, color: String, stream: InputStream): Unit =
|
||||
val reader = new BufferedReader(new InputStreamReader(stream))
|
||||
// scalafix:off DisableSyntax.var
|
||||
var done = false
|
||||
// scalafix:on DisableSyntax.var
|
||||
Iterator
|
||||
.continually(reader.readLine())
|
||||
.map(Option(_))
|
||||
.takeWhile(opt => opt.isDefined && running && !done)
|
||||
.flatten
|
||||
.foreach { line =>
|
||||
parse(line).foreach: node =>
|
||||
node.path("type").asText() match
|
||||
case "move" =>
|
||||
maybeMove(cfg, gameId, color, node.path("turn").asText(), "ongoing", node.path("fen").asText())
|
||||
case "gameEnd" => log.infof("Game %s ended — status=%s", gameId, node.path("status").asText()); done = true
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
private def maybeMove(
|
||||
cfg: TournamentBotConfig,
|
||||
gameId: String,
|
||||
color: String,
|
||||
turn: String,
|
||||
status: String,
|
||||
fen: String,
|
||||
): Unit =
|
||||
if turn == color && status == "ongoing" && fen.nonEmpty then
|
||||
computeUci(cfg, fen) match
|
||||
case None => log.warnf("No move found for game %s (fen=%s)", gameId, fen)
|
||||
case Some(uci) => submitMove(cfg, gameId, uci)
|
||||
|
||||
private def computeUci(cfg: TournamentBotConfig, fen: String): Option[String] =
|
||||
FenParser.parseFen(fen) match
|
||||
case Left(err) => log.warnf("FEN parse failed: %s (%s)", fen, err.toString); None
|
||||
case Right(context) => engine(cfg).apply(context).map(toUci)
|
||||
|
||||
private def submitMove(cfg: TournamentBotConfig, gameId: String, uci: String): Unit =
|
||||
Try {
|
||||
val response = authed(cfg, target(cfg).path("game").path(gameId).path("move").path(uci))
|
||||
.post(Entity.entity("", MediaType.APPLICATION_JSON))
|
||||
if response.getStatus == 200 then log.infof("Played %s in game %s", uci, gameId)
|
||||
else log.warnf("Move %s rejected in game %s — status %d", uci, gameId, response.getStatus)
|
||||
response.close()
|
||||
} match
|
||||
case Failure(ex) => log.errorf(ex, "Error submitting move %s in game %s", uci, gameId)
|
||||
case Success(_) => ()
|
||||
|
||||
private def fetchGame(cfg: TournamentBotConfig, gameId: String): Option[JsonNode] =
|
||||
Try {
|
||||
val response = target(cfg).path("game").path(gameId).request(MediaType.APPLICATION_JSON).get()
|
||||
val node = if response.getStatus == 200 then Some(response.readEntity(classOf[JsonNode])) else None
|
||||
response.close()
|
||||
node
|
||||
}.getOrElse(None)
|
||||
|
||||
private def openGameStream(cfg: TournamentBotConfig, gameId: String): Option[InputStream] =
|
||||
Try {
|
||||
val response = authed(cfg, target(cfg).path("game").path(gameId).path("stream"))
|
||||
.header("Accept", "application/x-ndjson")
|
||||
.get()
|
||||
if response.getStatus == 200 then Some(response.readEntity(classOf[InputStream]))
|
||||
else { log.warnf("Game stream %s returned status %d", gameId, response.getStatus); response.close(); None }
|
||||
}.getOrElse(None)
|
||||
|
||||
private def engine(cfg: TournamentBotConfig): Bot =
|
||||
botController.getBot(cfg.difficulty).orElse(botController.getBot("medium")).get
|
||||
|
||||
private def target(cfg: TournamentBotConfig) =
|
||||
client.target(cfg.serverUrl).path("api").path("tournament").path(cfg.tournamentId)
|
||||
|
||||
private def authed(cfg: TournamentBotConfig, t: jakarta.ws.rs.client.WebTarget) =
|
||||
t.request(MediaType.APPLICATION_JSON).header("Authorization", s"Bearer ${cfg.token}")
|
||||
|
||||
private def parse(line: String): Option[JsonNode] =
|
||||
val trimmed = line.trim
|
||||
if trimmed.isEmpty then None else Try(objectMapper.readTree(trimmed)).toOption
|
||||
|
||||
private def forEachLine(stream: InputStream)(handle: String => Unit): Unit =
|
||||
val reader = new BufferedReader(new InputStreamReader(stream))
|
||||
Iterator
|
||||
.continually(reader.readLine())
|
||||
.map(Option(_))
|
||||
.takeWhile(opt => opt.isDefined && running)
|
||||
.flatten
|
||||
.foreach { line =>
|
||||
Try(handle(line)).failed.foreach(ex => log.warnf(ex, "Error handling stream line"))
|
||||
}
|
||||
|
||||
private def toUci(move: Move): String =
|
||||
val base = s"${move.from}${move.to}"
|
||||
move.moveType match
|
||||
case MoveType.Promotion(piece) => base + promotionChar(piece)
|
||||
case _ => base
|
||||
|
||||
private def promotionChar(piece: PromotionPiece): String =
|
||||
piece match
|
||||
case PromotionPiece.Knight => "n"
|
||||
case PromotionPiece.Bishop => "b"
|
||||
case PromotionPiece.Rook => "r"
|
||||
case PromotionPiece.Queen => "q"
|
||||
|
||||
private def sleep(ms: Long): Unit = Try(Thread.sleep(ms))
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=13
|
||||
MINOR=16
|
||||
PATCH=0
|
||||
|
||||
@@ -232,3 +232,257 @@
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
## (2026-05-16)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* **config:** update application.yml to nest HTTP port configuration ([3efebd5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3efebd5ed0493159c51f7246d18d59bac58cf875))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
## (2026-05-17)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* **config:** update application.yml to nest HTTP port configuration ([3efebd5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3efebd5ed0493159c51f7246d18d59bac58cf875))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure full hierarchy registration for reflection in NativeReflectionConfig ([ebba729](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ebba729af3265df1619dfbe46fd1945b2a7e30b7))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
## (2026-05-19)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* **config:** update application.yml to nest HTTP port configuration ([3efebd5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3efebd5ed0493159c51f7246d18d59bac58cf875))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure full hierarchy registration for reflection in NativeReflectionConfig ([ebba729](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ebba729af3265df1619dfbe46fd1945b2a7e30b7))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add log message for starting Writeback listener ([b610678](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b610678005de645115f48348e66aa9e6f5deb3d5))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
## (2026-05-19)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* **config:** update application.yml to nest HTTP port configuration ([3efebd5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3efebd5ed0493159c51f7246d18d59bac58cf875))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* **redis:** add @Startup annotation to GameWritebackStreamListener ([d61fe97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d61fe97b4c8e2db5e34b4a14d995297cc09f9435))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure full hierarchy registration for reflection in NativeReflectionConfig ([ebba729](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ebba729af3265df1619dfbe46fd1945b2a7e30b7))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add log message for starting Writeback listener ([b610678](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b610678005de645115f48348e66aa9e6f5deb3d5))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
## (2026-05-19)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* **config:** update application.yml to nest HTTP port configuration ([3efebd5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3efebd5ed0493159c51f7246d18d59bac58cf875))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* **redis:** add @Startup annotation to GameWritebackStreamListener ([d61fe97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d61fe97b4c8e2db5e34b4a14d995297cc09f9435))
|
||||
* **redis:** use ManagedExecutor for asynchronous writeback processing ([af6b0ed](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/af6b0ed8b73724fcc8f20dfccbe6fe8f84fd792d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure full hierarchy registration for reflection in NativeReflectionConfig ([ebba729](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ebba729af3265df1619dfbe46fd1945b2a7e30b7))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add log message for starting Writeback listener ([b610678](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b610678005de645115f48348e66aa9e6f5deb3d5))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
## (2026-05-22)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add GameWritebackEventDtoMixin for JSON deserialization ([381161f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/381161f00345612a1789e08243746083dff884c5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* **config:** update application.yml to nest HTTP port configuration ([3efebd5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3efebd5ed0493159c51f7246d18d59bac58cf875))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* **redis:** add @Startup annotation to GameWritebackStreamListener ([d61fe97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d61fe97b4c8e2db5e34b4a14d995297cc09f9435))
|
||||
* **redis:** use ManagedExecutor for asynchronous writeback processing ([af6b0ed](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/af6b0ed8b73724fcc8f20dfccbe6fe8f84fd792d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure full hierarchy registration for reflection in NativeReflectionConfig ([ebba729](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ebba729af3265df1619dfbe46fd1945b2a7e30b7))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add log message for starting Writeback listener ([b610678](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b610678005de645115f48348e66aa9e6f5deb3d5))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
## (2026-05-22)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add GameWritebackEventDtoMixin for JSON deserialization ([381161f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/381161f00345612a1789e08243746083dff884c5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* **config:** update application.yml to nest HTTP port configuration ([3efebd5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3efebd5ed0493159c51f7246d18d59bac58cf875))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **dto:** update GameWritebackEventDto for JSON deserialization and remove unused mixin ([576e3fe](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/576e3fea9bf1082549ea53efd3288474c42be93d))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* **redis:** add @Startup annotation to GameWritebackStreamListener ([d61fe97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d61fe97b4c8e2db5e34b4a14d995297cc09f9435))
|
||||
* **redis:** use ManagedExecutor for asynchronous writeback processing ([af6b0ed](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/af6b0ed8b73724fcc8f20dfccbe6fe8f84fd792d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure full hierarchy registration for reflection in NativeReflectionConfig ([ebba729](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ebba729af3265df1619dfbe46fd1945b2a7e30b7))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add log message for starting Writeback listener ([b610678](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b610678005de645115f48348e66aa9e6f5deb3d5))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
## (2026-05-31)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add GameWritebackEventDtoMixin for JSON deserialization ([381161f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/381161f00345612a1789e08243746083dff884c5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* **config:** update application.yml to nest HTTP port configuration ([3efebd5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3efebd5ed0493159c51f7246d18d59bac58cf875))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **dto:** update GameWritebackEventDto for JSON deserialization and remove unused mixin ([576e3fe](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/576e3fea9bf1082549ea53efd3288474c42be93d))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* **redis:** add @Startup annotation to GameWritebackStreamListener ([d61fe97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d61fe97b4c8e2db5e34b4a14d995297cc09f9435))
|
||||
* **redis:** implement game writeback stream processing with error handling and retries ([ae3ef76](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ae3ef766e8b7596a09e466cd4fb386119f17ca5c))
|
||||
* **redis:** use ManagedExecutor for asynchronous writeback processing ([af6b0ed](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/af6b0ed8b73724fcc8f20dfccbe6fe8f84fd792d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure full hierarchy registration for reflection in NativeReflectionConfig ([ebba729](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ebba729af3265df1619dfbe46fd1945b2a7e30b7))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add log message for starting Writeback listener ([b610678](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b610678005de645115f48348e66aa9e6f5deb3d5))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* **store:** replace null check with Option for stream messages ([252851d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/252851de1cd715f797847e0660ee501c3a77237e))
|
||||
## (2026-06-03)
|
||||
|
||||
### Features
|
||||
|
||||
* add initialization metrics for various services ([d438e97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d438e97f32bdde0bfc63c1b4a8cc810cdd093166))
|
||||
* add OpenTelemetry trace configuration with parentbased sampler ([3904d5a](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3904d5ad8ad4930ddee65287a7bfab785a6148f5))
|
||||
* **config:** add GameWritebackEventDtoMixin for JSON deserialization ([381161f](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/381161f00345612a1789e08243746083dff884c5))
|
||||
* **config:** update application.yml for PostgreSQL and remove staging/production configurations ([2404e61](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2404e6164c3b50ffccbea5238d636060d6abe4d6))
|
||||
* **config:** update application.yml for staging and production environments ([6113432](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6113432a14c476a3a0dfc0d449e17d023697f2ba))
|
||||
* **config:** update application.yml to nest HTTP port configuration ([3efebd5](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3efebd5ed0493159c51f7246d18d59bac58cf875))
|
||||
* configure logging and add OpenTelemetry support ([#49](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/49)) ([d57c488](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d57c4886612d1d92da0e1b79209fc83e6ef537a1))
|
||||
* **docker:** add .dockerignore and .gitignore files for build exclusions ([c987d8e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c987d8e258c0e6c4cfbdaa8381c64c410d7a2b83))
|
||||
* **docker:** add Dockerfiles for building Quarkus application in native and JVM modes ([3f2d2bb](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3f2d2bb4c97fa8cddba66e1da4427c54236dfeed))
|
||||
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
|
||||
* **dto:** update GameWritebackEventDto for JSON deserialization and remove unused mixin ([576e3fe](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/576e3fea9bf1082549ea53efd3288474c42be93d))
|
||||
* implement clock expiry scanning and handling for game records ([#53](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/53)) ([8f9eb12](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8f9eb12f663efabe4dc72b94394438652ad0ef02))
|
||||
* NCS-78 Add Traceability to the Applications ([#46](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/46)) ([649566e](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/649566eb3fcf38f91c8896a739f74ea318af312d))
|
||||
* NCS-78 Add Traceability to the Applications ([#47](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/47)) ([87dfc6c](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/87dfc6c2bcce7f7d58fc641bd8d468a2e584c108))
|
||||
* **redis:** add @Startup annotation to GameWritebackStreamListener ([d61fe97](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/d61fe97b4c8e2db5e34b4a14d995297cc09f9435))
|
||||
* **redis:** implement game writeback stream processing with error handling and retries ([ae3ef76](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ae3ef766e8b7596a09e466cd4fb386119f17ca5c))
|
||||
* **redis:** use ManagedExecutor for asynchronous writeback processing ([af6b0ed](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/af6b0ed8b73724fcc8f20dfccbe6fe8f84fd792d))
|
||||
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
|
||||
* update application.yml with new API root paths and add Micrometer and OpenTelemetry dependencies ([72ce262](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/72ce262bc491f94297700e6002fb5d0812e2cc2a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure full hierarchy registration for reflection in NativeReflectionConfig ([ebba729](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/ebba729af3265df1619dfbe46fd1945b2a7e30b7))
|
||||
* NCS-85 Database Writeback fails without Logs ([#52](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/52)) ([7323908](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/73239088d985f01aa6b1067ed9097a845e471d4f))
|
||||
* **redis:** add log message for starting Writeback listener ([b610678](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/b610678005de645115f48348e66aa9e6f5deb3d5))
|
||||
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
|
||||
* remove unused HTTP root-path configurations from application.yml ([3ed3e59](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/3ed3e59ee456d54cd3d65ece4f36623e256b9736))
|
||||
* **store:** cap game-writeback stream with MAXLEN trimming ([#58](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/58)) ([32c3887](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/32c388760b4f40f2937e4f3b4a04495313144fc0))
|
||||
* **store:** replace null check with Option for stream messages ([252851d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/252851de1cd715f797847e0660ee501c3a77237e))
|
||||
|
||||
@@ -60,6 +60,7 @@ dependencies {
|
||||
implementation("io.quarkus:quarkus-opentelemetry")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-scala_3:${versions["JACKSON_SCALA"]!!}")
|
||||
implementation("io.quarkus:quarkus-redis-client")
|
||||
implementation("io.quarkus:quarkus-scheduler")
|
||||
|
||||
testImplementation(platform("org.junit:junit-bom:5.13.4"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
|
||||
@@ -9,5 +9,6 @@ import io.quarkus.runtime.annotations.RegisterForReflection
|
||||
classOf[GameRecord],
|
||||
classOf[GameWritebackEventDto],
|
||||
),
|
||||
registerFullHierarchy = true,
|
||||
)
|
||||
class NativeReflectionConfig
|
||||
|
||||
+87
-13
@@ -2,16 +2,22 @@ package de.nowchess.store.redis
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.nowchess.api.dto.GameWritebackEventDto
|
||||
import de.nowchess.store.config.RedisConfig
|
||||
import de.nowchess.store.service.GameWritebackService
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import io.quarkus.redis.datasource.stream.{StreamMessage, XAddArgs, XGroupCreateArgs, XReadGroupArgs}
|
||||
import io.quarkus.runtime.Startup
|
||||
import jakarta.annotation.PostConstruct
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import org.eclipse.microprofile.context.ManagedExecutor
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.{Failure, Success, Try}
|
||||
import java.util.function.Consumer
|
||||
import java.util.UUID
|
||||
|
||||
@Startup
|
||||
@ApplicationScoped
|
||||
class GameWritebackStreamListener:
|
||||
@Inject
|
||||
@@ -19,20 +25,88 @@ class GameWritebackStreamListener:
|
||||
var redis: RedisDataSource = uninitialized
|
||||
@Inject var objectMapper: ObjectMapper = uninitialized
|
||||
@Inject var writebackService: GameWritebackService = uninitialized
|
||||
@Inject var executor: ManagedExecutor = uninitialized
|
||||
@Inject var redisConfig: RedisConfig = uninitialized
|
||||
// scalafix:on
|
||||
|
||||
private val log = Logger.getLogger(classOf[GameWritebackStreamListener])
|
||||
private val log = Logger.getLogger(classOf[GameWritebackStreamListener])
|
||||
private val groupName = "store-writeback"
|
||||
|
||||
private def streamKey = s"${redisConfig.prefix}:game-writeback"
|
||||
private def dlqKey = s"${redisConfig.prefix}:game-writeback-dlq"
|
||||
private val maxRetries = 3
|
||||
private val consumerId = UUID.randomUUID().toString
|
||||
private val maxStreamLen = 1000L
|
||||
|
||||
@PostConstruct
|
||||
def startListening(): Unit =
|
||||
val handler: Consumer[String] = json =>
|
||||
Try(objectMapper.readValue(json, classOf[GameWritebackEventDto])) match
|
||||
case Failure(ex) =>
|
||||
log.errorf(ex, "Failed to parse game-writeback event: %s", json)
|
||||
case Success(event) =>
|
||||
Try(writebackService.writeBack(event)) match
|
||||
case Failure(ex) =>
|
||||
log.errorf(ex, "Failed to write back game event for gameId=%s", event.gameId)
|
||||
case Success(_) => ()
|
||||
redis.pubsub(classOf[String]).subscribe("game-writeback", handler)
|
||||
()
|
||||
createGroupIfAbsent()
|
||||
executor.submit(
|
||||
new Runnable:
|
||||
def run(): Unit = pollLoop(),
|
||||
)
|
||||
log.infof("Started listening to game-writeback stream (consumer=%s)", consumerId)
|
||||
|
||||
private def createGroupIfAbsent(): Unit =
|
||||
Try(redis.stream(classOf[String]).xgroupCreate(streamKey, groupName, "0", new XGroupCreateArgs().mkstream())) match
|
||||
case Failure(ex) if Option(ex.getMessage).exists(_.contains("BUSYGROUP")) => ()
|
||||
case Failure(ex) => log.warnf(ex, "Failed to create consumer group")
|
||||
case Success(_) => ()
|
||||
|
||||
private def pollLoop(): Unit =
|
||||
while true do
|
||||
Try {
|
||||
val messages = redis
|
||||
.stream(classOf[String])
|
||||
.xreadgroup(
|
||||
groupName,
|
||||
consumerId,
|
||||
streamKey,
|
||||
">",
|
||||
new XReadGroupArgs().count(10).block(java.time.Duration.ofSeconds(2)),
|
||||
)
|
||||
Option(messages).foreach(_.forEach(msg => handleMessage(msg)))
|
||||
} match
|
||||
case Failure(ex) => log.warnf(ex, "Error in writeback poll loop")
|
||||
case Success(_) => ()
|
||||
|
||||
private def handleMessage(msg: StreamMessage[String, String, String]): Unit =
|
||||
val payload = msg.payload()
|
||||
val json = payload.get("data")
|
||||
val attempt = Option(payload.get("attempt")).flatMap(_.toIntOption).getOrElse(0)
|
||||
|
||||
Try(objectMapper.readValue(json, classOf[GameWritebackEventDto])) match
|
||||
case Failure(ex) =>
|
||||
log.errorf(ex, "Unparseable writeback event, sending to DLQ: %s", json)
|
||||
xadd(dlqKey, json, attempt)
|
||||
ack(msg.id())
|
||||
case Success(event) =>
|
||||
Try(writebackService.writeBack(event)) match
|
||||
case Success(_) =>
|
||||
ack(msg.id())
|
||||
case Failure(ex) if attempt + 1 < maxRetries =>
|
||||
log.warnf(ex, "Writeback failed for gameId=%s attempt=%d, retrying", event.gameId, attempt)
|
||||
xadd(streamKey, json, attempt + 1)
|
||||
ack(msg.id())
|
||||
case Failure(ex) =>
|
||||
log.errorf(ex, "Writeback failed for gameId=%s after %d attempts, sending to DLQ", event.gameId, maxRetries)
|
||||
xadd(dlqKey, json, attempt)
|
||||
ack(msg.id())
|
||||
|
||||
private def ack(id: String): Unit =
|
||||
Try(redis.stream(classOf[String]).xack(streamKey, groupName, id)) match
|
||||
case Failure(ex) => log.warnf(ex, "Failed to ack message %s", id)
|
||||
case Success(_) => ()
|
||||
|
||||
private def xadd(key: String, json: String, attempt: Int): Unit =
|
||||
Try(
|
||||
redis
|
||||
.stream(classOf[String])
|
||||
.xadd(
|
||||
key,
|
||||
new XAddArgs().maxlen(maxStreamLen).nearlyExactTrimming(),
|
||||
Map("data" -> json, "attempt" -> attempt.toString).asJava,
|
||||
),
|
||||
) match
|
||||
case Failure(ex) => log.errorf(ex, "Failed to publish to stream %s", key)
|
||||
case Success(_) => ()
|
||||
|
||||
@@ -34,6 +34,19 @@ class GameRecordRepository:
|
||||
.asScala
|
||||
.toList
|
||||
|
||||
def findExpiredLiveClockGames(nowMs: Long): List[GameRecord] =
|
||||
em.createQuery(
|
||||
"SELECT g FROM GameRecord g WHERE g.result IS NULL AND g.clockLastTickAt IS NOT NULL AND g.whiteRemainingMs IS NOT NULL",
|
||||
classOf[GameRecord],
|
||||
).getResultList
|
||||
.asScala
|
||||
.toList
|
||||
.filter { g =>
|
||||
val remaining =
|
||||
if g.clockActiveColor == "white" then g.whiteRemainingMs.longValue else g.blackRemainingMs.longValue
|
||||
g.clockLastTickAt.longValue + remaining < nowMs
|
||||
}
|
||||
|
||||
def findByPlayerIdRunning(playerId: String, offset: Int, limit: Int): List[GameRecord] =
|
||||
em.createQuery(
|
||||
"SELECT g FROM GameRecord g WHERE g.whiteId = :id OR g.blackId = :id AND g.result = null ORDER BY g.updatedAt DESC",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.nowchess.store.service
|
||||
|
||||
import de.nowchess.store.config.RedisConfig
|
||||
import de.nowchess.store.repository.GameRecordRepository
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import io.quarkus.scheduler.Scheduled
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
|
||||
@ApplicationScoped
|
||||
class ClockExpiryScanner:
|
||||
@Inject
|
||||
// scalafix:off DisableSyntax.var
|
||||
var repository: GameRecordRepository = uninitialized
|
||||
@Inject var redis: RedisDataSource = uninitialized
|
||||
@Inject var redisConfig: RedisConfig = uninitialized
|
||||
// scalafix:on
|
||||
|
||||
private val log = Logger.getLogger(classOf[ClockExpiryScanner])
|
||||
|
||||
private def clockExpireChannel: String = s"${redisConfig.prefix}:game:clock:expire"
|
||||
|
||||
@Scheduled(every = "30s")
|
||||
def scan(): Unit =
|
||||
try
|
||||
val nowMs = System.currentTimeMillis()
|
||||
val expired = repository.findExpiredLiveClockGames(nowMs)
|
||||
if expired.nonEmpty then
|
||||
log.infof("Found %d games with expired clocks", expired.size)
|
||||
expired.foreach { record =>
|
||||
log.infof("Publishing clock expiry for game %s", record.gameId)
|
||||
redis.pubsub(classOf[String]).publish(clockExpireChannel, record.gameId)
|
||||
}
|
||||
catch case ex: Exception => log.warnf(ex, "Clock expiry scan failed")
|
||||
@@ -1,3 +1,3 @@
|
||||
MAJOR=0
|
||||
MINOR=15
|
||||
MINOR=24
|
||||
PATCH=0
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
plugins {
|
||||
id("scala")
|
||||
id("org.scoverage") version "8.1"
|
||||
id("io.quarkus")
|
||||
}
|
||||
|
||||
group = "de.nowchess"
|
||||
version = "1.0-SNAPSHOT"
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val versions = rootProject.extra["VERSIONS"] as Map<String, String>
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
scala {
|
||||
scalaVersion = versions["SCALA3"]!!
|
||||
}
|
||||
|
||||
scoverage {
|
||||
scoverageVersion.set(versions["SCOVERAGE"]!!)
|
||||
}
|
||||
|
||||
tasks.withType<ScalaCompile> {
|
||||
scalaCompileOptions.additionalParameters = listOf("-encoding", "UTF-8")
|
||||
}
|
||||
|
||||
val quarkusPlatformGroupId: String by project
|
||||
val quarkusPlatformArtifactId: String by project
|
||||
val quarkusPlatformVersion: String by project
|
||||
|
||||
dependencies {
|
||||
implementation(project(":modules:api"))
|
||||
implementation(project(":modules:security"))
|
||||
|
||||
runtimeOnly("io.quarkus:quarkus-jdbc-h2")
|
||||
|
||||
compileOnly("org.scala-lang:scala3-compiler_3") {
|
||||
version {
|
||||
strictly(versions["SCALA3"]!!)
|
||||
}
|
||||
}
|
||||
implementation("org.scala-lang:scala3-library_3") {
|
||||
version {
|
||||
strictly(versions["SCALA3"]!!)
|
||||
}
|
||||
}
|
||||
|
||||
implementation(platform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}"))
|
||||
implementation("io.quarkus:quarkus-rest")
|
||||
implementation("io.quarkus:quarkus-rest-jackson")
|
||||
implementation("io.quarkus:quarkus-rest-client-jackson")
|
||||
implementation("io.quarkus:quarkus-config-yaml")
|
||||
implementation("io.quarkus:quarkus-arc")
|
||||
implementation("io.quarkus:quarkus-hibernate-orm-panache")
|
||||
implementation("io.quarkus:quarkus-jdbc-postgresql")
|
||||
implementation("io.quarkus:quarkus-smallrye-jwt")
|
||||
implementation("io.quarkus:quarkus-elytron-security-common")
|
||||
implementation("io.quarkus:quarkus-smallrye-health")
|
||||
implementation("io.quarkus:quarkus-logging-json")
|
||||
implementation("io.quarkus:quarkus-micrometer")
|
||||
implementation("io.quarkus:quarkus-micrometer-registry-prometheus")
|
||||
implementation("io.quarkus:quarkus-opentelemetry")
|
||||
implementation("io.quarkus:quarkus-smallrye-openapi")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-scala_3:${versions["JACKSON_SCALA"]!!}")
|
||||
implementation("io.quarkus:quarkus-redis-client")
|
||||
|
||||
testImplementation(platform("org.junit:junit-bom:5.13.4"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
testImplementation("io.quarkus:quarkus-smallrye-jwt-build")
|
||||
testImplementation("org.scalatest:scalatest_3:${versions["SCALATEST"]!!}")
|
||||
testImplementation("co.helmethair:scalatest-junit-runner:${versions["SCALATEST_JUNIT"]!!}")
|
||||
testImplementation("io.quarkus:quarkus-junit5")
|
||||
testImplementation("io.quarkus:quarkus-junit5-mockito")
|
||||
testImplementation("io.rest-assured:rest-assured")
|
||||
testImplementation("io.quarkus:quarkus-jdbc-h2")
|
||||
testImplementation("io.quarkus:quarkus-test-security")
|
||||
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
}
|
||||
|
||||
configurations.matching { !it.name.startsWith("scoverage") }.configureEach {
|
||||
resolutionStrategy.force("org.scala-lang:scala-library:${versions["SCALA_LIBRARY"]!!}")
|
||||
}
|
||||
configurations.scoverage {
|
||||
resolutionStrategy.eachDependency {
|
||||
if (requested.group == "org.scoverage" && requested.name.startsWith("scalac-scoverage-plugin_")) {
|
||||
useTarget("${requested.group}:scalac-scoverage-plugin_2.13.16:2.3.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
options.compilerArgs.add("-parameters")
|
||||
}
|
||||
|
||||
tasks.withType<Jar>().configureEach {
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform {
|
||||
includeEngines("scalatest", "junit-jupiter")
|
||||
testLogging {
|
||||
events("passed", "skipped", "failed")
|
||||
showStandardStreams = true
|
||||
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
||||
}
|
||||
}
|
||||
finalizedBy(tasks.reportScoverage)
|
||||
}
|
||||
tasks.reportScoverage {
|
||||
dependsOn(tasks.test)
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
quarkus:
|
||||
http:
|
||||
port: 8088
|
||||
application:
|
||||
name: nowchess-tournament
|
||||
redis:
|
||||
hosts: redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379}
|
||||
rest-client:
|
||||
core-service:
|
||||
url: http://localhost:8080
|
||||
datasource:
|
||||
db-kind: h2
|
||||
username: sa
|
||||
password: ""
|
||||
jdbc:
|
||||
url: jdbc:h2:mem:nowchess-tournament;DB_CLOSE_DELAY=-1
|
||||
hibernate-orm:
|
||||
schema-management:
|
||||
strategy: drop-and-create
|
||||
smallrye-jwt:
|
||||
enabled: true
|
||||
|
||||
nowchess:
|
||||
redis:
|
||||
host: ${REDIS_HOST:localhost}
|
||||
port: ${REDIS_PORT:6379}
|
||||
prefix: ${REDIS_PREFIX:nowchess}
|
||||
internal:
|
||||
secret: ${INTERNAL_SECRET:123abc}
|
||||
|
||||
mp:
|
||||
jwt:
|
||||
verify:
|
||||
publickey:
|
||||
location: keys/public.pem
|
||||
issuer: nowchess
|
||||
|
||||
"%deployed":
|
||||
quarkus:
|
||||
datasource:
|
||||
db-kind: postgresql
|
||||
username: ${DB_USER:nowchess}
|
||||
password: ${DB_PASSWORD:nowchess}
|
||||
jdbc:
|
||||
url: ${DB_URL:jdbc:postgresql://localhost:5432/nowchess}
|
||||
hibernate-orm:
|
||||
schema-management:
|
||||
strategy: update
|
||||
|
||||
"%test":
|
||||
quarkus:
|
||||
datasource:
|
||||
jdbc:
|
||||
url: jdbc:h2:mem:nowchess-tournament;DB_CLOSE_DELAY=-1
|
||||
hibernate-orm:
|
||||
schema-management:
|
||||
strategy: drop-and-create
|
||||
arc:
|
||||
exclude-types: de.nowchess.tournament.redis.GameResultStreamListener
|
||||
@@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxDsnsCAl0vQx7Vu9CLDZ
|
||||
g0SG05NgUzu9T+3DTEaHGq60T2uriO8BenwyvsF3BnDqTbKf4voohZ1DNfzdbT1J
|
||||
Fj8B62FrDmxcO+sp1/b5HUCJP6y2uSRCmzOHe5k7Pk1IEi72FgBpKXSRkFibRlVf
|
||||
634g7mgsPZAQ9PJEsv4Qvm05T9L6+Gmq6N3bMVLKRXs4RhDhaFbYH9GtUg1eI0yH
|
||||
YjGyRfqzW/nqVMstOLHt8CuPouq4p7eMzeDH3YHkxPm4GG5foCXMOd2DZrW0SCcr
|
||||
7dhFeNVWzQ2m53eOhBzNQX+v3pgjVStsePhBRt2LyGfwkNzmqDgqWsMzSHRMY+cn
|
||||
WQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.nowchess.tournament.client
|
||||
|
||||
import de.nowchess.security.{InternalClientHeadersFactory, InternalSecretClientFilter}
|
||||
import jakarta.ws.rs.*
|
||||
import jakarta.ws.rs.core.MediaType
|
||||
import org.eclipse.microprofile.rest.client.annotation.{RegisterClientHeaders, RegisterProvider}
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient
|
||||
|
||||
case class CorePlayerInfo(id: String, displayName: String)
|
||||
case class CoreTimeControl(limitSeconds: Option[Int], incrementSeconds: Option[Int], daysPerMove: Option[Int])
|
||||
case class CoreCreateGameRequest(
|
||||
white: Option[CorePlayerInfo],
|
||||
black: Option[CorePlayerInfo],
|
||||
timeControl: Option[CoreTimeControl],
|
||||
mode: Option[String],
|
||||
)
|
||||
case class CoreGameResponse(gameId: String)
|
||||
|
||||
@Path("/api/board/game")
|
||||
@RegisterRestClient(configKey = "core-service")
|
||||
@RegisterProvider(classOf[InternalSecretClientFilter])
|
||||
@RegisterClientHeaders(classOf[InternalClientHeadersFactory])
|
||||
trait CoreGameClient:
|
||||
|
||||
@POST
|
||||
@Consumes(Array(MediaType.APPLICATION_JSON))
|
||||
@Produces(Array(MediaType.APPLICATION_JSON))
|
||||
def createGame(req: CoreCreateGameRequest): CoreGameResponse
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.nowchess.tournament.config
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.scala.DefaultScalaModule
|
||||
import io.quarkus.jackson.ObjectMapperCustomizer
|
||||
import jakarta.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class JacksonConfig extends ObjectMapperCustomizer:
|
||||
def customize(objectMapper: ObjectMapper): Unit =
|
||||
objectMapper.registerModule(DefaultScalaModule)
|
||||
@@ -0,0 +1,12 @@
|
||||
package de.nowchess.tournament.config
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty
|
||||
import scala.compiletime.uninitialized
|
||||
|
||||
@ApplicationScoped
|
||||
class RedisConfig:
|
||||
// scalafix:off DisableSyntax.var
|
||||
@ConfigProperty(name = "nowchess.redis.prefix", defaultValue = "nowchess")
|
||||
var prefix: String = uninitialized
|
||||
// scalafix:on DisableSyntax.var
|
||||
@@ -0,0 +1,33 @@
|
||||
package de.nowchess.tournament.domain
|
||||
|
||||
import jakarta.persistence.*
|
||||
import scala.compiletime.uninitialized
|
||||
import java.time.Instant
|
||||
|
||||
@Entity
|
||||
@Table(name = "tournaments")
|
||||
class Tournament:
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Id
|
||||
var id: String = uninitialized
|
||||
|
||||
@Column(nullable = false)
|
||||
var fullName: String = uninitialized
|
||||
|
||||
var nbRounds: Int = 0
|
||||
var clockLimit: Int = 0
|
||||
var clockIncrement: Int = 0
|
||||
var rated: Boolean = true
|
||||
|
||||
@Column(nullable = false)
|
||||
var status: String = "created"
|
||||
|
||||
var currentRound: Int = 0
|
||||
|
||||
@Column(nullable = false)
|
||||
var createdBy: String = uninitialized
|
||||
|
||||
var startsAt: Instant = uninitialized
|
||||
var winnerId: String = uninitialized
|
||||
var winnerName: String = uninitialized
|
||||
// scalafix:on
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package de.nowchess.tournament.domain
|
||||
|
||||
import jakarta.persistence.*
|
||||
import scala.compiletime.uninitialized
|
||||
import java.util.UUID
|
||||
|
||||
@Entity
|
||||
@Table(name = "tournament_pairings")
|
||||
class TournamentPairing:
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
var id: UUID = uninitialized
|
||||
|
||||
@Column(nullable = false)
|
||||
var tournamentId: String = uninitialized
|
||||
|
||||
var round: Int = 0
|
||||
var whiteId: String = uninitialized
|
||||
var whiteName: String = uninitialized
|
||||
|
||||
@Column(nullable = false)
|
||||
var blackId: String = uninitialized
|
||||
|
||||
@Column(nullable = false)
|
||||
var blackName: String = uninitialized
|
||||
|
||||
var gameId: String = uninitialized
|
||||
var winner: String = uninitialized
|
||||
var moveList: String = uninitialized
|
||||
// scalafix:on
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package de.nowchess.tournament.domain
|
||||
|
||||
import jakarta.persistence.*
|
||||
import scala.compiletime.uninitialized
|
||||
import java.util.UUID
|
||||
|
||||
@Entity
|
||||
@Table(name = "tournament_participants")
|
||||
class TournamentParticipant:
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
var id: UUID = uninitialized
|
||||
|
||||
@Column(nullable = false)
|
||||
var tournamentId: String = uninitialized
|
||||
|
||||
@Column(nullable = false)
|
||||
var botId: String = uninitialized
|
||||
|
||||
@Column(nullable = false)
|
||||
var botName: String = uninitialized
|
||||
|
||||
var points: Double = 0.0
|
||||
var tieBreak: Double = 0.0
|
||||
var nbGames: Int = 0
|
||||
var wins: Int = 0
|
||||
var draws: Int = 0
|
||||
var losses: Int = 0
|
||||
var byeCount: Int = 0
|
||||
// scalafix:on
|
||||
@@ -0,0 +1,74 @@
|
||||
package de.nowchess.tournament.dto
|
||||
|
||||
case class BotRef(id: String, name: String)
|
||||
|
||||
case class Clock(limit: Int, increment: Int)
|
||||
|
||||
case class Variant(key: String, name: String)
|
||||
|
||||
case class CreateTournamentForm(
|
||||
name: String,
|
||||
nbRounds: Int,
|
||||
clockLimit: Int,
|
||||
clockIncrement: Int,
|
||||
rated: Boolean = true,
|
||||
)
|
||||
|
||||
case class ResultDto(
|
||||
rank: Int,
|
||||
points: Double,
|
||||
tieBreak: Double,
|
||||
bot: BotRef,
|
||||
nbGames: Int,
|
||||
wins: Int,
|
||||
draws: Int,
|
||||
losses: Int,
|
||||
)
|
||||
|
||||
case class Standing(page: Int, players: List[ResultDto])
|
||||
|
||||
case class TournamentDto(
|
||||
id: String,
|
||||
fullName: String,
|
||||
clock: Clock,
|
||||
variant: Variant,
|
||||
rated: Boolean,
|
||||
nbPlayers: Int,
|
||||
nbRounds: Int,
|
||||
createdBy: String,
|
||||
startsAt: Option[String],
|
||||
status: String,
|
||||
round: Int,
|
||||
standing: Standing,
|
||||
winner: Option[BotRef],
|
||||
)
|
||||
|
||||
case class TournamentListDto(
|
||||
created: List[TournamentDto],
|
||||
started: List[TournamentDto],
|
||||
finished: List[TournamentDto],
|
||||
)
|
||||
|
||||
case class PairingDto(
|
||||
id: String,
|
||||
round: Int,
|
||||
white: Option[BotRef],
|
||||
black: BotRef,
|
||||
gameId: Option[String],
|
||||
winner: Option[String],
|
||||
)
|
||||
|
||||
case class GameExportDto(
|
||||
id: String,
|
||||
round: Int,
|
||||
white: BotRef,
|
||||
black: BotRef,
|
||||
winner: Option[String],
|
||||
moves: String,
|
||||
)
|
||||
|
||||
case class RoundPairingsDto(round: Int, pairings: List[PairingDto])
|
||||
|
||||
case class ErrorDto(error: String)
|
||||
|
||||
case class OkDto(ok: Boolean = true)
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.nowchess.tournament.error
|
||||
|
||||
enum TournamentError(val message: String):
|
||||
case NotFound(id: String) extends TournamentError(s"Tournament $id not found")
|
||||
case NotDirector extends TournamentError("Not the tournament director")
|
||||
case WrongStatus(expected: String) extends TournamentError(s"Tournament must be in $expected status")
|
||||
case AlreadyJoined extends TournamentError("Already joined this tournament")
|
||||
case NotJoined extends TournamentError("Not joined this tournament")
|
||||
case NotEnoughParticipants extends TournamentError("Need at least 2 participants to start")
|
||||
case NotABot extends TournamentError("Only bot accounts can join tournaments")
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package de.nowchess.tournament.redis
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import de.nowchess.api.dto.GameWritebackEventDto
|
||||
import de.nowchess.tournament.config.RedisConfig
|
||||
import de.nowchess.tournament.service.TournamentService
|
||||
import io.quarkus.redis.datasource.RedisDataSource
|
||||
import io.quarkus.redis.datasource.stream.{StreamMessage, XGroupCreateArgs, XReadGroupArgs}
|
||||
import io.quarkus.runtime.Startup
|
||||
import jakarta.annotation.PostConstruct
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import org.eclipse.microprofile.context.ManagedExecutor
|
||||
import org.jboss.logging.Logger
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.util.{Failure, Success, Try}
|
||||
import java.util.UUID
|
||||
|
||||
@Startup
|
||||
@ApplicationScoped
|
||||
class GameResultStreamListener:
|
||||
// scalafix:off DisableSyntax.var
|
||||
@Inject var redis: RedisDataSource = uninitialized
|
||||
@Inject var objectMapper: ObjectMapper = uninitialized
|
||||
@Inject var tournamentService: TournamentService = uninitialized
|
||||
@Inject var executor: ManagedExecutor = uninitialized
|
||||
@Inject var redisConfig: RedisConfig = uninitialized
|
||||
// scalafix:on
|
||||
|
||||
private val log = Logger.getLogger(classOf[GameResultStreamListener])
|
||||
private val groupName = "tournament-result"
|
||||
private val consumerId = UUID.randomUUID().toString
|
||||
|
||||
private def streamKey = s"${redisConfig.prefix}:game-writeback"
|
||||
|
||||
@PostConstruct
|
||||
def startListening(): Unit =
|
||||
createGroupIfAbsent()
|
||||
executor.submit(
|
||||
new Runnable:
|
||||
def run(): Unit = pollLoop(),
|
||||
)
|
||||
log.infof("Tournament result listener started (consumer=%s)", consumerId)
|
||||
|
||||
private def createGroupIfAbsent(): Unit =
|
||||
Try(redis.stream(classOf[String]).xgroupCreate(streamKey, groupName, "0", new XGroupCreateArgs().mkstream())) match
|
||||
case Failure(ex) if Option(ex.getMessage).exists(_.contains("BUSYGROUP")) => ()
|
||||
case Failure(ex) => log.warnf(ex, "Failed to create consumer group")
|
||||
case Success(_) => ()
|
||||
|
||||
private def pollLoop(): Unit =
|
||||
// scalafix:off DisableSyntax.var
|
||||
var running = true
|
||||
// scalafix:on DisableSyntax.var
|
||||
while running do
|
||||
Try {
|
||||
val messages = redis
|
||||
.stream(classOf[String])
|
||||
.xreadgroup(
|
||||
groupName,
|
||||
consumerId,
|
||||
streamKey,
|
||||
">",
|
||||
new XReadGroupArgs().count(10).block(java.time.Duration.ofSeconds(2)),
|
||||
)
|
||||
Option(messages).foreach(_.forEach(msg => handleMessage(msg)))
|
||||
} match
|
||||
case Failure(ex) if isInterrupted(ex) =>
|
||||
Thread.currentThread().interrupt()
|
||||
running = false
|
||||
case Failure(ex) => log.warnf(ex, "Error in result poll loop")
|
||||
case Success(_) => ()
|
||||
|
||||
private def isInterrupted(ex: Throwable): Boolean =
|
||||
ex match
|
||||
case _: InterruptedException => true
|
||||
case _ =>
|
||||
Option(ex.getCause) match
|
||||
case Some(_: InterruptedException) => true
|
||||
case _ => false
|
||||
|
||||
private def handleMessage(msg: StreamMessage[String, String, String]): Unit =
|
||||
val json = msg.payload().get("data")
|
||||
Try(objectMapper.readValue(json, classOf[GameWritebackEventDto])) match
|
||||
case Failure(ex) =>
|
||||
log.errorf(ex, "Unparseable game result event: %s", json)
|
||||
ack(msg.id())
|
||||
case Success(event) =>
|
||||
if event.result.isDefined then
|
||||
Try(tournamentService.handleGameResult(event.gameId, event.result.get, event.pgn)) match
|
||||
case Failure(ex) => log.errorf(ex, "Failed to handle game result for %s", event.gameId)
|
||||
case Success(_) => ()
|
||||
ack(msg.id())
|
||||
|
||||
private def ack(id: String): Unit =
|
||||
Try(redis.stream(classOf[String]).xack(streamKey, groupName, id)) match
|
||||
case Failure(ex) => log.warnf(ex, "Failed to ack message %s", id)
|
||||
case Success(_) => ()
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package de.nowchess.tournament.repository
|
||||
|
||||
import de.nowchess.tournament.domain.TournamentPairing
|
||||
import jakarta.enterprise.context.ApplicationScoped
|
||||
import jakarta.inject.Inject
|
||||
import jakarta.persistence.EntityManager
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import java.util.UUID
|
||||
|
||||
@ApplicationScoped
|
||||
class PairingRepository:
|
||||
|
||||
@Inject
|
||||
// scalafix:off DisableSyntax.var
|
||||
var em: EntityManager = uninitialized
|
||||
// scalafix:on
|
||||
|
||||
def findByTournamentId(tournamentId: String): List[TournamentPairing] =
|
||||
em.createQuery("FROM TournamentPairing WHERE tournamentId = :tid", classOf[TournamentPairing])
|
||||
.setParameter("tid", tournamentId)
|
||||
.getResultList
|
||||
.asScala
|
||||
.toList
|
||||
|
||||
def findByTournamentIdAndRound(tournamentId: String, round: Int): List[TournamentPairing] =
|
||||
em.createQuery(
|
||||
"FROM TournamentPairing WHERE tournamentId = :tid AND round = :round",
|
||||
classOf[TournamentPairing],
|
||||
).setParameter("tid", tournamentId)
|
||||
.setParameter("round", round)
|
||||
.getResultList
|
||||
.asScala
|
||||
.toList
|
||||
|
||||
def findByGameId(gameId: String): Option[TournamentPairing] =
|
||||
em.createQuery("FROM TournamentPairing WHERE gameId = :gid", classOf[TournamentPairing])
|
||||
.setParameter("gid", gameId)
|
||||
.getResultList
|
||||
.asScala
|
||||
.headOption
|
||||
|
||||
def persist(p: TournamentPairing): TournamentPairing =
|
||||
if Option(p.id).isEmpty then
|
||||
em.persist(p)
|
||||
p
|
||||
else em.merge(p)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user