# Changelog All notable changes to shopdb-flask are recorded here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 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 - 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. ## [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//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`. [Unreleased]: https://gitea.proudtech.net/ge-aerospace/shopdb-flask/compare/v0.5.0...HEAD [0.5.0]: https://gitea.proudtech.net/ge-aerospace/shopdb-flask/releases/tag/v0.5.0