# Scrum Solitare

Enterprise-style Scrum Poker application using Go, Gin, and SSE for real-time room updates.

## Highlights

- Go backend with layered architecture (`handlers`, `state`, `routes`, `config`)
- Memory-first room state with disk synchronization to JSON files
- Real-time updates via Server-Sent Events (SSE)
- Strict state sanitization: unrevealed votes from other users are never broadcast
- Backend authorization for admin-only actions (`reveal`, `reset`)
- Themeable frontend with:
  - CSS architecture split into `main.css`, `layout.css`, and `/themes/*`
  - Theme options: `win98` (default), `modern`, `No Theme`
  - Light/Dark mode independent from active theme
  - Desktop taskbar controls + mobile top controls for theme/mode switching
  - Config page and card deck preview
  - Drag-and-drop card ordering
  - Card add/remove with animation completion handling
  - Room password option
  - Room interface with voting area, participants, and admin controls
- Username persistence through `localStorage`

## Project Layout

- `src/main.go`: app bootstrap
- `src/config/`: environment configuration
- `src/server/`: Gin engine setup
- `src/routes/`: page/api route registration
- `src/handlers/`: HTTP handlers (pages + API + SSE)
- `src/state/`: in-memory room manager, sanitization, persistence
- `src/middleware/`: static cache headers middleware
- `src/models/`: template page data models
- `src/templates/`: HTML templates (`index.html`, `room.html`)
- `static/css/main.css`: shared component primitives
- `static/css/layout.css`: grids/flex/positioning/responsive layout
- `static/css/themes/`: drop-in theme files
- `static/js/ui-controls.js`: global theme + mode engine
- `static/js/`: page logic (`config.js`, `room.js`)

## Environment Variables

- `HOST`: server host/interface to bind (default all interfaces, equivalent to `0.0.0.0`)
- `PORT`: server port (default `8002`)
- `DATA_PATH`: directory for room JSON files (default `./data`)
- `MAX_ACTIVITY_LOG_ENTRIES`: max stored activity log entries per room (default `400`)
- `ADMIN_LOG_BROADCAST_LIMIT`: max recent admin log entries sent in SSE payloads (default `200`)
- `STALE_ROOM_CLEANUP_INTERVAL`: cleanup ticker interval for stale rooms as Go duration (default `5m`)
- `STALE_ROOM_TTL`: delete empty rooms when last activity is older than this Go duration (default `30m`)

## Run Locally

```bash
go mod tidy
go run ./src
```

Open `http://localhost:8002`.

To bind explicitly:

```bash
HOST=localhost PORT=8002 go run ./src
HOST=0.0.0.0 PORT=8002 go run ./src
```

State tuning example:

```bash
MAX_ACTIVITY_LOG_ENTRIES=600 \
ADMIN_LOG_BROADCAST_LIMIT=300 \
STALE_ROOM_CLEANUP_INTERVAL=2m \
STALE_ROOM_TTL=45m \
go run ./src
```

## Docker

Build:

```bash
docker build -t scrum-solitare .
```

Run:

```bash
docker run --rm -p 8002:8002 -e DATA_PATH=/app/data scrum-solitare
```

## Real-Time Flow (SSE)

- Client joins room via `POST /api/rooms/:roomID/join`
- Client subscribes to `GET /api/rooms/:roomID/events?participantId=...`
- Server broadcasts sanitized room state updates on critical mutations:
  - room creation
  - join/leave
  - vote cast
  - reveal
  - reset
