Phase 6: Q.C. inspection, project folders, packet documents and the digital ITP
ci / frontend (push) Successful in 37s
ci / server (push) Successful in 9m18s
ci / image (push) Successful in 35s
ci / e2e (push) Successful in 2m17s

The Q.C. screen (KPIs, boards, project folders), the Q.C. tab on the packet
page (check items from the qc_check_items settings row, visual exam per weld,
NDE, hardness with the NACE label, notes), accept with a route and a
signature gated by qc_missing_empty, reject with a reason or an NCR number
closing the inspection into qc_history, Q.C. folder documents per project and
unit with superseding revisions, packet documents as a closed set with
take-out reasons, the digital ITP per unit from the frozen template (line
initials with CAS, unsign, N/A, customer codes, rejects with NCR, block
signatures, sign-off with the PDF hook, admin reopen, the ITP log), hold-point
warnings by department page group, the scoped policy check for unit and
project writes, migration 0007, tests, Playwright scenarios and docs.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
2026-10-17 20:08:53 -06:00
co-authored by Claude Fable 5.1
parent 8bb1f7ae4d
commit 00531cb329
64 changed files with 11715 additions and 260 deletions
+13 -1
View File
@@ -2,7 +2,7 @@
This document is rewritten for the server build. The old browser build's security document is in the old repo (`C:\Users\spencerm\Coding\PacketStation\docs\SECURITY.md`). The design comes from [BRIEF.md](BRIEF.md) and [PLAN.md](PLAN.md).
Status: phase 5. The identity controls (sessions, PIN, rate limits, audit, Origin check, derived group map) and the policy controls (server policy on every write, workflow steps as compare-and-set, server-side validation and limits, IT edit reasons, the filed lock, the upload pipeline for drawings and documents) are built and tested. Phase 3 adds the worker controls (read-only VISUAL and M-Files reads, stack guard, advisory locks, redacted errors, audited system writes). No requirement ID closes in phase 3. Phase 4 completes the upload pipeline (a kind per upload with its own types and limit, XLSX and CSV by content, the optional ClamAV scan, the assets volume quota alert) and adds the warehouse rules (the heat gate on release, closed hold and short reasons, receive by custody). Phase 4 closes D5. Phase 5 adds the shop rules (the server as the clock of record, server-assigned mark numbers under the packet row lock, insert-only change-order verifications with a signature, VOID sheets never edited). Every other control names the phase that builds it.
Status: phase 6. The identity controls (sessions, PIN, rate limits, audit, Origin check, derived group map) and the policy controls (server policy on every write, workflow steps as compare-and-set, server-side validation and limits, IT edit reasons, the filed lock, the upload pipeline for drawings and documents) are built and tested. Phase 3 adds the worker controls (read-only VISUAL and M-Files reads, stack guard, advisory locks, redacted errors, audited system writes). No requirement ID closes in phase 3. Phase 4 completes the upload pipeline (a kind per upload with its own types and limit, XLSX and CSV by content, the optional ClamAV scan, the assets volume quota alert) and adds the warehouse rules (the heat gate on release, closed hold and short reasons, receive by custody). Phase 4 closes D5. Phase 5 adds the shop rules (the server as the clock of record, server-assigned mark numbers under the packet row lock, insert-only change-order verifications with a signature, VOID sheets never edited). Phase 6 adds the Q.C. rules (server gates on accept, block sign and sign-off, NCR numbers checked by pattern, Q.C. documents never deleted, the append-only ITP log, server-verified signatures on every Q.C. and ITP sign-off). No requirement ID closes in phase 6. Every other control names the phase that builds it.
Contents:
@@ -109,6 +109,18 @@ The M: drive build had 20 layers of protection, most of them enforced in the bro
- A borrowed heat map is read-only. Nothing on the sibling packet can be written through the borrowing packet.
- Presence over SSE carries display names, never other personal data. Each entry is the user id, display name, screen and packet id.
### Q.C. rules (phase 6)
- Accept is refused on the server until the Q.C. record is complete (`qc_missing_empty`: every check item, a visual result on every weld and none rejected, an acceptable NDE result when a method is set, the inspector name). The screen only shows the reason.
- A block signature is refused until every line of the block is initialed or N/A. The sign-off is refused until every block is signed. Both are server rules. A signed-off ITP refuses every write but the reopen, which needs a Q.C. Supervisor, or an admin with an IT reason, and a reason.
- An ITP line rejected without an NCR number cannot be approved (server check). Line initials and block signatures can be removed only by the person who made them, or an admin.
- NCR numbers are checked against the pattern `NCR-YYYY-NNNN` on the server. Checking them against pesco-ncr is reserved for a later phase (`domain/ncr.py`, `validate_ncr`). The NCR link opens in a new tab with `rel="noopener noreferrer"`.
- Documents are never deleted. A packet document is taken out of the data book with a reason and the row is kept. A Q.C. folder document is replaced by a new revision; the old row stays and points at the new one. Packet document kinds and Q.C. document types are closed sets, checked on the server and by database CHECKs. Every document file is a PDF, PNG or JPEG, typed by content.
- `itp_log` is append-only, like `packet_log`: the app role has SELECT and INSERT only, and a trigger refuses updates, deletes and truncate. `itp_rejects` stays append-only, so every reject and its NCR number survive a later approval.
- Signatures verified on the server, with a content hash: Q.C. accept, Q.C. accept and route, Q.C. reject, the ITP block signature and the ITP sign-off.
- The ITP and the Q.C. folder are checked with `check_scoped()`: the same system, admin bypass, who and precondition steps as a packet write. An admin outside Q.C. and Clerical needs an IT reason, recorded in `itp_log` and the audit row.
- Every ITP write and every Q.C. folder document writes an audit row (`itp.<action>`, `qc_doc.add`, `qc_doc.revise`).
### Worker (phase 3)
- The worker publishes no port and joins no proxy network. It reaches out to VISUAL and M-Files only; nothing reaches in. Admin and Clerical reach it only through rows in PostgreSQL (`job_requests`, the `feed` settings row) and NOTIFY.