Initial import: shopdb-flask multi-site asset platform
Flask + Vue rewrite of the classic-ASP shopdb, built as a plugin framework so sister GE Aerospace sites can adopt it. Product version 0.7.0-pre-0.8.0, plugin contract 0.11.0, 966 backend tests. Key entry points: - docs/INSTALL-WINDOWS-IIS.md - tested Windows + IIS install runbook (own-site and subpath deployment methods) - docs/PILOT-DEPLOY.md - production pilot: stand up + import + verify - docs/IMPORT-API.md - schema-agnostic legacy data import contract - scripts/site_imports/wjf/ - West Jefferson reference import loader - docs/adr/ - twelve accepted architecture decision records
This commit is contained in:
133
plugins/employees/README.md
Normal file
133
plugins/employees/README.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# Employees plugin - directory database contract
|
||||
|
||||
Read-only lookups against a **separate** employee/HR directory database. Powers:
|
||||
|
||||
- Employee search (add people to a notification, browse the directory)
|
||||
- Single + batch SSO lookup
|
||||
- Recognition notifications (name + photo on the shopfloor / lobby displays)
|
||||
|
||||
The plugin never writes to this database. Use a read-only account.
|
||||
|
||||
> **This is the integration most likely to differ per site.** HR / directory
|
||||
> systems vary widely, so expect to map a site's schema to the contract below -
|
||||
> the `CREATE VIEW` recipe at the end is the normal way to do it.
|
||||
|
||||
## 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 | `employee_db_host` | `EMPLOYEE_DB_HOST` |
|
||||
| Database | `employee_db_name` | `EMPLOYEE_DB_NAME` |
|
||||
| User | `employee_db_user` | `EMPLOYEE_DB_USER` |
|
||||
| Password | (not stored) | `EMPLOYEE_DB_PASSWORD` |
|
||||
|
||||
Set the password in `.env`; the setup wizard's Features step shows the exact
|
||||
line to paste. Engine is MySQL/MariaDB (pymysql).
|
||||
|
||||
## Required schema
|
||||
|
||||
The plugin runs these queries verbatim, so a site's database must expose a
|
||||
table (or **view** - see below) named `employees` with these columns:
|
||||
|
||||
| Column | Type | Notes |
|
||||
| ------------ | ------------------- | ------------------------------------------------- |
|
||||
| `SSO` | INT | Unique person id. Lookups require it to be numeric |
|
||||
| `First_Name` | VARCHAR | Displayed as the given name |
|
||||
| `Last_Name` | VARCHAR | Displayed as the surname; sort key |
|
||||
| `Team` | VARCHAR | Team / group label |
|
||||
| `Role` | VARCHAR | Job title / role |
|
||||
| `Picture` | VARCHAR | **Image filename** (see Photos) |
|
||||
|
||||
Queries actually executed:
|
||||
|
||||
```sql
|
||||
-- search
|
||||
SELECT SSO, First_Name, Last_Name, Team, Role, Picture
|
||||
FROM employees
|
||||
WHERE First_Name LIKE %s OR Last_Name LIKE %s OR CAST(SSO AS CHAR) LIKE %s
|
||||
ORDER BY Last_Name, First_Name LIMIT %s;
|
||||
|
||||
-- single / batch
|
||||
SELECT SSO, First_Name, Last_Name, Team, Role, Picture FROM employees WHERE SSO = %s;
|
||||
SELECT SSO, First_Name, Last_Name, Team, Role, Picture FROM employees WHERE SSO IN (...);
|
||||
```
|
||||
|
||||
Rows are returned to the API **with these exact column names**. The frontend
|
||||
(EmployeeSearch, NotificationForm, EmployeeDetail, ShopfloorDashboard) reads
|
||||
`SSO`, `First_Name`, `Last_Name`, `Team`, `Role`, `Picture` as-is - do not
|
||||
rename them in the response.
|
||||
|
||||
## Photos
|
||||
|
||||
`Picture` holds an **image filename** (e.g. `123456.jpg`), not a path or blob.
|
||||
The app renders it as `/static/employees/<Picture>`, so the image files must
|
||||
live in the app's `static/employees/` directory. Leave `Picture` empty/NULL for
|
||||
people with no photo; the UI falls back to initials.
|
||||
|
||||
## Two ways to provide the directory
|
||||
|
||||
**Option A - map an existing HR/directory database** (see the view recipe
|
||||
below). Use this when the site already has a system of record for people.
|
||||
|
||||
**Option B - self-hosted directory (managed in-app)** for sites with no HR
|
||||
database. Set `employee_directory_mode` to `selfhosted` and manage people under
|
||||
**Settings > Employee Directory** (add / edit / delete + CSV import) - no SQL
|
||||
needed. The app owns a `directoryemployees` table (migration 7d16); the lookup
|
||||
APIs read it automatically in this mode.
|
||||
|
||||
If you would rather load it with SQL, the canonical table is equivalent to:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE shopdb_directory CHARACTER SET utf8mb4;
|
||||
USE shopdb_directory;
|
||||
|
||||
CREATE TABLE employees (
|
||||
SSO INT NOT NULL PRIMARY KEY,
|
||||
First_Name VARCHAR(100) NOT NULL,
|
||||
Last_Name VARCHAR(100) NOT NULL,
|
||||
Team VARCHAR(100) NULL,
|
||||
Role VARCHAR(100) NULL,
|
||||
Picture VARCHAR(255) NULL
|
||||
);
|
||||
|
||||
-- add people (or bulk-load from CSV with LOAD DATA INFILE)
|
||||
INSERT INTO employees (SSO, First_Name, Last_Name, Team, Role, Picture)
|
||||
VALUES (123456, 'Jane', 'Doe', 'Inspection', 'Quality Tech', '123456.jpg');
|
||||
```
|
||||
|
||||
Put photo files (named as in `Picture`) under the app's `static/employees/`.
|
||||
In self-hosted mode the `directoryemployees` table lives in the main app DB, so
|
||||
no separate database is required.
|
||||
|
||||
## Adapting a different site schema (recommended: a view)
|
||||
|
||||
Sites whose HR/directory database uses different table or column names should
|
||||
**not** be forced to rename anything. Instead, create a read-only **view**
|
||||
named `employees` that maps local columns to the names above:
|
||||
|
||||
```sql
|
||||
CREATE VIEW employees AS
|
||||
SELECT
|
||||
person_id AS SSO,
|
||||
given_name AS First_Name,
|
||||
surname AS Last_Name,
|
||||
department AS Team,
|
||||
job_title AS Role,
|
||||
photo_filename AS Picture
|
||||
FROM hr_people
|
||||
WHERE active = 1;
|
||||
```
|
||||
|
||||
Grant the app's read-only user `SELECT` on the view. No app code changes -
|
||||
point `employee_db_*` at that database and the plugin works.
|
||||
|
||||
Notes:
|
||||
- `SSO` must be numeric (single/batch lookup validate `isdigit()`).
|
||||
- Column-name case follows your database's identifier casing; match the names
|
||||
above exactly on case-sensitive platforms.
|
||||
- If the directory is unreachable or the `employees` object is missing, lookups
|
||||
return a 500 and the rest of the app keeps working (the feature degrades, it
|
||||
does not crash the app).
|
||||
Reference in New Issue
Block a user