From 2df2fdeeb95d79f2f0d5d9d9216073ed6b51b45a Mon Sep 17 00:00:00 2001 From: Janis Date: Sat, 28 Mar 2026 13:35:49 +0100 Subject: [PATCH] feat: add memory structure documentation and update index (#5) Reviewed-on: https://git.janis-eccarius.de/NowChess/NowChessSystems/pulls/5 --- .claude/memory/MEMORY.md | 9 +++ .../memory/feedback_keep_structure_updated.md | 16 ++++++ .claude/memory/project_structure_api.md | 51 +++++++++++++++++ .claude/memory/project_structure_core.md | 48 ++++++++++++++++ .claude/memory/project_structure_root.md | 55 +++++++++++++++++++ CLAUDE.md | 4 ++ gradlew | 0 7 files changed, 183 insertions(+) create mode 100644 .claude/memory/MEMORY.md create mode 100644 .claude/memory/feedback_keep_structure_updated.md create mode 100644 .claude/memory/project_structure_api.md create mode 100644 .claude/memory/project_structure_core.md create mode 100644 .claude/memory/project_structure_root.md mode change 100644 => 100755 gradlew diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md new file mode 100644 index 0000000..81be3d8 --- /dev/null +++ b/.claude/memory/MEMORY.md @@ -0,0 +1,9 @@ +# Memory Index + +## Feedback +- [feedback_keep_structure_updated.md](feedback_keep_structure_updated.md) — Update structure memory files whenever source files are added, removed, or changed + +## Project Structure +- [project_structure_root.md](project_structure_root.md) — Top-level layout, modules list, VERSIONS map, navigation rules (skip `build/`, `.gradle/`, `.idea/`) +- [project_structure_api.md](project_structure_api.md) — `modules/api`: all files and types (Board, Piece, Square, GameState, Move, ApiResponse, PlayerInfo) +- [project_structure_core.md](project_structure_core.md) — `modules/core`: all files and types (GameContext, GameRules, MoveValidator, GameController, Parser, Renderer) diff --git a/.claude/memory/feedback_keep_structure_updated.md b/.claude/memory/feedback_keep_structure_updated.md new file mode 100644 index 0000000..74512b8 --- /dev/null +++ b/.claude/memory/feedback_keep_structure_updated.md @@ -0,0 +1,16 @@ +--- +name: keep-structure-memory-updated +description: Always update the project structure memory files when adding, removing, or changing source files +type: feedback +--- + +After any change that adds, removes, renames, or significantly alters a source file, update the relevant structure memory file: + +- New/renamed/deleted file in `modules/api` → update `project_structure_api.md` +- New/renamed/deleted file in `modules/core` → update `project_structure_core.md` +- New module, dependency version change, or new top-level directory → update `project_structure_root.md` +- New module added → create a new `project_structure_.md` and add it to `MEMORY.md` + +**Why:** Structure memories are the primary navigation aid. Stale entries cause wasted exploration. + +**How to apply:** Treat the structure memory update as part of completing any implementation task — do it in the same session, not as a follow-up. diff --git a/.claude/memory/project_structure_api.md b/.claude/memory/project_structure_api.md new file mode 100644 index 0000000..5901d9b --- /dev/null +++ b/.claude/memory/project_structure_api.md @@ -0,0 +1,51 @@ +--- +name: module-api-structure +description: File and type overview for the modules/api module (shared domain types) +type: project +--- + +# Module: `modules/api` + +**Purpose:** Shared domain model — pure data types with no game logic. Depended on by `modules/core`. + +**Gradle:** `id("scala")`, no `application` plugin. No Quarkus. Uses scoverage plugin. + +**Package root:** `de.nowchess.api` + +## Source files (`src/main/scala/de/nowchess/api/`) + +### `board/` +| File | Contents | +|------|----------| +| `Board.scala` | `opaque type Board = Map[Square, Piece]` — extensions: `pieceAt`, `withMove`, `pieces`; `Board.initial` sets up start position | +| `Color.scala` | `enum Color { White, Black }` — `.opposite`, `.label` | +| `Piece.scala` | `case class Piece(color, pieceType)` — convenience vals `WhitePawn`…`BlackKing` | +| `PieceType.scala` | `enum PieceType { Pawn, Knight, Bishop, Rook, Queen, King }` — `.label` | +| `Square.scala` | `enum File { A–H }`, `enum Rank { R1–R8 }`, `case class Square(file, rank)` — `.toString` algebraic, `Square.fromAlgebraic(s)` | + +### `game/` +| File | Contents | +|------|----------| +| `GameState.scala` | `case class CastlingRights(kingSide, queenSide)` + `.None`/`.Both`; `enum GameResult { WhiteWins, BlackWins, Draw }`; `enum GameStatus { NotStarted, InProgress, Finished(result) }`; `case class GameState(piecePlacement, activeColor, castlingWhite, castlingBlack, enPassantTarget, halfMoveClock, fullMoveNumber, status)` — FEN-compatible snapshot | + +### `move/` +| File | Contents | +|------|----------| +| `Move.scala` | `enum PromotionPiece { Knight, Bishop, Rook, Queen }`; `enum MoveType { Normal, CastleKingside, CastleQueenside, EnPassant, Promotion(piece) }`; `case class Move(from, to, moveType = Normal)` | + +### `player/` +| File | Contents | +|------|----------| +| `PlayerInfo.scala` | `opaque type PlayerId = String`; `case class PlayerInfo(id: PlayerId, displayName: String)` | + +### `response/` +| File | Contents | +|------|----------| +| `ApiResponse.scala` | `sealed trait ApiResponse[+A]` → `Success[A](data)` / `Failure(errors)`; `case class ApiError(code, message, field?)`; `case class Pagination(page, pageSize, totalItems)` + `.totalPages`; `case class PagedResponse[A](items, pagination)` | + +## Test files (`src/test/scala/de/nowchess/api/`) +Mirror of main structure — one `*Test.scala` per source file using `AnyFunSuite with Matchers`. + +## Notes +- `GameState` is FEN-style but `Board` (in `core`) is a `Map[Square,Piece]` — the two are separate representations +- `CastlingRights` is defined here in `api`; the castling logic lives in `core` diff --git a/.claude/memory/project_structure_core.md b/.claude/memory/project_structure_core.md new file mode 100644 index 0000000..6014779 --- /dev/null +++ b/.claude/memory/project_structure_core.md @@ -0,0 +1,48 @@ +--- +name: module-core-structure +description: File and type overview for the modules/core module (TUI chess engine) +type: project +--- + +# Module: `modules/core` + +**Purpose:** Standalone TUI chess application. All game logic, move validation, rendering. Depends on `modules/api`. + +**Gradle:** `id("scala")` + `application` plugin. Main class: `de.nowchess.chess.Main`. Uses scoverage plugin. + +**Package root:** `de.nowchess.chess` + +## Source files (`src/main/scala/de/nowchess/chess/`) + +### Root +| File | Contents | +|------|----------| +| `Main.scala` | Entry point — prints welcome, starts `GameController.gameLoop(GameContext.initial, Color.White)` | + +### `controller/` +| File | Contents | +|------|----------| +| `GameController.scala` | `sealed trait MoveResult` ADT: `Quit`, `InvalidFormat`, `NoPiece`, `WrongColor`, `IllegalMove`, `Moved`, `MovedInCheck`, `Checkmate`, `Stalemate`; `object GameController` — `processMove(ctx, turn, raw): MoveResult` (pure), `gameLoop(ctx, turn)` (I/O loop), `applyRightsRevocation(...)` (castling rights bookkeeping) | +| `Parser.scala` | `object Parser` — `parseMove(input): Option[(Square, Square)]` parses coordinate notation e.g. `"e2e4"` | + +### `logic/` +| File | Contents | +|------|----------| +| `GameContext.scala` | `enum CastleSide { Kingside, Queenside }`; `case class GameContext(board, whiteCastling, blackCastling)` — `.castlingFor(color)`, `.withUpdatedRights(color, rights)`; `GameContext.initial`; `extension (Board).withCastle(color, side)` moves king+rook atomically | +| `GameRules.scala` | `enum PositionStatus { Normal, InCheck, Mated, Drawn }`; `object GameRules` — `isInCheck(board, color)`, `legalMoves(ctx, color): Set[(Square,Square)]`, `gameStatus(ctx, color): PositionStatus` | +| `MoveValidator.scala` | `object MoveValidator` — `isLegal(board, from, to)`, `legalTargets(board, from): Set[Square]` (board-only, no castling), `legalTargets(ctx, from)` (context-aware, includes castling), `isCastle`, `castleSide`, `castlingTargets(ctx, color)` — full castling legality (empty squares, no check through transit) | + +### `view/` +| File | Contents | +|------|----------| +| `Renderer.scala` | `object Renderer` — `render(board): String` outputs ANSI-colored board with file/rank labels | +| `PieceUnicode.scala` | `extension (Piece).unicode: String` maps each piece to its Unicode chess symbol | + +## Test files (`src/test/scala/de/nowchess/chess/`) +Mirror of main structure — one `*Test.scala` per source file using `AnyFunSuite with Matchers`. + +## Key design notes +- `MoveValidator` has two overloaded `legalTargets`: one takes `Board` (geometry only), one takes `GameContext` (adds castling) +- `GameRules.legalMoves` filters by check — it calls `MoveValidator.legalTargets(ctx, from)` then simulates each move +- Castling rights revocation is in `GameController.applyRightsRevocation`, triggered after every move +- No `@QuarkusTest` — this module is a plain Scala application, not a Quarkus service diff --git a/.claude/memory/project_structure_root.md b/.claude/memory/project_structure_root.md new file mode 100644 index 0000000..a6aa4d0 --- /dev/null +++ b/.claude/memory/project_structure_root.md @@ -0,0 +1,55 @@ +--- +name: project-root-structure +description: Top-level project structure, modules list, and navigation notes for NowChessSystems +type: project +--- + +# NowChessSystems — Root Structure + +## Directory layout (skip `build/`, `.gradle/`, `.idea/`) + +``` +NowChessSystems/ +├── build.gradle.kts # Root: sonarqube plugin, VERSIONS map +├── settings.gradle.kts # include(":modules:core", ":modules:api") +├── gradlew / gradlew.bat +├── CLAUDE.md # Project instructions for Claude Code +├── .claude/ +│ ├── CLAUDE.MD # Working agreement (plan/verify/unresolved) +│ ├── settings.json +│ └── agents/ # architect, code-reviewer, gradle-builder, scala-implementer, test-writer +├── docs/ +│ ├── Claude-Skills.md +│ ├── Security.md +│ └── unresolved.md +├── jacoco-reporter/ # Python scripts for coverage gap reporting +└── modules/ + ├── api/ # Shared domain types (no logic) + └── core/ # TUI chess engine + game logic +``` + +## Modules + +| Module | Gradle path | Purpose | +|--------|-------------|---------| +| `api` | `:modules:api` | Shared domain model: Board, Piece, Move, GameState, ApiResponse | +| `core` | `:modules:core` | TUI chess app: game logic, move validation, rendering | + +`core` depends on `api` via `implementation(project(":modules:api"))`. + +## VERSIONS (root `build.gradle.kts`) + +| Key | Value | +|-----|-------| +| `QUARKUS_SCALA3` | 1.0.0 | +| `SCALA3` | 3.5.1 | +| `SCALA_LIBRARY` | 2.13.18 | +| `SCALATEST` | 3.2.19 | +| `SCALATEST_JUNIT` | 0.1.11 | +| `SCOVERAGE` | 2.1.1 | + +## Navigation rules +- **Always skip** `build/`, `.gradle/`, `.idea/` when exploring — they are generated artifacts +- Tests use `AnyFunSuite with Matchers` (ScalaTest), not JUnit `@Test` +- No Quarkus in current modules — Quarkus is planned for future services +- Agent workflow: architect → scala-implementer → test-writer → gradle-builder → code-reviewer diff --git a/CLAUDE.md b/CLAUDE.md index 2695d7e..e3c4473 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,6 +3,10 @@ ## Stack Scala 3.5.x · Quarkus + quarkus-scala3 · Hibernate/Jakarta · Lanterna TUI · K8s + ArgoCD + Kargo · Frontend TBD (Vite/React/Angular/Vue) +### Memory + +Your memory is saved under .claude/memory/MEMORY.md. + ## Structure ``` build.gradle.kts / settings.gradle.kts # root; include(":modules:") per service diff --git a/gradlew b/gradlew old mode 100644 new mode 100755