Skip to content

Latest commit

 

History

History
50 lines (32 loc) · 2.99 KB

File metadata and controls

50 lines (32 loc) · 2.99 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project

Printomat lets people submit text and images to be printed on a receipt printer. Three components: a FastAPI server that queues print requests, a client that connects via WebSocket and drives an ESC/POS receipt printer, and services that automatically generate and submit print jobs (weather forecasts, chess puzzles, etc.).

Commands

# Run server
uv run python -m server

# Run client (--no-printer for testing without hardware)
uv run python -m client

# Run a service (from repo root; each service is a separate process)
uv run python -m services.weather_service
uv run python -m services.chess_puzzle_service
uv run python -m services.echo_service

# Run a service with immediate print (skip waiting for scheduled time)
uv run python -m services.weather_service --print

# Database migrations (from server/)
uv run alembic upgrade head

Each component needs a config.toml copied from its config.example.toml before first run.

Architecture

UV workspace — root pyproject.toml declares three workspace members (server, client, services), each with its own pyproject.toml. Single uv.lock at root. Requires Python 3.13+.

Server (server/) — FastAPI app with SQLite (SQLAlchemy + Alembic). REST API for submissions (/submit), WebSocket for client connection. Rate limiting by IP, friendship tokens to bypass limits, service tokens for automated services. Interactive admin console (console.py).

Client (client/) — WebSocket client that receives jobs from the server and prints via python-escpos. Handles text rendering (custom fonts in client/font/) and image processing (Pillow for resizing/conversion, ESC/POS dithering for monochrome output).

Services (services/) — BaseService ABC in base.py provides the framework. Each service inherits it, implements loop() for its periodic task, and calls send_print_request() to POST to the server's /submit endpoint. Services are configured and enabled/disabled in services/config.toml. Entry point is ClassName.run_from_config() which handles arg parsing, config loading, and the asyncio event loop.

To add a new service: create services/foo_service.py, define FooService(BaseService), implement loop() and from_config(), call FooService.run_from_config() at module level, add a [services.foo] section to config.example.toml.

Key patterns

  • All services and the client are async (asyncio). Services use aiohttp for HTTP, client uses websockets.
  • Config is TOML-based (tomli for parsing). Each component reads its own config.toml relative to its package directory.
  • Service name is derived from class name: WeatherServiceweather, used to look up [services.weather] in config.
  • Images are transmitted as base64-encoded PNG strings.
  • Services run from the repo root (imports are relative to package, e.g. from config import ServiceConfig).