Make the app distributable to other GE Aerospace sites (one self-hosted
instance per site, ADR-004). GE values remain the shipped defaults; every
site-specific behavior is now a Setting an admin can change in the UI.
Settings-driven site config:
- Branding: site/QR/badge logos, favicon, primary color (upload endpoints
mirror the map-blueprint pattern; new Settings > Branding section).
- ServiceNow: search/incident/change URL templates ({ticket}), ticket
prefixes, enable toggle. Defaults point at the current
geaerospaceqa.service-now.com global search. Disabled = plain-text tickets.
- Employee-id regex (employeeid_pattern), printer hostname template,
QR label targets (qr_target_printer / qr_target_usb, blank = asset page,
else URL template with placeholders), usb_label_style (barcode|qr).
- West Jefferson floor-plan PNGs removed from the tree; generic placeholder
ships as the map default and sites upload their own blueprint.
Security closeout:
- dashboarddefaults writes now require admin.
- Collector: generic error messages (no str(exc) leak); API key accepted
via X-API-Key header only (BREAKING: querystring api_key removed).
- IP-based login rate limiting (AUTH_RATELIMIT_* knobs) atop account lockout.
- Setting.set() creation race fixed (IntegrityError retry).
Release engineering and docs:
- __version__ 0.5.0 (distinct from __contract_version__, ADR-007),
CHANGELOG.md, Gitea Actions CI config, frontend version aligned.
- One wizard-first install story across README/DEPLOY; new CONFIG.md,
UPGRADE.md, BACKUP-RESTORE.md; CLAUDE.md and ROADMAP de-staled.
- Dockerfile multi-stage build now bundles the frontend; compose binds
MySQL to 127.0.0.1; stale database/schema.sql and one-off SQL removed.
Debt and fixes:
- .query.get() -> db.session.get() sweep; datetime.utcnow() removed
(naive-UTC via timezone-aware now); users.py on authz decorators.
- Fixed 4 stale tests (slides feed shape, shopfloor splitperemployee,
plugin contract purity) and the USB label page field mapping (both usb
modes emit the cmmc shape: device_id/device_desc).
- Health endpoint reports the real version.
248 tests pass; naming/style check green; frontend builds; fresh-DB
flask db upgrade + seeds verified; QR targets verified by decoding
rendered codes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.6 KiB
Collector integration (PC auto-update)
How the shopfloor PC fleet pushes inventory into shopdb-flask, replacing the
classic ASP api.asp?action=updateCompleteAsset path.
Endpoint
POST /api/collector/computers
Auth: API key header X-API-Key: <key>, resolved as COLLECTOR_API_KEY_COMPUTERS
then the shared COLLECTOR_API_KEY (ADR-006). Idempotent upsert keyed on
hostname.
Breaking change: the API key must be sent in the
X-API-Keyheader. The old?api_key=<key>querystring fallback has been removed, on every collector endpoint (/api/collector/<plugin>,/pc,/apps,/heartbeat,/bulk,/status). Querystring keys leak into access logs and proxy history. Update any caller still passingapi_keyin the URL to use the header instead.
Payload (project naming convention: lowercase concatenated)
| Field | Meaning | Flask target |
|---|---|---|
hostname (required) |
identity | Computer.hostname |
machinenumber |
machine number | Asset.assetnumber (skips 9999 placeholder, falls back to hostname) |
pctype |
imaging pc-type | Computer.computertypeid via the configurable mapping |
pcsubtype |
finer class | accepted, not yet stored (warning) |
serialnumber |
BIOS serial | Asset.serialnumber |
loggedinuser |
current user | Computer.loggedinuser |
lastboottime |
ISO datetime | Computer.lastboottime |
lastcheckin |
ISO datetime | accepted (heartbeat) |
ipaddress |
primary IP | primary Communication |
vendorname |
manufacturer | Computer.vendorid (created if missing) |
modelnumber |
model | Computer.modelnumberid (created if missing) |
osname |
OS caption | Computer.osid (looked up; warned if unknown) |
installedsoftware |
[{name, version}] |
ComputerInstalledApp (known apps only) |
Response: {status, action: created|updated, assetid, identityvalue, warnings[]}.
Source of truth on the PC (current method, may change)
The data already exists at image time and at runtime:
- machine number: registry
HKLM\SOFTWARE\[WOW6432Node\]GE Aircraft Engines\Dnc\General\MachineNoFIRST (authoritative post Update-MachineNumber; ignore the9999placeholder), thenC:\Enrollment\machine-number.txtas fallback. This is exactly what GE-Enforce.ps1 already does. - pc-type / pc-subtype:
C:\Enrollment\pc-type.txt/pc-subtype.txt(thegea-shopfloor-*taxonomy). - serial / vendor / model / os / user / boot: live WMI on the PC.
GE-Enforce currently writes a status JSON to the SFLD share rather than POSTing. Whatever transport is used (a relay reading those status files, or a direct POST later), map its field names to the table above.
pc-type mapping (configurable)
pctype (e.g. gea-shopfloor-cmm) is mapped to a flask Computer Type through
pctypemap_<pxetype> settings (Settings > System > "Collector PC Type Mapping").
Defaults live in plugins/computers/pctypemap.py and are seeded on plugin
install; edit per site in the UI. Unmapped pc-types are recorded as a warning,
not an error.
Classic api.asp field mapping (for migrating the PowerShell scripts)
Classic updateCompleteAsset form field |
Collector field |
|---|---|
hostname |
hostname |
machineNo |
machinenumber |
pcType |
pctype |
serialNumber |
serialnumber |
loggedInUser |
loggedinuser |
lastBootUpTime / lastBootTime |
lastboottime |
manufacturer |
vendorname |
model |
modelnumber |
osVersion |
osname |
installedApps |
installedsoftware |
Not carried over (no current home): warranty fields, DNC config, multi-NIC detail beyond the primary IP, VNC/WinRM flags.