# AI Agent Guidelines for MineSeeker

This document provides guidelines and context for AI coding agents working on the MineSeeker project.

## Project Overview

**MineSeeker** is a real-time multiplayer 1v1 minesweeper game built with Symfony (PHP) and React. Players compete to claim mines on a shared 16×16 grid, with the first to reach 26 mines winning.

### Tech Stack

- **Backend:** Symfony 7.2 (PHP 8.3)
- **Frontend:** React 18, Vite 6
- **Database:** PostgreSQL 17 with materialized views
- **Storage:** MinIO (S3-compatible)
- **Real-time:** Mercure (Server-Sent Events)
- **Styling:** SCSS, MUI (Material-UI), Emotion
- **Fonts:** @fontsource packages (web), Carlito-Bold.ttf (server-side images)

### Key Features

**Core Gameplay:**
- **Multiplayer-focused:** 1v1 competitive gameplay where players race to claim more mines than their opponent
- **Win condition:** First player to claim 26 out of 51 mines wins
- **Real-time updates:** WebSocket-like gameplay using Mercure (Server-Sent Events)
- **Game restoration:** Players can resume unfinished games from where they left off
- **Bonus points system:** Rewards skilled play (blind hits, chain combos, edge mines, endgame mines, safe cell reveals)

**User Features:**
- **Authentication:** Password + optional TOTP + optional WebAuthn passkeys
- **Anonymous play:** Guest players can play without creating an account
- **Profile statistics:** Detailed stats including wins, losses, draws, win rate, average score, total mines hit, and bonus points
- **Battle history:** View and replay past games move-by-move

**Sharing & Social:**
- **Battle reports:** Shareable public pages for each completed game (`/battle/{uuid}`)
- **OG image generation:** Automatic creation of 1200×630 PNG images for social media sharing (using PHP GD)
- **Open Graph tags:** Battle share pages include rich preview cards with player names, avatars, scores, and bonus points

---

## Architecture Overview

### Backend (Symfony)

```
src/
├── Controller/        # HTTP endpoints (game, profile, battle sharing)
├── Entity/           # Doctrine ORM entities
├── Repository/       # Database queries (uses QueryBuilder, not raw SQL)
├── Service/          # Business logic (BattleCardGenerator, WebAuthn, Email)
├── Dto/              # Data Transfer Objects (immutable, readonly)
├── Util/             # Game logic (TopicManager for Mercure)
└── Migrations/       # Database schema changes
```

**Important patterns:**
- Use Doctrine ORM QueryBuilder (not raw SQL) in repositories
- DTOs are `final readonly` classes with constructor property promotion
- Services use dependency injection via `config/services.yaml`
- Materialized views for performance (auto-refreshed via triggers)

### Frontend (React)

```
assets/
├── js/
│   ├── mine-seeker/           # Main game bundle (self-contained)
│   │   ├── MineSeeker.jsx     # Root component, wraps GameProvider + QueryClientProvider
│   │   ├── components/        # Game-specific components
│   │   │   ├── GameBoard.jsx          # Main game board grid
│   │   │   ├── GameTimer.jsx          # Game timer display
│   │   │   ├── BonusBox.jsx           # Bonus points indicator
│   │   │   ├── BonusStatsDialog.jsx   # Bonus statistics modal
│   │   │   ├── CaptchaOverlay.jsx     # Captcha challenge overlay
│   │   │   ├── ChallengeCountdown.jsx # Challenge timer
│   │   │   ├── OnlinePlayersDialog.jsx # Online players list
│   │   │   ├── WaitingOverlayContent.jsx # Waiting for opponent
│   │   │   ├── grid/           # Grid-related components (cells, mines)
│   │   │   ├── profile/        # In-game profile components (PlayerColumn)
│   │   │   ├── timer/          # Timer-related components
│   │   │   └── user/           # User-related components
│   │   ├── contexts/          # React Context API
│   │   │   ├── GameContext.jsx     # Game state context
│   │   │   └── GameProvider.jsx    # Context provider with state logic
│   │   ├── hooks/             # Custom React hooks
│   │   │   ├── useGameDataProvider.js    # React Query data provider
│   │   │   ├── useGameRefs.jsx           # Refs for DOM elements
│   │   │   ├── useGameState.jsx          # Game state management
│   │   │   ├── useServerCommunication.jsx # Mercure SSE connection
│   │   │   └── useStepTimer.jsx          # Step-by-step timer
│   │   └── utils/             # Game-specific utilities
│   │       └── constants.jsx   # Game constants, colors, defaults
│   ├── components/      # Shared UI components
│   ├── utils/           # Shared utilities
│   ├── profile.jsx      # Profile page entry
│   ├── passkey.jsx      # Passkey management entry
│   └── contact.jsx      # Contact form entry
├── css/
│   └── homepage/        # SCSS partials (imported by style.homepage.scss)
└── fonts/
    └── Carlito-Bold.ttf # TTF font for PHP GD image generation
```

**Important patterns:**
- Vite aliases: `@mine-components`, `@mine-contexts`, `@mine-hooks`, `@mine-utils`, `@global-components`, `@global-utils`
- React Query only available inside `mine-seeker` bundle
- Avoid circular dependencies (e.g., don't import from `@global-components` inside `components/` directory)
- PropTypes required on all components

---

## Common Tasks

### Adding a New Feature

1. **Backend:**
   - Create migration for schema changes
   - Add/update entities and repositories
   - Create DTOs for data transfer
   - Add controller endpoints
   - Update service configuration if needed

2. **Frontend:**
   - Create components in appropriate bundle
   - Add PropTypes to all components
   - Use existing hooks and utilities
   - Follow styled-components pattern for MUI customization

3. **Documentation:**
   - Update relevant docs in `docs/` folder
   - Add examples if introducing new patterns

### Database Changes

- Always create migrations: `bin/console make:migration`
- Use Doctrine QueryBuilder in repositories (not raw SQL)
- For PostgreSQL-specific features (materialized views, triggers), use raw SQL in migrations only
- Materialized views should auto-refresh via triggers

### Styling

- **Web fonts:** Use `@fontsource` packages (WOFF/WOFF2)
- **Server-side images:** Use TTF fonts in `assets/fonts/` (PHP GD requires TTF)
- **CSS:** Create SCSS partials in `assets/css/homepage/`, import in main file
- **Components:** Use Emotion styled-components or CSS classes

### File Headers

All PHP and JS/JSX files should have this header:

```php
<?php declare(strict_types=1);
/*
 * This file is part of the SplendidBear Websites' projects.
 *
 * Copyright (c) 2026 @ www.splendidbear.org
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
```

```javascript
/**
 * This file is part of the SplendidBear Websites' projects.
 *
 * Copyright (c) 2026 @ www.splendidbear.org
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
```

---

## Coding Standards

### PHP

- **PSR Standards:** Follow PSR-1, PSR-12 coding standards
- **Type declarations:** Use strict types (`declare(strict_types=1)`)
- **Property promotion:** Use constructor property promotion for DTOs and services
- **Readonly:** Use `readonly` for immutable properties
- **Final:** Mark DTOs as `final`
- **Doctrine:** Use QueryBuilder with `expr()` methods, not string concatenation
- **Null safety:** Use null coalescing `??` and null-safe operator `?->`
- **Formatting:** 4-space indentation, opening braces on same line for methods/classes

**Example DTO:**

```php
final readonly class ProfileGameDto implements JsonSerializable
{
    public function __construct(
        public ?int    $id,
        public string  $redName,
        public string  $blueName,
        public bool    $bothRegistered,
    ) {}
}
```

### JavaScript/React

- **Components:** Functional components with hooks
- **PropTypes:** Required on all components
- **Imports:** Use aliases (`@global-components`, `@mine-hooks`, etc.)
- **State:** Use `useState`, `useEffect`, `useCallback`, `useMemo` appropriately
- **Avoid:** Circular dependencies, especially with barrel exports

**Example component:**

```javascript
import React, { useState } from 'react';
import { string, number } from 'prop-types';

export const MyComponent = ({ title, count }) => {
  const [value, setValue] = useState(0);
  
  return <div>{title}: {count + value}</div>;
};

MyComponent.propTypes = {
  title: string.isRequired,
  count: number.isRequired,
};
```

---

## Important Files & Locations

### Configuration

- `config/services.yaml` - Service definitions and parameters
- `vite.config.js` - Vite build config, aliases
- `.env` - Environment variables (not in git)
- `composer.json` - PHP dependencies
- `package.json` - Node dependencies

### Key Services

- `BattleCardGenerator` - Generates 1200×630 PNG OG images using PHP GD
- `TopicManager` - Mercure topic management and game logic
- `WebAuthnService` - Passkey authentication
- `Email services` - Various email senders in `src/Service/Email/`

### Important Entities

- `User` - Registered users
- `PlayedGame` - Game records with moves, grid, scores
- `RecentBattle` - Read-only entity from materialized view
- `UserStats` - Read-only entity from materialized view

### Documentation

- `docs/game-mechanics/BONUS_POINTS_SYSTEM.md` - Bonus points reference
- `docs/FONTS.md` - Font usage and management
- `AGENTS.md` - This file
- `CHANGELOG.md` - Project changelog

---

## Common Pitfalls

### ❌ Don't Do

- **Don't use raw SQL in repositories** (use Doctrine QueryBuilder)
- **Don't create circular imports** (e.g., importing `@global-components` from within `components/`)
- **Don't use system fonts directly** (bundle TTF in `assets/fonts/`)
- **Don't skip PropTypes** on React components
- **Don't use `var`** in JavaScript (use `const` or `let`)
- **Don't define variables after using them** (hoisting issues with `const`)

### ✅ Do

- **Use Doctrine QueryBuilder** with `expr()` methods
- **Import components directly** to avoid circular dependencies
- **Bundle fonts in project** for portability
- **Add PropTypes** to all components
- **Use `const` for immutable values**, `let` for mutable
- **Define variables before using them**

---

## Keeping Components in Sync

### Battle Report Display

The battle report/statistics appear in **two places** that must be kept synchronized:

#### 1. BattleDialog Component (React)
**File:** `assets/js/components/BattleDialog.jsx`
- React dialog component shown on profile page
- Uses Material-UI and styled-components
- Displays game stats, bonus points, winner information

#### 2. Battle Share Page (Twig)
**File:** `templates/Game/battle_share.html.twig`
- Public battle share page (accessible via `/battle/{uuid}`)
- Server-rendered HTML with SCSS styling
- Shows same information as BattleDialog

### Synchronization Rules

**When updating BattleDialog.jsx, also update battle_share.html.twig:**

✅ Adding new stats or fields
✅ Changing display logic (winner calculation, formatting)
✅ Modifying bonus points display
✅ Updating labels or text

**Keep in sync:**
- Game outcome logic (win/loss/draw/abandoned)
- Bonus points formatting
- Player name display
- Score display
- Stats and metadata shown

**Example:** If you add a new stat to BattleDialog showing "fastest mine claim time", you must also add it to battle_share.html.twig so both displays show the same information.

---

## Testing & Building

### Backend

```bash
# Run migrations
bin/console doctrine:migrations:migrate

# Clear cache
bin/console cache:clear

# Refresh materialized views
bin/console dbal:run-sql "REFRESH MATERIALIZED VIEW CONCURRENTLY recent_battles"
```

### Frontend

```bash
# Development build with watch
npm run dev

# Production build
npm run build

# After changing fonts
rm -rf var/og-cache/*
```

---

## Git Workflow

### Commit Messages

Follow conventional commits:

- `feat: add bonus points to battle cards`
- `fix: resolve circular dependency in BattleDialog`
- `refactor: use Doctrine QueryBuilder in RecentBattleRepository`
- `docs: add AGENTS.md for AI coding agents`
- `chore: update dependencies`

### Creating Pull Requests

When creating PRs, include:

1. **Summary** - What was changed and why
2. **Changes** - List of modified files/components
3. **Testing** - How to verify the changes
4. **Screenshots** - For UI changes

---

## Performance Considerations

### Database

- Use materialized views for expensive queries (profile stats, recent battles)
- Auto-refresh materialized views via triggers on source table changes
- Index frequently queried columns
- Use `COALESCE()` for nullable aggregates

### Frontend

- Lazy load large components
- Use React Query for data fetching and caching
- Avoid unnecessary re-renders (use `useMemo`, `useCallback`)
- Bundle code per entry point (profile, passkey, contact, game)

### Images

- Battle card images are cached in `var/og-cache/`
- Images regenerated when games change (via deterministic UUID)
- Use appropriate image sizes (1200×630 for OG images)

---

## Security

### Authentication

- Password + TOTP (optional) + WebAuthn passkeys (optional)
- Backup codes for TOTP recovery
- Session-based authentication with `IS_AUTHENTICATED_REMEMBERED`

### Data Access

- Controllers check `denyAccessUnlessGranted()`
- Materialized views filter by `user_id`
- Guest players use separate `Gamer` entity (no `User` account)

### Input Validation

- Symfony forms for user input
- File upload validation (size, MIME type)
- WebAuthn challenge validation

---

## Useful Commands

```bash
# Symfony
bin/console debug:container ServiceName        # Inspect service configuration
bin/console debug:router                       # List all routes
bin/console make:migration                     # Create new migration
bin/console doctrine:migrations:list           # List migrations

# Database
bin/console dbal:run-sql "SELECT * FROM ..."  # Run SQL query

# Assets
npm run build                                  # Build production assets
npm run dev                                    # Build with watch mode

# Git
git log --oneline --graph                      # View commit history
git diff origin/main...HEAD                    # See changes since main
```

---

## Need Help?

- **Bonus Points:** See `docs/game-mechanics/BONUS_POINTS_SYSTEM.md`
- **Fonts:** See `docs/FONTS.md`
- **Symfony Docs:** https://symfony.com/doc/current/
- **React Docs:** https://react.dev/
- **Doctrine ORM:** https://www.doctrine-project.org/projects/doctrine-orm/en/current/

---

## Version History

- **2026-04-21:** Initial AGENTS.md created
- Document common patterns, pitfalls, and project structure
- Include coding standards and examples

---

**Happy coding! 🚀**
