Compare commits

...

28 Commits

Author SHA1 Message Date
TeamCity 708ebaf6e5 ci: bump version with Build-68 2026-05-06 07:06:52 +00:00
Janis 0eb752d493 fix(redis): enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling
Build & Test (NowChessSystems) TeamCity build finished
2026-05-06 08:41:30 +02:00
Janis e279c39246 fix(auth): add InternalClientHeadersFactory for custom client headers management
Build & Test (NowChessSystems) TeamCity build failed
2026-05-06 08:07:58 +02:00
TeamCity a101866bcf ci: bump version with Build-67 2026-05-05 18:20:39 +00:00
Janis 5baf6a7cdb fix(redis): update Redis configuration with max pool size and waiting parameters
Build & Test (NowChessSystems) TeamCity build finished
2026-05-05 20:01:32 +02:00
TeamCity a10958b0d1 ci: bump version with Build-66 2026-05-05 07:07:00 +00:00
Janis dc224abe26 fix: Lints
Build & Test (NowChessSystems) TeamCity build finished
2026-05-05 08:44:25 +02:00
Janis 1813ea1d2d fix(redis): simplify refreshRedisHeartbeat logic and ensure proper error handling
Build & Test (NowChessSystems) TeamCity build failed
2026-05-05 08:24:10 +02:00
Janis 6e0fd9523e fix(auth): update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration
Build & Test (NowChessSystems) TeamCity build failed
2026-05-05 06:49:45 +02:00
Janis 847b13202c fix(redis): prevent concurrent Redis heartbeat refreshes using AtomicBoolean
Build & Test (NowChessSystems) TeamCity build failed
2026-05-04 22:45:45 +02:00
Janis c08d5303eb fix(auth): change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation
Build & Test (NowChessSystems) TeamCity build failed
2026-05-03 17:27:30 +02:00
Janis 33e5017f51 fix(redis): add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates
Build & Test (NowChessSystems) TeamCity build failed
2026-05-03 16:47:54 +02:00
TeamCity de391113dc ci: bump version with Build-65 2026-05-03 11:30:40 +00:00
Janis 85b187293f fix(auth): correct internal secret validation logic in InternalAuthFilter
Build & Test (NowChessSystems) TeamCity build finished
2026-05-03 13:12:57 +02:00
TeamCity 4a145cb538 ci: bump version with Build-64 2026-05-03 10:34:44 +00:00
Janis 327c23a6aa fix(ci): update image existence check to use GitHub token for authentication
Build & Test (NowChessSystems) TeamCity build finished
2026-05-03 12:16:31 +02:00
Janis d522f7f6ed fix(coordinator): refine type casting in rolloutSpec method (#45)
Build & Test (NowChessSystems) TeamCity build failed
Reviewed-on: #45
Co-authored-by: Janis <janis.e.20@gmx.de>
Co-committed-by: Janis <janis.e.20@gmx.de>
2026-05-03 12:12:39 +02:00
Janis 82d0b754be fix(coordinator): use genericKubernetesResources API for Argo Rollout scaling (#44)
Build & Test (NowChessSystems) TeamCity build failed
Reviewed-on: #44
Co-authored-by: Janis <janis.e.20@gmx.de>
Co-committed-by: Janis <janis.e.20@gmx.de>
2026-05-02 22:27:18 +02:00
TeamCity 4694f516fa ci: bump version with Build-63 2026-05-02 19:39:06 +00:00
Janis fa3c6b2886 fix(coordinator): use genericKubernetesResources API for Argo Rollout scaling (#43)
Build & Test (NowChessSystems) TeamCity build finished
fabric8 disallows client.resources(classOf[GenericKubernetesResource]) — throws
KubernetesClientException at runtime. Switch to genericKubernetesResources(apiVersion, kind)
which is the correct API for CRDs.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

Reviewed-on: #43
Co-authored-by: Janis <janis.e.20@gmx.de>
Co-committed-by: Janis <janis.e.20@gmx.de>
2026-05-02 21:22:53 +02:00
TeamCity e472fb75ad ci: bump version with Build-62 2026-05-02 17:12:34 +00:00
Janis 5f44570b35 fix(dependencies): replace Fabric8 Kubernetes client with Quarkus Kubernetes client
Build & Test (NowChessSystems) TeamCity build finished
2026-05-02 18:52:47 +02:00
Janis c16f139c8e fix(ci): add version check and conditional steps for image existence in GHCR
Build & Test (NowChessSystems) TeamCity build failed
2026-05-02 18:39:09 +02:00
TeamCity cabf1bca73 ci: bump version with Build-61 2026-05-02 16:33:43 +00:00
Janis 0c981517da fix(heartbeat): inject ObjectMapper into InstanceHeartbeatService (#42)
Build & Test (NowChessSystems) TeamCity build finished
Reviewed-on: #42
Co-authored-by: Janis <janis.e.20@gmx.de>
Co-committed-by: Janis <janis.e.20@gmx.de>
2026-05-02 18:15:29 +02:00
TeamCity 18a4b1cc15 ci: bump version with Build-60 2026-05-02 15:53:05 +00:00
Janis 804a4bf179 feat(logging): add DEBUG/INFO/WARN logging across services (NCS-72) (#41)
Build & Test (NowChessSystems) TeamCity build finished
Reviewed-on: #41
Co-authored-by: Janis <janis.e.20@gmx.de>
Co-committed-by: Janis <janis.e.20@gmx.de>
2026-05-02 17:33:27 +02:00
TeamCity 3c47d2b8c9 ci: bump version with Build-58 2026-05-01 18:23:46 +00:00
52 changed files with 1176 additions and 186 deletions
+5 -2
View File
@@ -351,7 +351,10 @@
- function unsubscribe - function unsubscribe
- _...1 more_ - _...1 more_
- `modules/core/src/main/scala/de/nowchess/chess/redis/C2sMessage.scala` — class C2sMessage - `modules/core/src/main/scala/de/nowchess/chess/redis/C2sMessage.scala` — class C2sMessage
- `modules/core/src/main/scala/de/nowchess/chess/redis/GameRedisPublisher.scala` — class GameRedisPublisher, function onGameEvent - `modules/core/src/main/scala/de/nowchess/chess/redis/GameRedisPublisher.scala`
- class GameRedisPublisher
- class GameRedisPublisher
- function onGameEvent
- `modules/core/src/main/scala/de/nowchess/chess/redis/GameRedisSubscriberManager.scala` - `modules/core/src/main/scala/de/nowchess/chess/redis/GameRedisSubscriberManager.scala`
- class GameRedisSubscriberManager - class GameRedisSubscriberManager
- function subscribeGame - function subscribeGame
@@ -657,7 +660,7 @@
- `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` — imported by **9** files - `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` — imported by **9** files
- `modules/account/src/main/scala/de/nowchess/account/config/RedisConfig.scala` — imported by **8** files - `modules/account/src/main/scala/de/nowchess/account/config/RedisConfig.scala` — imported by **8** files
- `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala` — imported by **8** files - `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala` — imported by **8** files
- `modules/core/src/main/scala/de/nowchess/chess/grpc/IoGrpcClientWrapper.scala` — imported by **7** files - `modules/core/src/main/scala/de/nowchess/chess/grpc/IoGrpcClientWrapper.scala` — imported by **8** files
- `modules/api/src/main/scala/de/nowchess/api/player/PlayerInfo.scala` — imported by **6** files - `modules/api/src/main/scala/de/nowchess/api/player/PlayerInfo.scala` — imported by **6** files
- `modules/api/src/main/scala/de/nowchess/api/game/GameMode.scala` — imported by **6** files - `modules/api/src/main/scala/de/nowchess/api/game/GameMode.scala` — imported by **6** files
+1 -1
View File
@@ -19,7 +19,7 @@
- `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` — imported by **9** files - `modules/core/src/main/scala/de/nowchess/chess/observer/Observer.scala` — imported by **9** files
- `modules/account/src/main/scala/de/nowchess/account/config/RedisConfig.scala` — imported by **8** files - `modules/account/src/main/scala/de/nowchess/account/config/RedisConfig.scala` — imported by **8** files
- `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala` — imported by **8** files - `modules/api/src/main/scala/de/nowchess/api/io/GameContextImport.scala` — imported by **8** files
- `modules/core/src/main/scala/de/nowchess/chess/grpc/IoGrpcClientWrapper.scala` — imported by **7** files - `modules/core/src/main/scala/de/nowchess/chess/grpc/IoGrpcClientWrapper.scala` — imported by **8** files
- `modules/api/src/main/scala/de/nowchess/api/player/PlayerInfo.scala` — imported by **6** files - `modules/api/src/main/scala/de/nowchess/api/player/PlayerInfo.scala` — imported by **6** files
- `modules/api/src/main/scala/de/nowchess/api/game/GameMode.scala` — imported by **6** files - `modules/api/src/main/scala/de/nowchess/api/game/GameMode.scala` — imported by **6** files
+4 -1
View File
@@ -295,7 +295,10 @@
- function unsubscribe - function unsubscribe
- _...1 more_ - _...1 more_
- `modules/core/src/main/scala/de/nowchess/chess/redis/C2sMessage.scala` — class C2sMessage - `modules/core/src/main/scala/de/nowchess/chess/redis/C2sMessage.scala` — class C2sMessage
- `modules/core/src/main/scala/de/nowchess/chess/redis/GameRedisPublisher.scala` — class GameRedisPublisher, function onGameEvent - `modules/core/src/main/scala/de/nowchess/chess/redis/GameRedisPublisher.scala`
- class GameRedisPublisher
- class GameRedisPublisher
- function onGameEvent
- `modules/core/src/main/scala/de/nowchess/chess/redis/GameRedisSubscriberManager.scala` - `modules/core/src/main/scala/de/nowchess/chess/redis/GameRedisSubscriberManager.scala`
- class GameRedisSubscriberManager - class GameRedisSubscriberManager
- function subscribeGame - function subscribeGame
+46 -11
View File
@@ -19,12 +19,20 @@ jobs:
- id: check - id: check
run: | run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "Triggered manually — allowing build"
echo "allowed=true" >> "$GITHUB_OUTPUT" echo "allowed=true" >> "$GITHUB_OUTPUT"
else else
COMMIT_AUTHOR=$(git log -1 --format='%an') COMMIT_AUTHOR=$(git log -1 --format='%an')
COMMIT_SHA=$(git log -1 --format='%H')
COMMIT_MSG=$(git log -1 --format='%s')
echo "Commit: ${COMMIT_SHA}"
echo "Author: ${COMMIT_AUTHOR}"
echo "Message: ${COMMIT_MSG}"
if [[ "$COMMIT_AUTHOR" == "TeamCity" ]]; then if [[ "$COMMIT_AUTHOR" == "TeamCity" ]]; then
echo "Author is TeamCity — allowing build"
echo "allowed=true" >> "$GITHUB_OUTPUT" echo "allowed=true" >> "$GITHUB_OUTPUT"
else else
echo "Author is not TeamCity — skipping build"
echo "allowed=false" >> "$GITHUB_OUTPUT" echo "allowed=false" >> "$GITHUB_OUTPUT"
fi fi
fi fi
@@ -53,7 +61,39 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Read version from versions.env
id: version
run: |
if [ -f "modules/${{ matrix.module }}/versions.env" ]; then
source modules/${{ matrix.module }}/versions.env
VERSION="${MAJOR}.${MINOR}.${PATCH}"
echo "[${{ matrix.module }}] Version: ${VERSION}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
else
echo "[${{ matrix.module }}] No versions.env found — using 'latest'"
echo "version=latest" >> "$GITHUB_OUTPUT"
fi
- name: Check if image exists in GHCR
id: image-check
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PACKAGE="now-chess-systems%2F${{ matrix.module }}"
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)"
if echo "${EXISTING_TAGS}" | grep -qx "${VERSION}"; then
echo "[${{ matrix.module }}] Image ${VERSION} already exists — skipping build"
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "[${{ matrix.module }}] Image ${VERSION} not found — will build"
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Set up GraalVM - name: Set up GraalVM
if: steps.image-check.outputs.exists == 'false'
uses: graalvm/setup-graalvm@v1 uses: graalvm/setup-graalvm@v1
with: with:
java-version: '21' java-version: '21'
@@ -61,6 +101,7 @@ jobs:
native-image-job-reports: 'true' native-image-job-reports: 'true'
- name: Cache Gradle packages - name: Cache Gradle packages
if: steps.image-check.outputs.exists == 'false'
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: | path: |
@@ -69,24 +110,16 @@ jobs:
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}- restore-keys: gradle-${{ runner.os }}-
- name: Read version from versions.env
id: version
run: |
if [ -f "modules/${{ matrix.module }}/versions.env" ]; then
source modules/${{ matrix.module }}/versions.env
VERSION="${MAJOR}.${MINOR}.${PATCH}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
else
echo "version=latest" >> "$GITHUB_OUTPUT"
fi
- name: Build native binary - 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: ./gradlew :modules:${{ matrix.module }}:build -x test -Dquarkus.native.enabled=true -Dquarkus.package.jar.enabled=false -Dquarkus.profile=deployed --no-daemon
- name: Set up Docker Buildx - name: Set up Docker Buildx
if: steps.image-check.outputs.exists == 'false'
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry - name: Log in to GitHub Container Registry
if: steps.image-check.outputs.exists == 'false'
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
@@ -94,6 +127,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata - name: Extract metadata
if: steps.image-check.outputs.exists == 'false'
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
with: with:
@@ -103,6 +137,7 @@ jobs:
type=raw,value=latest type=raw,value=latest
- name: Build and push - name: Build and push
if: steps.image-check.outputs.exists == 'false'
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
with: with:
context: . context: .
+39
View File
@@ -40,3 +40,42 @@
* **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 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)) * **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299)) * true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-01)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-02)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-06)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
### Bug Fixes
* **auth:** add InternalClientHeadersFactory for custom client headers management ([e279c39](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e279c39246470156bf11e745ee72204018d4229d))
@@ -1,9 +1,9 @@
package de.nowchess.account.client package de.nowchess.account.client
import de.nowchess.security.InternalSecretClientFilter import de.nowchess.security.{InternalClientHeadersFactory, InternalSecretClientFilter}
import jakarta.ws.rs.* import jakarta.ws.rs.*
import jakarta.ws.rs.core.MediaType import jakarta.ws.rs.core.MediaType
import org.eclipse.microprofile.rest.client.annotation.RegisterProvider import org.eclipse.microprofile.rest.client.annotation.{RegisterClientHeaders, RegisterProvider}
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient import org.eclipse.microprofile.rest.client.inject.RegisterRestClient
case class CorePlayerInfo(id: String, displayName: String) case class CorePlayerInfo(id: String, displayName: String)
@@ -19,6 +19,7 @@ case class CoreGameResponse(gameId: String)
@Path("/api/board/game") @Path("/api/board/game")
@RegisterRestClient(configKey = "core-service") @RegisterRestClient(configKey = "core-service")
@RegisterProvider(classOf[InternalSecretClientFilter]) @RegisterProvider(classOf[InternalSecretClientFilter])
@RegisterClientHeaders(classOf[InternalClientHeadersFactory])
trait CoreGameClient: trait CoreGameClient:
@POST @POST
@@ -9,6 +9,7 @@ import io.smallrye.jwt.build.Jwt
import jakarta.enterprise.context.ApplicationScoped import jakarta.enterprise.context.ApplicationScoped
import jakarta.inject.Inject import jakarta.inject.Inject
import jakarta.transaction.Transactional import jakarta.transaction.Transactional
import org.jboss.logging.Logger
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import java.time.Instant import java.time.Instant
@@ -17,6 +18,8 @@ import java.util.UUID
@ApplicationScoped @ApplicationScoped
class AccountService: class AccountService:
private val log = Logger.getLogger(classOf[AccountService])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@Inject @Inject
var userAccountRepository: UserAccountRepository = uninitialized var userAccountRepository: UserAccountRepository = uninitialized
@@ -30,6 +33,7 @@ class AccountService:
@Transactional @Transactional
def register(req: RegisterRequest): Either[AccountError, UserAccount] = def register(req: RegisterRequest): Either[AccountError, UserAccount] =
log.infof("Registering user %s", req.username)
if userAccountRepository.findByUsername(req.username).isDefined then Left(AccountError.UsernameTaken(req.username)) if userAccountRepository.findByUsername(req.username).isDefined then Left(AccountError.UsernameTaken(req.username))
else if userAccountRepository.findByEmail(req.email).isDefined then else if userAccountRepository.findByEmail(req.email).isDefined then
Left(AccountError.EmailAlreadyRegistered(req.email)) Left(AccountError.EmailAlreadyRegistered(req.email))
@@ -40,15 +44,23 @@ class AccountService:
account.passwordHash = BcryptUtil.bcryptHash(req.password) account.passwordHash = BcryptUtil.bcryptHash(req.password)
account.createdAt = Instant.now() account.createdAt = Instant.now()
userAccountRepository.persist(account) userAccountRepository.persist(account)
log.infof("User %s registered successfully", req.username)
Right(account) Right(account)
def login(req: LoginRequest): Either[AccountError, String] = def login(req: LoginRequest): Either[AccountError, String] =
userAccountRepository.findByUsername(req.username) match userAccountRepository.findByUsername(req.username) match
case None => Left(AccountError.InvalidCredentials) case None =>
log.warnf("Login failed for unknown user %s", req.username)
Left(AccountError.InvalidCredentials)
case Some(account) => case Some(account) =>
if !BcryptUtil.matches(req.password, account.passwordHash) then Left(AccountError.InvalidCredentials) if !BcryptUtil.matches(req.password, account.passwordHash) then
else if account.banned then Left(AccountError.UserBanned) log.warnf("Login failed — invalid credentials for %s", req.username)
Left(AccountError.InvalidCredentials)
else if account.banned then
log.warnf("Login rejected — user %s is banned", req.username)
Left(AccountError.UserBanned)
else else
log.infof("User %s logged in successfully", req.username)
Right( Right(
Jwt Jwt
.issuer("nowchess") .issuer("nowchess")
@@ -65,6 +77,7 @@ class AccountService:
@Transactional @Transactional
def createBotAccount(ownerId: UUID, botName: String): Either[AccountError, BotAccount] = def createBotAccount(ownerId: UUID, botName: String): Either[AccountError, BotAccount] =
log.infof("Creating bot account %s for owner %s", botName, ownerId.toString)
userAccountRepository.findById(ownerId) match userAccountRepository.findById(ownerId) match
case None => Left(AccountError.UserNotFound) case None => Left(AccountError.UserNotFound)
case Some(owner) => case Some(owner) =>
@@ -77,6 +90,7 @@ class AccountService:
bot.token = generateBotToken(bot.id) bot.token = generateBotToken(bot.id)
bot.createdAt = Instant.now() bot.createdAt = Instant.now()
botAccountRepository.persist(bot) botAccountRepository.persist(bot)
log.infof("Bot account %s created for owner %s", botName, ownerId.toString)
Right(bot) Right(bot)
def getBotAccounts(ownerId: UUID): List[BotAccount] = def getBotAccounts(ownerId: UUID): List[BotAccount] =
@@ -93,6 +107,7 @@ class AccountService:
case None => Left(AccountError.BotNotFound) case None => Left(AccountError.BotNotFound)
case Some(_) => case Some(_) =>
botAccountRepository.delete(botId) botAccountRepository.delete(botId)
log.infof("Deleting bot account %s", botId.toString)
Right(()) Right(())
@Transactional @Transactional
@@ -146,6 +161,7 @@ class AccountService:
@Transactional @Transactional
def banUser(userId: UUID): Either[AccountError, UserAccount] = def banUser(userId: UUID): Either[AccountError, UserAccount] =
log.infof("Banning user %s", userId.toString)
userAccountRepository.findById(userId) match userAccountRepository.findById(userId) match
case None => Left(AccountError.UserNotFound) case None => Left(AccountError.UserNotFound)
case Some(user) => case Some(user) =>
@@ -156,6 +172,7 @@ class AccountService:
@Transactional @Transactional
def unbanUser(userId: UUID): Either[AccountError, UserAccount] = def unbanUser(userId: UUID): Either[AccountError, UserAccount] =
log.infof("Unbanning user %s", userId.toString)
userAccountRepository.findById(userId) match userAccountRepository.findById(userId) match
case None => Left(AccountError.UserNotFound) case None => Left(AccountError.UserNotFound)
case Some(user) => case Some(user) =>
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=4 MINOR=7
PATCH=0 PATCH=0
+21
View File
@@ -37,3 +37,24 @@
* **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 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)) * **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299)) * true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-01)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-02)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
@@ -6,6 +6,7 @@ import io.quarkus.redis.datasource.pubsub.PubSubCommands
import io.smallrye.mutiny.subscription.MultiEmitter import io.smallrye.mutiny.subscription.MultiEmitter
import jakarta.enterprise.context.ApplicationScoped import jakarta.enterprise.context.ApplicationScoped
import jakarta.inject.Inject import jakarta.inject.Inject
import org.jboss.logging.Logger
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.function.Consumer import java.util.function.Consumer
@@ -13,6 +14,8 @@ import java.util.function.Consumer
@ApplicationScoped @ApplicationScoped
class BotRegistry: class BotRegistry:
private val log = Logger.getLogger(classOf[BotRegistry])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@Inject var redis: RedisDataSource = uninitialized @Inject var redis: RedisDataSource = uninitialized
@Inject var redisConfig: RedisConfig = uninitialized @Inject var redisConfig: RedisConfig = uninitialized
@@ -25,14 +28,17 @@ class BotRegistry:
val handler: Consumer[String] = msg => emitter.emit(msg) val handler: Consumer[String] = msg => emitter.emit(msg)
val subscriber = redis.pubsub(classOf[String]).subscribe(channel, handler) val subscriber = redis.pubsub(classOf[String]).subscribe(channel, handler)
connections.put(botId, (emitter, subscriber)) connections.put(botId, (emitter, subscriber))
log.infof("Bot %s registered", botId)
() ()
def unregister(botId: String): Unit = def unregister(botId: String): Unit =
Option(connections.remove(botId)).foreach { (_, subscriber) => Option(connections.remove(botId)).foreach { (_, subscriber) =>
subscriber.unsubscribe(s"${redisConfig.prefix}:bot:$botId:events") subscriber.unsubscribe(s"${redisConfig.prefix}:bot:$botId:events")
} }
log.infof("Bot %s unregistered", botId)
def dispatch(botId: String, event: String): Unit = def dispatch(botId: String, event: String): Unit =
log.debugf("Dispatching event to bot %s", botId)
redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:bot:$botId:events", event) redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:bot:$botId:events", event)
() ()
@@ -10,6 +10,7 @@ import jakarta.inject.Inject
import jakarta.ws.rs.* import jakarta.ws.rs.*
import jakarta.ws.rs.core.{MediaType, Response} import jakarta.ws.rs.core.{MediaType, Response}
import org.eclipse.microprofile.jwt.JsonWebToken import org.eclipse.microprofile.jwt.JsonWebToken
import org.jboss.logging.Logger
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import java.util.function.Consumer import java.util.function.Consumer
@@ -18,6 +19,8 @@ import java.util.function.Consumer
@RolesAllowed(Array("**")) @RolesAllowed(Array("**"))
class BotEventResource: class BotEventResource:
private val log = Logger.getLogger(classOf[BotEventResource])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@Inject var registry: BotRegistry = uninitialized @Inject var registry: BotRegistry = uninitialized
@Inject var jwt: JsonWebToken = uninitialized @Inject var jwt: JsonWebToken = uninitialized
@@ -32,8 +35,10 @@ class BotEventResource:
val tokenType = Option(jwt.getClaim[AnyRef]("type")).map(_.toString).getOrElse("") val tokenType = Option(jwt.getClaim[AnyRef]("type")).map(_.toString).getOrElse("")
val subject = Option(jwt.getSubject).getOrElse("") val subject = Option(jwt.getSubject).getOrElse("")
if tokenType != "bot" || subject != botId then if tokenType != "bot" || subject != botId then
log.warnf("Unauthorized bot stream access — tokenType=%s subject=%s botId=%s", tokenType, subject, botId)
Multi.createFrom().failure(new ForbiddenException("Not authorized for this bot")) Multi.createFrom().failure(new ForbiddenException("Not authorized for this bot"))
else else
log.infof("Bot %s connected to event stream", botId)
Multi.createFrom().emitter[String] { emitter => Multi.createFrom().emitter[String] { emitter =>
registry.register(botId, emitter) registry.register(botId, emitter)
emitter.onTermination(() => registry.unregister(botId)) emitter.onTermination(() => registry.unregister(botId))
@@ -58,6 +63,7 @@ class BotEventResource:
@PathParam("uci") uci: String, @PathParam("uci") uci: String,
): Response = ): Response =
val playerId = Option(jwt.getSubject).getOrElse("") val playerId = Option(jwt.getSubject).getOrElse("")
val moveMsg = s"""{"type":"MOVE","uci":"$uci","playerId":"$playerId"}""" log.debugf("Bot move %s in game %s by player %s", uci, gameId, playerId)
val moveMsg = s"""{"type":"MOVE","uci":"$uci","playerId":"$playerId"}"""
redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:game:$gameId:c2s", moveMsg) redis.pubsub(classOf[String]).publish(s"${redisConfig.prefix}:game:$gameId:c2s", moveMsg)
Response.ok().build() Response.ok().build()
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=4 MINOR=6
PATCH=0 PATCH=0
+101
View File
@@ -37,3 +37,104 @@
* **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 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)) * **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299)) * true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-01)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
### Bug Fixes
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
## (2026-05-02)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
### Bug Fixes
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
## (2026-05-02)
### Features
* **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))
* **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))
* 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:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
## (2026-05-02)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
### Bug Fixes
* **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))
* **dependencies:** replace Fabric8 Kubernetes client with Quarkus Kubernetes client ([5f44570](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5f44570b357277d09f33b7296860c421e2e70ce0))
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
## (2026-05-03)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
### Bug Fixes
* **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))
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
## (2026-05-05)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
### Bug Fixes
* **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))
* **middleware:** update paths for bot generation and stockfish configuration ([2dd0501](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/2dd0501687db08dcd242359f6837125baf8a2fdc))
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
+1 -1
View File
@@ -73,7 +73,7 @@ dependencies {
implementation("io.quarkus:quarkus-rest-client-jackson") implementation("io.quarkus:quarkus-rest-client-jackson")
implementation("com.fasterxml.jackson.module:jackson-module-scala_3:${versions["JACKSON_SCALA"]!!}") implementation("com.fasterxml.jackson.module:jackson-module-scala_3:${versions["JACKSON_SCALA"]!!}")
implementation("io.quarkus:quarkus-redis-client") implementation("io.quarkus:quarkus-redis-client")
implementation("io.fabric8:kubernetes-client:6.13.0") implementation("io.quarkus:quarkus-kubernetes-client")
testImplementation(platform("org.junit:junit-bom:${versions["JUNIT_BOM"]!!}")) testImplementation(platform("org.junit:junit-bom:${versions["JUNIT_BOM"]!!}"))
testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.junit.jupiter:junit-jupiter")
@@ -5,11 +5,12 @@ quarkus:
port: 8086 port: 8086
redis: redis:
hosts: redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379} hosts: redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379}
max-pool-size: 64
max-pool-waiting: 128
grpc: grpc:
server: server:
port: 9086 port: 9086
rest-client: rest-client:
connection-timeout: 5000
read-timeout: 10000 read-timeout: 10000
smallrye-openapi: smallrye-openapi:
info-title: NowChess Coordinator Service info-title: NowChess Coordinator Service
@@ -27,13 +27,24 @@ class CoordinatorGrpcServer extends CoordinatorServiceGrpc.CoordinatorServiceImp
override def heartbeatStream( override def heartbeatStream(
responseObserver: StreamObserver[CoordinatorCommand], responseObserver: StreamObserver[CoordinatorCommand],
): StreamObserver[HeartbeatFrame] = ): StreamObserver[HeartbeatFrame] =
log.info("New heartbeat stream connection established")
new StreamObserver[HeartbeatFrame]: new StreamObserver[HeartbeatFrame]:
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
private var lastInstanceId = "" private var lastInstanceId = ""
private var firstFrameSeen = false
// scalafix:on DisableSyntax.var // scalafix:on DisableSyntax.var
override def onNext(frame: HeartbeatFrame): Unit = override def onNext(frame: HeartbeatFrame): Unit =
lastInstanceId = frame.getInstanceId lastInstanceId = frame.getInstanceId
if !firstFrameSeen then
firstFrameSeen = true
log.infof(
"First heartbeat from instance %s (host=%s http=%d grpc=%d)",
frame.getInstanceId,
frame.getHostname,
frame.getHttpPort,
frame.getGrpcPort,
)
instanceRegistry instanceRegistry
.updateInstanceFromRedis(frame.getInstanceId) .updateInstanceFromRedis(frame.getInstanceId)
.subscribe() .subscribe()
@@ -16,10 +16,18 @@ class CoreGrpcClient:
private val channels = ConcurrentHashMap[String, ManagedChannel]() private val channels = ConcurrentHashMap[String, ManagedChannel]()
private def getChannel(host: String, port: Int): ManagedChannel = private def getChannel(host: String, port: Int): ManagedChannel =
channels.computeIfAbsent(s"$host:$port", _ => ManagedChannelBuilder.forAddress(host, port).usePlaintext().build()) channels.computeIfAbsent(
s"$host:$port",
_ =>
log.infof("Opening gRPC channel to %s:%d", host, port)
ManagedChannelBuilder.forAddress(host, port).usePlaintext().build(),
)
private def evictStaleChannel(host: String, port: Int): Unit = private def evictStaleChannel(host: String, port: Int): Unit =
Option(channels.remove(s"$host:$port")).foreach(_.shutdownNow()) Option(channels.remove(s"$host:$port")).foreach { ch =>
log.infof("Evicting stale gRPC channel to %s:%d", host, port)
ch.shutdownNow()
}
@PreDestroy @PreDestroy
def shutdown(): Unit = def shutdown(): Unit =
@@ -33,7 +41,9 @@ class CoreGrpcClient:
try try
val stub = CoordinatorServiceGrpc.newBlockingStub(getChannel(host, port)) val stub = CoordinatorServiceGrpc.newBlockingStub(getChannel(host, port))
val request = BatchResubscribeRequest.newBuilder().addAllGameIds(gameIds.asJava).build() val request = BatchResubscribeRequest.newBuilder().addAllGameIds(gameIds.asJava).build()
stub.batchResubscribeGames(request).getSubscribedCount val count = stub.batchResubscribeGames(request).getSubscribedCount
log.debugf("batchResubscribeGames %s:%d — subscribed %d games", host, port, count)
count
catch catch
case ex: Exception => case ex: Exception =>
log.warnf(ex, "batchResubscribeGames RPC failed for %s:%d", host, port) log.warnf(ex, "batchResubscribeGames RPC failed for %s:%d", host, port)
@@ -44,7 +54,9 @@ class CoreGrpcClient:
try try
val stub = CoordinatorServiceGrpc.newBlockingStub(getChannel(host, port)) val stub = CoordinatorServiceGrpc.newBlockingStub(getChannel(host, port))
val request = UnsubscribeGamesRequest.newBuilder().addAllGameIds(gameIds.asJava).build() val request = UnsubscribeGamesRequest.newBuilder().addAllGameIds(gameIds.asJava).build()
stub.unsubscribeGames(request).getUnsubscribedCount val count = stub.unsubscribeGames(request).getUnsubscribedCount
log.debugf("unsubscribeGames %s:%d — unsubscribed %d games", host, port, count)
count
catch catch
case ex: Exception => case ex: Exception =>
log.warnf(ex, "unsubscribeGames RPC failed for %s:%d", host, port) log.warnf(ex, "unsubscribeGames RPC failed for %s:%d", host, port)
@@ -55,7 +67,9 @@ class CoreGrpcClient:
try try
val stub = CoordinatorServiceGrpc.newBlockingStub(getChannel(host, port)) val stub = CoordinatorServiceGrpc.newBlockingStub(getChannel(host, port))
val request = EvictGamesRequest.newBuilder().addAllGameIds(gameIds.asJava).build() val request = EvictGamesRequest.newBuilder().addAllGameIds(gameIds.asJava).build()
stub.evictGames(request).getEvictedCount val count = stub.evictGames(request).getEvictedCount
log.debugf("evictGames %s:%d — evicted %d games", host, port, count)
count
catch catch
case ex: Exception => case ex: Exception =>
log.warnf(ex, "evictGames RPC failed for %s:%d", host, port) log.warnf(ex, "evictGames RPC failed for %s:%d", host, port)
@@ -30,14 +30,15 @@ class AutoScaler:
if kubeClientInstance.isUnsatisfied then None if kubeClientInstance.isUnsatisfied then None
else Some(kubeClientInstance.get()) else Some(kubeClientInstance.get())
private val argoApiVersion = "argoproj.io/v1alpha1"
private val argoKind = "Rollout"
// scalafix:off DisableSyntax.asInstanceOf // scalafix:off DisableSyntax.asInstanceOf
// scalafix:off DisableSyntax.isInstanceOf
private def rolloutSpec(rollout: GenericKubernetesResource): Option[java.util.Map[String, AnyRef]] = private def rolloutSpec(rollout: GenericKubernetesResource): Option[java.util.Map[String, AnyRef]] =
Option(rollout.get("spec")).collect { Option(rollout.get[AnyRef]("spec")).collect { case m: java.util.Map[?, ?] =>
case m if m.isInstanceOf[java.util.Map[?, ?]] => m.asInstanceOf[java.util.Map[String, AnyRef]] m.asInstanceOf[java.util.Map[String, AnyRef]]
} }
// scalafix:on DisableSyntax.asInstanceOf // scalafix:on DisableSyntax.asInstanceOf
// scalafix:on DisableSyntax.isInstanceOf
def checkAndScale: Unit = def checkAndScale: Unit =
if config.autoScaleEnabled then if config.autoScaleEnabled then
@@ -61,7 +62,7 @@ class AutoScaler:
try try
Option( Option(
kube kube
.resources(classOf[GenericKubernetesResource]) .genericKubernetesResources(argoApiVersion, argoKind)
.inNamespace(config.k8sNamespace) .inNamespace(config.k8sNamespace)
.withName(config.k8sRolloutName) .withName(config.k8sRolloutName)
.get(), .get(),
@@ -102,7 +103,7 @@ class AutoScaler:
try try
Option( Option(
kube kube
.resources(classOf[GenericKubernetesResource]) .genericKubernetesResources(argoApiVersion, argoKind)
.inNamespace(config.k8sNamespace) .inNamespace(config.k8sNamespace)
.withName(config.k8sRolloutName) .withName(config.k8sRolloutName)
.get(), .get(),
@@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
import de.nowchess.coordinator.dto.InstanceMetadata import de.nowchess.coordinator.dto.InstanceMetadata
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import io.smallrye.mutiny.Uni import io.smallrye.mutiny.Uni
import org.jboss.logging.Logger
@ApplicationScoped @ApplicationScoped
class InstanceRegistry: class InstanceRegistry:
@@ -18,6 +19,7 @@ class InstanceRegistry:
private var redisPrefix = "nowchess" private var redisPrefix = "nowchess"
// scalafix:on DisableSyntax.var // scalafix:on DisableSyntax.var
private val log = Logger.getLogger(classOf[InstanceRegistry])
private val mapper = ObjectMapper() private val mapper = ObjectMapper()
private val instances = ConcurrentHashMap[String, InstanceMetadata]() private val instances = ConcurrentHashMap[String, InstanceMetadata]()
@@ -39,17 +41,30 @@ class InstanceRegistry:
.transformToUni { value => .transformToUni { value =>
try try
val metadata = mapper.readValue(value, classOf[InstanceMetadata]) val metadata = mapper.readValue(value, classOf[InstanceMetadata])
val isNew = !instances.containsKey(instanceId)
instances.put(instanceId, metadata) instances.put(instanceId, metadata)
if isNew then
log.infof("Instance %s joined registry (subscriptions=%d)", instanceId, metadata.subscriptionCount)
else
log.debugf(
"Instance %s updated (subscriptions=%d state=%s)",
instanceId,
metadata.subscriptionCount,
metadata.state,
)
Uni.createFrom().item(()) Uni.createFrom().item(())
catch case _: Exception => Uni.createFrom().item(()) catch
case ex: Exception =>
log.warnf(ex, "Failed to parse instance metadata for %s", instanceId)
Uni.createFrom().item(())
} }
.onFailure() .onFailure()
.recoverWithItem(()) .recoverWithItem(())
def markInstanceDead(instanceId: String): Unit = def markInstanceDead(instanceId: String): Unit =
instances.computeIfPresent(instanceId, (_, inst) => inst.copy(state = "DEAD")) instances.computeIfPresent(instanceId, (_, inst) => inst.copy(state = "DEAD"))
() log.infof("Instance %s marked dead", instanceId)
def removeInstance(instanceId: String): Unit = def removeInstance(instanceId: String): Unit =
instances.remove(instanceId) instances.remove(instanceId)
() log.infof("Instance %s removed from registry", instanceId)
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=4 MINOR=10
PATCH=0 PATCH=0
+240
View File
@@ -602,3 +602,243 @@
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289)) * IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
* update main class path in build configuration and adjust VCS directory mapping ([7b1f8b1](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/7b1f8b117623d327232a1a92a8a44d18582e0189)) * 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)) * 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))
## (2026-05-01)
### Features
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
* **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))
* 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))
* 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-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))
* 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))
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
* 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))
## (2026-05-02)
### Features
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
* **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))
* 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))
* **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-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))
* 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))
* correct test board positions and captureOutput/withInput interaction ([f0481e2](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/f0481e2561b779df00925b46ee281dc36a795150))
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
* 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))
## (2026-05-02)
### Features
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
* **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))
* 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))
* **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-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))
* 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))
* 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))
* 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))
## (2026-05-05)
### Features
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
* **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))
* 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))
* **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-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))
* 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))
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
* **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))
* 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))
## (2026-05-05)
### Features
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
* **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))
* 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))
* **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-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))
* 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))
* **redis:** add max pool wait time and switch to ReactiveRedisDataSource for heartbeat updates ([33e5017](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/33e5017f51a998327b180f778f73964cc10c05d3))
* **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))
* 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))
## (2026-05-06)
### Features
* add GameRules stub with PositionStatus enum ([76d4168](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/76d4168038de23e5d6083d4e8f0504fbf31d15a3))
* add MovedInCheck/Checkmate/Stalemate MoveResult variants (stub dispatch) ([8b7ec57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/8b7ec57e5ea6ee1615a1883848a426dc07d26364))
* **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))
* 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))
* **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-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))
* 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))
* **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))
* 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))
@@ -3,8 +3,15 @@ quarkus:
port: 8080 port: 8080
application: application:
name: nowchess-core name: nowchess-core
index-dependency:
security:
group-id: de.nowchess
artifact-id: security
redis: redis:
hosts: redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379} hosts: redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379}
max-pool-wait-time: 30s
max-pool-size: 64
max-pool-waiting: 128
grpc: grpc:
clients: clients:
rule-grpc: rule-grpc:
@@ -7,11 +7,15 @@ import scala.compiletime.uninitialized
import de.nowchess.coordinator.proto.{CoordinatorServiceGrpc, *} import de.nowchess.coordinator.proto.{CoordinatorServiceGrpc, *}
import de.nowchess.chess.redis.GameRedisSubscriberManager import de.nowchess.chess.redis.GameRedisSubscriberManager
import io.grpc.stub.StreamObserver import io.grpc.stub.StreamObserver
import org.jboss.logging.Logger
import scala.jdk.CollectionConverters.* import scala.jdk.CollectionConverters.*
@GrpcService @GrpcService
@Singleton @Singleton
class CoordinatorServiceHandler extends CoordinatorServiceGrpc.CoordinatorServiceImplBase: class CoordinatorServiceHandler extends CoordinatorServiceGrpc.CoordinatorServiceImplBase:
private val log = Logger.getLogger(classOf[CoordinatorServiceHandler])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@Inject @Inject
private var gameSubscriberManager: GameRedisSubscriberManager = uninitialized private var gameSubscriberManager: GameRedisSubscriberManager = uninitialized
@@ -22,6 +26,7 @@ class CoordinatorServiceHandler extends CoordinatorServiceGrpc.CoordinatorServic
responseObserver: StreamObserver[BatchResubscribeResponse], responseObserver: StreamObserver[BatchResubscribeResponse],
): Unit = ): Unit =
val count = gameSubscriberManager.batchResubscribeGames(request.getGameIdsList) val count = gameSubscriberManager.batchResubscribeGames(request.getGameIdsList)
log.infof("Coordinator: batch resubscribe %d games → subscribed %d", request.getGameIdsList.size(), count)
val response = BatchResubscribeResponse val response = BatchResubscribeResponse
.newBuilder() .newBuilder()
.setSubscribedCount(count) .setSubscribedCount(count)
@@ -34,6 +39,7 @@ class CoordinatorServiceHandler extends CoordinatorServiceGrpc.CoordinatorServic
responseObserver: StreamObserver[UnsubscribeGamesResponse], responseObserver: StreamObserver[UnsubscribeGamesResponse],
): Unit = ): Unit =
val count = gameSubscriberManager.unsubscribeGames(request.getGameIdsList) val count = gameSubscriberManager.unsubscribeGames(request.getGameIdsList)
log.infof("Coordinator: unsubscribe %d games → unsubscribed %d", request.getGameIdsList.size(), count)
val response = UnsubscribeGamesResponse val response = UnsubscribeGamesResponse
.newBuilder() .newBuilder()
.setUnsubscribedCount(count) .setUnsubscribedCount(count)
@@ -46,6 +52,7 @@ class CoordinatorServiceHandler extends CoordinatorServiceGrpc.CoordinatorServic
responseObserver: StreamObserver[EvictGamesResponse], responseObserver: StreamObserver[EvictGamesResponse],
): Unit = ): Unit =
val count = gameSubscriberManager.evictGames(request.getGameIdsList) val count = gameSubscriberManager.evictGames(request.getGameIdsList)
log.infof("Coordinator: evict %d games → evicted %d", request.getGameIdsList.size(), count)
val response = EvictGamesResponse val response = EvictGamesResponse
.newBuilder() .newBuilder()
.setEvictedCount(count) .setEvictedCount(count)
@@ -58,6 +65,7 @@ class CoordinatorServiceHandler extends CoordinatorServiceGrpc.CoordinatorServic
responseObserver: StreamObserver[DrainInstanceResponse], responseObserver: StreamObserver[DrainInstanceResponse],
): Unit = ): Unit =
val migrated = gameSubscriberManager.drainInstance() val migrated = gameSubscriberManager.drainInstance()
log.infof("Coordinator: drain instance → migrated %d games", migrated)
val response = DrainInstanceResponse val response = DrainInstanceResponse
.newBuilder() .newBuilder()
.setGamesMigrated(migrated) .setGamesMigrated(migrated)
@@ -5,29 +5,63 @@ import de.nowchess.chess.client.CombinedExportResponse
import de.nowchess.core.proto.* import de.nowchess.core.proto.*
import io.quarkus.grpc.GrpcClient import io.quarkus.grpc.GrpcClient
import jakarta.enterprise.context.ApplicationScoped import jakarta.enterprise.context.ApplicationScoped
import org.jboss.logging.Logger
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
@ApplicationScoped @ApplicationScoped
class IoGrpcClientWrapper: class IoGrpcClientWrapper:
private val log = Logger.getLogger(classOf[IoGrpcClientWrapper])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@GrpcClient("io-grpc") @GrpcClient("io-grpc")
var stub: IoServiceGrpc.IoServiceBlockingStub = uninitialized var stub: IoServiceGrpc.IoServiceBlockingStub = uninitialized
// scalafix:on DisableSyntax.var // scalafix:on DisableSyntax.var
def exportCombined(ctx: GameContext): CombinedExportResponse = def exportCombined(ctx: GameContext): CombinedExportResponse =
val combined = stub.exportCombined(CoreProtoMapper.toProtoGameContext(ctx)) try
CombinedExportResponse(combined.getFen, combined.getPgn) val combined = stub.exportCombined(CoreProtoMapper.toProtoGameContext(ctx))
CombinedExportResponse(combined.getFen, combined.getPgn)
catch
case ex: Exception =>
log.warnf(ex, "IO gRPC exportCombined failed")
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
def importFen(fen: String): GameContext = def importFen(fen: String): GameContext =
CoreProtoMapper.fromProtoGameContext(stub.importFen(ProtoImportFenRequest.newBuilder().setFen(fen).build())) try CoreProtoMapper.fromProtoGameContext(stub.importFen(ProtoImportFenRequest.newBuilder().setFen(fen).build()))
catch
case ex: Exception =>
log.warnf(ex, "IO gRPC importFen failed for fen %s", fen)
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
def importPgn(pgn: String): GameContext = def importPgn(pgn: String): GameContext =
CoreProtoMapper.fromProtoGameContext(stub.importPgn(ProtoImportPgnRequest.newBuilder().setPgn(pgn).build())) try CoreProtoMapper.fromProtoGameContext(stub.importPgn(ProtoImportPgnRequest.newBuilder().setPgn(pgn).build()))
catch
case ex: Exception =>
log.warnf(ex, "IO gRPC importPgn failed")
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
def exportFen(ctx: GameContext): String = def exportFen(ctx: GameContext): String =
stub.exportFen(CoreProtoMapper.toProtoGameContext(ctx)).getValue try stub.exportFen(CoreProtoMapper.toProtoGameContext(ctx)).getValue
catch
case ex: Exception =>
log.warnf(ex, "IO gRPC exportFen failed")
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
def exportPgn(ctx: GameContext): String = def exportPgn(ctx: GameContext): String =
stub.exportPgn(CoreProtoMapper.toProtoGameContext(ctx)).getValue try stub.exportPgn(CoreProtoMapper.toProtoGameContext(ctx)).getValue
catch
case ex: Exception =>
log.warnf(ex, "IO gRPC exportPgn failed")
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
@@ -7,6 +7,7 @@ import de.nowchess.api.rules.{PostMoveStatus, RuleSet}
import de.nowchess.core.proto.* import de.nowchess.core.proto.*
import io.quarkus.grpc.GrpcClient import io.quarkus.grpc.GrpcClient
import jakarta.enterprise.context.ApplicationScoped import jakarta.enterprise.context.ApplicationScoped
import org.jboss.logging.Logger
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import scala.jdk.CollectionConverters.* import scala.jdk.CollectionConverters.*
@@ -14,28 +15,59 @@ import scala.jdk.CollectionConverters.*
@ApplicationScoped @ApplicationScoped
class RuleSetGrpcAdapter extends RuleSet: class RuleSetGrpcAdapter extends RuleSet:
private val log = Logger.getLogger(classOf[RuleSetGrpcAdapter])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@GrpcClient("rule-grpc") @GrpcClient("rule-grpc")
var stub: RuleServiceGrpc.RuleServiceBlockingStub = uninitialized var stub: RuleServiceGrpc.RuleServiceBlockingStub = uninitialized
// scalafix:on DisableSyntax.var // scalafix:on DisableSyntax.var
def candidateMoves(ctx: GameContext)(sq: Square): List[Move] = def candidateMoves(ctx: GameContext)(sq: Square): List[Move] =
val req = try
ProtoSquareRequest.newBuilder().setContext(CoreProtoMapper.toProtoGameContext(ctx)).setSquare(sq.toString).build() val req =
stub.candidateMoves(req).getMovesList.asScala.flatMap(CoreProtoMapper.fromProtoMove).toList ProtoSquareRequest
.newBuilder()
.setContext(CoreProtoMapper.toProtoGameContext(ctx))
.setSquare(sq.toString)
.build()
stub.candidateMoves(req).getMovesList.asScala.flatMap(CoreProtoMapper.fromProtoMove).toList
catch
case ex: Exception =>
log.warnf(ex, "Rule gRPC candidateMoves failed")
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
def legalMoves(ctx: GameContext)(sq: Square): List[Move] = def legalMoves(ctx: GameContext)(sq: Square): List[Move] =
val req = try
ProtoSquareRequest.newBuilder().setContext(CoreProtoMapper.toProtoGameContext(ctx)).setSquare(sq.toString).build() val req =
stub.legalMoves(req).getMovesList.asScala.flatMap(CoreProtoMapper.fromProtoMove).toList ProtoSquareRequest
.newBuilder()
.setContext(CoreProtoMapper.toProtoGameContext(ctx))
.setSquare(sq.toString)
.build()
stub.legalMoves(req).getMovesList.asScala.flatMap(CoreProtoMapper.fromProtoMove).toList
catch
case ex: Exception =>
log.warnf(ex, "Rule gRPC legalMoves failed")
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
def allLegalMoves(ctx: GameContext): List[Move] = def allLegalMoves(ctx: GameContext): List[Move] =
stub try
.allLegalMoves(CoreProtoMapper.toProtoGameContext(ctx)) stub
.getMovesList .allLegalMoves(CoreProtoMapper.toProtoGameContext(ctx))
.asScala .getMovesList
.flatMap(CoreProtoMapper.fromProtoMove) .asScala
.toList .flatMap(CoreProtoMapper.fromProtoMove)
.toList
catch
case ex: Exception =>
log.warnf(ex, "Rule gRPC allLegalMoves failed")
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
def isCheck(ctx: GameContext): Boolean = def isCheck(ctx: GameContext): Boolean =
stub.isCheck(CoreProtoMapper.toProtoGameContext(ctx)).getValue stub.isCheck(CoreProtoMapper.toProtoGameContext(ctx)).getValue
@@ -56,19 +88,33 @@ class RuleSetGrpcAdapter extends RuleSet:
stub.isThreefoldRepetition(CoreProtoMapper.toProtoGameContext(ctx)).getValue stub.isThreefoldRepetition(CoreProtoMapper.toProtoGameContext(ctx)).getValue
def applyMove(ctx: GameContext)(move: Move): GameContext = def applyMove(ctx: GameContext)(move: Move): GameContext =
val req = ProtoMoveRequest try
.newBuilder() val req = ProtoMoveRequest
.setContext(CoreProtoMapper.toProtoGameContext(ctx)) .newBuilder()
.setMove(CoreProtoMapper.toProtoMove(move)) .setContext(CoreProtoMapper.toProtoGameContext(ctx))
.build() .setMove(CoreProtoMapper.toProtoMove(move))
CoreProtoMapper.fromProtoGameContext(stub.applyMove(req)) .build()
CoreProtoMapper.fromProtoGameContext(stub.applyMove(req))
catch
case ex: Exception =>
log.warnf(ex, "Rule gRPC applyMove failed")
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
override def postMoveStatus(ctx: GameContext): PostMoveStatus = override def postMoveStatus(ctx: GameContext): PostMoveStatus =
val p = stub.postMoveStatus(CoreProtoMapper.toProtoGameContext(ctx)) try
PostMoveStatus( val p = stub.postMoveStatus(CoreProtoMapper.toProtoGameContext(ctx))
p.getIsCheckmate, PostMoveStatus(
p.getIsStalemate, p.getIsCheckmate,
p.getIsInsufficientMaterial, p.getIsStalemate,
p.getIsCheck, p.getIsInsufficientMaterial,
p.getIsThreefoldRepetition, p.getIsCheck,
) p.getIsThreefoldRepetition,
)
catch
case ex: Exception =>
log.warnf(ex, "Rule gRPC postMoveStatus failed")
// scalafix:off DisableSyntax.throw
throw ex
// scalafix:on DisableSyntax.throw
@@ -10,6 +10,10 @@ import de.nowchess.chess.observer.{GameEvent, Observer}
import de.nowchess.chess.registry.GameRegistry import de.nowchess.chess.registry.GameRegistry
import de.nowchess.chess.resource.GameDtoMapper import de.nowchess.chess.resource.GameDtoMapper
import io.quarkus.redis.datasource.RedisDataSource import io.quarkus.redis.datasource.RedisDataSource
import org.jboss.logging.Logger
object GameRedisPublisher:
private val log = Logger.getLogger(classOf[GameRedisPublisher])
class GameRedisPublisher( class GameRedisPublisher(
gameId: String, gameId: String,
@@ -23,57 +27,60 @@ class GameRedisPublisher(
) extends Observer: ) extends Observer:
def onGameEvent(event: GameEvent): Unit = def onGameEvent(event: GameEvent): Unit =
registry.get(gameId).foreach { entry => try
val dto = GameDtoMapper.toGameStateDto(entry, ioClient) GameRedisPublisher.log.debugf("Publishing game event for game %s", gameId)
val json = objectMapper.writeValueAsString(GameStateEventDto(dto)) registry.get(gameId).foreach { entry =>
redis.pubsub(classOf[String]).publish(s2cTopicName, json) 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 clock = entry.engine.currentClockState
val wb = GameWritebackEventDto( val wb = GameWritebackEventDto(
gameId = gameId, gameId = gameId,
fen = dto.fen, fen = dto.fen,
pgn = dto.pgn, pgn = dto.pgn,
moveCount = entry.engine.context.moves.size, moveCount = entry.engine.context.moves.size,
whiteId = entry.white.id.value, whiteId = entry.white.id.value,
whiteName = entry.white.displayName, whiteName = entry.white.displayName,
blackId = entry.black.id.value, blackId = entry.black.id.value,
blackName = entry.black.displayName, blackName = entry.black.displayName,
mode = entry.mode.toString, mode = entry.mode.toString,
resigned = entry.resigned, resigned = entry.resigned,
limitSeconds = entry.engine.timeControl match { limitSeconds = entry.engine.timeControl match {
case de.nowchess.api.game.TimeControl.Clock(l, _) => Some(l); case _ => None case de.nowchess.api.game.TimeControl.Clock(l, _) => Some(l); case _ => None
}, },
incrementSeconds = entry.engine.timeControl match { incrementSeconds = entry.engine.timeControl match {
case de.nowchess.api.game.TimeControl.Clock(_, i) => Some(i); case _ => None case de.nowchess.api.game.TimeControl.Clock(_, i) => Some(i); case _ => None
}, },
daysPerMove = entry.engine.timeControl match { daysPerMove = entry.engine.timeControl match {
case de.nowchess.api.game.TimeControl.Correspondence(d) => Some(d); case _ => None case de.nowchess.api.game.TimeControl.Correspondence(d) => Some(d); case _ => None
}, },
whiteRemainingMs = clock.collect { case c: LiveClockState => c.whiteRemainingMs }, whiteRemainingMs = clock.collect { case c: LiveClockState => c.whiteRemainingMs },
blackRemainingMs = clock.collect { case c: LiveClockState => c.blackRemainingMs }, blackRemainingMs = clock.collect { case c: LiveClockState => c.blackRemainingMs },
incrementMs = clock.collect { case c: LiveClockState => c.incrementMs }, incrementMs = clock.collect { case c: LiveClockState => c.incrementMs },
clockLastTickAt = clock.collect { case c: LiveClockState => c.lastTickAt.toEpochMilli }, clockLastTickAt = clock.collect { case c: LiveClockState => c.lastTickAt.toEpochMilli },
clockMoveDeadline = clock.collect { case c: CorrespondenceClockState => c.moveDeadline.toEpochMilli }, clockMoveDeadline = clock.collect { case c: CorrespondenceClockState => c.moveDeadline.toEpochMilli },
clockActiveColor = clock.map(_.activeColor.label.toLowerCase), clockActiveColor = clock.map(_.activeColor.label.toLowerCase),
pendingDrawOffer = entry.engine.pendingDrawOfferBy.map(_.label.toLowerCase), pendingDrawOffer = entry.engine.pendingDrawOfferBy.map(_.label.toLowerCase),
result = entry.engine.context.result.map { result = entry.engine.context.result.map {
case GameResult.Win(Color.White, _) => "white" case GameResult.Win(Color.White, _) => "white"
case GameResult.Win(Color.Black, _) => "black" case GameResult.Win(Color.Black, _) => "black"
case GameResult.Draw(_) => "draw" case GameResult.Draw(_) => "draw"
}, },
terminationReason = entry.engine.context.result.map { terminationReason = entry.engine.context.result.map {
case GameResult.Win(_, WinReason.Checkmate) => "checkmate" case GameResult.Win(_, WinReason.Checkmate) => "checkmate"
case GameResult.Win(_, WinReason.Resignation) => "resignation" case GameResult.Win(_, WinReason.Resignation) => "resignation"
case GameResult.Win(_, WinReason.TimeControl) => "timeout" case GameResult.Win(_, WinReason.TimeControl) => "timeout"
case GameResult.Draw(DrawReason.Stalemate) => "stalemate" case GameResult.Draw(DrawReason.Stalemate) => "stalemate"
case GameResult.Draw(DrawReason.InsufficientMaterial) => "insufficient_material" case GameResult.Draw(DrawReason.InsufficientMaterial) => "insufficient_material"
case GameResult.Draw(DrawReason.FiftyMoveRule) => "fifty_move" case GameResult.Draw(DrawReason.FiftyMoveRule) => "fifty_move"
case GameResult.Draw(DrawReason.ThreefoldRepetition) => "repetition" case GameResult.Draw(DrawReason.ThreefoldRepetition) => "repetition"
case GameResult.Draw(DrawReason.Agreement) => "agreement" case GameResult.Draw(DrawReason.Agreement) => "agreement"
}, },
redoStack = entry.engine.redoStackMoves.map(GameDtoMapper.moveToUci), redoStack = entry.engine.redoStackMoves.map(GameDtoMapper.moveToUci),
pendingTakebackRequest = entry.engine.pendingTakebackRequestBy.map(_.label.toLowerCase), pendingTakebackRequest = entry.engine.pendingTakebackRequestBy.map(_.label.toLowerCase),
) )
writebackEmit(objectMapper.writeValueAsString(wb)) writebackEmit(objectMapper.writeValueAsString(wb))
if entry.engine.context.result.isDefined then onGameOver(gameId) 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)
@@ -10,12 +10,14 @@ import de.nowchess.chess.observer.Observer
import de.nowchess.chess.registry.GameRegistry import de.nowchess.chess.registry.GameRegistry
import de.nowchess.chess.resource.GameDtoMapper import de.nowchess.chess.resource.GameDtoMapper
import de.nowchess.chess.service.InstanceHeartbeatService import de.nowchess.chess.service.InstanceHeartbeatService
import io.quarkus.redis.datasource.ReactiveRedisDataSource
import io.quarkus.redis.datasource.RedisDataSource import io.quarkus.redis.datasource.RedisDataSource
import io.quarkus.redis.datasource.pubsub.PubSubCommands import io.quarkus.redis.datasource.pubsub.ReactivePubSubCommands
import jakarta.annotation.PreDestroy import jakarta.annotation.PreDestroy
import jakarta.enterprise.context.ApplicationScoped import jakarta.enterprise.context.ApplicationScoped
import jakarta.enterprise.inject.Instance import jakarta.enterprise.inject.Instance
import jakarta.inject.Inject import jakarta.inject.Inject
import org.jboss.logging.Logger
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import scala.util.Try import scala.util.Try
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@@ -24,8 +26,11 @@ import java.util.function.Consumer
@ApplicationScoped @ApplicationScoped
class GameRedisSubscriberManager: class GameRedisSubscriberManager:
private val log = Logger.getLogger(classOf[GameRedisSubscriberManager])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@Inject var redis: RedisDataSource = uninitialized @Inject var redis: RedisDataSource = uninitialized
@Inject var reactiveRedis: ReactiveRedisDataSource = uninitialized
@Inject var registry: GameRegistry = uninitialized @Inject var registry: GameRegistry = uninitialized
@Inject var objectMapper: ObjectMapper = uninitialized @Inject var objectMapper: ObjectMapper = uninitialized
@Inject var redisConfig: RedisConfig = uninitialized @Inject var redisConfig: RedisConfig = uninitialized
@@ -37,7 +42,7 @@ class GameRedisSubscriberManager:
if heartbeatServiceInstance.isUnsatisfied then None if heartbeatServiceInstance.isUnsatisfied then None
else Some(heartbeatServiceInstance.get()) else Some(heartbeatServiceInstance.get())
private val c2sListeners = new ConcurrentHashMap[String, PubSubCommands.RedisSubscriber]() private val c2sListeners = new ConcurrentHashMap[String, ReactivePubSubCommands.ReactiveRedisSubscriber]()
private val s2cObservers = new ConcurrentHashMap[String, Observer]() private val s2cObservers = new ConcurrentHashMap[String, Observer]()
private def c2sTopic(gameId: String): String = private def c2sTopic(gameId: String): String =
@@ -47,40 +52,44 @@ class GameRedisSubscriberManager:
s"${redisConfig.prefix}:game:$gameId:s2c" s"${redisConfig.prefix}:game:$gameId:s2c"
def subscribeGame(gameId: String): Unit = def subscribeGame(gameId: String): Unit =
try val writebackFn: String => Unit = json => redis.pubsub(classOf[String]).publish("game-writeback", json)
val handler: Consumer[String] = msg => handleC2sMessage(gameId, msg) val obs = new GameRedisPublisher(
val subscriber = redis.pubsub(classOf[String]).subscribe(c2sTopic(gameId), handler) gameId,
c2sListeners.put(gameId, subscriber) registry,
redis,
objectMapper,
s2cTopicName(gameId),
writebackFn,
ioClient,
unsubscribeGame,
)
s2cObservers.put(gameId, obs)
registry.get(gameId).foreach(_.engine.subscribe(obs))
heartbeatServiceOpt.foreach(_.addGameSubscription(gameId))
val writebackFn: String => Unit = json => redis.pubsub(classOf[String]).publish("game-writeback", json) val handler: Consumer[String] = msg => handleC2sMessage(gameId, msg)
val obs = new GameRedisPublisher( reactiveRedis
gameId, .pubsub(classOf[String])
registry, .subscribe(c2sTopic(gameId), handler)
redis, .subscribe()
objectMapper, .`with`(
s2cTopicName(gameId), subscriber => {
writebackFn, c2sListeners.put(gameId, subscriber)
ioClient, log.debugf("Subscribed to game %s", gameId)
unsubscribeGame, },
failure => log.warnf(failure, "Redis subscription failed for game %s", gameId),
) )
s2cObservers.put(gameId, obs)
registry.get(gameId).foreach(_.engine.subscribe(obs))
heartbeatServiceOpt.foreach(_.addGameSubscription(gameId))
catch
case e: Exception =>
System.err.println(s"Warning: Redis subscription failed for game $gameId: ${e.getMessage}")
()
def unsubscribeGame(gameId: String): Unit = def unsubscribeGame(gameId: String): Unit =
Option(c2sListeners.remove(gameId)).foreach { subscriber => Option(c2sListeners.remove(gameId)).foreach { subscriber =>
subscriber.unsubscribe(c2sTopic(gameId)) subscriber.unsubscribe(c2sTopic(gameId)).subscribe().`with`(_ => (), _ => ())
} }
Option(s2cObservers.remove(gameId)).foreach { obs => Option(s2cObservers.remove(gameId)).foreach { obs =>
registry.get(gameId).foreach(_.engine.unsubscribe(obs)) registry.get(gameId).foreach(_.engine.unsubscribe(obs))
} }
heartbeatServiceOpt.foreach(_.removeGameSubscription(gameId)) heartbeatServiceOpt.foreach(_.removeGameSubscription(gameId))
log.debugf("Unsubscribed from game %s", gameId)
private def handleC2sMessage(gameId: String, msg: String): Unit = private def handleC2sMessage(gameId: String, msg: String): Unit =
parseC2sMessage(msg) match parseC2sMessage(msg) match
@@ -97,6 +106,7 @@ class GameRedisSubscriberManager:
} }
private def handleMove(gameId: String, uci: String, playerId: Option[String]): Unit = private def handleMove(gameId: String, uci: String, playerId: Option[String]): Unit =
log.debugf("Processing move %s for game %s by player %s", uci, gameId, playerId.getOrElse("anonymous"))
registry.get(gameId).foreach { entry => registry.get(gameId).foreach { entry =>
entry.mode match entry.mode match
case GameMode.Open => entry.engine.processUserInput(uci) case GameMode.Open => entry.engine.processUserInput(uci)
@@ -127,6 +137,7 @@ class GameRedisSubscriberManager:
def batchResubscribeGames(gameIds: java.util.List[String]): Int = def batchResubscribeGames(gameIds: java.util.List[String]): Int =
gameIds.forEach(subscribeGame) gameIds.forEach(subscribeGame)
log.infof("Batch resubscribed %d games", gameIds.size())
gameIds.size() gameIds.size()
def unsubscribeGames(gameIds: java.util.List[String]): Int = def unsubscribeGames(gameIds: java.util.List[String]): Int =
@@ -135,15 +146,17 @@ class GameRedisSubscriberManager:
def evictGames(gameIds: java.util.List[String]): Int = def evictGames(gameIds: java.util.List[String]): Int =
gameIds.forEach(unsubscribeGame) gameIds.forEach(unsubscribeGame)
log.infof("Evicting %d games", gameIds.size())
gameIds.size() gameIds.size()
def drainInstance(): Int = def drainInstance(): Int =
val gameIds = new java.util.ArrayList(c2sListeners.keySet()) val gameIds = new java.util.ArrayList(c2sListeners.keySet())
val count = gameIds.size() val count = gameIds.size()
gameIds.forEach(unsubscribeGame) gameIds.forEach(unsubscribeGame)
log.infof("Draining instance, unsubscribing %d games", count)
count count
@PreDestroy @PreDestroy
def cleanup(): Unit = def cleanup(): Unit =
c2sListeners.forEach((gameId, subscriber) => subscriber.unsubscribe(c2sTopic(gameId))) c2sListeners.forEach((gameId, subscriber) => subscriber.unsubscribe(c2sTopic(gameId)).await().indefinitely())
s2cObservers.forEach((gameId, obs) => registry.get(gameId).foreach(_.engine.unsubscribe(obs))) s2cObservers.forEach((gameId, obs) => registry.get(gameId).foreach(_.engine.unsubscribe(obs)))
@@ -17,6 +17,7 @@ import jakarta.enterprise.context.ApplicationScoped
import jakarta.inject.Inject import jakarta.inject.Inject
import org.eclipse.microprofile.rest.client.inject.RestClient import org.eclipse.microprofile.rest.client.inject.RestClient
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import org.jboss.logging.Logger
import scala.util.Try import scala.util.Try
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.security.{MessageDigest, SecureRandom} import java.security.{MessageDigest, SecureRandom}
@@ -35,6 +36,7 @@ class RedisGameRegistry extends GameRegistry:
@Inject @RestClient var storeClient: StoreServiceClient = uninitialized @Inject @RestClient var storeClient: StoreServiceClient = uninitialized
// scalafix:on // scalafix:on
private val log = Logger.getLogger(classOf[RedisGameRegistry])
private val localEngines = ConcurrentHashMap[String, GameEntry]() private val localEngines = ConcurrentHashMap[String, GameEntry]()
private val rng = new SecureRandom() private val rng = new SecureRandom()
@@ -48,6 +50,12 @@ class RedisGameRegistry extends GameRegistry:
localEngines.put(entry.gameId, entry) localEngines.put(entry.gameId, entry)
val combined = ioClient.exportCombined(entry.engine.context) val combined = ioClient.exportCombined(entry.engine.context)
redis.value(classOf[String]).setex(cacheKey(entry.gameId), 1800L, toJson(entry, combined.fen, combined.pgn)) redis.value(classOf[String]).setex(cacheKey(entry.gameId), 1800L, toJson(entry, combined.fen, combined.pgn))
log.infof(
"Stored game %s in registry (white=%s black=%s)",
entry.gameId,
entry.white.displayName,
entry.black.displayName,
)
def get(gameId: String): Option[GameEntry] = def get(gameId: String): Option[GameEntry] =
Option(localEngines.get(gameId)) match Option(localEngines.get(gameId)) match
@@ -71,9 +79,15 @@ class RedisGameRegistry extends GameRegistry:
private def fromRedis(gameId: String): Option[GameEntry] = private def fromRedis(gameId: String): Option[GameEntry] =
readRedisDto(gameId) readRedisDto(gameId)
.flatMap(dto => Try(reconstruct(dto)).toOption) .flatMap { dto =>
Try(reconstruct(dto)).toOption.orElse {
log.warnf("Failed to reconstruct game %s from Redis", gameId)
None
}
}
.map { entry => .map { entry =>
localEngines.put(gameId, entry) localEngines.put(gameId, entry)
log.infof("Loaded game %s from Redis cache", gameId)
entry entry
} }
@@ -102,12 +116,15 @@ class RedisGameRegistry extends GameRegistry:
pendingDrawOffer = Option(record.pendingDrawOffer), pendingDrawOffer = Option(record.pendingDrawOffer),
) )
(dto, reconstruct(dto)) (dto, reconstruct(dto))
}.toOption } match
.map { case (dto, entry) => case scala.util.Success((dto, entry)) =>
log.infof("Loaded game %s from store service", gameId)
localEngines.put(gameId, entry) localEngines.put(gameId, entry)
redis.value(classOf[String]).setex(cacheKey(gameId), 1800L, objectMapper.writeValueAsString(dto)) redis.value(classOf[String]).setex(cacheKey(gameId), 1800L, objectMapper.writeValueAsString(dto))
entry Some(entry)
} case scala.util.Failure(ex) =>
log.warnf(ex, "Failed to load game %s from store service", gameId)
None
private def reconstruct(dto: GameCacheDto): GameEntry = private def reconstruct(dto: GameCacheDto): GameEntry =
val ctx = if dto.pgn.nonEmpty then ioClient.importPgn(dto.pgn) else GameContext.initial val ctx = if dto.pgn.nonEmpty then ioClient.importPgn(dto.pgn) else GameContext.initial
@@ -30,6 +30,7 @@ import jakarta.inject.Inject
import jakarta.ws.rs.* import jakarta.ws.rs.*
import jakarta.ws.rs.core.{MediaType, Response} import jakarta.ws.rs.core.{MediaType, Response}
import org.eclipse.microprofile.jwt.JsonWebToken import org.eclipse.microprofile.jwt.JsonWebToken
import org.jboss.logging.Logger
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
@@ -38,6 +39,8 @@ import scala.compiletime.uninitialized
@ApplicationScoped @ApplicationScoped
class GameResource: class GameResource:
private val log = Logger.getLogger(classOf[GameResource])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@Inject @Inject
var registry: GameRegistry = uninitialized var registry: GameRegistry = uninitialized
@@ -165,7 +168,13 @@ class GameResource:
val entry = newEntry(GameContext.initial, white, black, tc, mode) val entry = newEntry(GameContext.initial, white, black, tc, mode)
registry.store(entry) registry.store(entry)
subscriberManager.subscribeGame(entry.gameId) subscriberManager.subscribeGame(entry.gameId)
println(s"Created game ${entry.gameId}") log.infof(
"Game %s created — white=%s black=%s mode=%s",
entry.gameId,
white.displayName,
black.displayName,
mode.toString,
)
created(GameDtoMapper.toGameFullDto(entry, ioClient)) created(GameDtoMapper.toGameFullDto(entry, ioClient))
@GET @GET
@@ -182,6 +191,7 @@ class GameResource:
val entry = registry.get(gameId).getOrElse(throw GameNotFoundException(gameId)) val entry = registry.get(gameId).getOrElse(throw GameNotFoundException(gameId))
assertGameNotOver(entry) assertGameNotOver(entry)
val color = colorOf(entry) val color = colorOf(entry)
log.infof("Game %s — resign by %s", gameId, color.label)
entry.engine.resign(color) entry.engine.resign(color)
registry.update(entry.copy(resigned = true)) registry.update(entry.copy(resigned = true))
ok(OkResponseDto()) ok(OkResponseDto())
@@ -194,6 +204,7 @@ class GameResource:
val entry = registry.get(gameId).getOrElse(throw GameNotFoundException(gameId)) val entry = registry.get(gameId).getOrElse(throw GameNotFoundException(gameId))
assertGameNotOver(entry) assertGameNotOver(entry)
assertIsCurrentPlayer(entry) assertIsCurrentPlayer(entry)
log.debugf("Game %s — move %s by %s", gameId, uci, colorOf(entry).label)
if Parser.parseMove(uci).isEmpty then if Parser.parseMove(uci).isEmpty then
throw BadRequestException("INVALID_UCI", s"Invalid UCI notation: $uci", Some("uci")) throw BadRequestException("INVALID_UCI", s"Invalid UCI notation: $uci", Some("uci"))
applyMoveInput(entry.engine, uci).foreach(err => throw BadRequestException("INVALID_MOVE", err, Some("uci"))) applyMoveInput(entry.engine, uci).foreach(err => throw BadRequestException("INVALID_MOVE", err, Some("uci")))
@@ -284,6 +295,7 @@ class GameResource:
val entry = newEntry(ctx, white, black, tc) val entry = newEntry(ctx, white, black, tc)
registry.store(entry) registry.store(entry)
subscriberManager.subscribeGame(entry.gameId) subscriberManager.subscribeGame(entry.gameId)
log.infof("Imported FEN game %s", entry.gameId)
created(GameDtoMapper.toGameFullDto(entry, ioClient)) created(GameDtoMapper.toGameFullDto(entry, ioClient))
@POST @POST
@@ -295,6 +307,7 @@ class GameResource:
val entry = newEntry(ctx, DefaultWhite, DefaultBlack) val entry = newEntry(ctx, DefaultWhite, DefaultBlack)
registry.store(entry) registry.store(entry)
subscriberManager.subscribeGame(entry.gameId) subscriberManager.subscribeGame(entry.gameId)
log.infof("Imported PGN game %s", entry.gameId)
created(GameDtoMapper.toGameFullDto(entry, ioClient)) created(GameDtoMapper.toGameFullDto(entry, ioClient))
@GET @GET
@@ -8,8 +8,10 @@ import io.quarkus.runtime.ShutdownEvent
import io.quarkus.grpc.GrpcClient import io.quarkus.grpc.GrpcClient
import org.eclipse.microprofile.config.inject.ConfigProperty import org.eclipse.microprofile.config.inject.ConfigProperty
import io.quarkus.redis.datasource.RedisDataSource import io.quarkus.redis.datasource.RedisDataSource
import io.quarkus.redis.datasource.ReactiveRedisDataSource
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import java.util.concurrent.{Executors, TimeUnit} import java.util.concurrent.{Executors, TimeUnit}
import java.util.concurrent.atomic.AtomicBoolean
import java.net.InetAddress import java.net.InetAddress
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import org.jboss.logging.Logger import org.jboss.logging.Logger
@@ -24,6 +26,12 @@ class InstanceHeartbeatService:
@Inject @Inject
private var redis: RedisDataSource = uninitialized private var redis: RedisDataSource = uninitialized
@Inject
private var reactiveRedis: ReactiveRedisDataSource = uninitialized
@Inject
private var mapper: ObjectMapper = uninitialized
@GrpcClient("coordinator-grpc") @GrpcClient("coordinator-grpc")
private var channel: Channel = uninitialized private var channel: Channel = uninitialized
@@ -38,7 +46,6 @@ class InstanceHeartbeatService:
private var coordinatorStub: CoordinatorServiceStub = uninitialized private var coordinatorStub: CoordinatorServiceStub = uninitialized
private val log = Logger.getLogger(classOf[InstanceHeartbeatService]) private val log = Logger.getLogger(classOf[InstanceHeartbeatService])
private val mapper = ObjectMapper()
private var instanceId = "" private var instanceId = ""
private var redisPrefix = "nowchess" private var redisPrefix = "nowchess"
private var streamObserver: Option[StreamObserver[HeartbeatFrame]] = None private var streamObserver: Option[StreamObserver[HeartbeatFrame]] = None
@@ -49,6 +56,7 @@ class InstanceHeartbeatService:
private var serviceActive = false private var serviceActive = false
private var shuttingDown = false private var shuttingDown = false
// scalafix:on DisableSyntax.var // scalafix:on DisableSyntax.var
private val redisHeartbeatPending = new AtomicBoolean(false)
def onStart(@Observes event: StartupEvent): Unit = def onStart(@Observes event: StartupEvent): Unit =
if coordinatorEnabled then if coordinatorEnabled then
@@ -165,25 +173,36 @@ class InstanceHeartbeatService:
} }
private def refreshRedisHeartbeat(): Unit = private def refreshRedisHeartbeat(): Unit =
try if redisHeartbeatPending.compareAndSet(false, true) then
val key = s"$redisPrefix:instances:$instanceId" try
val key = s"$redisPrefix:instances:$instanceId"
val metadata = Map( val metadata = Map(
"instanceId" -> instanceId, "instanceId" -> instanceId,
"hostname" -> getHostname, "hostname" -> getHostname,
"httpPort" -> httpPort, "httpPort" -> httpPort,
"grpcPort" -> grpcPort, "grpcPort" -> grpcPort,
"subscriptionCount" -> subscriptionCount, "subscriptionCount" -> subscriptionCount,
"localCacheSize" -> localCacheSize, "localCacheSize" -> localCacheSize,
"lastHeartbeat" -> java.time.Instant.now().toString, "lastHeartbeat" -> java.time.Instant.now().toString,
"state" -> "HEALTHY", "state" -> "HEALTHY",
) )
val json = mapper.writeValueAsString(metadata) val json = mapper.writeValueAsString(metadata)
redis.value(classOf[String]).setex(key, 5L, json) reactiveRedis
catch .value(classOf[String])
case ex: Exception => .setex(key, 5L, json)
log.warnf(ex, "Failed to refresh Redis heartbeat") .subscribe()
.`with`(
_ => redisHeartbeatPending.set(false),
(ex: Throwable) =>
redisHeartbeatPending.set(false)
log.warnf(ex, "Failed to refresh Redis heartbeat"),
)
catch
case ex: Exception =>
redisHeartbeatPending.set(false)
log.warnf(ex, "Failed to serialize Redis heartbeat metadata")
private def getHostname: String = private def getHostname: String =
try InetAddress.getLocalHost.getHostName try InetAddress.getLocalHost.getHostName
@@ -0,0 +1,72 @@
package de.nowchess.chess.resource
import de.nowchess.chess.grpc.{IoGrpcClientWrapper, RuleSetGrpcAdapter}
import de.nowchess.chess.redis.GameRedisSubscriberManager
import io.quarkus.test.InjectMock
import io.quarkus.test.junit.{QuarkusTest, TestProfile}
import io.quarkus.test.junit.QuarkusTestProfile
import io.restassured.RestAssured
import jakarta.ws.rs.core.MediaType
import org.junit.jupiter.api.{DisplayName, Test}
import java.util.Map as JMap
// scalafix:off
class InternalAuthEnabledProfile extends QuarkusTestProfile:
override def getConfigOverrides(): JMap[String, String] =
JMap.of(
"nowchess.internal.auth.enabled",
"true",
"nowchess.internal.secret",
"test-secret-123",
)
@QuarkusTest
@TestProfile(classOf[InternalAuthEnabledProfile])
@DisplayName("InternalAuthFilter HTTP")
class InternalAuthFilterHttpTest:
@InjectMock
var ioWrapper: IoGrpcClientWrapper = scala.compiletime.uninitialized
@InjectMock
var ruleAdapter: RuleSetGrpcAdapter = scala.compiletime.uninitialized
@InjectMock
var subscriberManager: GameRedisSubscriberManager = scala.compiletime.uninitialized
@Test
@DisplayName("POST /api/board/game without secret returns 401")
def rejectNoSecret(): Unit =
RestAssured
.`given`()
.contentType(MediaType.APPLICATION_JSON)
.body("{}")
.when()
.post("/api/board/game")
.`then`()
.statusCode(401)
@Test
@DisplayName("POST /api/board/game with wrong secret returns 401")
def rejectWrongSecret(): Unit =
RestAssured
.`given`()
.contentType(MediaType.APPLICATION_JSON)
.header("X-Internal-Secret", "wrong-secret")
.body("{}")
.when()
.post("/api/board/game")
.`then`()
.statusCode(401)
@Test
@DisplayName("GET /api/board/game/{id} without secret returns 404 not 401")
def nonInternalEndpointNotBlocked(): Unit =
RestAssured
.`given`()
.when()
.get("/api/board/game/nonexistent")
.`then`()
.statusCode(404)
// scalafix:on
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=24 MINOR=30
PATCH=0 PATCH=0
+38
View File
@@ -190,3 +190,41 @@
### Bug Fixes ### Bug Fixes
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289)) * IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
## (2026-05-01)
### Features
* **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))
### 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-02)
### Features
* **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))
### Bug Fixes
* IO microservice ([#38](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/38)) ([a386f57](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/a386f57c21d34ead6cc6f92836c52b714597e289))
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=17 MINOR=19
PATCH=0 PATCH=0
+10
View File
@@ -18,3 +18,13 @@
### Features ### Features
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299)) * true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-01)
### Features
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-02)
### Features
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=4 MINOR=6
PATCH=0 PATCH=0
+20
View File
@@ -37,3 +37,23 @@
* **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 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)) * **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299)) * true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-01)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-02)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=4 MINOR=6
PATCH=0 PATCH=0
+36
View File
@@ -203,3 +203,39 @@
### Bug Fixes ### Bug Fixes
* NCS-32 Queenside Castle doesn't care about pieces in the way ([#23](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/23)) ([fe8e3c0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fe8e3c05397f433bfa34d1999e9738c82790adf7)) * NCS-32 Queenside Castle doesn't care about pieces in the way ([#23](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/23)) ([fe8e3c0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fe8e3c05397f433bfa34d1999e9738c82790adf7))
## (2026-05-01)
### Features
* **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))
* **docker:** update COPY command in native Dockerfile to reflect new build path ([952cf00](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/952cf00413fcbc5e9df1bad224d2e99f07064bf7))
* 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-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
* NCS-32 Queenside Castle doesn't care about pieces in the way ([#23](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/23)) ([fe8e3c0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fe8e3c05397f433bfa34d1999e9738c82790adf7))
## (2026-05-02)
### Features
* **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))
* **docker:** update COPY command in native Dockerfile to reflect new build path ([952cf00](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/952cf00413fcbc5e9df1bad224d2e99f07064bf7))
* 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-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
* NCS-32 Queenside Castle doesn't care about pieces in the way ([#23](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/23)) ([fe8e3c0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/fe8e3c05397f433bfa34d1999e9738c82790adf7))
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=13 MINOR=15
PATCH=0 PATCH=0
+32
View File
@@ -18,3 +18,35 @@
### Features ### Features
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299)) * true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-01)
### Features
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-02)
### Features
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-03)
### Features
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
### Bug Fixes
* **auth:** correct internal secret validation logic in InternalAuthFilter ([85b1872](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/85b187293f12f149494986872d6b06789945ea18))
## (2026-05-06)
### Features
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
### Bug Fixes
* **auth:** add InternalClientHeadersFactory for custom client headers management ([e279c39](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e279c39246470156bf11e745ee72204018d4229d))
* **auth:** change InternalAuthFilter to use @Singleton and add HTTP tests for secret validation ([c08d530](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/c08d5303eb9e70d36c8eebf6a061ccb71e118fe5))
* **auth:** correct internal secret validation logic in InternalAuthFilter ([85b1872](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/85b187293f12f149494986872d6b06789945ea18))
* **auth:** update InternalAuthFilter to use @ApplicationScoped and add index-dependency configuration ([6e0fd95](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/6e0fd9523e001756ce7109e639ebb54be4fcdabf))
* **redis:** enhance GameRedisSubscriberManager to use ReactiveRedisDataSource and improve subscription handling ([0eb752d](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/0eb752d4935377f75aab710b7f4eda4b29098e6a))
@@ -23,5 +23,5 @@ class InternalAuthFilter extends ContainerRequestFilter:
override def filter(ctx: ContainerRequestContext): Unit = override def filter(ctx: ContainerRequestContext): Unit =
if authEnabled then if authEnabled then
val header = Option(ctx.getHeaderString("X-Internal-Secret")) val header = Option(ctx.getHeaderString("X-Internal-Secret"))
if header.isEmpty || header.get.equals(secret) then if header.isEmpty || (!header.get.equals(secret)) then
ctx.abortWith(Response.status(Response.Status.UNAUTHORIZED).build()) ctx.abortWith(Response.status(Response.Status.UNAUTHORIZED).build())
@@ -0,0 +1,30 @@
package de.nowchess.security
import jakarta.enterprise.context.ApplicationScoped
import jakarta.ws.rs.core.MultivaluedMap
import org.eclipse.microprofile.config.inject.ConfigProperty
import org.eclipse.microprofile.rest.client.ext.DefaultClientHeadersFactoryImpl
import scala.compiletime.uninitialized
@ApplicationScoped
class InternalClientHeadersFactory extends DefaultClientHeadersFactoryImpl {
@ConfigProperty(name = "nowchess.internal.secret", defaultValue = "")
// scalafix:off DisableSyntax.var
var secret: String = uninitialized
@ConfigProperty(name = "nowchess.internal.auth.enabled", defaultValue = "true")
var authEnabled: Boolean = uninitialized
// scalafix:on DisableSyntax.var
override def update(
incomingHeaders: MultivaluedMap[String, String],
clientOutgoingHeaders: MultivaluedMap[String, String],
): MultivaluedMap[String, String] = {
val default = super.update(incomingHeaders, clientOutgoingHeaders)
default.putSingle("X-Internal-Secret", secret)
default
}
}
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=4 MINOR=8
PATCH=0 PATCH=0
+37
View File
@@ -39,3 +39,40 @@
* **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 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)) * **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299)) * true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-01)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-02)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-05)
### Features
* **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))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
### Bug Fixes
* **redis:** update Redis configuration with max pool size and waiting parameters ([5baf6a7](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/5baf6a7cdbea484fc49c02e2b5a1c3919b7fa2c4))
@@ -8,6 +8,8 @@ quarkus:
enabled: true enabled: true
redis: redis:
hosts: redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379} hosts: redis://${REDIS_HOST:localhost}:${REDIS_PORT:6379}
max-pool-size: 64
max-pool-waiting: 128
datasource: datasource:
db-kind: postgresql db-kind: postgresql
username: ${DB_USER:nowchess} username: ${DB_USER:nowchess}
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=4 MINOR=7
PATCH=0 PATCH=0
+23
View File
@@ -41,3 +41,26 @@
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e)) * **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([34b9933](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/34b993304670cf2aa62cd2f6460cee7b9864b08e))
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([e5fe7d0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5fe7d07a58e018151bb24f4ee37c06e72608ded)) * **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([e5fe7d0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5fe7d07a58e018151bb24f4ee37c06e72608ded))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299)) * true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-01)
### Features
* **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))
* **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))
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([e5fe7d0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5fe7d07a58e018151bb24f4ee37c06e72608ded))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
## (2026-05-02)
### Features
* **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))
* **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))
* **docker:** add Dockerfiles for Quarkus application in JVM and native modes ([e5fe7d0](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/e5fe7d07a58e018151bb24f4ee37c06e72608ded))
* **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))
* true-microservices ([#40](https://git.janis-eccarius.de/NowChess/NowChessSystems/issues/40)) ([5909242](https://git.janis-eccarius.de/NowChess/NowChessSystems/commit/590924254e8a2754de661a57a03e43f89ceb6299))
@@ -6,6 +6,7 @@ import io.quarkus.redis.datasource.pubsub.PubSubCommands
import io.quarkus.websockets.next.* import io.quarkus.websockets.next.*
import io.smallrye.jwt.auth.principal.JWTParser import io.smallrye.jwt.auth.principal.JWTParser
import jakarta.inject.Inject import jakarta.inject.Inject
import org.jboss.logging.Logger
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import scala.util.Try import scala.util.Try
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@@ -14,6 +15,8 @@ import java.util.function.Consumer
@WebSocket(path = "/api/board/game/{gameId}/ws") @WebSocket(path = "/api/board/game/{gameId}/ws")
class GameWebSocketResource: class GameWebSocketResource:
private val log = Logger.getLogger(classOf[GameWebSocketResource])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@Inject @Inject
var redis: RedisDataSource = uninitialized var redis: RedisDataSource = uninitialized
@@ -40,6 +43,7 @@ class GameWebSocketResource:
.filter(_.nonEmpty) .filter(_.nonEmpty)
.flatMap(token => Try(jwtParser.parse(token)).toOption) .flatMap(token => Try(jwtParser.parse(token)).toOption)
.map(_.getSubject) .map(_.getSubject)
log.infof("Game WebSocket opened — gameId=%s playerId=%s", gameId, playerId.getOrElse("anonymous"))
val handler: Consumer[String] = msg => connection.sendText(msg).subscribe().`with`(_ => (), _ => ()) val handler: Consumer[String] = msg => connection.sendText(msg).subscribe().`with`(_ => (), _ => ())
val subscriber = redis.pubsub(classOf[String]).subscribe(s2cTopic(gameId), handler) val subscriber = redis.pubsub(classOf[String]).subscribe(s2cTopic(gameId), handler)
connections.put(connection.id(), ConnectionMeta(gameId, subscriber, playerId)) connections.put(connection.id(), ConnectionMeta(gameId, subscriber, playerId))
@@ -60,6 +64,7 @@ class GameWebSocketResource:
@OnClose @OnClose
def onClose(connection: WebSocketConnection): Unit = def onClose(connection: WebSocketConnection): Unit =
Option(connections.remove(connection.id())).foreach { meta => Option(connections.remove(connection.id())).foreach { meta =>
log.infof("Game WebSocket closed — gameId=%s", meta.gameId)
meta.subscriber.unsubscribe(s2cTopic(meta.gameId)) meta.subscriber.unsubscribe(s2cTopic(meta.gameId))
} }
@@ -6,6 +6,7 @@ import io.quarkus.redis.datasource.pubsub.PubSubCommands
import io.quarkus.websockets.next.* import io.quarkus.websockets.next.*
import io.smallrye.jwt.auth.principal.JWTParser import io.smallrye.jwt.auth.principal.JWTParser
import jakarta.inject.Inject import jakarta.inject.Inject
import org.jboss.logging.Logger
import scala.compiletime.uninitialized import scala.compiletime.uninitialized
import scala.util.Try import scala.util.Try
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@@ -14,6 +15,8 @@ import java.util.function.Consumer
@WebSocket(path = "/api/user/ws") @WebSocket(path = "/api/user/ws")
class UserWebSocketResource: class UserWebSocketResource:
private val log = Logger.getLogger(classOf[UserWebSocketResource])
// scalafix:off DisableSyntax.var // scalafix:off DisableSyntax.var
@Inject @Inject
var redis: RedisDataSource = uninitialized var redis: RedisDataSource = uninitialized
@@ -38,8 +41,11 @@ class UserWebSocketResource:
.map(_.getSubject) .map(_.getSubject)
userIdOpt match userIdOpt match
case None => connection.close().subscribe().`with`(_ => (), _ => ()) case None =>
log.warn("WebSocket opened with no valid JWT — closing connection")
connection.close().subscribe().`with`(_ => (), _ => ())
case Some(userId) => case Some(userId) =>
log.infof("User WebSocket opened — userId=%s", userId)
val handler: Consumer[String] = msg => connection.sendText(msg).subscribe().`with`(_ => (), _ => ()) val handler: Consumer[String] = msg => connection.sendText(msg).subscribe().`with`(_ => (), _ => ())
val subscriber = redis.pubsub(classOf[String]).subscribe(userTopic(userId), handler) val subscriber = redis.pubsub(classOf[String]).subscribe(userTopic(userId), handler)
connections.put(connection.id(), (userId, subscriber)) connections.put(connection.id(), (userId, subscriber))
@@ -48,6 +54,7 @@ class UserWebSocketResource:
@OnClose @OnClose
def onClose(connection: WebSocketConnection): Unit = def onClose(connection: WebSocketConnection): Unit =
log.infof("User WebSocket closed — connectionId=%s", connection.id())
Option(connections.remove(connection.id())).foreach { (userId, subscriber) => Option(connections.remove(connection.id())).foreach { (userId, subscriber) =>
subscriber.unsubscribe(userTopic(userId)) subscriber.unsubscribe(userTopic(userId))
} }
+1 -1
View File
@@ -1,3 +1,3 @@
MAJOR=0 MAJOR=0
MINOR=4 MINOR=6
PATCH=0 PATCH=0
+1 -1
View File
@@ -1,7 +1,7 @@
#! /usr/bin/env bash #! /usr/bin/env bash
set -euo pipefail set -euo pipefail
./gradlew test ./gradlew test -Dquarkus.profile=test
if [ "$#" -eq 0 ]; then if [ "$#" -eq 0 ]; then
PYTHONUTF8=1 python3 jacoco-reporter/test_gaps.py PYTHONUTF8=1 python3 jacoco-reporter/test_gaps.py