# Claude Instructions for WLED Screen Controller Server

## Development Workflow

### Server Restart Policy

**IMPORTANT**: When making changes to server code (Python files in `src/wled_controller/`), you MUST restart the server if it's currently running to ensure the changes take effect.

**NOTE**: Auto-reload is currently disabled (`reload=False` in `main.py`) due to watchfiles causing an infinite reload loop. Changes to server code will NOT be automatically picked up - manual server restart is required.

#### When to restart:
- After modifying API routes (`api/routes.py`, `api/schemas.py`)
- After updating core logic (`core/*.py`)
- After changing configuration (`config.py`)
- After modifying utilities (`utils/*.py`)
- After updating data models or database schemas

#### How to check if server is running:
```bash
# Look for running Python processes with wled_controller
ps aux | grep wled_controller
# Or check for processes listening on port 8080
netstat -an | grep 8080
```

#### How to restart:
1. **Find the task ID** of the running server (look for background bash tasks in conversation)
2. **Stop the server** using TaskStop with the task ID
3. **Check for port conflicts** (port 8080 may still be in use):
   ```bash
   netstat -ano | findstr :8080
   ```
   If a process is still using port 8080, kill it:
   ```bash
   powershell -Command "Stop-Process -Id <PID> -Force"
   ```
4. **Start a new server instance** in the background:
   ```bash
   cd server && python -m wled_controller.main
   ```
   Use `run_in_background: true` parameter in Bash tool
5. **Wait 3 seconds** for server to initialize:
   ```bash
   sleep 3
   ```
6. **Verify startup** by reading the output file:
   - Look for "Uvicorn running on http://0.0.0.0:8080"
   - Check for any errors in stderr
   - Verify "Application startup complete" message

**Common Issues:**
- **Port 8080 in use**: Old process didn't terminate cleanly - kill it manually
- **Module import errors**: Check that all Python files are syntactically correct
- **Permission errors**: Ensure file permissions allow Python to execute

#### Files that DON'T require restart:
- Static files (`static/*.html`, `static/*.css`, `static/*.js`) - but you **MUST rebuild the bundle** after changes: `cd server && npm run build`
- Locale files (`static/locales/*.json`) - loaded by frontend
- Documentation files (`*.md`)
- Configuration files in `config/` if server supports hot-reload (check implementation)

### Git Commit and Push Policy

**CRITICAL**: NEVER commit OR push code changes without explicit user approval.

#### Rules

- You MUST NOT create commits without explicit user instruction
- You MUST NOT push commits unless explicitly instructed by the user
- Wait for the user to review changes and ask you to commit
- If the user says "commit", create a commit but DO NOT push
- If the user says "commit and push", you may push after committing
- Always wait for explicit permission before any commit or push operation

#### Workflow

1. Make changes to code
2. **STOP and WAIT** - inform the user of changes and wait for instruction
3. Only create commit when user explicitly requests it (e.g., "commit", "create a commit")
4. **STOP and WAIT** - do not push
5. Only push when user explicitly requests it (e.g., "push", "commit and push", "push to remote")

### Testing Changes

After restarting the server with new code:
1. Test the modified endpoints/functionality
2. Check browser console for any JavaScript errors
3. Verify API responses match updated schemas
4. Test with different locales if i18n was modified

## Project Structure Notes

- `src/wled_controller/main.py` - FastAPI application entry point
- `src/wled_controller/api/` - REST API endpoints and schemas
- `src/wled_controller/core/` - Core business logic (screen capture, WLED client, processing)
- `src/wled_controller/utils/` - Utility functions (logging, monitor detection)
- `src/wled_controller/static/` - Frontend files (HTML, CSS, JS, locales)
- `config/` - Configuration files (YAML)
- `data/` - Runtime data (devices.json, persistence)

## Common Tasks

### Adding a new API endpoint:
1. Add route to `api/routes.py`
2. Define request/response schemas in `api/schemas.py`
3. **Restart the server**
4. Test the endpoint via `/docs` (Swagger UI)

### Adding a new field to existing API:
1. Update Pydantic schema in `api/schemas.py`
2. Update corresponding dataclass (if applicable)
3. Update backend logic to populate the field
4. **Restart the server**
5. Update frontend to display the new field

### Modifying display/monitor detection:
1. Update functions in `utils/monitor_names.py` or `core/screen_capture.py`
2. **Restart the server**
3. Test with `GET /api/v1/config/displays`

### Modifying server login:
1. Update the logic.
2. **Restart the server**

### Adding translations:
1. Add keys to `static/locales/en.json` and `static/locales/ru.json`
2. Add `data-i18n` attributes to HTML elements in `static/index.html`
3. Use `t('key')` function in `static/app.js` for dynamic content
4. No server restart needed (frontend only)

## Frontend UI Patterns

### Entity Cards

All entity cards (devices, targets, CSS sources, streams, scenes, automations, etc.) **must support clone functionality**. Clone buttons use the `ICON_CLONE` (📋) icon in `.card-actions`.

**Clone pattern**: Clone must open the entity's add/create modal with fields prefilled from the cloned item. It must **never** silently create a duplicate — the user should review and confirm.

Implementation:

1. Export a `cloneMyEntity(id)` function that fetches (or finds in cache) the entity data
2. Call the add/create modal function, passing the entity data as `cloneData`
3. In the modal opener, detect clone mode (no ID + cloneData present) and prefill all fields
4. Append `' (Copy)'` to the name
5. Set the modal title to the "add" variant (not "edit")
6. The save action creates a new entity (POST), not an update (PUT)

```javascript
export async function cloneMyEntity(id) {
    const entity = myCache.data.find(e => e.id === id);
    if (!entity) return;
    showMyEditor(null, entity);  // null id = create mode, entity = cloneData
}
```

Register the clone function in `app.js` window exports so inline `onclick` handlers can call it.

### Modal Dialogs

**IMPORTANT**: All modal dialogs must follow these standards for consistent UX:

#### Backdrop Click Behavior
All modals MUST close when the user clicks outside the dialog (on the backdrop). Implement this by adding a click handler that checks if the clicked element is the modal backdrop itself:

```javascript
// Show modal
const modal = document.getElementById('my-modal');
modal.style.display = 'flex';

// Add backdrop click handler to close modal
modal.onclick = function(event) {
    if (event.target === modal) {
        closeMyModal();
    }
};
```

**Where to add**: In every function that shows a modal (e.g., `showAddTemplateModal()`, `editTemplate()`, `showTestTemplateModal()`).

#### Close Button Requirement
Each modal dialog that has a "Cancel" button MUST also have a cross (×) close button at the top-right corner of the dialog. This provides users with multiple intuitive ways to dismiss the dialog:

1. Click the backdrop (outside the dialog)
2. Click the × button (top-right corner)
3. Click the Cancel button (bottom of dialog)
4. Press Escape key (if implemented)

**HTML Structure**:
```html
<div class="modal-content">
    <button class="close-btn" onclick="closeMyModal()">&times;</button>
    <h2>Dialog Title</h2>
    <!-- dialog content -->
    <div class="modal-actions">
        <button onclick="closeMyModal()">Cancel</button>
        <button onclick="submitAction()">Submit</button>
    </div>
</div>
```

**CSS Requirements**:
- Close button should be positioned absolutely at top-right
- Should be easily clickable (min 24px × 24px hit area)
- Should have clear hover state

## Authentication

Server uses API key authentication. Keys are configured in:
- `config/default_config.yaml` under `auth.api_keys`
- Or via environment variables: `WLED_AUTH__API_KEYS`

For development, ensure at least one API key is configured or the server won't start.
