Files
shopdb-flask/docs/COLLECTOR-INTEGRATION.md
cproudlock b8c22244a1
Some checks failed
CI / backend (push) Failing after 2s
CI / naming (push) Successful in 1s
CI / frontend (push) Successful in 7s
Multi-site distribution readiness: settings-driven site config, security closeout, release engineering, v0.5.0
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>
2026-07-10 15:02:07 -04:00

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-Key header. 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 passing api_key in 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\MachineNo FIRST (authoritative post Update-MachineNumber; ignore the 9999 placeholder), then C:\Enrollment\machine-number.txt as fallback. This is exactly what GE-Enforce.ps1 already does.
  • pc-type / pc-subtype: C:\Enrollment\pc-type.txt / pc-subtype.txt (the gea-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.