89 Commits
Author SHA1 Message Date
grabowski 58a0a2efaf Make Devices and Components grids fill widescreens
Deploy to LXC / deploy (push) Successful in 30s
Both list pages were capped at max-w-6xl and 3 columns, wasting most
of the horizontal space on wide monitors. Drop the width cap
(w-full) and step the card grid up to 4 columns at xl and 6 at 2xl.
2026-07-01 13:30:27 +07:00
grabowski 48c5eaeb40 Store LCSC number per part; use Key Attributes as part name
Deploy to LXC / deploy (push) Successful in 36s
Adds a nullable lcsc_number column to parts so each part records its
LCSC code for reordering -- surfaced as an "LCSC #" field on the
add/edit forms (autofilled by the lookup) and as a click-through link
to the LCSC product page on the detail view.

The autofilled Name now comes from LCSC's human-readable "Key
Attributes" summary (e.g. "RES 10kohm +/-1% 100mW 0603") scraped from
the product page's SSR data, falling back to the manufacturer name if
that scrape returns nothing. Also normalizes lowercase LCSC codes to
uppercase so "c25804" resolves instead of dead-ending on a 404.
2026-07-01 13:01:05 +07:00
grabowski f45adceef0 Bound deploy SSH step to 5m so a hung session fails fast
Deploy to LXC / deploy (push) Successful in 35s
A leftover child process from npm ci/build can keep the SSH
session's file descriptors open even after the remote script
exits, leaving the Action step hanging indefinitely with no
useful signal -- the actual deploy work (build, restart, health
check) normally finishes in well under a minute.
2026-07-01 11:51:59 +07:00
grabowski 193673a9ce Fix flaky deploy health check: poll instead of fixed 2s sleep
Deploy to LXC / deploy (push) Has been cancelled
The service can take longer than 2s to finish starting after
restart (DB pool init, etc), so systemctl is-active would
occasionally still report "activating" at the fixed check point --
CI marked the run failed even though the app came up moments later
and was actually fine. Poll for up to 15s instead, and dump service
status on a real failure so debugging doesn't require SSH access.
2026-07-01 11:44:36 +07:00
grabowski 01107c414e Close mutating-action auth bypass; add LCSC part-number autofill
Deploy to LXC / deploy (push) Failing after 13m2s
Form actions and API endpoints under (app) previously relied only on
the layout load's redirect, which SvelteKit never runs before POST
actions/+server.ts handlers -- an unauthenticated request could reach
any mutating action directly. Gate it centrally in hooks.server.ts
instead of patching ~20 files individually.

Also adds a part-number lookup box on Add/Edit Part: paste an LCSC
code (e.g. C25804) and category/value/voltage/tolerance/mounting/
package auto-fill from LCSC's product data. Digikey is wired as a
dispatcher branch, inactive until DIGIKEY_CLIENT_ID/SECRET are set.
2026-07-01 11:23:22 +07:00
grabowskiandClaude Sonnet 4.6 dd2440db9f Fix value parser (Hz vs Henry), accept uF/uH, redirect to parts list after create
Deploy to LXC / deploy (push) Failing after 13m21s
- Drop /i flag: m (milli) vs M (mega) are now case-sensitive
- Put Hz before H in unit alternation so kHz isn't parsed as kH (kiloHenry)
- u already accepted as micro alongside µ; unit suffix optional (100u, 10k work)
- After adding a part, redirect to /parts overview instead of detail page

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-29 16:58:05 +07:00
grabowskiandClaude Sonnet 4.6 4eed83e4dd Add SI value sorting to parts: parse Ohms/Farads/Henrys/Hz numerically
Deploy to LXC / deploy (push) Failing after 14m27s
- New value_numeric column (double precision) stores parsed base-SI value
- parseValueNumeric() handles SI prefixes (p/n/µ/m/k/M/G) for F, H, Ω, Hz
- Computed on save in new/edit actions
- List page sortable by value_numeric (sorts within category, nulls last)
- Sort toggle added to filter bar

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-29 16:51:58 +07:00
grabowskiandClaude Sonnet 4.6 dc9217f3b6 Add Parts section: consumable stock inventory (caps, resistors, etc.)
Deploy to LXC / deploy (push) Failing after 13m44s
- New parts table with category, MPN, value, voltage, tolerance, power, mounting (THT/SMT), package, quantity, location
- /parts list (table view, category + mounting filters, colour-coded stock)
- /parts/new and /parts/[id]/edit with dynamic fields per category
- /parts/[id] detail with ± stock adjustment
- Sidebar nav entry and count badge
- Drizzle migration generated (run db:push to apply)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-29 16:32:21 +07:00
grabowskiandClaude Opus 4.7 ba32984a52 Add NFC tag support: write tag from device page, scan page for lookup
Deploy to LXC / deploy (push) Successful in 24s
Tags carry a URL record (https://host/d/{uuid}) plus a text record with the
raw UUID, so iOS scan-to-open works natively and the UUID stays recoverable
if the domain ever changes. Short-link routes /d/{id} and /i/{id} keep tag
payloads compact and decouple them from canonical paths. Write flow detects
Web NFC support and degrades gracefully (Android Chrome only) with a clear
fallback message. Each successful write is logged in a new device_tags
table; the device page surfaces "NFC tag written X ago".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 10:15:22 +07:00
grabowskiandClaude Opus 4.7 da27ae5541 Add device autocomplete to todo forms: type name or paste ID
Deploy to LXC / deploy (push) Successful in 21s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 16:11:06 +07:00
grabowskiandClaude Opus 4.7 8ab4673059 Add device-edit dropdown and jump-to-device button on todos list
Deploy to LXC / deploy (push) Successful in 24s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 15:35:53 +07:00
grabowskiandClaude Opus 4.6 03e23cf0c0 Add image upload to Markdown editor: paste, drag-drop, toolbar button
Deploy to LXC / deploy (push) Successful in 22s
- /api/upload-image endpoint saves images and returns URL
- Paste images from clipboard directly into the editor
- Drag and drop images onto the editor
- Toolbar image button opens file picker for manual upload
- Uploaded images inserted as ![alt](url) Markdown at cursor position

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:15:16 +07:00
grabowskiandClaude Opus 4.6 bc73595018 Add WYSIWYG Markdown editor (EasyMDE) to wiki pages
Deploy to LXC / deploy (push) Successful in 21s
Reusable MarkdownEditor component using EasyMDE:
- Toolbar: bold, italic, headings, quotes, lists, links, images,
  tables, code blocks, preview, side-by-side, fullscreen
- Dark mode support with custom CSS overrides
- Value syncs via bind:value for form submission
- Applied to both wiki new and edit pages
- Replaces the plain textarea + manual preview toggle

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:03:37 +07:00
grabowskiandClaude Opus 4.6 f937394b5e Add live tag input with chips, autocomplete, and suggestions
Deploy to LXC / deploy (push) Successful in 19s
Reusable TagInput component:
- Tags appear as blue chips instantly on comma/Enter press
- Remove tags by clicking X on the chip or Backspace when empty
- Autocomplete dropdown filters existing tags as you type
- All existing tags shown as clickable suggestions below
- Hidden input submits comma-separated value
- Applied to wiki new and edit pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:55:30 +07:00
grabowskiandClaude Opus 4.6 9a73c60d10 Fix deploy: git checkout before pull, use npm ci
Deploy to LXC / deploy (push) Successful in 19s
Prevents package-lock.json conflicts by resetting local changes
before pulling. Uses npm ci (clean install from lockfile) instead
of npm ci --production=false.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:45:48 +07:00
grabowskiandClaude Opus 4.6 4322383ed8 Add Wiki feature with Markdown, categories, tags, and search
Deploy to LXC / deploy (push) Failing after 4s
- wiki_categories, wiki_pages, wiki_tags, wiki_page_tags tables
- /wiki overview with category-grouped pages, tag sidebar, search
- /wiki/new create page with Markdown editor and live preview
- /wiki/[slug] view page with rendered Markdown, tags, edit/delete
- /wiki/[slug]/edit with pre-populated editor
- Tag input with existing tag suggestions (click to add)
- Category management (add/delete) in sidebar
- Tailwind Typography plugin for prose styling
- marked package for Markdown rendering
- Sidebar nav item with book icon

Run db:push on server to create wiki tables.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:42:34 +07:00
grabowskiandClaude Opus 4.6 6252041631 Fix NetBird login: set Secure cookie flag from actual origin, not forwarded proto
Deploy to LXC / deploy (push) Successful in 19s
Caddy sets X-Forwarded-Proto: https on all routes, making SvelteKit
think the request is HTTPS. The session cookie got the Secure flag,
but the browser on http://100.81.174.129 won't send Secure cookies
over plain HTTP. Now checks the actual Origin header to determine
if the connection is truly HTTPS.

Tor works because .onion is treated as a secure context by Tor Browser.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:38:20 +07:00
grabowskiandClaude Opus 4.6 0ceee55f9b Replace SvelteKit CSRF with custom multi-origin check
Deploy to LXC / deploy (push) Successful in 19s
SvelteKit's built-in CSRF only allows one origin, breaking access via
NetBird/Yggdrasil/Tor IPs. Now:
- Disabled checkOrigin in svelte.config.js
- Custom CSRF in hooks.server.ts checks Origin against ALLOWED_ORIGINS
- ALLOWED_ORIGINS env var: comma-separated list of trusted origins
- Caddy no longer needs to rewrite Host/Origin headers
- Each access method (public domain, NetBird IP, Yggdrasil, Tor onion)
  just needs its URL added to ALLOWED_ORIGINS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:23:02 +07:00
grabowskiandClaude Opus 4.6 dbc140c1f9 Fix CSRF 403: override Origin header in Caddy proxy snippet
Deploy to LXC / deploy (push) Successful in 18s
SvelteKit checks the browser's Origin header, not just Host or
X-Forwarded-Proto. Rewrite Origin to https://collection.newedge.house
so CSRF passes on all non-public routes (NetBird, Yggdrasil, Tor).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:18:56 +07:00
grabowskiandClaude Opus 4.6 d41ff1112d Fix Caddy proxy: hardcode X-Forwarded-Proto to https on all routes
Deploy to LXC / deploy (push) Successful in 18s
SvelteKit expects ORIGIN=https://... so all routes must send
X-Forwarded-Proto: https regardless of actual connection scheme.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:15:02 +07:00
grabowskiandClaude Opus 4.6 392747e639 Update Caddy guide: upstream TLS, NetBird, Tor, Yggdrasil
Deploy to LXC / deploy (push) Successful in 19s
Rewritten for the actual architecture: separate upstream Caddy handles
TLS for public domain, LXC Caddy only does HTTP. Added NetBird
interface binding, explicit per-interface blocks, upstream Caddy
config snippet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:08:28 +07:00
grabowskiandClaude Opus 4.6 e6c213f35c Add Caddy reverse proxy guide for internal, Tor, and Yggdrasil access
Deploy to LXC / deploy (push) Successful in 20s
Caddyfile config with shared proxy snippet that sets Host header for
CSRF compatibility. Handles:
- Public domain with auto HTTPS (Let's Encrypt)
- LAN/internal on port 80
- Tor hidden service via localhost:8880
- Yggdrasil IPv6 on port 80

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:02:01 +07:00
grabowskiandClaude Opus 4.6 5a0d6f150a Label: more space between details and barcode row (1mm → 2.5mm)
Deploy to LXC / deploy (push) Successful in 19s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:23:36 +07:00
grabowskiandClaude Opus 4.6 342d6f0c19 Label: add | separator between brand and model
Deploy to LXC / deploy (push) Successful in 19s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:20:38 +07:00
grabowskiandClaude Opus 4.6 e7638d5268 Label: voltage|Hz separator, barcode left of ID
Deploy to LXC / deploy (push) Successful in 19s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:18:14 +07:00
grabowskiandClaude Opus 4.6 3d590ff685 Label layout: barcode next to ID, bigger detail text, more spacing
Deploy to LXC / deploy (push) Successful in 19s
- ID and barcode on same row (flex horizontal, ID left, barcode right)
- 1mm gap between title and details section
- Detail text bumped to 6-6.5pt (from 5-5.5pt)
- Details grouped in their own block for consistent spacing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:13:47 +07:00
grabowskiandClaude Opus 4.6 a0e32e679e Label: large ID below barcode (9pt, same as title), left-align text
Deploy to LXC / deploy (push) Successful in 19s
- Barcode rendered without embedded text (includetext: false)
- ID rendered as separate HTML text at 9pt bold with letter-spacing
- All label text left-aligned instead of centred
- Barcode height reduced to 5mm to fit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:57:51 +07:00
grabowskiandClaude Opus 4.6 2f1675af1d Fix 2-page label: reset @page margin to 0, shrink barcode to fit
Deploy to LXC / deploy (push) Successful in 19s
The custom @page margins conflicted with browser minimum margins,
causing overflow. Now @page margin is 0, barcode height 8mm→6mm,
scale 3→2, text size 12→10 so content fits within 29mm even with
browser minimum margins selected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:52:01 +07:00
grabowskiandClaude Opus 4.6 bb125396f2 Update label margins to match Brother QL-820NWB: 0/0/2mm/0.5mm
Deploy to LXC / deploy (push) Successful in 20s
Set @page margins to top:0 right:0.5mm bottom:0 left:2mm matching
the working configuration found for DK-11209 labels. Updated setup
hint text on all print pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:43:10 +07:00
grabowskiandClaude Opus 4.6 142b27301b Replace QR code with barcode on labels, centre all text
Deploy to LXC / deploy (push) Successful in 31s
All print labels (device, component, batch) now show centred text
with a Code 128 barcode at the bottom instead of a QR code on the
left. Layout uses vertical flex column for clean centring.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:38:49 +07:00
grabowskiandClaude Opus 4.6 e16c50d854 Add feature requests page with voting and status tracking
Deploy to LXC / deploy (push) Successful in 21s
- feature_requests table with title, description, status, votes, createdBy
- Submit new requests with title and description
- Upvote button sorted by most votes
- Status dropdown: open, planned, in-progress, done, declined
- Color-coded status badges
- Delete button per request
- Sidebar nav item with lightbulb icon

Run db:push on the server to create the new table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:03:56 +07:00
grabowskiandClaude Opus 4.6 f6f31341ea Add voltage/frequency to labels, switch to JetBrains Mono font
Deploy to LXC / deploy (push) Successful in 20s
- All print labels (device, component, batch) now use JetBrains Mono
- Device labels show voltage and frequency below serial number
- Batch print labels include voltage/frequency from server data
- Font loaded from Google Fonts on print pages only

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 18:07:11 +07:00
grabowskiandClaude Opus 4.6 510eb719eb Add batch print page for printing multiple device labels at once
Deploy to LXC / deploy (push) Successful in 20s
- /batch-print page with device table, checkboxes, search, category filter
- Select all / individual selection with highlighted rows
- "Print N Labels" button opens popup with all selected labels
- /print/batch renders one DK-11209 label per device with page breaks
- Auto-print on popup open, last label avoids trailing blank page
- Sidebar nav item added

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 18:02:13 +07:00
grabowskiandClaude Opus 4.6 c7f7be64c4 Switch label size to DK-11209 (29mm x 62mm)
Deploy to LXC / deploy (push) Successful in 19s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:54:18 +07:00
grabowskiandClaude Opus 4.6 ac0dd18d8f Replace barcode with QR code + large ID on printed labels
Deploy to LXC / deploy (push) Successful in 18s
- QR code on left encodes the short ID (not URL)
- Text centred on right: title, brand/model, serial, large bold ID
- ID displayed at 11pt bold with letter-spacing for readability
- Removed barcode dependency from print pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:40:58 +07:00
grabowskiandClaude Opus 4.6 941b41d3de Fix label fitting on single DK-22210 page
Deploy to LXC / deploy (push) Successful in 19s
- Reduced padding (1.5mm → 1mm), barcode height (7mm → 6mm)
- Tighter line heights, combined serial/voltage on one line
- Barcode text size 14 → 12 to reduce image height
- Vertical flex layout instead of horizontal (no QR = more space)
- Should now fit within 29mm height without overflow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:33:58 +07:00
grabowskiandClaude Opus 4.6 cad82119ca Increase barcode ID text size (8 → 14) for readability
Deploy to LXC / deploy (push) Successful in 20s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:30:46 +07:00
grabowskiandClaude Opus 4.6 64040f7391 Remove QR code from printed labels, keep barcode only
Deploy to LXC / deploy (push) Successful in 19s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:25:48 +07:00
grabowskiandClaude Opus 4.6 3a3781ba7a Show thumbnails on component list cards
Deploy to LXC / deploy (push) Successful in 30s
Component cards now display the first uploaded image as a thumbnail,
matching the device list card design. Falls back to a placeholder
icon when no image is uploaded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:04:18 +07:00
grabowskiandClaude Opus 4.6 2695de25a3 Add image lightbox: click any image to view full-screen
Deploy to LXC / deploy (push) Successful in 20s
Reusable ImageLightbox component with dark overlay, close on
click/Escape, zoom-in cursor on thumbnails. Applied to both
device and component detail pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:52:19 +07:00
grabowskiandClaude Opus 4.6 99371648be Add collapsible checklists on device detail, auto-collapse completed
Deploy to LXC / deploy (push) Successful in 19s
- Click chevron or checklist title to expand/collapse
- Completed checklists (100%) auto-collapse on page load
- Completed title shown in green with checkmark icon
- Progress bar and count always visible when collapsed
- Items and add-item form hidden when collapsed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:37:39 +07:00
grabowskiandClaude Opus 4.6 36f4d4b8d5 Redesign file uploads: drag-and-drop zones for images and documents
Deploy to LXC / deploy (push) Successful in 20s
New reusable components:
- ImageUpload.svelte: drag-and-drop / click / paste zone with file
  icon, preview of selected filename, caption field, 50MB limit
- DocumentUpload.svelte: same pattern for documents with description
  field instead of caption

Applied to both device and component detail pages, replacing the old
inline file input forms. Cleaner look matching modern upload UIs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:23:30 +07:00
grabowskiandClaude Opus 4.6 7429130630 Add open todo count badge to sidebar menu
Deploy to LXC / deploy (push) Successful in 30s
Shows number of non-done todos (todo + in_progress) next to the
Todos nav item. Hides when count is zero.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:07:27 +07:00
grabowskiandClaude Opus 4.6 1011e69031 Switch label size to DK-22210 (29mm x 70mm continuous)
Deploy to LXC / deploy (push) Successful in 19s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 15:43:31 +07:00
grabowskiandClaude Opus 4.6 29d2aa943c Add image uploads to components, fix sidebar count for disabled
Deploy to LXC / deploy (push) Successful in 19s
- Image upload/delete on component detail page (same pattern as devices)
- Images section with grid, hover-to-delete, 50MB client-side limit
- Sidebar component count now excludes disabled components by joining
  componentInstances with components and filtering disabled=false

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 15:31:56 +07:00
grabowskiandClaude Opus 4.6 9a59213da0 Add soft delete for components (disabled flag)
Deploy to LXC / deploy (push) Successful in 22s
- disabled boolean on components table (default false)
- Component list filters out disabled components
- Component detail returns 404 for disabled
- Delete button with confirmation on component detail page
- Installation form filters out instances of disabled components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:50:18 +07:00
grabowskiandClaude Opus 4.6 5c4595ed16 Restructure components into types + instances
Deploy to LXC / deploy (push) Successful in 29s
Components are now split into two concepts:
- Component (type definition): title, componentType, brand, partNumber,
  specs, notes, default condition/firmware/location
- Component Instance (individual physical unit): serialNumber, condition,
  firmwareVersion, notes, currentDeviceId, locationId

Key changes:
- New component_instances table with per-unit tracking
- Component list shows cards with total/installed/available counts
- Component detail page shows all instances with inline edit
- Add instances: bulk (quantity) or one at a time
- Each instance has install/remove/edit/delete actions
- Installation log now references instances, not components
- Device detail shows installed instances with instance numbers
- Dashboard and sidebar counts use instance totals
- Location pages show instances, not component types
- Labels show component type info (serial is per-instance)

IMPORTANT: Run db:push on the server after deploy to create the new
tables and columns. Existing component data will need manual migration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:41:06 +07:00
grabowskiandClaude Opus 4.6 bb8a96d281 Fix upload size limit: add BODY_SIZE_LIMIT env and error handling
Deploy to LXC / deploy (push) Successful in 21s
- Added BODY_SIZE_LIMIT=52428800 (50MB) to .env.example
- handleError in hooks catches body size exceeded and returns friendly message
- Client-side file size check on image upload input (alerts before submit)
- adapter-node uses BODY_SIZE_LIMIT env var (default was 512KB)

To fix: add BODY_SIZE_LIMIT=52428800 to .env on the server and restart.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:15:36 +07:00
grabowskiandClaude Opus 4.6 50689c46e5 Fix image upload 500 in production: use UPLOAD_DIR env for absolute path
Deploy to LXC / deploy (push) Successful in 20s
In production with adapter-node, the relative path 'static/uploads'
doesn't resolve correctly. Now uses UPLOAD_DIR env variable (absolute
path) for both saving and serving uploaded files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:08:00 +07:00
grabowskiandClaude Opus 4.6 6cd5f28bf7 Rename to My Collection, add favicon to sidebar and login
Deploy to LXC / deploy (push) Successful in 20s
- Replaced all 'B4L Repair' references with 'My Collection'
- Added favicon.png next to the title in the sidebar
- Added favicon.png on the login page above the title
- Updated all page <title> tags

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:30:08 +07:00
grabowskiandClaude Opus 4.6 57e1d3fcc7 Redesign checklists: grid overview + dedicated edit page
Deploy to LXC / deploy (push) Successful in 20s
- /checklists now shows templates in a responsive grid (cards with
  title, description, item count, last updated)
- Clicking a card opens /checklists/[id] dedicated edit page
- "New Template" creates and redirects to the edit page
- Edit page has: rename title/description, add/edit/delete/reorder
  items, delete template (redirects back to grid)
- Breadcrumb navigation back to grid

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:27:49 +07:00
grabowskiandClaude Opus 4.6 68abb3e734 Add checklist editing: rename, edit items, reorder with arrows
Deploy to LXC / deploy (push) Successful in 20s
Templates page (/checklists):
- Edit template name/description inline (pencil icon)
- Edit item text and unit inline (pencil icon on hover)
- Move items up/down with arrow buttons
- Reorder swaps sort order values in the database

Device checklists:
- Rename checklist title inline (pencil icon)
- Edit item text and unit inline (pencil icon on hover)
- Move items up/down with arrow buttons
- All item types (checkbox and input) support editing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 09:47:51 +07:00
grabowskiandClaude Opus 4.6 1dcc69482e Add server route to serve uploaded files in production
Deploy to LXC / deploy (push) Successful in 17s
adapter-node only serves pre-built static assets, not files uploaded
at runtime. Added /uploads/[...path] catch-all route that reads from
static/uploads/ with proper MIME types and cache headers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 17:18:21 +07:00
grabowskiandClaude Opus 4.6 642359fec9 Fix image uploads: accept more formats, convert to JPEG, show errors
Deploy to LXC / deploy (push) Successful in 18s
- Added HEIF, GIF, AVIF, BMP, TIFF to allowed image types
- All uploads converted to JPEG via sharp (fixes HEIC/HEIF from iPhones)
- Upload action wrapped in try/catch, errors shown in UI
- Error banner displayed above image section on failure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 17:16:02 +07:00
grabowskiandClaude Opus 4.6 0113803378 Add location detail page showing devices and components at that location
Deploy to LXC / deploy (push) Successful in 17s
- /locations/[id] shows all devices and stored components at a location
- Breadcrumb navigation with parent location
- Sub-location chips for navigating to children
- Location names are clickable links everywhere: location list page,
  device detail sidebar, component detail current location

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 17:10:25 +07:00
grabowskiandClaude Opus 4.6 9102ffd8b4 Show parent > child location on detail pages, add location move
Deploy to LXC / deploy (push) Successful in 18s
- Device/component detail pages show "Parent › Child" for locations
- Device list cards show full location path
- Location edit form now includes a Parent selector to move locations
  between parents or make them top-level
- Prevents setting a location as its own parent

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 17:07:08 +07:00
grabowskiandClaude Opus 4.6 948617a285 Add cascading location picker: select parent first, then child
Deploy to LXC / deploy (push) Successful in 19s
LocationPicker component shows parent locations first. Once a parent
is selected, a second dropdown appears with its children. If the
parent has no children, it's selected directly. Used in device
create/edit, component create/edit, and installation log forms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:59:49 +07:00
grabowskiandClaude Opus 4.6 63b57e8ac3 Add rename option for locations with inline edit
Deploy to LXC / deploy (push) Successful in 27s
Pencil icon on each location opens inline form to edit name and
description. Saves via rename action, cancel to discard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:52:13 +07:00
grabowskiandClaude Opus 4.6 5e4021bc60 Add settings page with password change
Deploy to LXC / deploy (push) Successful in 17s
Settings page shows account info and a change password form.
Validates current password, minimum 8 chars, confirmation match.
Added Settings link in sidebar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:45:46 +07:00
grabowskiandClaude Opus 4.6 0baf17897c Remove .claude from repo and add to .gitignore
Deploy to LXC / deploy (push) Successful in 18s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:44:05 +07:00
grabowskiandClaude Opus 4.6 c12f727734 Update deploy workflow for private repo with deploy keys
Deploy to LXC / deploy (push) Successful in 19s
Two SSH keys needed:
- DEPLOY_KEY: CI runner → LXC server (SSH access)
- REPO_DEPLOY_KEY: LXC server → Gitea repo (git pull access)

Workflow writes the repo deploy key to ~/.ssh on the server and
configures SSH to use it for git.b4l.co.th. Handles first deploy
(clone) and subsequent deploys (pull) automatically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:26:04 +07:00
grabowskiandClaude Opus 4.6 12a6e9ef0b Add Gitea Actions workflow for auto-deploy to LXC on push
Deploy to LXC / deploy (push) Failing after 6s
SSH-based deploy: git pull, npm ci, build, db:push, systemctl restart.
Secrets configured in Gitea repo settings (DEPLOY_HOST, DEPLOY_USER,
DEPLOY_KEY). Includes setup guide in docs/ci-deploy-setup.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:07:12 +07:00
grabowskiandClaude Opus 4.6 fe2217eff7 Make label ID text bigger (text-xs → text-sm font-medium)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:55:57 +07:00
grabowskiandClaude Opus 4.6 117646d2cb Add document uploads to components (PDFs, manuals, datasheets)
- component_documents table matching device_documents structure
- Upload/delete actions on component detail page
- Documents section in sidebar with file icon, filename, delete on hover
- Devices already had document support; components now match

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:03:43 +07:00
grabowskiandClaude Opus 4.6 d6b53d8ec8 Replace individual AC voltages with range options (100-120, 220-240, 100-240)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:59:30 +07:00
grabowskiandClaude Opus 4.6 cff1c2d82b Fix todo edit buttons: add type=button, switch to list view from kanban
Edit buttons were missing type="button" so they could trigger parent
form submissions. Kanban edit now switches to list view where the
inline edit form is rendered.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:08:22 +07:00
grabowskiandClaude Opus 4.6 fe54496d79 Add todo list with kanban board view
- todos table with title, description, status (todo/in_progress/done),
  priority (urgent/high/medium/low), optional device link, due date
- List view: sorted by priority, inline edit, click-to-advance status
  circle (empty → blue dot → green check), edit/delete actions
- Kanban board view: three columns, move buttons between statuses,
  priority badges, device links, due dates
- Toggle between List and Board views via URL param
- Optional link to a device for repair-related todos
- Sidebar nav item added

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:55:16 +07:00
grabowskiandClaude Opus 4.6 59371d0cbb Fix all svelte-check warnings: derived props, a11y labels, warning filter
- Sidebar navItems uses $derived() so badge counts stay reactive
- const destructures (c, d, cd) use $derived() to track prop changes
- Added aria-label to hamburger and add-item buttons
- Filter state_referenced_locally warnings in svelte.config.js — these
  are intentional one-shot initializers for mutable form inputs

Result: 0 errors, 0 warnings, 0 files with problems.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:45:11 +07:00
grabowskiandClaude Opus 4.6 eac11c3a24 Add Proxmox LXC deployment guide
Covers NixOS LXC (recommended, uses the flake module) and Debian/Ubuntu
LXC (traditional setup). Includes PostgreSQL setup, systemd service,
nginx reverse proxy, backup strategies, and update instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:30:52 +07:00
grabowskiandClaude Opus 4.6 d017101ae8 Add voltage and frequency to printed device labels
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:49:49 +07:00
grabowskiandClaude Opus 4.6 d17eed5bfc Fix extra blank page when printing single label
Removed page-break-after: always and reset html/body height to auto
so the print renderer doesn't generate a trailing empty page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:47:44 +07:00
grabowskiandClaude Opus 4.6 4e05910cd3 Move print labels to (print) layout group to fix blank output
The (app) layout's flex h-screen + overflow-hidden container was
clipping label content in the print renderer. Print routes now use
a dedicated (print) layout group with no sidebar/header/flex shell,
just the raw label HTML. Routes changed to /print/device/[id] and
/print/component/[id].

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:45:59 +07:00
grabowskiandClaude Opus 4.6 b33966b26e Fix empty label preview: use inline styles to avoid Tailwind reset conflicts
Moved all label styling to inline styles with explicit color: black and
background: white so dark mode and Tailwind resets can't hide content.
Print styles use :global() scoped selectors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:43:32 +07:00
grabowskiandClaude Opus 4.6 3fedc70503 Fix empty print labels: apply dimensions in all media not just screen
Label width/height was inside @media screen so print had no dimensions.
Moved to base CSS so labels render in both screen preview and print.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:41:15 +07:00
grabowskiandClaude Opus 4.6 7095b68169 Switch label printing to DK-1201 (29mm x 90.3mm) horizontal layout
QR code on the left, text and barcode on the right. Fits the pre-cut
DK-1201 address label format.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:36:43 +07:00
grabowskiandClaude Opus 4.6 45d93738d7 Add DK-22210 label printing with barcode and QR code
- Print page formatted for Brother DK-22210 (29mm continuous tape)
- Each label has: title, brand/model, serial, QR code, Code 128 barcode
- CSS @page sized to 29mm width with minimal margins
- Print button opens popup that auto-triggers print dialog
- Copies selector to print multiple labels at once
- Barcode encodes short ID (first 8 chars) scannable by the lookup endpoint
- Available on both device and component detail pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:26:53 +07:00
grabowskiandClaude Opus 4.6 8859f32b4f Add DC voltage options and USB/Battery to voltage list
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:11:47 +07:00
grabowskiandClaude Opus 4.6 3ceabf4e9e Change voltage to multiselect on device create and edit forms
Multiple voltages are stored as comma-separated string (e.g. "110V, 220V").
Edit form pre-selects existing values by parsing the stored string.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:10:04 +07:00
grabowskiandClaude Opus 4.6 adcc8df7cd Align checklist input fields to the right side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:06:47 +07:00
grabowskiandClaude Opus 4.6 722349738a Fix checklist input alignment: fixed-width label and unit columns
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:06:14 +07:00
grabowskiandClaude Opus 4.6 d40dc9b796 Fix checklist alignment and input completion tracking
- All items use a consistent grid layout (checkbox/indicator, content, delete)
- Input items show a green check indicator when a value is filled
- Saving a value auto-sets checked=true (clearing it sets checked=false)
- Progress bar and count now include input items with values as completed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:03:24 +07:00
grabowskiandClaude Opus 4.6 97f97f5571 Add text input type to checklist items for measurements
Checklist items can now be either 'checkbox' (tick/untick) or 'input'
(text value with optional unit). Useful for recording measurements
like RPM, wow & flutter, torque, voltage, dB levels, etc.

- itemType and unit fields on template_items and checklist_items
- Template page shows type selector and unit field when adding items
- Device checklist renders input items as labeled text fields with unit
- Save button persists measured values
- Import copies item types and units from templates

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:57:19 +07:00
grabowskiandClaude Opus 4.6 cceba73785 Fix checklist item add: form value cleared before submission
The bind:value + onsubmit pattern caused the input to be empty when
enhance submitted the form. Replaced with post-submission DOM reset
so the value is intact during submission.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:53:16 +07:00
grabowskiandClaude Opus 4.6 1351b77034 Add checklist templates with import into devices
- checklist_templates and template_items tables for reusable checklists
- /checklists page: create/edit/delete templates with ordered items
- "Import" button on device detail imports a template as a new checklist
  with all items copied (unchecked)
- Sidebar nav item for Checklists between Locations and Gallery

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:36:02 +07:00
grabowskiandClaude Opus 4.6 dbe82c1019 Add device checklists and retro Mac favicon
Checklists feature:
- device_checklists and checklist_items tables
- Create multiple named checklists per device
- Add/toggle/delete items with progress bar
- Checkbox UI with green check, strikethrough for completed items
- Delete checklist button with item count display

Also adds the classic Mac happy face as favicon.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:31:38 +07:00
grabowskiandClaude Opus 4.6 04ca0a8299 Add session-based authentication with login/logout
- Users and sessions tables (Argon2 password hashing, SHA-256 session tokens)
- Server hooks validate session cookie on every request
- (app) routes redirect to /login if not authenticated
- Login page with email/password, styled matching budget app
- Logout via POST form action (invalidates session)
- User display name and sign out button in header
- create-user CLI script: npm run create-user <email> <password> [name]
- 30-day sessions with auto-refresh after 15 days

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:21:06 +07:00
grabowskiandClaude Opus 4.6 cc4d8480cf Fix flake.nix: node 22, shebang indentation, databaseUrl default, assertion
- Upgrade to nodejs_22 (22.22.2) for better Vite 6 compatibility
- Fix wrapper script shebang broken by heredoc indentation
- Add preBuild step for svelte-kit sync
- Default databaseUrl to "" so environmentFile-only configs don't fail eval
- Add assertion ensuring either databaseUrl or environmentFile is set

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:13:22 +07:00
grabowskiandClaude Opus 4.6 28f8e3b7b2 Add NixOS flake with dev shell, package, and systemd module
Includes nix develop shell (node, pg, vips), buildNpmPackage derivation,
and a NixOS module for deploying as a systemd service with hardening,
dedicated user, and configurable secrets via environmentFile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:04:14 +07:00
grabowskiandClaude Opus 4.6 6f0e0ad6c6 Initial commit: buildfor_life_repair inventory system
SvelteKit + PostgreSQL app for tracking vintage computers, audio equipment,
components, and installation history. Features device/component CRUD, operation
logs, QR code labels, global search, image uploads, and dark mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 17:11:05 +07:00