Adopting a site means getting its asset register in. The HTTP import API suits a
site with a source system and someone to script against it; a sister site with a
spreadsheet and no developer needs something else, and that is the common case.
FOREIGN KEYS TAKE NAMES. This is the whole design. A CSV row has to say where an
asset is, and the database stores locationid, an integer. Requiring the number
means importing locations, reading back the generated ids and pasting them into
the asset sheet - a workflow nobody finishes. Every foreign key here accepts
either a numeric id or the referenced row's name:
assetnumber,assettypeid,statusid,locationid
CMM-01,Measuring Tool,Active,Gage Lab
The column keeps its database name, per CONTRIBUTING.md; the value is whatever
the operator actually knows. Names resolve across files in one run, so
assets.csv can reference a location that only exists because locations.csv was
read moments earlier. A name that does not resolve is reported with its line,
column and value, not as a foreign key violation from three layers down.
Dry run is the default, and writes go into the transaction either way - the
rollback is what makes it a dry run. Skipping the writes instead made every
cross-file reference fail, which is the one thing a folder-wide check exists to
verify. Validation covers every row before anything is written, so a typo on
line 400 cannot leave 399 rows imported. Files are matched on a natural key, so
correcting a spreadsheet and re-running updates rather than duplicates.
TEMPLATES ARE GENERATED, NOT MAINTAINED. "flask csv templates" builds them from
the live schema, annotated with required/optional and which file each foreign
key refers to. The prompt for this was a hand-written template set that had
invented columns on seven of eleven tables and named a table that does not
exist, while looking entirely plausible - and described an import mechanism
(a Data Import page, a flask import-csv command) that had never existed. A test
fails the build if a generated template ever offers a column the schema lacks.
User accounts are deliberately not importable: passwords do not belong in a
spreadsheet in either direction.
Verified end to end against MySQL 5.6 - a folder dry run catching one bad
reference, the fix, the commit, and a re-run reporting updates rather than
inserts. 16 tests.
95 lines
5.2 KiB
Plaintext
95 lines
5.2 KiB
Plaintext
# ShopDB Flask API - LLM guide
|
|
|
|
ShopDB is a plugin-based asset-management system (PCs, printers, machines,
|
|
network devices, measuring tools, applications, knowledge base, USB, warranties)
|
|
for GE Aerospace sites. This file is the quick entrypoint; the full machine
|
|
spec is the OpenAPI at `/api/docs/openapi.json` (browse it at `/api/docs`).
|
|
|
|
## Installing and operating this server (read this before answering "how do I install/fix it")
|
|
The people running these servers are often not Windows, IIS or Python
|
|
specialists, and they ask assistants for help. Two documents are authoritative:
|
|
- `docs/INSTALL-WINDOWS.md` - installing a NEW site. One offline installer `.exe`.
|
|
- `docs/OPERATE-WINDOWS.md` - restart, logs, backups, upgrades, troubleshooting.
|
|
Both ship in `docs/` inside the install directory on every installed server.
|
|
|
|
Do NOT walk someone through `docs/INSTALL-WINDOWS-IIS.md` or
|
|
`docs/DEPLOY-WINDOWS-IIS.md` for a new site. Those are the MANUAL procedure, kept
|
|
only for hand-built servers that predate the installer; following them produces a
|
|
server the installer then refuses to upgrade.
|
|
|
|
Day-2 operations all go through `shopdb-admin.ps1` in the install directory
|
|
(default `C:\shopdb-flask`): `status`, `restart`, `logs`, `check`, `verify`,
|
|
`backup`, `plugins`, `open`. Before diagnosing anything, ask for the output of
|
|
`shopdb-admin.ps1 check -Json` - it reports version, publishing method, IIS and
|
|
pool state, HTTP reachability, database host and reachability, Python version,
|
|
installed plugins and errors, and it contains no secrets. `verify -Path <name>`
|
|
answers "does this server carry component X" from the on-box CycloneDX SBOM.
|
|
|
|
Python is 3.14 and the wheelhouse is locked to it; an upgrade against a venv
|
|
built by a different minor version is refused by design.
|
|
|
|
## Bulk-loading a site's data
|
|
Two routes, and the right answer depends on what the site has:
|
|
- SPREADSHEET, no developer (the common case): `flask csv templates --out <dir>`
|
|
generates templates FROM THE LIVE SCHEMA, then `flask csv import --dir <dir>`
|
|
checks and `--commit` applies. Foreign keys accept the NAME of the referenced
|
|
row ('Bay 3'), not a numeric id, and resolve across files in one run. Dry run
|
|
is the default; nothing is written unless every row passes; re-importing an
|
|
edited file updates rather than duplicates. See `docs/CSV-IMPORT.md`.
|
|
- A SOURCE DATABASE to script against: the HTTP import API, `docs/IMPORT-API.md`
|
|
and `docs/IMPORT-ADOPTION.md`.
|
|
Do NOT hand-write CSV templates - generate them. User accounts are deliberately
|
|
not CSV-importable.
|
|
|
|
## Base URL
|
|
Prod (West Jefferson): `https://tsgwp00525.wjs.geaerospace.net/shopdb`
|
|
All API paths are under `/api` (e.g. `<base>/api/assets`). Dev: `http://localhost:5001`.
|
|
|
|
## Auth
|
|
Three schemes:
|
|
- **Bearer JWT** - most endpoints. Get one by logging in, or use a managed
|
|
Personal Access Token (PAT). Send `Authorization: Bearer <token>`.
|
|
- Login: `POST /api/auth/login` `{ "username": "...", "password": "..." }`
|
|
-> `data.access_token`. Refresh: `POST /api/auth/refresh`.
|
|
- PATs are minted in the UI (Settings > API Tokens); a *scoped* PAT is limited
|
|
to named permissions and suspends the admin bypass.
|
|
- **X-API-Key** - unattended/service endpoints (collector ingest, GE-Enforce
|
|
fetch). Send `X-API-Key: <managed-token>`.
|
|
- **Public** - some read endpoints (e.g. printer install-list, employee search,
|
|
dashboards) need no auth.
|
|
|
|
Auth level per endpoint is in the OpenAPI `security` field: `bearerAuth`,
|
|
`apiKeyAuth`, or none. Admin-only and permission-gated routes both use bearer.
|
|
|
|
## Response envelope
|
|
JSON endpoints return `{ "status": "success", "data": <payload>, "meta": {...} }`.
|
|
Errors: `{ "status": "error", "message": "...", "code": "..." }` with an HTTP 4xx/5xx.
|
|
Lists include `meta.total` / pagination. A few feed endpoints (screensaver, some
|
|
installer text formats) return raw text/JSON without the envelope - noted per route.
|
|
|
|
## Common recipes
|
|
- Search everything: `GET /api/search?q=<term>` (multi-word = AND across words).
|
|
- List assets on the map: `GET /api/assets/map`.
|
|
- List a type: `GET /api/printers`, `/api/computers`, `/api/machines`,
|
|
`/api/network`, `/api/measuringtools` (paginated: `?page=&perpage=`).
|
|
- Get one: `GET /api/printers/<id>` etc.
|
|
- Create (bearer): `POST /api/printers` `{assetnumber, windowsname, vendorid, ...}`.
|
|
- Reports: `GET /api/reports` (list), `GET /api/reports/pc-relationships` (PC<->machine).
|
|
- Printer installer data: `GET /api/printers/install-list` (public; add
|
|
`?format=text` for a pipe-delimited variant); `GET /api/printers/pc-default?machine=<n>`.
|
|
- Collector ingest (X-API-Key): `POST /api/collector/computers`.
|
|
- GE-Enforce: `GET /api/geenforce/manifest?pctype=<scope>`,
|
|
`GET /api/geenforce/payload/<sha256>`, `POST /api/geenforce/report`.
|
|
- Import (admin PAT, preserves timestamps with `X-Import-Mode`): see docs/IMPORT-API.md.
|
|
|
|
## Conventions
|
|
- DB-mirrored params/fields use lowercase concatenated names (no underscores):
|
|
`locationid`, `vendorid`, `windowsname` - match them exactly.
|
|
- IDs in paths are integers.
|
|
- Plugin endpoints live under the plugin's prefix (`/api/<plugin>/...`).
|
|
|
|
## Full reference
|
|
- Machine spec: `GET /api/docs/openapi.json` (OpenAPI 3.1, 362 operations).
|
|
- Interactive: `GET /api/docs` (Redoc).
|
|
- Human reference: `docs/API-REFERENCE.md`.
|