Optimize CLAUDE.md from 408 to 54 lines

Remove full code style guide with examples, architecture code blocks, game engine
patterns, and testing examples. Keep commands, critical rules, and architecture summary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2026-02-14 08:31:08 -06:00
parent 69daedfa02
commit 1c30d3fe56

424
CLAUDE.md
View File

@ -1,407 +1,53 @@
# Mantimon TCG # Mantimon TCG
Guidelines for agentic coding agents working on this codebase. Pokemon TCG-inspired web app with single-player RPG campaign mode. Home-rule-modified rules.
## Project-Specific Skills ## Project Skills
Local skills are available in `.claude/skills/`. Load them when the user invokes the corresponding command: | Command | Description |
|---------|-------------|
| `/backend-phase` | Manage phased backend development |
| `/frontend-phase` | Manage phased frontend development |
| `/code-audit` | Audit backend Python code |
| `/frontend-code-audit` | Audit frontend Vue/TypeScript/Phaser code |
| `/dev-server` | Start/stop/status the dev environment |
| Command | Skill File | Description | Skills in `.claude/skills/` — read the SKILL.md before executing.
|---------|------------|-------------|
| `/backend-phase` | `.claude/skills/backend-phase/SKILL.md` | Manage phased backend development workflow. Track tasks, mark progress, generate phase plans. |
| `/frontend-phase` | `.claude/skills/frontend-phase/SKILL.md` | Manage phased frontend development workflow. Track tasks, mark progress, generate phase plans. |
| `/code-audit` | `.claude/skills/code-audit/SKILL.md` | Audit backend Python code for errors, security issues, and architecture violations. Uses patterns in `patterns/` subdirectory. |
| `/frontend-code-audit` | `.claude/skills/frontend-code-audit/SKILL.md` | Audit frontend Vue/TypeScript/Phaser code for errors, security issues, and architecture violations. |
| `/dev-server` | `.claude/skills/dev-server/SKILL.md` | Start/stop/status the complete dev environment (Docker infra + backend + frontend). |
When a user invokes one of these commands, **read the corresponding SKILL.md file first** to understand the full instructions before executing. ## Commands
## Project Overview
Mantimon TCG is a home-rule-modified Pokemon Trading Card Game web application inspired by the Gameboy Color game *Pokemon TCG*. The core experience is a **single-player RPG campaign**:
- **Campaign Mode**: Challenge NPCs at themed clubs, defeat Club Leaders to earn medals, collect all medals to face Grand Masters and become Champion
- **Collection Building**: Win matches to earn booster packs, build your card collection
- **Deck Building**: Construct decks from your collection to take on tougher opponents
- **Multiplayer (Optional)**: PvP matches for competitive play
## Tech Stack
### Frontend
| Technology | Purpose |
|------------|---------|
| Vue 3 | UI framework (Composition API + `<script setup>`) |
| Phaser 3 | Game canvas (matches, pack opening) |
| TypeScript | Type safety |
| Pinia | State management |
| Tailwind CSS | Styling |
| Socket.io-client | Real-time communication |
| Vite | Build tool |
### Backend
| Technology | Purpose |
|------------|---------|
| FastAPI | REST API framework |
| Python 3.11+ | Backend language |
| SQLAlchemy 2.0 | ORM (async) |
| PostgreSQL | Database |
| Redis | Caching, session storage |
| python-socketio | WebSocket server |
| Pydantic v2 | Validation |
| Alembic | Database migrations |
---
## Quick Commands
### Development Servers
```bash
cd frontend && npm run dev # Frontend dev server
cd backend && uv run uvicorn app.main:app --reload # Backend dev server
```
### Testing
```bash
# Frontend (Vitest)
cd frontend && npm run test # Run all tests
cd frontend && npm run test -- path/to/file # Run single test file
cd frontend && npm run test -- -t "test name" # Run by test name
# Backend (pytest with uv)
cd backend && uv run pytest # Run all tests
cd backend && uv run pytest tests/test_file.py # Single file
cd backend && uv run pytest tests/test_file.py::test_fn # Single test
cd backend && uv run pytest -k "test_name" # By name pattern
cd backend && uv run pytest -x # Stop on first failure
cd backend && uv run pytest --cov=app # With coverage
```
### Linting & Formatting
```bash ```bash
# Frontend # Frontend
cd frontend && npm run lint # ESLint cd frontend && npm run dev # Dev server
cd frontend && npm run typecheck # TypeScript check cd frontend && npm run test # Vitest
cd frontend && npm run lint # ESLint
cd frontend && npm run typecheck # TypeScript
# Backend (uses uv for all commands) # Backend (all via uv)
cd backend && uv run black app tests # Format with Black cd backend && uv run uvicorn app.main:app --reload # Dev server
cd backend && uv run black --check . # Check formatting (CI) cd backend && uv run pytest # Tests
cd backend && uv run ruff check . # Lint with Ruff cd backend && uv run pytest -x # Stop on first failure
cd backend && uv run ruff check --fix . # Auto-fix lint issues cd backend && uv run black app tests && uv run ruff check . # Format + lint
cd backend && uv run mypy app # Type check cd backend && uv run mypy app # Type check
``` ```
### Dependency Management (Backend)
```bash
cd backend && uv add <package> # Add runtime dependency
cd backend && uv add --dev <package> # Add dev dependency
cd backend && uv sync # Install all dependencies
cd backend && uv lock # Update lock file
```
---
## Code Style ## Code Style
- Line length: 100 chars
### General Rules
- Line length: 100 characters max
- Indentation: 2 spaces (frontend), 4 spaces (backend) - Indentation: 2 spaces (frontend), 4 spaces (backend)
- Trailing commas in multi-line structures - Use `import type` for type-only TS imports, `@/` alias for local imports
- Explicit over implicit - Python: type hints required on all function signatures
### TypeScript/Vue ## Architecture
**Import order** (separated by blank lines): - **Frontend**: Vue 3 + Phaser 3 (game canvas). Communication via event bridge (`phaserGame.events.emit/on`)
1. Standard library / Vue core - **Backend**: FastAPI + PostgreSQL + Redis + Socket.io. Service layer pattern — never bypass services for DB access
2. Third-party packages - **Game Engine** (`app/core/`): Must stay decoupled from DB/network (forkable for offline mode). No imports from `app.services`, `app.api`, or SQLAlchemy in core.
3. Local imports (use `@/` alias)
```typescript ## Critical Rules
import { ref, computed } from 'vue'
import { useGameStore } from '@/stores/game' 1. Never commit without user approval. Never commit directly to `main`.
import type { Card, GameState } from '@/types' 2. **Hidden info**: Never send deck contents, opponent hand, or unrevealed prizes to client
3. All game logic server-side. Client sends intentions, server validates.
// Always use `import type` for type-only imports 4. Test docstrings required explaining "what" and "why"
import type { Player } from '@/types/player' 5. Phaser scenes handle rendering only — game logic lives in backend
6. `app/core/` imports only from `app.core.*` — see `docs/ARCHITECTURE.md#offline-standalone-fork`
// Prefer const over let
const cards = ref<Card[]>([])
```
**Naming conventions:**
| Type | Convention | Example |
|------|------------|---------|
| Vue components | PascalCase | `CardHand.vue`, `GameBoard.vue` |
| Phaser scenes | PascalCase | `MatchScene.ts`, `PackOpeningScene.ts` |
| TypeScript files | camelCase | `useWebSocket.ts`, `cardUtils.ts` |
| Constants | UPPER_SNAKE_CASE | `MAX_HAND_SIZE`, `PRIZE_COUNT` |
### Python
**Import order** (separated by blank lines):
1. Standard library
2. Third-party packages
3. Local imports
```python
from typing import Optional
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from app.models import Card, Player
from app.services.game_service import GameService
```
**Type hints required** for all function signatures:
```python
async def get_card(card_id: int, db: AsyncSession = Depends(get_db)) -> Card:
...
```
**Naming conventions:**
| Type | Convention | Example |
|------|------------|---------|
| Modules | snake_case | `game_engine.py`, `card_service.py` |
| Database tables | snake_case | `user_collections`, `match_history` |
| Constants | UPPER_SNAKE_CASE | `MAX_HAND_SIZE`, `PRIZE_COUNT` |
---
## Architecture Patterns
### Frontend: Vue + Phaser Integration
Phaser mounts as a Vue component. Communication via event bridge:
```typescript
// Vue -> Phaser
phaserGame.value?.events.emit('card:play', { cardId, targetId })
// Phaser -> Vue
phaserGame.value?.events.on('animation:complete', handleAnimationComplete)
```
### Frontend: State Management (Pinia)
```typescript
export const useGameStore = defineStore('game', () => {
const gameState = ref<GameState | null>(null)
const myHand = computed(() => gameState.value?.myHand ?? [])
return { gameState, myHand }
})
```
### Backend: Service Layer
**Never bypass services for business logic:**
```python
# CORRECT
card = await card_service.get_card(card_id)
result = await game_service.play_card(game_id, player_id, card_id)
# WRONG - direct DB access in endpoint
card = await db.execute(select(Card).where(Card.id == card_id))
```
### Backend: Async by Default
All I/O operations use async/await:
```python
async def resolve_attack(attacker: Card, defender: Card) -> AttackResult:
...
```
### Backend: WebSocket Events
```python
# All game actions go through WebSocket for real-time sync
@sio.on('game:action')
async def handle_game_action(sid, data):
action_type = data['type']
# Validate action is legal
validation = await game_engine.validate_action(game_id, player_id, data)
if not validation.valid:
await sio.emit('game:error', {'message': validation.reason}, to=sid)
return
# Execute and broadcast
new_state = await game_engine.execute_action(game_id, data)
await broadcast_game_state(game_id, new_state)
```
---
## Game Engine Patterns
### Card Effect System
Cards are data-driven. Effects reference handler functions:
```python
# Card definition (JSON/DB)
{
"id": "pikachu_base_001",
"name": "Pikachu",
"hp": 60,
"type": "lightning",
"attacks": [
{
"name": "Thunder Shock",
"cost": ["lightning"],
"damage": 20,
"effect": "may_paralyze", # References effect handler
"effect_params": {"chance": 0.5}
}
]
}
# Effect handler (Python)
@effect_handler("may_paralyze")
async def handle_may_paralyze(context: EffectContext, params: dict) -> None:
if random.random() < params["chance"]:
context.defender.add_status("paralyzed")
```
### Turn State Machine
```python
class TurnPhase(Enum):
DRAW = "draw"
MAIN = "main"
ATTACK = "attack"
END = "end"
# Transitions are explicit
VALID_TRANSITIONS = {
TurnPhase.DRAW: [TurnPhase.MAIN],
TurnPhase.MAIN: [TurnPhase.ATTACK, TurnPhase.END], # Can skip attack
TurnPhase.ATTACK: [TurnPhase.END],
TurnPhase.END: [TurnPhase.DRAW], # Next player's turn
}
```
---
## Testing Guidelines
### Test Docstrings Required
Every test must include a docstring explaining "what" and "why":
```python
@pytest.mark.asyncio
async def test_draw_card():
"""
Test that drawing a card moves it from deck to hand.
Verifies the fundamental draw mechanic works correctly
and updates both zones appropriately.
"""
# test implementation
```
### Frontend Tests (Vitest)
```typescript
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
describe('CardHand', () => {
it('renders cards in hand', () => {
const wrapper = mount(CardHand, {
props: { cards: [{ id: '1', name: 'Pikachu' }] }
})
expect(wrapper.text()).toContain('Pikachu')
})
})
```
---
## Critical Security Rules
### Hidden Information
**Never expose to clients:**
- Deck order (either player)
- Opponent's hand contents
- Unrevealed prize cards
- RNG seeds or future random results
```python
# Correct: Only send counts for opponent's hidden zones
opponent_hand_count=len(opponent.hand) # ONLY count, not contents
opponent_deck_count=len(opponent.deck) # ONLY count
```
### Server Authority
- All game logic runs server-side
- Client sends intentions, server validates and executes
- Never trust client-provided game state
---
## Critical Rules Summary
1. **Git**: Never commit directly to `main`. Create feature branches.
2. **Commits**: Do not commit without user approval.
3. **Hidden Info**: Never send deck contents, opponent hand, or unrevealed prizes to client.
4. **Validation**: Always validate actions server-side. Never trust client.
5. **Tests**: Include docstrings explaining "what" and "why" for each test.
6. **Phaser in Vue**: Keep Phaser scenes focused on rendering. Game logic lives in backend.
7. **Services**: Never bypass the service layer for business logic.
8. **Core Engine Independence**: Keep `app/core/` decoupled from DB/network (see below).
---
## Core Engine Independence (Offline Fork Support)
> **Long-term goal**: The `backend/app/core/` module should remain forkable as a standalone offline game.
The game engine must stay **completely decoupled** from network and database concerns to enable a future offline/standalone version of the RPG campaign mode.
### Rules for `app/core/` Module
| DO | DON'T |
|----|-------|
| Accept `CardDefinition` objects as parameters | Import from `app.services` or `app.api` |
| Use `RandomProvider` protocol for RNG | Import database session types |
| Keep state self-contained in `GameState` | Make network calls or database queries |
| Use sync logic (async wrappers at service layer) | Require authentication or user sessions |
| Load configuration from `RulesConfig` objects | Hard-code database connection strings |
### Import Boundaries
```python
# ALLOWED in app/core/
from app.core.models import CardDefinition, GameState
from app.core.config import RulesConfig
from app.core.rng import RandomProvider
# FORBIDDEN in app/core/
from app.services.card_service import CardService # NO - DB dependency
from app.api.deps import get_current_user # NO - Auth dependency
from sqlalchemy.ext.asyncio import AsyncSession # NO - DB dependency
```
### Why This Matters
See `docs/ARCHITECTURE.md#offline-standalone-fork` for full details. The core engine should be directly copyable to a standalone Python application with:
- Card definitions loaded from JSON files
- Save data stored locally
- No network or authentication requirements
---
## Project Structure
```
mantimon-tcg/
├── frontend/ # Vue 3 + Phaser 3
│ ├── src/
│ │ ├── components/ # Vue components
│ │ ├── pages/ # Route pages
│ │ ├── stores/ # Pinia stores
│ │ ├── game/ # Phaser scenes and game objects
│ │ └── composables/ # Vue composables
│ └── package.json
├── backend/ # FastAPI + PostgreSQL
│ ├── app/
│ │ ├── api/ # REST endpoints
│ │ ├── core/ # Game engine
│ │ ├── models/ # Pydantic + SQLAlchemy models
│ │ ├── services/ # Business logic
│ │ └── websocket/ # Socket.io handlers
│ └── pyproject.toml
└── shared/ # Shared types/schemas
```