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

7.2 KiB
Raw Blame History

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):

python start_app.py  # Launches uvicorn on 0.0.0.0:8000 with --reload

Manual method:

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):

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: pendingapprovedprinted

  • Users can only submit (creates pending)
  • Admins can approve (pendingapproved)
  • 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:

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