# 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.

Another site adopting the shop-floor tools - the asset reporter that feeds the
collector API, and the EventSaver screensaver - should read
`docs/ADOPTING-AT-ANOTHER-SITE.md`. It has worked deployment examples for Intune
(including Machine Configuration/DSC), GE-Enforce and manual installation.
Neither tool is site-specific: the server URL, the API key and the targeting are
inputs, not code.

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
Each site runs its own instance (ADR-004), so there is no single production URL:
it is whatever that site serves, e.g. `https://shopdb.example.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 nest under `data`, NOT at the top level:
`{ "status": "error", "data": { "error": { "code": "...", "message": "...", "details": {...} } } }`
with an HTTP 4xx/5xx. Reading `message` or `code` off the root gives `undefined`.
Lists carry `meta.pagination.{page, perpage, total, pages}` - again nested, not
`meta.total`. 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). Operation and
  plugin counts live in `docs/PROJECT-MAP.md`, which is generated.
- Interactive: `GET /api/docs` (Redoc).
- Human reference: `docs/API-REFERENCE.md`.
