Files
shopdb-flask/CHANGELOG.md
cproudlock 4fd110a33d
All checks were successful
CI / backend (push) Successful in 1m13s
CI / naming (push) Successful in 1s
CI / frontend (push) Successful in 7s
Wire relationship directionality and dualpath controls propagation
Symmetric relationship types (isdirectional flag, migration 7d19) show
one entry per peer on the relationships card - a Dualpath pair no
longer lists its partner twice - and directional types read naturally
instead of Outgoing/Incoming. Deleting a collapsed entry removes every
underlying direction row.

Propagation is now real (migration 7d20): relationship types declare
propagation-through pairs in relationshiptypepropagations (M:N,
replacing the never-consumed single column); creating a controls link
on either bay of a Dualpath pair auto-creates it on the partner,
mirrored across both endpoints because live data stores controls as
bay -> PC. flask relationships propagate backfills existing data (29
rows fanned out on the WJ dataset, idempotent).

This also completes the tree that commit 1d21bf0 accidentally split
(core/models/__init__ imported RelationshipTypePropagation ahead of the
file that defines it), returning CI to green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 06:07:36 -04:00

12 KiB

Changelog

All notable changes to shopdb-flask are recorded here.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. The product version (__version__) and the plugin-contract version (__contract_version__) are distinct series with independent bump rules; see ADR-007 and ADR-002.

Unreleased

Added

  • Relationship propagation, wired and data-driven: relationship types declare propagation-through pairs (relationshiptypepropagations M:N, replacing the never-consumed single column); creating a controls link on one Dualpath bay auto-creates it on the partner bay, and flask relationships propagate backfills existing data.

  • Employee photos, mode-aware: self-hosted directory employees support upload/replace/delete (admin), served publicly for kiosk cards; external directory mode passes the HR-supplied picture URL through read-only. One resolver feeds the shopfloor recognition/recert cards and the employee detail hero in either mode.

  • Vendor-model photo management. New admin-gated core endpoints POST /api/models/<modelid>/image (multipart file, png/jpg/jpeg/gif/webp/svg, one image per model, replace semantics) and DELETE /api/models/<modelid>/image, plus the public GET /api/models/image/<filename> serve route. Uploads land in instance/modelimages/ (survives upgrades, backed up with the rest of instance/) and set models.imageurl to the served URL; the manual Image URL field still accepts external URLs and the shipped /images/models/* assets (upload is additive). Delete only removes files we own under the instance dir. The Models settings page grows a thumbnail, Upload/Replace, and Remove controls in the edit modal. Asset hero images (e.g. the machine badge) read imageurl unchanged, so uploaded photos render with no consumer changes.

  • Application support teams with contacts, replacing the legacy supportteams/appowners pair. New core supportteamcontacts table (multiple named contacts per team, ordered by sortorder); supportteams keeps teamname (now unique) and teamurl (a ServiceNow group deep link) and sheds the single-owner appownerid FK. New core blueprint at /api/supportteams (team + nested contact CRUD, admin-gated; ?teamname exact-match lookup for import; delete a team 409s while any application still references it). Migration 7d18_supportteamcontacts migrates each legacy team's app owner into one contact. Application payloads now flatten supportteamname, teamurl, and the team's active contacts; a Support card on the application detail page and a new settings/supportteams management page render them.

  • Import mode: a complete, idempotent HTTP migration surface so a script or LLM can import the classic ASP shopdb through the API alone (no direct DB writes).

    • Contract surface (plugin contract bumped 0.7.0 -> 0.8.0, additive): new shopdb.api helpers apply_import_timestamps, import_mode_active, parse_import_datetime in shopdb/utils/import_mode.py. When the caller is an admin AND sends header X-Import-Mode: true, create/update endpoints accept optional createddate / modifieddate (ISO or legacy YYYY-MM-DD HH:MM:SS, naive-UTC) and preserve them instead of stamping now. Non-admin or missing header: the fields are ignored exactly as before. Wired into every timestamped import target: assets (all five type plugins), vendors, models, modeltypes, businessunits, locations, operating systems, applications, knowledge base, USB devices, and asset relationships.
    • Natural-key exact-match lookup filters for the documented lookup-then-upsert idempotency recipe: assetnumber on all five asset plugin list endpoints; vendor, modelnumber, modeltype, businessunit, locationname, osname/osversion, appname, knowledge base linkurl/shortdescription, warranty servicetag/vendor, and notification ticketnumber.
    • Backdated event history: in import mode the selfhosted USB checkout/checkin endpoints accept optional checkouttime / checkintime overrides so migrated usbcheckouts rows keep their real event times.
    • New operator manual docs/IMPORT-API.md grounded in the real prodscratch legacy schema: order of operations, a full table-by-table mapping, honest no-target list with dispositions, a worked idempotent Python importer, and row-count parity checks.

Fixed

  • Following a relationship link between two assets of the same type now loads the destination page instead of stale content (router-view keyed on path; query-only URL changes still avoid a remount).
  • Asset relationships card no longer lists a symmetric peer twice. Relationship types gain relationshiptypes.isdirectional (migration 7d19_relationshiptype_directional; seeded false for the connection-like types Dualpath, connectedto, Cluster Member, Serial Cable, Direct Ethernet, USB, WiFi, true for controls/Controlled By/Backup For/Master-Slave/partof/ defaultprinter). The card now collapses every stored direction row of a symmetric type into one direction-blind "Connected" entry per peer (deleting it removes all collapsed rows), while directional types drop the Outgoing/Incoming headers for inline Type -> peer / <- Type from peer phrasing. The type CRUD and the per-asset relationships endpoint carry isdirectional; the Relationship Types settings page gains a Directional toggle.

[0.6.0] - 2026-07-11

Added

  • measuringtools plugin (ADR-005): gage-lab instruments as Asset extensions with type lookup (color-coded), calibration tracking (derived overdue/due-soon/current status), calibration report, and full frontend. Built as the framework exemplar; docs/PLUGIN-GUIDE.md walks through its construction step by step as the plugin-system tutorial.
  • CSV export on the Warranty and Toner report pages; per-report filter controls (business unit, asset type, location, application, limit) on the inline core reports; report open-state is URL-backed and deep-linkable.
  • Per-plugin Alembic migration chains (ADR-008): every bundled plugin now carries its own chain with a stamp-only anchor; new plugin schema changes land in plugins/<name>/migrations/, never the core chain. Deploys run flask plugin upgrade-all after flask db upgrade.
  • Frontend plugin route gating (ADR-009): a disabled backend plugin's pages redirect to the dashboard; new public GET /api/plugins/enabled.
  • get_reports() plugin hook (plugin contract 0.5.0 -> 0.6.0): plugins contribute their own report cards; warranty and toner cards moved off the hardcoded frontend list.
  • Reports hub grouped by category with a search filter.
  • Configurable QR label targets: qr_target_printer / qr_target_usb settings (blank = the asset's own page, else a URL template with placeholders) and a usb_label_style barcode/QR toggle for USB mini-labels. New Settings > Printing & Labels section.
  • Site palette theming: optional brand_primary_dark_color, brand_accent_color, brand_sidebar_color settings applied at bootstrap.
  • Collector integration guide rewrite: header-only auth reference and a paste-ready GE-Enforce PowerShell reporting function.

Changed

  • Equipment -> machines rename (backend). The equipment plugin is now the machines plugin: /api/equipment -> /api/machines, tables equipment/equipmenttypes -> machines/machinetypes (columns equipmentid -> machineid, equipmenttypeid -> machinetypeid, equipmenttype -> machinetype), permissions equipment.* -> machines.*, assettype value equipment -> machine. The legacy core machinetypes lookup (it types the vendor MODELS catalog, not machine instances) is renamed to modeltypes (/api/machinetypes -> /api/modeltypes, models.machinetypeid -> models.modeltypeid) to free the name. Data flips migrate assettypes, auditlog entitytype, settings keys (identifier_*_equipment_enabled -> identifier_*_machine_enabled, search_equipment_enabled -> search_machine_enabled), and permission rows in place; plugins.json registry entries carry over automatically. Upgrade: run flask db upgrade then flask plugin upgrade-all.

  • Inter (variable) replaces Roboto, bundled locally - no Google Fonts fetch, so air-gapped installs render correctly. Tables use tabular numerals.

  • ServiceNow defaults point at the current geaerospaceqa.service-now.com global search (search, incident, and change links).

Fixed

  • USB frontend remapped to the actual API shape (device_id / device_desc): device list, detail, form, label batch, and the employee profile's checked-out/history panels were all reading dead legacy fields.
  • External-mode GET /api/usb/checkouts/active now honors the badge filter.
  • Warranties list page no longer demands login (matches every other list page; reads were already public).
  • Removed the dead legacy Warranty Status report (always-zero buckets from a retired column); the warranty plugin's report is the real one.
  • Pruned dead usbApi client methods that had no backend routes.

0.5.0 - 2026-07-10

First release cut with a version, tag, changelog, and CI. Focused on letting other GE Aerospace sites stand up their own self-hosted instance (single-tenant per ADR-004).

Added

  • First-run setup wizard (/setup): creates the initial superadmin in-app, configures each plugin (create tables here vs connect your own database), uploads light/dark floor-map blueprints, and seeds starter reference data.
  • Self-hosted employee directory and USB plugins: in-app management plus CSV import, no external database required. Both ship default-disabled with an enable-time provisioning note.
  • Dell warranty plugin: real Dell provider, bulk warranty sync, add-warranty from asset pages, PC hero warranty badge, disk-cached Dell API token.
  • Custom fields, and a two-pane settings shell with tabbed, searchable System Settings and Settings index pages.
  • Dashboard defaults (visitor-IP to business-unit mapping) for kiosk displays; printer installer endpoint (data plus floor-map positions).
  • Global toast notifications replacing alert() calls.
  • Multi-stage Docker build that compiles the Vue frontend and ships frontend/dist, which Flask serves.
  • Documentation overhaul: new CONFIG, UPGRADE, and BACKUP-RESTORE guides; reconciled README, DEPLOY, CLAUDE, and ROADMAP.
  • ADR-007 (product versioning and releases), CHANGELOG, and best-effort Gitea Actions CI (backend tests, naming/style gate, frontend build).

Changed

  • Plugin contract (__contract_version__) settled at 0.5.0: full plugin import surface exposed via shopdb.api, dead search hook removed, and the dashboard-widgets hook wired to a real consumer.
  • Role-based access control now enforced on write routes, including admin-only guards on dashboard-defaults writes.
  • Branding, ServiceNow integration, employee-ID pattern, printer hostname template, and floor-plan blueprints are settings-driven and per-site configurable, with GE defaults preserved as shipped fallbacks (branding and floor-plan configurability landed in this release; some consumer wiring continues under Unreleased).

Security

  • Dashboard-defaults writes now require admin authorization instead of any authenticated user.
  • Collector error responses no longer leak exception detail; failures are logged server-side with generic client-facing messages.
  • Login rate limiting added (IP-based fixed window) on top of the existing account lockout.

BREAKING

  • Collector API key must now be sent in the X-API-Key header. The api-key-in-querystring fallback has been removed. Update any collector integration that passed the key as a query parameter. See docs/COLLECTOR-INTEGRATION.md.