- USBLabelBatch.vue: recolor controls/selection/cell borders to the app CSS
variables (was hardcoded #667eea/#28a745/#dc3545) and add
`print-color-adjust: exact` so barcodes print even with "Background graphics"
off. (Barcodes render as vector SVG, so no canvas->img change needed.)
- ADR-004: document the resolved migration strategy - single core Alembic chain
(`flask db upgrade`), bundled plugin schema folded into core (7c04), resolving
the Phase 7B per-plugin-chain conflict footgun. External plugins may still
ship their own chains.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
QR codes were drawn to live <canvas> elements, which print unreliably (often
blank in the printout). The print pages also used hardcoded off-brand colors
(#667eea indigo) instead of the app's palette.
- PrinterQRBatch.vue + PrinterQRSingle.vue: render each QR (with the GE
monogram composited in) to a data-URL <img> instead of a live <canvas>.
Images print every time.
- Add `print-color-adjust: exact` so the browser prints the QR images and
borders even when the user's "Background graphics" option is off.
- Cache the GE logo image once instead of reloading it per code.
- Recolor controls/buttons/selection/label borders to the app CSS variables
(--primary, --success, --danger, --bg-card, --text...), so the pages match
the scheme and adapt to dark mode. Printed labels stay black-on-white.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The identifier-flags composable fetched settings once and cached them in a
module singleton, so toggling an identifier in Settings (gauge/maintenance/FQDN
per asset type) did not take effect on already-open asset views until a full
page reload. Disabled identifiers kept showing.
- identifierSettings.js: extract applySetting/fetchFlags; export
reloadIdentifierFlags() and setIdentifierFlag(name, assettype, enabled) to
mutate the shared reactive state.
- SystemSettings.vue: push each successful matrix toggle into the shared state
via setIdentifierFlag so dependent views react immediately.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Optional asset identifiers (gauge lab reference, maintenance reference, FQDN)
were global per-identifier and only surfaced on equipment. Now they are
toggleable per asset type and rendered on every asset type.
- settings: replace 3 global identifier toggles with a per-type matrix. New
keys identifier_<name>_<assettype>_enabled (3 identifiers x 4 types).
IDENTIFIER_LABELS / IDENTIFIER_ASSETTYPES constants drive the seed (API seed
and CLI seed settings).
- composable: identifierSettings now exposes isEnabled(name, assettype),
per-type flag winning over the legacy global key, defaulting on.
- backend writes: computers, network, printers asset create + update now
accept gaugelabreference and maintenancereference (equipment already did).
Reads already flowed through Asset.to_dict.
- frontend: Settings page renders an identifier x asset-type toggle matrix.
Equipment, PC, printer, network forms and detail pages show gauge/maintenance
(and FQDN where applicable) gated by isEnabled(name, type).
Legacy global identifier_<name>_enabled keys are still honored as a fallback
for older installs. SystemSettings toggles upsert (create on 404) so a deploy
that has not re-seeded still works on first toggle.
144 tests pass, naming/style check green, frontend builds. Verified live:
matrix renders, PC form shows the fields, PUT persists gauge/maintenance on a
PC and reads back.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GET /api/plugins now lists all discovered plugins (enabled or not) with status;
PUT /api/plugins/<name> toggles enabled (persists to plugins.json). New
Settings > Plugins admin page with per-plugin toggles. Route changes apply on
next restart. Replaces CLI-only enable/disable for self-serve admin.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On a new PC, the PC Number (assetnumber) auto-fills from the serial number as
it is typed, but stops auto-filling once the user edits it manually. Edit mode
never auto-overwrites.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PCs are identified by hostname (the primary identifier) with serial as the
fallback; the assetnumber is seeded from hostname rather than a separate
"PC Number" field. PC list shows Hostname/Serial (Asset Tag column removed),
PC detail title leads with hostname.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New locationtypes lookup (LocationType model) seeded with section, cell,
subcell, operation, meetingroom, lab, office, storage, hallway,
networkcloset, building.
- locations gains locationtypeid + parentlocationid (self-FK) for the site
location tree. Migration 7c03; cli reference-data seeds the types.
- GET /api/locations/types; locations CRUD accepts type + parent; list/detail
return locationtypename + parentlocationname.
- Locations settings page: Type column + Type/Parent selectors in the modal.
Realizes the operation-as-Location model (operations are locations with
locationtypeid='operation').
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add applications.isrequired (model + migration 7c02 + create/update + form
checkbox). The software-compliance report compared required apps against
installs but no such flag existed, so it 500'd; now it works.
- Repair relationshiptypes rows with 0000-00-00 createddate/modifieddate
(partof/connectedto) to real timestamps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The asset/computer model is now the single source of truth. Remove the Machine
instance layer end to end:
- Delete models Machine, MachineStatus, PCType, MachineRelationship,
InstalledApp, PrinterData; keep MachineType (models.machinetypeid still
references it).
- Delete the /api/machines, /api/statuses, /api/pctypes blueprints and the
legacy /api/printers/legacy (PrinterData) blueprint.
- Drop the deprecated communications.machineid column and its FK.
- Migration 7c01 drops tables machines, machinestatuses, pctypes,
machinerelationships, installedapps, printerdata (idempotent).
- Fix remaining readers (applications install counts) to ComputerInstalledApp.
- Frontend: remove dead machinesApi/statusesApi/pctypesApi wrappers; repoint
the PC Types settings page at computer types.
143 tests pass; all asset/computer/dashboard/report/collector endpoints 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- applications.py installed-on + per-computer install/uninstall/update endpoints
now use Computer / ComputerInstalledApp instead of Machine / InstalledApp.
- ApplicationDetail "Installed On" list reads the computer shape.
- Drop the unused Machine/MachineType import from the assets map endpoint.
No active core endpoint uses the Machine model anymore (only the legacy
/api/machines blueprint and reference-data seeder remain).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add /api/assets/relationshiptypes (GET/POST) serving RelationshipType; point
relationshipTypesApi at it instead of the legacy /api/machines blueprint.
- Dashboard recent-devices widget reads assetsApi.list (asset shape) instead
of machinesApi.
No frontend code references machinesApi anymore.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Last form still reading /api/statuses (MachineStatus); repoint to
assetsApi.statuses so its status dropdown matches the rest of the app.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dedicated assets.gaugelabreference and assets.maintenancereference columns
(distinct from assetnumber), surfaced on equipment. Add global per-identifier
enable/disable settings (gauge/maintenance/FQDN) read via a shared composable
and toggled in System Settings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lock the position-resolution columns from ADR-001 in code so
resolve_asset_position's relationship walk activates.
Schema
- Asset.mapleft -> Asset.mapx, Asset.maptop -> Asset.mapy
- Location.mapx / Location.mapy added (fallback for priority 3 of the
ADR-001 resolution chain)
- AssetRelationship.label (free-text nuance per ADR-001)
- AssetRelationship.inheritsposition (bool, server_default true, controls
whether the resolved-position walk follows the edge)
- RelationshipType.propagatesthroughid (self-FK; sibling-propagation rail)
Seeds
- Three canonical ADR-001 relationship types created idempotently:
partof, controls, connectedto
- controls.propagatesthroughid wired to partof (partof + connectedto stay
null per ADR-001 table). Both via Alembic migration AND CLI seed command
so a fresh test fixture and a sister-site deploy both end up correct.
- Legacy connection types (Serial Cable, Direct Ethernet, USB, WiFi,
Dualpath) retained for backward compat with pre-1.0 relationship rows.
Resolver
- shopdb.api.resolve_asset_position now walks inheritsposition=true edges
of type partof (then controls), recursively, depth-capped at 3 with
visited-set cycle protection. Inactive edges + non-inheritable types
are skipped. Falls through to the existing location fallback when the
walk yields nothing.
Tests
- 11 new test_api_namespace cases cover: partof walk, controls-after-
partof ordering, connectedto skipped, inheritsposition=false skipped,
recursion, cycle break, depth-3 cap, self-beats-related, related-beats-
location, inactive-edge skip.
- 111 tests pass. Naming/style check green.
Migration
- migrations/versions/7a01_adr001_position_contract.py:
- alter_column renames on assets (no data loss)
- add_column on locations + relationshiptypes + assetrelationships
- idempotent seed of three ADR types + propagation FK wire-up
- downgrade reverses + best-effort deletion of seeded types that have
no FK refs
Backend rename (mapleft/maptop -> mapx/mapy)
- shopdb/core/api/assets.py
- plugins/{computers,equipment,network,printers}/api/...
- scripts/migration/migrate_assets.py
- Legacy Machine model + machines API + import_from_mysql.py UNCHANGED
(per ADR-001 Machine retires; not part of the asset contract)
Frontend rename
- frontend/src/components/ShopFloorMap.vue
- frontend/src/views/{MapEditor.vue, pcs/{PCDetail,PCForm}.vue,
printers/{PrinterDetail,PrinterForm}.vue,
machines/{MachineDetail,MachineForm}.vue,
network/NetworkDeviceForm.vue}
- Form field labels + v-model bindings + computed flags switched in
lockstep with the backend.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
System Settings:
- Add SystemSettings.vue with Zabbix integration, SMTP/email config, SAML SSO settings
- Add Setting model with key-value storage and typed values
- Add settings API with caching
Audit Logging:
- Add AuditLog model tracking user, IP, action, entity changes
- Add comprehensive audit logging to all CRUD operations:
- Machines, Computers, Equipment, Network devices, VLANs, Subnets
- Printers, USB devices (including checkout/checkin)
- Applications, Settings, Users/Roles
- Track old/new values for all field changes
- Mask sensitive values (passwords, tokens) in logs
User Management:
- Add UsersList.vue with full user CRUD
- Add Role management with granular permissions
- Add 41 predefined permissions across 10 categories
- Add users API with roles and permissions endpoints
Reports:
- Add TonerReport.vue for printer supply monitoring
Dark Mode Fixes:
- Fix map position section in PCForm, PrinterForm
- Fix alert-warning in KnowledgeBaseDetail
- All components now use CSS variables for theming
CLI Commands:
- Add flask seed permissions
- Add flask seed settings
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix equipment badge barcode not rendering (loading race condition)
- Fix printer QR code not rendering on initial load (same race condition)
- Add model image to equipment badge via imageurl from Model table
- Fix white-on-white machine number text on badge, tighten barcode spacing
- Add PaginationBar component used across all list pages
- Split monolithic router into per-plugin route modules
- Fix 25 GET API endpoints returning 401 (jwt_required -> optional=True)
- Align list page columns across Equipment, PCs, and Network pages
- Add print views: EquipmentBadge, PrinterQRSingle, PrinterQRBatch, USBLabelBatch
- Add PC Relationships report, migration docs, and CLAUDE.md project guide
- Various plugin model, API, and frontend refinements
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Search: refactor into modular helpers, add IP/hostname/notification/
vendor/model/type search, smart auto-redirects for exact matches,
ServiceNOW prefix detection, filter buttons with counts, share links
with highlight support, and dark mode badge colors.
Map: fix N+1 queries with eager loading (248->28 queries), switch to
canvas-rendered circleMarkers for better performance with 500+ assets.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add equipmentApi and computersApi to replace legacy machinesApi
- Add controller vendor/model fields to Equipment model and forms
- Fix map marker navigation to use plugin-specific IDs (equipmentid,
computerid, printerid, networkdeviceid) instead of assetid
- Fix search to use unified Asset table with correct plugin IDs
- Remove legacy printer search that used non-existent field names
- Enable optional JWT auth for detail endpoints (public read access)
- Clean up USB plugin models (remove unused checkout model)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New Plugins:
- USB plugin: Device checkout/checkin with employee lookup, checkout history
- Notifications plugin: Announcements with types, scheduling, shopfloor display
- Network plugin: Network device management with subnets and VLANs
- Equipment and Computers plugins: Asset type separation
Frontend:
- EmployeeSearch component: Reusable employee lookup with autocomplete
- USB views: List, detail, checkout/checkin modals
- Notifications views: List, form with recognition mode
- Network views: Device list, detail, form
- Calendar view with FullCalendar integration
- Shopfloor and TV dashboard views
- Reports index page
- Map editor for asset positioning
- Light/dark mode fixes for map tooltips
Backend:
- Employee search API with external lookup service
- Collector API for PowerShell data collection
- Reports API endpoints
- Slides API for TV dashboard
- Fixed AppVersion model (removed BaseModel inheritance)
- Added checkout_name column to usbcheckouts table
Styling:
- Unified detail page styles
- Improved pagination (page numbers instead of prev/next)
- Dark/light mode theme improvements
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Flask backend with Vue 3 frontend for shop floor machine management.
Includes database schema export for MySQL shopdb_flask database.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>