feat: add memory structure documentation and update index
Build & Test (NowChessSystems) TeamCity build finished
Build & Test (NowChessSystems) TeamCity build finished
This commit is contained in:
@@ -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)
|
||||||
@@ -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_<module>.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.
|
||||||
@@ -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`
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -3,6 +3,10 @@
|
|||||||
## Stack
|
## Stack
|
||||||
Scala 3.5.x · Quarkus + quarkus-scala3 · Hibernate/Jakarta · Lanterna TUI · K8s + ArgoCD + Kargo · Frontend TBD (Vite/React/Angular/Vue)
|
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
|
## Structure
|
||||||
```
|
```
|
||||||
build.gradle.kts / settings.gradle.kts # root; include(":modules:<svc>") per service
|
build.gradle.kts / settings.gradle.kts # root; include(":modules:<svc>") per service
|
||||||
|
|||||||
Reference in New Issue
Block a user