homelabby/.planning/phases/04-usb-manager-label-printing/04-02-SUMMARY.md

6.5 KiB

phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
04-usb-manager-label-printing 02 labels
go
qrcode
image
label-printing
bitmap
phase provides
04-usb-manager-label-printing Phase context, label dimensions, printer interface design
phase provides
01-foundation internal/netbox/types.go Device and CustomFields structs
internal/labels package: RenderStandard (384x120) and RenderCable (384x180) bitmap renderers
QR code generation encoding http://mac-mini.mg:8080/hw/HW-XXXXX URLs
IsCableDevice() heuristic detection for cable records
LabelData and CableLabelData structs as public API for printer driver
04-03-printer-driver
04-05-intake-integration
added patterns
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
golang.org/x/image v0.39.0
Label renderers return image.Image — driver-agnostic; printer driver converts to bytes
HWID format validated (HW-\d{5}) before any qrcode.New() call (T-04-07 mitigation)
TDD: failing tests committed first, implementation makes them pass
created modified
internal/labels/renderer.go
internal/labels/renderer_test.go
internal/labels/cable.go
internal/labels/cable_test.go
go.mod
go.sum
DisableBorder=true (not DisableBorderPadding — that field doesn't exist in skip2/go-qrcode v0.0.0-20200617195104)
HWID format validated before qrcode.New() to mitigate T-04-07 DoS via malformed input
IsCableDevice uses name/notes heuristic only — real device_type detection deferred to Phase 5
Cable label is 180px tall (vs 120px standard) to fit 4 text lines
Label renderers: pure image.Image output, no USB/printer dependency — testable in isolation
HWID validation: regexp.MustCompile at package level, checked at render entry points
Text layout: TextOffsetX=112 (after QR block), y positions proportional to label height
LBL-01
LBL-02
LBL-03
15min 2026-04-10

Phase 04 Plan 02: QR Code + Label Rendering Summary

image.NRGBA label bitmaps at 203 DPI using skip2/go-qrcode — standard (384x120) and cable (384x180) templates with HWID-encoded QR codes and basicfont text

Performance

  • Duration: ~15 min
  • Started: 2026-04-10T06:30:00Z
  • Completed: 2026-04-10T06:45:55Z
  • Tasks: 2
  • Files modified: 6 (4 created, 2 modified)

Accomplishments

  • Standard label renderer: 384x120px NRGBA bitmap with QR code (left 96x96), HW ID, name, spec line
  • Cable label renderer: 384x180px bitmap with 4 text lines — HW ID, name, USB version/speed, wattage/test date
  • IsCableDevice() heuristic returns true when device Name or AINotes contains "cable" (case-insensitive)
  • HWID format validated before QR generation (T-04-07 mitigation — prevents DoS via malformed input)
  • All 10 tests pass across both renderers and the cable detection helper

Task Commits

Each task was committed atomically:

  1. Task 1: QR code generation + standard label renderer - 8cbd840 (feat)
  2. Task 2: Cable label renderer + IsCableDevice detection helper - 7800917 (feat)

Files Created/Modified

  • internal/labels/renderer.go — LabelData, RenderStandard(), drawText(), truncate(), HWID validation
  • internal/labels/renderer_test.go — 5 tests: dimensions, QR non-blank, URL encoding, empty name fallback, white background
  • internal/labels/cable.go — CableLabelData, RenderCable(), IsCableDevice()
  • internal/labels/cable_test.go — 5 tests: dimensions, full data, IsCableDevice true/false, empty test date
  • go.mod / go.sum — added github.com/skip2/go-qrcode and golang.org/x/image

Decisions Made

  • Used DisableBorder = true (not DisableBorderPadding — that field does not exist in the installed version of go-qrcode)
  • HWID validated via regexp.MustCompile("^HW-\\d{5}$") at render entry points per T-04-07 threat disposition (mitigate)
  • Cable detection kept as heuristic (name/notes contains "cable") — device_type-based detection is a Phase 5 concern
  • go.mod upgraded from go 1.23.0 to 1.25.0 automatically when golang.org/x/image@v0.39.0 required it

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] DisableBorderPadding field does not exist in go-qrcode

  • Found during: Task 1 (standard label renderer)
  • Issue: Plan code snippet used qr.DisableBorderPadding = true but the installed version of skip2/go-qrcode has DisableBorder bool not DisableBorderPadding
  • Fix: Changed to qr.DisableBorder = true (inspected package source)
  • Files modified: internal/labels/renderer.go, internal/labels/cable.go
  • Verification: All tests pass after fix
  • Committed in: 8cbd840 (Task 1 commit)

2. [Rule 2 - Missing Critical] Added HWID format validation (T-04-07)

  • Found during: Task 1 — threat model review
  • Issue: Threat register marked T-04-07 (DoS via malformed HWID to qrcode.New) as mitigate — no validation was in the plan's code snippet
  • Fix: Added hwIDPattern = regexp.MustCompile("^HW-\\d{5}$") and guard at top of both RenderStandard and RenderCable
  • Files modified: internal/labels/renderer.go, internal/labels/cable.go
  • Verification: Passing invalid HWIDs returns error rather than passing to qrcode.New
  • Committed in: 8cbd840, 7800917 (both task commits)

Total deviations: 2 auto-fixed (1 bug, 1 missing critical security mitigation) Impact on plan: Both fixes necessary for correctness and threat mitigation. No scope creep.

Issues Encountered

  • golang.org/x/image@v0.39.0 requires go 1.25+ — go get automatically upgraded go.mod from 1.23.0 to 1.25.0. This is acceptable for the project.

User Setup Required

None — no external service configuration required.

Next Phase Readiness

  • internal/labels package is complete and fully tested
  • Printer driver (04-03) can import internal/labels and call RenderStandard / RenderCable to get image.Image, then convert to bytes for the PRT Qutie
  • Intake integration (04-05) can use IsCableDevice() to route to the correct label template
  • No blockers

Self-Check: PASSED

  • internal/labels/renderer.go: FOUND
  • internal/labels/renderer_test.go: FOUND
  • internal/labels/cable.go: FOUND
  • internal/labels/cable_test.go: FOUND
  • Commit 8cbd840: FOUND
  • Commit 7800917: FOUND

Phase: 04-usb-manager-label-printing Completed: 2026-04-10