Skip to content

Print jobs for print agents (server-side queue) - #1627

Draft
francisrath wants to merge 12 commits into
Part-DB:masterfrom
francisrath:feat/print-agent-jobs
Draft

francisrath wants to merge 12 commits into
Part-DB:masterfrom
francisrath:feat/print-agent-jobs

Conversation

@francisrath

@francisrath francisrath commented Oct 29, 2026 •

Copy link
Copy Markdown

Draft, not ready to merge. This hasn't been tested enough yet: one developer, one Brother QL, the Docker dev setup with SQLite (the migration was also run up and down on MySQL 8 and PostgreSQL 14). I'm opening it to get your feedback on the approach before polishing it.

Part of #1625; the second of three alternative PRs. It includes #1626. The commits new here start at "feat(agents): agent and agent job entities".

With #1626 the browser has to run on the same computer as the agent. This PR lets Part-DB keep the jobs instead: the agent connects outbound to Part-DB and fetches them. Printing then works from any device, phones included, and through NAT, with the agent on a PC or a Raspberry Pi next to the printer.

What it adds

  • Entities Agent and AgentJob, plus a migration for MySQL, PostgreSQL and SQLite.
    • An agent belongs to the user whose API token registered it.
    • A job is {type: "print", printer, payload: {profile_id, element_type, element_ids}} with a status.
    • There is no printer-specific schema: printers are whatever the agent reports.
  • A small JSON API under /<locale>/agent-api/v1, documented in docs/usage/labels.md:
    • POST agents/<uuid>/heartbeat: the agent registers and reports its printers.
    • GET agents/<uuid>/jobs
    • POST jobs/<id>/claim: atomic; returns 409 if the job was taken.
    • POST jobs/<id>/result
    • Only API tokens are accepted, and a read-only token is enough. The user needs the existing "create labels" and "access API" permissions; there are no new permissions. Users only see their own agents and jobs.
  • Print buttons send jobs to the agent:
    • The label generator gets a "Print on " split button.
    • The label menus get a one-click printer icon for profiles with a default printer.
    • The parts tables get "Print labels" bulk actions.
    • The Print button that hands labels to a local print agent #1626 local handoff stays available as "This computer".
  • A default printer per label profile, a free-text printer id with suggestions from the user's agents.
  • The agents page (Tools → Print agent) lists agents, their printers and recent jobs, with send again, cancel and remove.

Part-DB never re-queues a job by itself. A job claimed but never reported shows as "unknown" after 10 minutes, and the user can send it again. Finished jobs are deleted after 30 days.

Screenshots

The Print button in the label dialog, with the printer picker:
pr2-dialog

The menu icon that sends a label straight to the profile's default printer:
pr2-menu

The agents page (Tools → Print agent):
pr2-agents

Decisions you may want differently

  • A plain JSON controller, not API Platform resources. The API is small and agent-specific; it moves easily if you prefer API Platform.
  • The API sits under the locale prefix, like the KiCad API.
  • No settings toggle. Nothing changes until a user registers an agent.

Tests

  • New tests: AgentApiControllerTest, LabelControllerTest (many new cases), PartsTableActionHandlerTest, tests/Entity/AgentSystem/AgentJobTest.php.
  • PHPStan (level 5), lint:twig and doctrine:schema:validate pass.
  • Tested by hand against the Docker dev setup with pdb-print: the menu icon, the dialog, the agent offline and then back, and "Send again".
  • The parts-table bulk action was not clicked through in a browser.

🤖 Generated with Claude Code

francisrath and others added 12 commits October 28, 2026 21:47
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds a Tools entry for the print agent page and documents the agent contract.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bulk lot action and hand-typed ids can contain spaces, ';' or empty entries,
which agents don't have to accept. Also: lowercase pairing key, popup without
opener, per-profile labels on the menu icons, and the docs now say which bytes
form the HMAC key and how agents should check ts, replays and src.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agents register with an API token of their owner and identify themselves by a
UUID, so renewing the token keeps them. Jobs are never re-queued automatically.
Label profiles get an optional default printer id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agents send a heartbeat with their printers, list their pending jobs, claim one
atomically and report the result. Only API tokens are accepted, and agents only
see their owner's jobs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The label dialog offers the user's agent printers (default printer of the
profile first), the label menu icon prints on the profile's default printer, and
the parts table gets "print labels" actions. Without agent printers the buttons
keep handing labels to the browser's local agent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The print agent page lists your agents with their printers and recent jobs, with
"send again", cancel and remove. Label profiles get a default printer field that
suggests the printer ids your agents report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- reject heartbeats over 64 KiB, and require API access for agents
- the lot print action falls back to the dialog for parts without lots
- cancelling a job is atomic against an agent claiming it
- "send again" refuses printers the agent no longer reports
- redirects after printing refuse control characters
- label menus look up the user's printers once per request
- the agents page shows the reported model, media and status

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant