Compare commits

...

10 Commits

Author SHA1 Message Date
TeamCity e18b1df744 ci: bump version with Build-114
Build & Test (NowChessSystems) TeamCity build failed
2026-06-05 10:28:26 +00:00
Janis 595c172900 feat(api): define shared EventEnvelope and EventType for Redis EventBus (#61)
Build & Test (NowChessSystems) TeamCity build finished
- Add EventEnvelope case class (eventId, type, payload, timestamp, correlationId)
- Add EventType enum with all known event types
- Update account EventPublisher to use EventEnvelope instead of raw string interpolation
- Add EventEnvelope/EventType to account NativeReflectionConfig
- Add Jackson Scala and JSR310 modules to api dependencies
- Add api module dependency to account module
- Add NativeReflectionConfig rule to CLAUDE.md

Closes NCS-90
https://knockoutwhist.youtrack.cloud/issue/NCS-90

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Reviewed-on: #61
2026-06-05 12:11:14 +02:00
Janis cf225826c0 chore(commands): re-validate after review findings in fix/implement workflows
Add Step 5b to fix-defect and implement-feature commands: after applying
review comments, rerun compile, test, spotlessScalaApply, and lint, then
re-spawn reviewer to confirm findings are resolved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:17:54 +02:00
Janis 25c05bc2d8 chore(commands): fix ExitWorktree cleanup + ignore worktrees dir
Pass discard_changes: true so cleanup succeeds after branch is pushed.
Add .claude/worktrees/ to .gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:15:06 +02:00
Janis 4ec6295d1d docs(claude): mandate NativeReflectionConfig registration for all serialized types
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:00:45 +02:00
Janis 2d18478110 chore(commands): add auto-linking for blocks/relates-to/subtask relations
create-story: Step 7 prompts for issue links and auto-detects IDs in description.
fix-defect: Step 3b scans for referenced IDs; Step 7b prompts for post-push links.
split-story: Step 6b adds inter-subtask blocking chains; Step 6c links external issues.
All commands now use content-based project routing (not parent inheritance).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 10:13:18 +02:00
Janis 8b95f10c65 chore(commands): enforce blocking lint + spotless before commit
Build & Test (NowChessSystems) TeamCity build was removed from queue
Run spotlessScalaApply then lint synchronously (never background) in
fix-defect and implement-feature workflows. Hard gate: do not proceed
to review/commit until lint exits 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 09:53:30 +02:00
Janis f3d96fd700 fix(official-bots): auto-register official bots with account service (#60)
Build & Test (NowChessSystems) TeamCity build finished
Reviewed-on: #60
2026-06-05 09:49:30 +02:00
TeamCity 4762f6c0c3 ci: bump version with Build-111 2026-06-03 11:50:50 +00:00
shosho996 7117a93376 fix(official-bots): NCS-70-auto-register official bots with account service (#59)
Build & Test (NowChessSystems) TeamCity build finished
Co-authored-by: Janis <janis-e@gmx.de>
Reviewed-on: #59
2026-06-03 13:27:03 +02:00
28 changed files with 462 additions and 28 deletions
+29 -2
View File
@@ -66,10 +66,17 @@ 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 ambiguous, ask the user.
If still ambiguous, ask the user.
## Step 6 — Create Issue
@@ -79,7 +86,27 @@ Call `mcp__youtrack__create_issue` with:
- `description`: full formatted story from Step 3 (Markdown)
- `type`: `Feature` (or `Task` if purely technical with no user-facing value)
## Step 7 — Report
## 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.
+41 -5
View File
@@ -39,12 +39,16 @@ After root cause confirmed, assess scope:
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`: same project as parent ticket
- `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. List created subtask IDs to user.
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.
@@ -53,7 +57,10 @@ Then proceed to Step 4, implementing subtasks in order.
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 `./lint` — 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
@@ -61,6 +68,19 @@ If any step fails, iterate until all pass.
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.
@@ -98,7 +118,23 @@ Files changed:
- <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` to delete the worktree.
Report: branch pushed, ticket commented, worktree deleted, done.
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.
+19 -2
View File
@@ -33,7 +33,10 @@ All subsequent file work happens inside this worktree.
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 `./lint` — 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
@@ -41,6 +44,19 @@ If any step fails, iterate until all pass.
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.
@@ -80,5 +96,6 @@ Files changed:
## Step 8 — Cleanup
Call `ExitWorktree` to delete the worktree.
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.
+31 -4
View File
@@ -59,11 +59,15 @@ Rules:
- 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
## Step 5 — Determine Project per Subtask
Inherit project from parent story (`$ARGUMENTS`):
- If parent is `NCWF-*` → subtasks go in `NCWF`
- If parent is `NCS-*` → subtasks go in `NCS`
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
@@ -75,8 +79,31 @@ For each subtask call `mcp__youtrack__create_issue` with:
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.
+1
View File
@@ -48,3 +48,4 @@ graphify-out/
.DS_Store
/jacoco-reporter/.venv/
/.claude/settings.local.json
/.claude/worktrees/
+8
View File
@@ -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`
---
+69
View File
@@ -348,3 +348,72 @@
* 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))
+1
View File
@@ -45,6 +45,7 @@ dependencies {
}
}
implementation(project(":modules:api"))
implementation(project(":modules:security"))
implementation(platform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}"))
@@ -12,10 +12,13 @@ import de.nowchess.account.domain.{
UserAccount,
}
import de.nowchess.account.dto.*
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],
@@ -49,3 +49,5 @@ case class RotatedTokenDto(token: String)
case class OfficialBotAccountDto(id: String, name: String, rating: Int, createdAt: String)
case class OfficialChallengeResponse(gameId: String, botName: String, difficulty: Int)
case class SyncOfficialBotsRequest(bots: List[String])
@@ -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
@@ -179,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 =
@@ -206,6 +206,17 @@ class AccountService:
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)
log.infof("Auto-registered official bot: %s", name)
}
def getOfficialBotAccounts(): List[OfficialBotAccount] =
officialBotAccountRepository.findAll()
@@ -1,6 +1,8 @@
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 jakarta.enterprise.context.ApplicationScoped
import jakarta.inject.Inject
@@ -10,22 +12,36 @@ import scala.compiletime.uninitialized
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
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)
publish(s"${redisConfig.prefix}:bot:$botId:events", EventType.GameStart, payload)
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))
()
@@ -154,3 +154,35 @@ class AccountResourceTest:
.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)
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0
MINOR=18
MINOR=20
PATCH=0
+19
View File
@@ -145,3 +145,22 @@
* **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))
+2
View File
@@ -50,6 +50,8 @@ dependencies {
}
}
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,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 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0
MINOR=14
MINOR=15
PATCH=0
+23
View File
@@ -156,3 +156,26 @@
### 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))
+2
View File
@@ -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}
@@ -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
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
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
@@ -13,6 +14,8 @@ import jakarta.annotation.PostConstruct
import jakarta.enterprise.context.ApplicationScoped
import jakarta.enterprise.event.Observes
import jakarta.inject.Inject
import org.eclipse.microprofile.rest.client.inject.RestClient
import org.jboss.logging.Logger
import scala.compiletime.uninitialized
import java.util.function.Consumer
import java.util.concurrent.TimeUnit
@@ -20,12 +23,18 @@ 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
@RestClient
var accountServiceClient: AccountServiceClient = uninitialized
// scalafix:on DisableSyntax.var
private val terminalStatuses =
@@ -39,7 +48,10 @@ 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)
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0
MINOR=13
MINOR=14
PATCH=0