Ion-HomeLab 1.0.0 — full rebuild as a faithful port #1

Merged
domuk merged 2 commits from dev into main 2026-08-16 22:39:31 +01:00
Owner

Full rebuild of Ion-HomeLab as a faithful port of the reference tool, replacing the thin subset that failed review.

Built on the existing module framework — manifest, Dockerfile, install-from-Forgejo flow — which was always the part that worked. What changed is the app inside the container.

Server

  • 27-table schema; identity tables deliberately absent since the core owns identity
  • 26 declared permission keys, registered with the core on install
  • server-side enforcement on every route, asserted by a test that walks the router stack. The reference gated in the frontend: requirePerm appeared on 47 of ~181 routes, so most endpoints were open to anyone who knew a URL
  • all four connectors lifted faithfully rather than reinvented — Hawser/Docker, Proxmox (raw https for its self-signed cert), UniFi (dual auth probe with the winner cached), Ion-Monitor (pull plus token-authenticated push)
  • 159 routes generated through a CRUD factory, so a route cannot be added without a guard
  • seeds 602 device types, 8 manufacturers, 7 brand logos and 3 faceplates

Client

  • React on @ion-os/ui, rendering the shared OS Shell with its own tab row
  • defines no colours, radii or fonts of its own, so it matches the OS and follows theme switches
  • rack visualiser with the reference geometry: 1U = 53px, 19in = 580px, 10in = 305px, a 10in faceplate letterboxed at 53%, bottom-up U numbering, drag-drop with overlap rejection and width compatibility filtering
  • network map with the provider tier at the top, orthogonal link routing, arrowheads by link type, a midpoint link editor and stackable non-modal floating panels

Deliberate departures — all fixes, not redesigns

# Change Why
1 Server-side permission enforcement The reference's model left most endpoints unprotected
2 One unified devices / device_types pair The reference kept legacy duplicates alive alongside the real ones
3 Map coordinates in one table, one batched endpoint The reference scattered them across four places
4 U_HEIGHT standardised to 53px The reference used 44 in one file and 53 in another; 53 is correct (44.45mm x 1.2px/mm)
5 Identity and self-update removed The core owns both
6 Floorplan hotspot editing fixed The reference passed literal empty arrays for the pickers, so editing a hotspot showed empty dropdowns
7 Floorplan drawing fixed A dedicated draw layer means an existing hotspot no longer blocks a new one
8 Hotspot drag-to-reposition implemented The reference showed cursor:move but never built it
9 Device Types card alignment fixed Types with no manufacturer misaligned

Verification

  • 45/45 tests pass plus a staged smoke check that validates each layer independently
  • Client builds clean via Vite
  • Server boots standalone: health 200, client and assets served, 401 without identity
  • Container runs healthy: 602 types seeded, client + icons + uploads all serving, identity enforced
  • Two bugs caught during verification and fixed: the connector poller held the event loop open on import so tests hung, and /services/all was being shadowed by the CRUD router's GET /:id so the union view 404'd

Not verified

Installing through the core, and anything touching real infrastructure — no connector agents are configured and none of your hosts were contacted.

Ships empty

No locations, rooms, racks, devices, agents, providers or floorplans. Only the catalogue is seeded.

Full rebuild of Ion-HomeLab as a faithful port of the reference tool, replacing the thin subset that failed review. Built on the existing module framework — manifest, Dockerfile, install-from-Forgejo flow — which was always the part that worked. What changed is the app inside the container. ## Server - 27-table schema; identity tables deliberately absent since the core owns identity - 26 declared permission keys, registered with the core on install - **server-side enforcement on every route**, asserted by a test that walks the router stack. The reference gated in the frontend: `requirePerm` appeared on 47 of ~181 routes, so most endpoints were open to anyone who knew a URL - all four connectors lifted faithfully rather than reinvented — Hawser/Docker, Proxmox (raw `https` for its self-signed cert), UniFi (dual auth probe with the winner cached), Ion-Monitor (pull plus token-authenticated push) - 159 routes generated through a CRUD factory, so a route cannot be added without a guard - seeds 602 device types, 8 manufacturers, 7 brand logos and 3 faceplates ## Client - React on `@ion-os/ui`, rendering the shared OS Shell with its own tab row - defines no colours, radii or fonts of its own, so it matches the OS and follows theme switches - rack visualiser with the reference geometry: 1U = 53px, 19in = 580px, 10in = 305px, a 10in faceplate letterboxed at 53%, bottom-up U numbering, drag-drop with overlap rejection and width compatibility filtering - network map with the provider tier at the top, orthogonal link routing, arrowheads by link type, a midpoint link editor and stackable non-modal floating panels ## Deliberate departures — all fixes, not redesigns | # | Change | Why | |---|---|---| | 1 | Server-side permission enforcement | The reference's model left most endpoints unprotected | | 2 | One unified `devices` / `device_types` pair | The reference kept legacy duplicates alive alongside the real ones | | 3 | Map coordinates in one table, one batched endpoint | The reference scattered them across four places | | 4 | `U_HEIGHT` standardised to 53px | The reference used 44 in one file and 53 in another; 53 is correct (44.45mm x 1.2px/mm) | | 5 | Identity and self-update removed | The core owns both | | 6 | Floorplan hotspot editing fixed | The reference passed literal empty arrays for the pickers, so editing a hotspot showed empty dropdowns | | 7 | Floorplan drawing fixed | A dedicated draw layer means an existing hotspot no longer blocks a new one | | 8 | Hotspot drag-to-reposition implemented | The reference showed `cursor:move` but never built it | | 9 | Device Types card alignment fixed | Types with no manufacturer misaligned | ## Verification - **45/45 tests pass** plus a staged smoke check that validates each layer independently - Client builds clean via Vite - Server boots standalone: health 200, client and assets served, 401 without identity - **Container runs healthy**: 602 types seeded, client + icons + uploads all serving, identity enforced - Two bugs caught during verification and fixed: the connector poller held the event loop open on import so tests hung, and `/services/all` was being shadowed by the CRUD router's `GET /:id` so the union view 404'd ## Not verified Installing through the core, and anything touching real infrastructure — no connector agents are configured and none of your hosts were contacted. ## Ships empty No locations, rooms, racks, devices, agents, providers or floorplans. Only the catalogue is seeded.
Replaces the thin subset that failed review with the full app, built on the
existing module framework (manifest, Dockerfile, install-from-Forgejo flow) which
was the part that always worked.

Server
- 27-table schema; identity tables deliberately absent (Ion-OS core owns identity)
- 26 declared permission keys, registered with core on install
- server-side enforcement on EVERY route, asserted by test (the reference gated in
  the frontend: requirePerm on 47 of ~181 routes, so most endpoints were open)
- all four connectors lifted faithfully, not reinvented: Hawser/Docker, Proxmox
  (raw https for its self-signed cert), UniFi (dual auth probe), Ion-Monitor
  (pull + token-authenticated push)
- 159 routes via a CRUD factory so a route cannot be added without a guard
- seeds 602 device types + 8 manufacturers + brand logos + 3 faceplates

Client
- React on @ion-os/ui, rendering the shared OS Shell with its own tab row
- defines no colours/radii/fonts of its own, so it matches the OS and follows
  theme switches
- rack visualiser with the reference geometry (1U=53px, 19in=580px, 10in=305px,
  10in faceplate letterboxed at 53%), bottom-up U numbering, drag-drop with
  overlap rejection and width compatibility
- network map with provider tier at top, orthogonal links, typed arrowheads,
  midpoint link editor, stackable non-modal floating panels

Deliberate departures from the reference (all fixes, not redesigns)
- one unified devices/device_types pair, dropping the legacy duplicates
- map coordinates normalised from four places into one table, one batched endpoint
- U_HEIGHT standardised to 53px (the reference used 44 in one file, 53 in another)
- identity and self-update removed; core owns both
- floorplan hotspot editing fixed: targets served from the API, so the pickers are
  no longer empty (the reference passed literal empty arrays)
- floorplan drawing fixed: a dedicated draw layer means an existing hotspot no
  longer blocks a new one
- hotspot drag-to-reposition implemented (the reference showed cursor:move but
  never built it)
- Device Types card alignment fixed for types with no manufacturer

Also fixed during verification: /services/all and /services/sources were being
shadowed by the CRUD router's GET /:id handler, so the union view 404'd.

Ships empty: no locations, devices, agents or floorplans. Only the catalogue is
seeded. Verified by 45 tests plus a staged smoke check.
Built and verified as a container before release:
- starts healthy, seeds 602 device types / 8 manufacturers / 3 faceplate links
- serves the built client, shipped icons and the uploads volume
- returns 401 without core identity

Image 392MB, release tarball 90MB. 0.1.0 kept in the manifest history but
superseded — it was the thin subset, not a faithful port.
domuk merged commit 4abca076e6 into main 2026-08-16 22:39:31 +01:00
domuk deleted branch dev 2026-08-16 22:39:32 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
domuk/Ion-HomeLab!1
No description provided.