autokanban/.github/copilot-instructions.md
2025-11-20 11:13:09 +01:00

164 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copilot Instructions for AI Coding Agents
## Project Overview
AutoKanban is a FastAPI web app for managing a physical kanban workflow with a 58mm Arduino thermal printer. Users submit tasks via web UI, admins approve and print them to physical cards. Designed for Raspberry Pi deployment but tested on macOS.
## Architecture & Data Flow
```
User submits task → Task (pending) → Admin approves → Task (approved) → Admin prints → Task (printed) → Physical kanban card
```
### Core Components
- **`app/main.py`** (270 lines): Monolithic FastAPI app containing all routes, business logic, session management, and card rendering. All state managed in-memory with JSON persistence.
- **`app/models.py`**: Single Pydantic model `Task` with factory method `Task.create()` that generates UUID.
- **`app/printer.py`**: Minimal printer wrapper (currently unused in main.py - printer logic is duplicated in `/print` route).
- **`app/templates/`**: Jinja2 HTML templates with German localization and inline CSS/JS.
- **`app/static/fonts/`**: Custom fonts (BauPro, HealTheWeb) + Font Awesome 7.1.0 OTFs for semantic icons.
### State Management Pattern
- **Persistence**: Simple JSON file (`data/tasks.json`) loaded into in-memory list on startup. Call `save_tasks()` after every mutation.
- **Sessions**: Starlette `SessionMiddleware` stores admin auth state and flash messages (`login_result`, `print_result`, `preview_image`) in cookies.
- **Admin auth**: Password-only (no username), checked against `.env` variable. Session flag `admin: True/False`.
### Dual-Mode Printing Architecture
**Key insight**: App has two print modes controlled by `DEBUG_PRINT_TO_IMAGE` flag in `main.py`:
- `True` (default for testing): Generates PNG previews using Pillow with custom fonts, semantic icons, and card layout to `out/` directory.
- `False` (production): Prints to ESC/POS thermal printer via serial (`/dev/ttyUSB0`, 19200 baud).
**Why this matters**: When modifying print logic, update BOTH branches in the `/print/{task_id}` route (lines 142-244).
### Semantic Icon System
`KEYWORD_ICONS` list in `main.py` maps German/English keywords to Font Awesome unicode codepoints:
- Pattern: `(['keyword1', 'keyword2'], '\uf0f4')`
- Matching: Case-insensitive substring search in task content
- Default icon: `\uf328` (fa-sticky-note)
- Add new mappings by extending this list - requires knowing FA unicode values.
## Developer Workflows
### Running the App
**Preferred method** (handles venv automatically):
```bash
python start_app.py # Launches uvicorn on 0.0.0.0:8000 with --reload
```
**Manual method**:
```bash
source .venv/bin/activate
uvicorn app.main:app --reload
```
### First-Time Setup
1. Create `.env` file with `ADMIN_PASSWORD=yourpassword`
2. Ensure `data/` directory exists (create if missing - .gitignored)
3. Install system fonts or update font paths in `main.py` (lines 29-31)
4. For real printing: Set `DEBUG_PRINT_TO_IMAGE = False` and configure serial device
### Testing Print Without Hardware
1. Keep `DEBUG_PRINT_TO_IMAGE = True`
2. Submit task → approve → print
3. Check `out/task_{uuid}.png` for rendered card
4. Preview images shown in web UI after printing
### Debugging Font Issues
Font loading uses fallback chain (lines 129-135):
```python
load_font(path, size, fallback=None, font_label="descriptive_name")
```
- Logs errors but gracefully falls back to default font
- Font errors appended to `font_error_msgs[]` and rendered on card preview
## Project Conventions
### Code Organization
- **Monolithic by design**: All logic in `main.py` for simplicity. Don't split unless file exceeds 500 lines.
- **No database**: JSON file persistence is intentional. Don't add SQLite/Postgres without discussion.
- **German-first**: UI text, card labels, and comments use German. Keep this convention.
### Security Patterns
- **Never commit**: `.env`, `data/tasks.json`, `out/*.png` (all in `.gitignore`)
- **Session secret**: Hardcoded as `"CHANGE_THIS_SECRET"` (line 18) - should be env var in production
- **Admin password**: Must be set in `.env` or app will crash on login attempt
### Font Asset Management
- Custom fonts in `app/static/fonts/` (committed to repo)
- Font Awesome 7.1.0 desktop OTFs (committed) - use Solid 900 weight for card icons
- Paths defined as constants at top of `main.py` - update these if fonts move
- Required fonts: `FONT_BOLD`, `FONT_REGULAR`, `FA_FONT`
### Task Status Lifecycle
Tasks have exactly 3 states: `pending``approved``printed`
- Users can only submit (creates `pending`)
- Admins can approve (`pending``approved`)
- Anyone can print `approved` tasks
- Admins can re-print `printed` tasks
## Integration Points
### Thermal Printer (ESC/POS)
- Library: `python-escpos` v3.1
- Connection: Serial over USB (`/dev/ttyUSB0` on Linux, `/dev/tty.usbserial-*` on macOS)
- Baudrate: 19200 (standard for Arduino thermal printers)
- See `WIRING.md` for Raspberry Pi GPIO wiring diagram
- Permissions: User must be in `dialout` group on Linux
### Font Awesome Integration
- Version: 7.1.0 Free (Solid weight)
- Format: OTF desktop fonts (not web fonts)
- Icon mapping: Manual unicode lookup required for new icons
- Path: `app/static/fonts/fontawesome-free-7.1.0-desktop/otfs/Font Awesome 7 Free-Solid-900.otf`
## Critical Code Sections
### Card Rendering Logic (lines 142-239)
Complex Pillow-based layout with:
- Dynamic text wrapping based on pixel width (not character count)
- Vertical centering calculation using `getbbox()` for text height
- Icon positioning in lower-right corner
- Border and padding calculations for 354×236px card
**Common pitfalls**:
- Font methods (`getlength()`, `getbbox()`) may fail if font is None - wrap in try/except
- Text wrapping happens twice: word-based via `textwrap`, then pixel-based
- Changing card dimensions requires recalculating all spacing
### Task Persistence (lines 65-70)
Simple load/save pattern - no locking or concurrency control:
```python
tasks: List[Task] = load_tasks() # On startup
save_tasks() # After every mutation
```
**Risk**: Race conditions if multiple requests mutate simultaneously. Not handled - single-user/low-traffic assumption.
## Platform-Specific Notes
### macOS Development
- Printer device likely `/dev/tty.usbserial-*` (check `ls /dev/tty.*`)
- Use `DEBUG_PRINT_TO_IMAGE = True` for testing without hardware
- Font paths may need adjustment (DejaVu fonts not standard on macOS)
### Raspberry Pi Deployment
- Enable UART/serial interface via `raspi-config`
- Add user to `dialout` group: `sudo usermod -a -G dialout $USER`
- Default device `/dev/ttyUSB0` should work for USB-serial printers
- See `WIRING.md` for GPIO hardware serial wiring (pins 8/10)
## When Making Changes
### Adding New Routes
- Follow existing pattern: FastAPI route → mutate `tasks` list → call `save_tasks()` → redirect with session flash message
- Admin-only routes: Check `request.session.get("admin")` first
### Modifying Card Layout
- Update constants: `CARD_WIDTH_PX`, `CARD_HEIGHT_PX` (lines 25-26)
- Test with `DEBUG_PRINT_TO_IMAGE = True` before printing to hardware
- Remember to update BOTH debug and production print branches
### Adding Icon Keywords
- Extend `KEYWORD_ICONS` list (lines 33-58)
- Use Font Awesome unicode lookup: https://fontawesome.com/v7/icons
- Format: `(['keyword'], '\ufXXX')` where XXX is FA codepoint
---
_Last updated: 2025-11-20_