Files
shopdb-flask/plugins/usb/README.md
cproudlock bad7aa29bb Employee directory: note it varies per site + add self-hosted option
- Flag the employee directory as the integration most likely to differ per
  site; USB (cmmc_usb) is standardized and rarely needs adaptation.
- Add "Option B: stand up a self-hosted directory" with the canonical employees
  table DDL, for sites with no HR database. In-app management (CRUD/CSV import)
  noted as a possible future enhancement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 08:39:53 -04:00

4.9 KiB

USB plugin - CMMC USB check-in/out database contract

The USB plugin tracks removable-media check-in/out for CMMC compliance. Device and log state live in a separate, read-write MySQL database (cmmc_usb), reached with parameterized pymysql via cmmc_usb_connection(). Names of people are resolved from the HR employee directory (see the employees plugin).

The plugin's own reference tables (usbdevicetypes, usbdevices, usbcheckouts) live in the main app database; only the live check-in/out data is in cmmc_usb.

This schema is typically standardized across sites - the cmmc_usb check-in/out solution is the same deployment everywhere, so the tables below usually match as-is and no adaptation is needed. The view recipe at the end is a fallback for the rare site that differs. (Contrast the employee directory, which genuinely varies per site.)

Connection

Credentials resolve settings-first, then environment, except the password which is env-only (never stored in the app database).

Field Setting key (editable in the setup wizard) Env var (fallback)
Host cmmc_usb_db_host CMMC_USB_DB_HOST
Database cmmc_usb_db_name CMMC_USB_DB_NAME
User cmmc_usb_db_user CMMC_USB_DB_USER
Password (not stored) CMMC_USB_DB_PASSWORD

Set the password in .env; the setup wizard's Features step shows the exact line to paste. This database is read-write - the app account needs SELECT, INSERT, UPDATE. Engine is MySQL/MariaDB (pymysql).

Required schema

The plugin runs raw SQL against these tables (or views - see below).

devices

Column Type Notes
device_id VARCHAR Primary key; the device serial/tag
device_desc VARCHAR Description
device_owner VARCHAR Owner
status VARCHAR Check-in/out state
locker_location VARCHAR Where the device is stored

Operations: SELECT (list + by id), INSERT (register device), UPDATE (edit fields, change status).

checkinoutlog

Column Type Notes
log_id INT (PK) Auto id
badge_number VARCHAR Person's badge
device_id VARCHAR FK to devices.device_id
action VARCHAR check-in / check-out
timestamp DATETIME When it happened
scanned_viruses (text/int) Scan result
locker_location VARCHAR Locker at time of event
sanitized (bool/int) Sanitization flag

Operations: SELECT (history per device), INSERT (log an event).

users

Column Type Notes
badge_number VARCHAR Primary key; the scanned badge
first_name VARCHAR Given name
last_name VARCHAR Surname

Operations: SELECT by badge, INSERT (auto-add a badge on first scan).

Employee directory dependency

To turn a scanned badge into a name, the plugin also reads the HR employees directory (via the employees plugin's connection). A badge shaped 0<digits>BZ carries a PayNo (the digits); lookups try employees.SSO and employees.PayNo. See plugins/employees/README.md for that schema and connection.

Sites whose USB-tracking database uses different table/column names should create read-only/updatable views named devices, checkinoutlog, and users that map local columns to the names above. Example:

CREATE VIEW devices AS
SELECT
  asset_tag     AS device_id,
  description   AS device_desc,
  owner         AS device_owner,
  state         AS status,
  storage_bay   AS locker_location
FROM usb_assets;

Because the plugin writes to devices/checkinoutlog/users, either make the views updatable (single-table views usually are) or expose real tables with these column names. Grant the app account SELECT, INSERT, UPDATE.

Notes:

  • device_id and badge_number are the natural keys the plugin matches on.
  • If cmmc_usb is unreachable, USB endpoints return an error and the rest of the app keeps working (the feature degrades, it does not crash the app).