Most sites have no external HR database, so add a self-hosted directory mode. - New employee_directory_mode setting: 'external' (default; read a separate HR DB, unchanged) or 'selfhosted' (app-owned table). - DirectoryEmployee model + directoryemployees table (migration 7d16). to_dict emits the same keys the external contract uses (SSO/First_Name/...), so both modes share one response shape and the frontend is unchanged. - Employee search / single / batch lookup branch on the mode. - Self-hosted-only management endpoints: list, create, update, delete, and CSV import (upsert by SSO). Guarded so they only work in self-hosted mode. - EmployeeDirectory.vue management page (Settings > Locations & Organization): table + search + pagination, add/edit/delete, CSV import (file or paste). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
106 lines
5.0 KiB
Markdown
106 lines
5.0 KiB
Markdown
# 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`.
|
|
|
|
> **The schema is standardized across sites** - the `cmmc_usb` check-in/out
|
|
> solution is the same deployment everywhere, so the tables below match as-is
|
|
> and no schema adaptation is needed. The **database name may differ per site**,
|
|
> though - set `cmmc_usb_db_name` (default `cmmc_usb`) to match the local name.
|
|
> The view recipe at the end is only a fallback for a site that somehow 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.
|
|
|
|
## Adapting a different site schema (recommended: views)
|
|
|
|
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:
|
|
|
|
```sql
|
|
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).
|