Skip to content

feat(api,ui): cart + bulk-print across integrations #27

@strausmann

Description

@strausmann

Implements ADR 0013 — cart + bulk-print part.

Backend

  • POST /api/print/{printer_id}/batch with body:
    {
      "items": [
        {"integration": "snipeit", "lookup_id": "ASSET-12345", "layout_id": "<uuid>", "quantity": 3},
        {"integration": "grocy",   "lookup_id": "42",          "layout_id": "<uuid>", "quantity": 1}
      ]
    }
  • Returns single job_id; the job is a multi-page raster stream (Brother native: 0Ch between pages, 1Ah after last)
  • Each item is rendered once and the resulting page is repeated quantity times in the stream
  • Validates that every item's layout matches the printer's tape width — rejects 422 if mixed
  • Layout compatibility: must match printer-model filter if set on the layout
  • quantity defaults to 1 if omitted; valid range 1-99

Frontend

  • Cart state persisted in localStorage (key lph.cart), schema:
    {
      "version": 1,
      "items": [
        {"id": "ulid", "integration": "snipeit", "lookup_id": "...", "layout_id": "...",
         "quantity": 3, "title_snapshot": "...", "thumbnail_url": "...", "added_at": "..."}
      ],
      "updated_at": "..."
    }
  • Cart icon top-right (printer + badge), badge counter = sum of all quantity values
  • Cart icon visible from every view (sticky in app shell)
  • "Add to cart" button on the item detail view
  • Cart screen: items grouped by integration; per item: thumbnail, title, ID, layout dropdown, tape (auto from layout), quantity stepper (− / +) plus direct number input, remove button
  • Cart total summary: total label count, estimated tape consumption per tape size, target-printer breakdown
  • "Print all" → confirmation modal showing the batch breakdown (printer × tape × N items) → submits one batch per (printer, tape_mm) group
  • "Clear cart" secondary button (with confirmation)
  • Empty state with link back to browse mode

Acceptance

  • Cart survives page reload (localStorage)
  • Quantity stepper enforces 1-99 range
  • Cart icon badge updates immediately on add/remove/qty-change
  • Multi-tape cart shows correct grouping in the confirmation modal
  • Single-group cart submits exactly one job
  • Layout-mismatch rejected at API level (422 with clear message)
  • Print job total page count = sum of all quantities (verified in tests)

Out of scope (separate issue if requested)

  • Server-side cart sessions for cross-device persistence (Option D in ADR 0013)
  • "Save cart for later" / named carts

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiREST API + SSE endpointsarea:queuePrint queue + job lifecyclearea:uiUser interface, HTMX componentspriority:mediumNormal prioritytype:featureNew feature or enhancement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions