51 KiB
Changelog
All notable changes to this project are recorded here. The format follows Keep a Changelog. Versions follow Semantic Versioning.
[Unreleased]
Decided
- Gitea issues 10, 14, 15, 16, 22, 26, 28 and 29: SethD kept the built rules (cancelled work orders flagged only, data book date for Clerical and Q.C., signature undo rules, the server release gate, no "copy marks" button, block signature removal, the data book built at filing, every role may read the PDFs). Nothing changes in the build.
- Gitea issue 6: every policy tightening stays, filing for packets routed to Shipping included.
- Gitea issues 8, 18, 23, 32, 33 and 36: SethD changed six more defaults, to build in phase 10 (PLAN.md changes C6 to C11): the data book leaves out the history pages; a supervisor approves each received short and a packet cannot complete until every short is approved; checklists are per department, edited by its supervisor, and changes reach new packets only; Q.C. and Clerical may run the stamp check; the PM screen is for PS-ProjectMgmt and Admin; the Stall screen follows the supervisor's assignment.
- Gitea issues 7, 11, 13, 17, 30, 34 and 35: kept as built, or settled as planned (the archive gets the data book, the documents and a manifest at filing; nothing is purged).
- Gitea issues 1, 24, 25, 27 and 31: SethD changed five defaults, to build in phase 10 (PLAN.md changes C1 to C5): over target follows VISUAL ticket hours; a Q.C. reject always needs a reason and acceptance needs an NCR number; an incomplete ITP blocks filing; prints go to the print dialog from the page; filing waits until VISUAL shows the work order closed.
- Gitea issue 21: carried marks stay computed; the next department adds its welds to the same weld map.
- Gitea issue 37: production and test each run natively on their own Linux VM, not in Docker. docker-1 keeps CI only. Built in phase 10; the docker-1 test stack runs until the test VM is ready.
- Gitea issue 7: project files are also archived to an NFS share on the QNAP. Phase 10 adds an Admin setting for the archive folder that checks read and write. Nothing is deleted from Packet Station.
- Gitea issue 2: a PIN is enough for every sign-off, Q.C. accept and filing included. Nothing changes in the build.
- Gitea issue 3: shop devices keep the registered-device cookie. No device certificate is planned.
- Gitea issue 19: the upload limits stay (MTR 25 MB, hand BOM 5 MB). ClamAV stays off in both stacks. The workstations run Microsoft Defender.
- Gitea issue 20: the storage alert stays at 85 percent. Phase 9 mails it to PS-Admins.
- Gitea issue 38: the test stack's files stay under
~/packetstation/teston docker-1. The test env example, the compose header and the docs now give that path.
Fixed
- Gitea issue 42: work-order text on the traveler stays inside its own box. Each line shrinks down to 70 percent of its size, then is cut with "...", so a long work order, operation or drawing no longer runs over the next QR code. The gap between work-order boxes is 18 pt, a quiet zone for the kiosk scanner. On the Work orders tab the card text wraps inside the card, the work order is 22 px and cards are at least 340 px wide, one per row on a narrow screen.
- Board columns are frames about three cards tall (700 px, never taller than the screen) that scroll on their own, with the column heading staying put, so a long column no longer pushes the next one far down the page. Narrow screens keep the plain one-column flow.
- Sign-in refused as cross-origin in Firefox: the app sent
Referrer-Policy: no-referrer, under which Firefox sendsOrigin: nullon same-origin POSTs. The policy is nowsame-origin, which still sends nothing to other sites.
Changed
- Security fixes in the pinned dependencies, found by the new CI scan:
pypdf6.21.0 to 6.21.2 (GHSA-5hx5-vpf9-5wcv, a crafted PDF could reach the image parsers; 6.21.2 for GHSA-6c7f-9265-g8fw, GHSA-jr96-gvgh-j3r4 and GHSA-gmh7-3g9r-mjh5) andcertifi2026.7.22 to 2026.10.19 (PYSEC-2026-4320, a distrusted root removed). The image must be rebuilt for both to reach the stacks. POST /api/admin/ad/refreshno longer runs the AD refresh in the request. It asks the worker for anad-reconcilerun and answers 202{requested, pending, job};GET /api/admin/ad/reconcilegives the latest report.- The storage quota alert is now mailed through the Notifications rules (to PS-Admins by default), with a "Cleared" message when usage drops back.
- The session, lock and sign-in limit settings can be overridden on the Admin Security tab; the environment values are the defaults.
deploy/env/prod.env.examplesetsBACKUP_DIR=/var/backups/packetstation/prod, as the brief and the docs say.- Gitea issue 44: the packet tabs put Materials before Heat map.
- Gitea issue 45: Admin and Clerical sessions wait 60 idle minutes before the screen lock and before signing out (
SESSION_DESK_MINUTES, default 60; it never shortensSESSION_LOCK_MINUTESorSESSION_IDLE_MINUTES). Everyone else keeps 3 and 15.GET /api/auth/meanswers the session'slock_minutesand the browser's idle lock follows it. The hidden-tab lock after a minute is unchanged. - VISUAL is the source of truth for the drawing rev. When M-Files' Effective rev differs from the rev VISUAL calls but M-Files still holds that rev as Retired (or Effective), the drawing job attaches it to the draft with no flag and no Clerical approval, and the packet page says the drawing is retired in M-Files. Any other M-Files status, or no document at that rev, still flags
rev_mismatch; Packet Station only ever attaches Effective or Retired drawings. This replaces the "Use rev V as VISUAL calls it" choice from issue 41. Needs MFilesKit 0.1.3 (DrawingLookup.revision) and migration 0009.
Added
-
Phase 9: Admin completion, AD reconcile, integrity, notifications, backups. The Admin page gains eight tabs: Departments, Profiles, Checklists, Security, Access log, Who is in, Stamp check and Notifications. The tab list wraps into rows on a narrow screen.
-
Departments tab: every department with its AD groups (and whether each is in the OU) and its stations. Edit a department's name, turn it on or off, rename, reorder, add or hide stations. Stations are never deleted, since station limits and packets point at them. The code and the short name cannot change. "New department" adds a shop department with its stations and shows the three AD groups IT must create (
PS-<code>-<short name>-Worker,-Lead,-Supervisor) before it is saved. Only shop departments can be added; the support departments are fixed. -
Profiles tab: a person's welder stamp (1 to 12 letters, numbers or dashes, unique), whether their profile is active, and their station limits per department. An inactive profile drops out of the welder picker and the worker filter; it changes nothing the person may do. A CSV import by employee ID (columns
employee_id,welder_stamp,active,stations; an empty cell leaves a value,-clears it; thestationscell is the person's whole list) shows a preview with every change and every error, and applies only when the preview has no errors, in one go. The Directory flags panel lists active users with no employee ID and employee IDs shared by more than one account. -
Checklists tab: edit the weld and plain station checklists (group, key, text, order; at most 40 items; the placeholders
{drawing},{rev}and{wps}). A saved key cannot be renamed. A removed item drops out of new checklists only; open stages keep their answers. "Use the default list" restores the old build's list. -
Security tab: the session, lock and sign-in limit settings with their bounds (the per-account failure limit stays at 15 or under, below AD's 20), applied without a restart. Security alerts for the last 24, 72 or 168 hours: account cooldowns, repeated wrong PINs, wrong PINs or passwords at unlock or signature, denied actions, sign-in bursts, Admin changes, IT edits and integrity findings, with a filter per kind. The last integrity run and its findings.
-
Access log tab: every sign-in attempt and every sign-in, session, PIN, device and signature audit row for everyone, filtered by time, person or account, kind, result and address (or address range), 200 rows at a time, and downloaded as CSV (at most 50,000 rows, with the formula guard, logged in the print log and the audit).
-
Who is in tab: the live sessions, with the kind, device, address, when seen, locked or active, and the screen and packet the person has open. Refreshes every 30 seconds.
-
Stamp check tab: paste a stamp line from a printed or exported copy, or just its 16-character code, or upload the PDF, and the server says whether it is genuine, does not verify, or was never printed, with who printed what and when.
-
Notifications tab: one rule per event type (13 of them), each on or off, sent at once or in a daily digest at a set time, to AD groups (found with a directory search), single users, mailboxes, or the Supervisor group of the event's department. People can be left out of a rule, except on the three security event types. A test send goes to the rule's recipients or to one address, even on the test stack. The sent log lists every message with its recipients and the result. Every rule starts on, sent at once, to PS-Admins.
-
Account settings: a Notifications section that shows each event that reaches the person and why (a group, the Supervisor group of a department, a mailbox, by name), with an opt-out per event in a password session. Security events cannot be turned off.
-
Email through app-03 with STARTTLS and the PESCO CA, never in plain text. Subjects start
[Packet Station]on production and[Packet Station TEST]elsewhere. Recipients are in the envelope only, so nobody sees the list. The test stack records messages without sending them (NOTIFY_DRY_RUN), except a test send. Standing problems (feed failed or degraded, drawing lookups failing, change order waiting, group missing, backup stale, integrity failure, storage quota) send once when they start and a "Cleared" message when they end. -
Events raised: account cooldowns, a PIN disabled, a session ended after wrong PINs, sign-in bursts (one address over its limit, or 20 failed sign-ins across accounts in 5 minutes), integrity failures, failed and degraded feed runs, drawing lookups failing for more than 24 hours, change orders waiting for review more than 3 days, Q.C. and ITP rejects (to the department), the AD reconcile report, groups missing from the OU, a stale backup, a new version deployed and the storage quota (Gitea issue 20).
-
The AD reconcile every night at 01:30, and on "Refresh from AD now", which now asks the worker for a run and shows "Refresh requested" and the latest report: groups missing from or extra in the OU, users seen, added, updated and deactivated, sessions ended, and employee ID problems. A user disabled or gone in AD is marked inactive and signed out; a user left with no group is signed out. The reconcile refuses to change anything when no mapped group is in the OU, or when every group is empty while active users exist. A run that fails or refuses sends one "AD reconcile did not run" notice until a run succeeds.
-
The role refresh every 15 minutes (a Security setting): every signed-in person's groups and account state are read again from AD, their roles and sessions updated, and anyone disabled, gone or left with no role signed out. AD down changes nothing.
-
The integrity job every night at 04:00: every seal of a filed packet checked with the seal key, asset files rehashed (uploads of the last 7 days every night, all of them on Sundays), asset rows with no file, files with no asset row (reported, never deleted) and the audit hash chain. Findings are kept and raise an alert; a clean run clears it.
-
Nightly database backups on docker-1:
scripts/backup/ps-backup.shwith a systemd timer at 02:00 Denver time, an hour before the Proxmox backup. Each stack's database is dumped withpg_dump -Fcplus the roles without passwords, checked withpg_restore --list, 7 kept, withlast-successandlast-failuremarkers. The worker's backup-check job at 07:15 raises an alert when the newest dump is missing, empty, older than 26 hours or followed by a failure.scripts/backup/ps-restore.shrestores a dump into a fresh database, copies assets back without overwriting, checks every asset hash and prints row counts. The restore was rehearsed on the test stack on 2026-10-21: every table's row count and all 189 asset hashes matched. -
Denied actions are audited (
policy.denied, method, path and code only), as are account cooldowns (auth.lockout) and sign-in bursts (auth.signin_burst). Every Admin change is audited with before and after. -
CI dependency scanning:
pip-auditoverserver/requirements.txtfails on any known vulnerability;npm audit --audit-level=highfails on a high or critical one. -
Migration 0010: notification rules, recipients, exclusions, outbox and the sent log, the event columns for delivery,
integrity_findings,users.profile_active,assets.hash_checked_atandhash_ok,departments.created_atandcreated_by. -
Tests: every new Admin endpoint as every role (Admin password session 200, Admin PIN session 403, every other role 403, anonymous 401), departments, profiles and the CSV import, checklists, security settings and their effect on the limits, alerts, the access log and its CSV, presence and the stamp check; event raising, recovery, routing, the SMTP path against a local relay with STARTTLS, digests and directory failures; the reconcile, the role refresh, the integrity job (a tampered seal, a changed, missing and orphan file, an edited audit row) and the backup check; the backup script with a fake
docker; frontend tests for every new tab and the Account section; Playwright scenarios for Departments, Notifications, Security, the access log, the stamp check and Who is in. -
docs/SCHEMA.md, POLICY.md, SECURITY.md (I6 app part, M3, O1, O2 and S3 closed), DEPLOY.md and FEED.md updated; PLAN.md open questions 43 to 50.
-
Phase 8: Project Management, the find bar, presence and motion. The Project Management screen (
/pm, view only) with the tabs Overview (the headline numbers, a plain-words summary, the pipeline by step with the slowest step in pink, the units late or at risk), Projects & units (every project with its units, due date, days left, packets by step, % done and health: On track, At risk, Late, Complete, No packets yet; a project is as healthy as its worst unit; tap a project for its units and a unit for its jobs), Bottlenecks & aging (time in the current step, every open packet longest waiting first with over 3 days flagged, average time per step for completed moves), Hours vs target (station timer hours and VISUAL ticket hours side by side against the work-order target by department, worker and project, plus every packet over target), Quality & issues (Q.C. rejects, open shorts, open change orders, warehouse holds, sent back) and Find jobs. The period picker (30 days, 90 days, 12 months, all) sets the window for history figures. Every table has Excel (CSV); "Excel (CSV) — all" saves every report; "PDF report" builds the PESCO production status report (cover with the headline numbers, summary and pipeline, projects, flow, labor, issues) on the server with the controlled-copy stamp. Every export is logged as "report exported" in the audit and the print log. -
The find bar on every home screen: search over project number or name, lot, operation, drawing and rev, WPS, customer, PO, old project numbers, work orders, heat numbers, part IDs, welder name or stamp, change order and ECN numbers, with several words narrowing and Esc clearing; the project then unit picker; Filters with Department, Status (including At a station and Everything not filed), Station, Worker and, for Clerical and Project Management, the flag kind; the quick flags Change order open, Shorts open, Project overdue, Due within 7 days and Mine (what that screen is responsible for; hidden on the station and Project Management screens); Board or List with the list sortable by last updated, project / lot, due date, status or department. Filters and the view are saved per browser (
ps.flt); the search text is not. Tapping a number tile shows only those jobs; tapping again clears. The numbers follow the project pick but not the other filters. -
Every filter is applied by the server:
GET /api/packetsand the shop, stall, warehouse and Q.C. boards takeq,status,dept,station_id,welder_id,flags,flag,sort,mine_screenandmine_station_id, and answerfacets(the stations and workers in the project scope) for the dropdowns. A board never fetches more than it shows. -
Presence: the packet page shows "Also in this packet now: Name (role)" for everyone else with the packet open, from the event stream; a locked session drops out at once and a closed tab within the stream's ping cycle. Session events
lockedandunlockedare published alongsiderevoked. -
Motion: a "Motion on / off" switch in the top bar, saved per browser (
ps.motion), with reduced-motion honoured: screens and tabs ease in, a card that moved column glides there, a changed card glows, number tiles count up, sheets and toasts slide in. Back returns one page and restores the scroll position. Sheets sit centred on a desktop and at the bottom on a phone, scrolling inside when tall. An iPad-size pass: wide tables scroll sideways, boards stack below 820 px, sheets fit. -
The data book compared page by page with one exported from the old build on the same synthetic packet (both 17 pages in the same order): the sheet size rounds half up, the weld times use the old formats, the last closed stage shows its target, a manual change order with no sheets reads "documents changed", table cells wrap where the old tables did and headings sit left. The comparison is recorded in the phase notes.
-
Tests: the PM aggregates against synthetic data (health rules, periods, pipeline counts, hours), every search field, every filter and sort on the list and the boards, Mine per screen, presence join, leave, lock and revoke, export logging; frontend tests for the find bar state, saved filters, the KPI taps, the job list, motion, scroll restore and the PM tables; Playwright scenarios for the PM screen, the find bar, list, KPI taps, Back, sheets, motion and presence with two users, run at desktop and iPad viewports.
-
docs/POLICY.md, SECURITY.md and SCHEMA.md updated; PLAN.md open questions 38 to 42.
-
Phase 7: close, file, PDFs and prints. The "Close and file" panel on the packet page from status complete on: "Back from the shop, ready to close." with what the feed last saw in VISUAL (the job closed since a date, the work orders still open, or not checked yet), Job closed in VISUAL and Not closed in VISUAL, move back; "Ready for the data book." with File in the data book (PIN signature); "Filed in the data book" with the seal line (Seal intact, Seal does not match the record, or Seal unknown) and Reopen (IT). The packet read carries
vclose_check(the feed's observed and closed times, the open work orders aswo_base/lottext, and whether it agrees with the Clerical confirm). Confirming the close while the feed shows open work orders adds them to the log note. -
Filing past open work orders: when the feed still shows a work order open in VISUAL, filing answers 409
open_work_orderswith the list and the screen asks "File with open work orders?" before it sendsconfirm_open_wos. A warning, not a block, on both routes; checked before the signature, so a cancelled confirm costs no PIN attempt. The seal keeps the work orders and the log note says "Filed with work orders open in VISUAL: ...". A hand packet has no warning. -
The data book filed at filing: built on the server in the filing transaction, stored as an asset on the seal with its page count, logged as "Data book filed · N pages". A data book that cannot be built fails the filing (500
databook_failed, nothing filed); a part that cannot be read becomes a warning row in the index. Page for page after the old build: the cover (title, figures, equipment and design data, certification, signature lines), the index with page numbers, then 1 Drawings (live sheets at their own size, superseded sheets stamped VOID), 2 Material traceability (BOM and heat numbers, shorts and receipts, open items, the heat map rasters), 3 Welding record (the weld map rasters, a record per stage with the weld log and the station checklist), 4 Q.C. inspection (one set per inspection with checks, visual weld examination, NDE and testing, earlier inspections), 5 Q.C. and test documents (the unit's and project's Q.C. folder documents, ITP first, and the packet documents), 6 Material test reports, 7 Record history (change orders and every packet log row). Before filing, the data book can be viewed or downloaded from status complete on, stamped "not yet filed". -
The seal and reopen: the seal is HMAC-SHA256 with the server seal key. A reopen by IT (reason and signature) marks the seal broken with who, when and why, and keeps it with its data book; filing again writes a second seal. The packet read shows the newest seal with its data book (
seal.databook) andseals, the count. Migration 0008 addsdatabook_asset_id,databook_pagesandopen_wostopacket_seals. -
The job traveler with QR codes: job information, a QR box per work order for clocking on at the labor kiosk (
*%2{wo_base}${lot}${split}${sub}${seq}%*, the ID parts as text), the BOM and heat numbers with blanks to fill, the checklist with blanks to stamp, the weld log, the weld record, the sign-offs and a shop notes box. The Work orders tab shows the QR text and links to the traveler. -
The ITP PDF: one run of pages per page group (Weld Parts, Code, Final Assembly) with the header, the codes legend, each section and its items, the block tables and the sign-off line. The ITP sign-off now builds and files the signed PDF and the automatic
{no} — signed offfolder document in the same transaction (500itp_pdf_failedwhen it cannot, nothing signed off); the ITP page has ITP (PDF), Download, Print and Signed PDF. -
The traceability CSV as the old export (header rows, BOM with shorts and receipts, welds with the heats they join, the checklist, the Q.C. inspection), with the formula guard: a cell that starts with
=,+,-,@, a tab or a CR gets a leading'; quotes doubled; CRLF; UTF-8 without a BOM. -
Prints: the Print menu (Job traveler, Drawing with heat map, Drawing with weld map, Drawing (no markup), Superseded drawings (VOID), Data book) in the packet header and the close panel, Print this sheet on the drawing and map tabs, Print per MTR and per document, Print traveler on the Work orders tab. A print opens as a PDF in a new tab with "PRINTED COPY - {what} - printed by Name (emp) {UTC time} - {project} Lot {unit} dwg {drawing} R{rev} - verify revision before use" on every page. The old "Original packet PDF" kind is gone.
-
The print log: every print and export writes an append-only
print_logrow (who, when, what, how many pages, the stamp and its signature) and an audit rowprintorexport. The History tab lists them under "Printed copies and exports". -
The controlled-copy stamp on every exported PDF ("Controlled copy - exported by Name (emp) {UTC time}", the seal's first 12 hex or "not yet filed") and on prints carries a 16-hex signature made with the seal key, so a copy can be checked against the server later (
verify_stamp; the Admin screen comes in phase 9). PDF metadata: title, subject, keywords with the stamp signature, Author PESCO, Producer Packet Station. Every text in a PDF is cleaned and escaped. -
New endpoints:
GET /api/packets/{id}/pdf/databook,GET /api/packets/{id}/pdf/traveler,GET /api/packets/{id}/export/traceability.csv,GET /api/packets/{id}/print/{kind}with?sheet=and?asset=,GET /api/packets/{id}/prints,GET /api/itps/{id}/pdf,GET /api/itps/{id}/print;confirm_open_woson the file transition. Every role that can open the packet may read them, PM included. New dependencies: reportlab 5.0.1 and Pillow 13.0.0. -
Tests: close and file as every role and status against the policy oracle, the open work order confirm, the filed seal with its data book, reopen and refile, a failed data book build, the data book sections and index, VOID pages, warning rows, stamps and metadata, the traveler, the ITP PDF and the sign-off filing, every print kind and the print log, the CSV formula guard, the stamp signature; frontend tests for the close and file panel, the print menu, the prints list and the ITP buttons; a Playwright scenario for close, the PDFs and CSV, prints, filing with the seal, reopen and refile, and the signed ITP PDF.
-
docs/SCHEMA.md, POLICY.md and SECURITY.md updated (M2, S6, S7 and S8 closed); PLAN.md open questions 32 to 37.
-
Phase 6: Q.C. The Q.C. screen (the numbers Waiting for inspection, Accepted last 7 days and Rejected last 7 days; the boards Ready for inspection, Accepted and Rejected back with supervisor; the find bar; the Project folders grid with Active and All). The Q.C. tab on the packet page: the send details read-only as the supervisor set them (book, spool, location, note), inspector and stamp, the ten check items in two groups (Data book package, Physical spool) with the live hints (heats recorded, MTRs attached, welds on the map, checklist progress) ticked one key at a time, the visual weld inspection table with Accept and Reject per weld and a note, NDE method (None required, RT, UT, MT, PT), result (Acceptable, Rejectable) and report number, hardness labelled NACE when the WPS says so, inspection notes, and the earlier inspections. The check texts live in the
qc_check_itemssettings row (migration 0007). -
Q.C. accept with a route (Clerical – Data Book, Shipping, or a shop department) and a PIN signature, blocked on the server until every check is done, every weld has a visual result and none is rejected, the NDE result is Acceptable when a method is set, and an inspector is named; the missing items are listed on the bar. Q.C. reject to the supervisor with a reason, an NCR number (NCR-YYYY-NNNN, linked to the NCR system) or both, with a signature; the inspection closes into the history with its snapshot and a fresh one opens when the supervisor sends the packet back to Q.C. The supervisor and the station see the rejection, its NCR and the rejected welds at the top of the packet.
-
Q.C. project folders: documents per project and per unit (ITP, WPS / PQR, NDE procedure, Hydrotest procedure, PMI / material, Calibration certificate, Customer spec, Other), added by Q.C. or Clerical; a new revision supersedes the old one, which stays under Superseded; nothing is deleted. Project documents apply to every unit. A unit without an ITP is flagged.
-
Packet documents for the data book on the Documents tab: NDE, hydrotest, dimensional, PMI, coating reports, certificates of conformance, customer inspection reports, NCRs and Other, with a note; "Take out of data book" keeps the row and the file with who, when and why; the unit's and project's Q.C. folder documents are listed as also in the data book.
-
The digital ITP per unit, started from the Q.C. template ITP_Generation_Revised_2 (frozen into the ITP at creation: nine sections over the pages Weld Parts, Code and Final Assembly; items with the PESCO code, the customer code and the acceptance criteria; the legend O, R, A, I, AU, W, H, NA): line initials with a timestamp, undo by the same inspector or an admin before the block is signed, N/A per line or per section, customer code, witness and date, notes, rejects with an NCR number that must be entered before the line can be approved, signature blocks after sections 3 (covering 1 to 3), 4, 5, 6, 7, 8 and 9 signed with a PIN once every line is approved or N/A, QN number, remarks and the customer complete record per block, sign-off with a signature once every block is signed, reopen by a Q.C. supervisor or an admin with a reason, and the ITP log. Filing the signed ITP PDF is a hook that phase 7 implements.
-
Hold-point warnings: an open H or W point, or an open rejection, on a line not yet done shows as a warning on the unit's packets, filtered by the department's page group (01, 02, 03, 04, 05 and 10 see Weld Parts; 06, 07 and 13 see Code; 09 sees both; 08, 11, 12 and 14 see Final Assembly). Nothing is blocked.
-
New endpoints:
GET /api/qc/home,GET /api/qc/folders,GET /api/qc/folders/projects/{id},GET /api/qc/folders/units/{id},POST /api/qc/docs,PUT /api/packets/{id}/qc/checks/{key},PUT /api/packets/{id}/qc/welds/{no},PATCH /api/packets/{id}/qcwith field-level compare-and-set,GET/POST /api/units/{id}/itp, and the ITP writes under/api/itps/{id}. New policy actionsqc_doc_add,itp_start,itp_line_sign,itp_line_unsign,itp_block_unsign; the scoped check for writes that belong to a project or unit rather than a packet. -
Packet history texts as the old build: "Q.C. checked: …", "VT accept · W3", "NDE method: RT", "Q.C. accepted → Clerical – Data Book", "Q.C. rejected → supervisor", "Document added", "Document taken out of the data book"; the ITP log: "ITP started", "ITP line 1.3 approved", "ITP line 1.3 rejected", "ITP block 3 signed", "ITP signed off", "ITP reopened"; the audit: "Q.C. document added", "Q.C. document revised".
-
Tests: every Q.C. and ITP action as every role and status against a policy oracle, each
qc_missingcase, reject into history and the fresh inspection, Q.C. document supersession, document take-out, ITP line compare-and-set and unsign rules, block gates, the sign-off gate and the PDF hook, reopen, hold points per department page group; frontend tests for the inspection form, the Q.C. bar, the ITP page and the hold callout; Playwright scenarios for accept, reject with an NCR, the Q.C. folders, packet documents and the digital ITP through sign-off. -
docs/SCHEMA.md, POLICY.md and SECURITY.md updated; PLAN.md open questions 27 to 31.
-
Phase 5: the shop. The Supervisor screen (department chips for people who lead several departments, the change-order headline that cannot be closed, the numbers Ready to assign, At stations, Waiting on review and Station hours vs target, the Change orders on hold table, the station grid with a tile per station showing the job, the welder and stamp, the ticking clock against the target hours and a CHANGE ORDER tag, and the boards Ready to assign, Waiting on review, At Q.C., With warehouse and Routed on) and the Stall screen (station picker, the station hero, My packets and Submitted, waiting on supervisor).
-
The shop steps on the packet page, driven by
canandblocked: assign with the station select, a welder picker with search and the stamp filled from the welder's record; pull back to the queue (the clock freezes); Start work, Pause, Resume; Submit to supervisor with a PIN signature and the missing steps listed as links (checklist items, no welds on the drawing, filler metal); the supervisor's review with Data book package ready, Spool ready for inspection, the spool location and a note before Send to Q.C. (signature), Return to station with a return note, and Skip Q.C. with a route to another department (signature); a lead sees the review read-only. Send back to Warehouse and Send back to Clerical with reasons. -
The Weld map tab: the drawing rendered with pdf.js at scale min(2.2, 4200/width), pan, pinch and wheel zoom, FIT, full screen; Mark a weld then tap the joint; welds drawn as a leader line and arrowhead in pink with the id in a white circle; drag the bubble or the arrow; the weld sheet (work order, piece, type from Fillet, Groove, Fill, Seal, Tack, size default 5/16", process from GMAW, FCAW, SMAW, GTAW, SAW, stamp, the BOM items it joins) with Log weld, Save changes and Remove weld; the welds-on-this-sheet list; the weld record (filler, filler lot, preheat, notes) with field-level compare-and-set. Marks from an earlier department show as carried.
-
The Heat map tab: the heat table (HEAT NUMBERS, ITEM and HEAT NO., at most 12 rows per group side by side, live heats from the Materials tab, a missing heat as a red dash) placed on a sheet, dragged to move, A- and A+ in 0.15 steps from 0.6 to 2.1, removed; older heat tags in amber shown only when the sheet has no table; a packet with no heat map and no raw material of its own shows the heat map of a sibling packet in the same unit with the same drawing, read-only, with a note.
-
The Checklist tab: the department's checklist (weld departments: dwg, heat, wps, fit, pre before welding and vt, stamp, clean, qty after; other departments: dwg, prev, mat before and work, insp, qty when done) on the left and the weld record on the right. Each tick records done, when, who and the stamp. The templates live in the
checklist_templatessettings row (migration 0006). -
VOID stamps on voided drawing pages in the viewer (diagonal VOID, the void text, a red border); a VOID sheet refuses new marks.
-
Change orders in the shop: the Changes tab shows CO-n with its items, the required departments and who verified; a supervisor of a pending department verifies with a note and a PIN signature (insert-only). Clerical's approval of a feed change order applies the staged change: new pages added, old pages voided, rev and drawing set, work orders remapped, the BOM merged keeping heat, N/A, issued, location, pulled and the short on matching lines (vkey, else item and part), and the heat table copied to the new sheet. Required departments are the ones the packet touched, without Clerical; a minor change order needs none. The hold texts read "CO-2: Clerical is reviewing a change from VISUAL. Held until Clerical approves or rejects it." and "Change order CO-2 must be verified first by: 03 Weld Parts."
-
The station clock is kept on the server (start, pause, resume, folded on pull back and submit); the read model carries the live elapsed time and
server_now, and no client value is ever stored. VISUAL labor ticket hours from the feed cache are summed per work order and shown beside the clock. -
Presence: the packet page shows who else has it open ("Also here: ..."), from the event stream.
-
New endpoints:
GET /api/shop/board,GET /api/shop/stations,GET /api/shop/stall,GET /api/departments/{code}/people. Assign checks that the welder belongs to the department and that a limited worker's station is allowed. Welds and heat tags carry a label position (bfx,bfy); the heat table placement carriescarried_from. -
Packet history texts as the old build: "Sent to Stall 3", "Pulled back from Stall 3", "Work started", "Submitted to supervisor", "Sent to Q.C.", "Returned to Stall 3", "Routed to 09 Hydro", "Weld W4 marked", "Heat table placed on drawing", "Change order CO-2 verified by Weld Parts".
-
Tests: every shop step as every role and status against a policy oracle, the preconditions, clock arithmetic, server-assigned weld and heat tag numbers under concurrent inserts, carried marks on routing, change-order approval applying the staged change and the BOM merge rules, verification per department and the hold; frontend tests for the canvas geometry, the heat table layout, the clock, the checklist, the weld sheet, the shop screens and the role switcher; Playwright scenarios for assign, start, submit, review and send to Q.C., the heat table, the change-order banner and verify, custody, two users at once, and the skip-Q.C. route.
-
docs/SCHEMA.md, POLICY.md, SECURITY.md and FEED.md updated.
-
Phase 4: the Warehouse. The Warehouse home with the numbers (Waiting to pull, Being pulled, On hold, Ready for production, Open shorts, Released last 24 h), the Open shorts table with Receive, the find bar, and the task board: Waiting to pull, Being pulled, On hold, Pulled, ready for production, and Released to shop (3 days) built from the release transitions. Cards are grouped by department, oldest first by the day they were sent then VISUAL's release date, and move by button (Start pulling, Hold, Mark pulled with a warning when lines remain, Resume pulling, Back to pulling, Release…) or by dragging; a drop on the released column is refused. Hold asks for one of five reasons and a note ("Other" needs the note). Every role sees the real stage on a warehouse packet: the pill reads WH · waiting, being pulled, on hold or pulled, with who, how long and the hold reason under it.
-
The pull table on the Materials tab for the warehouse: Pulled (the first tick starts the pulling stage), issued quantity, location, heat number typed or scanned with Enter moving to the next line, Short (record, edit, Not short after all) with the seven reasons, quantity, PO or requisition, ETA and note, receive with quantity, heat and note as an append-only receipt, N/A for parts with no traceability, and an MTR (PDF, PNG or JPG) per line with a viewer. Send back to Clerical with a reason. Release to supervisor stays disabled with the server's reasons until every line not N/A is pulled or on an open short and every pulled line has a heat or is N/A or a sub-assembly.
-
GET /api/warehouse/board(numbers, the five columns, the open shorts). Board cards carry the warehouse stage with who and when, the sent date, VISUAL's release date and the pull counts. -
The server validates the heat number pattern, the hold reasons and the short reasons, and writes the packet history as the old build did: "Heat recorded · item 10", "Short recorded · item 10", "Short received · item 10", "Warehouse: Put on hold", "Released to supervisor with 1 short".
-
Receiving a short on a packet the warehouse no longer holds stays a warehouse right; the department that holds the packet can receive too, through custody.
-
Uploads are typed by content per kind: drawings are PDF, MTRs and documents PDF, PNG or JPG (25 MB), hand BOMs XLSX or CSV (5 MB). XLSX is checked as a real workbook, CSV as clean text. Names are sanitised, files stored by id, served with Content-Disposition (attachment for spreadsheets) and nosniff.
-
Optional ClamAV: a
clamavservice in compose behind theclamavprofile. WhenCLAMAV_HOSTis set every upload and every drawing the worker downloads is scanned before it is accepted; a hit is refused and audited, and an unreachable scanner refuses uploads. -
A storage quota alert: at 85 percent of the assets volume (configurable) the app raises a notification event, shown on the new Admin Storage tab with the usage, the ClamAV status and an Acknowledge button. Migration 0005 adds the
notification_eventstable that phase 9 builds the delivery on. -
Tests: every warehouse action as every role, the release gate, the short-receive exception, the heat pattern, upload sniffing and limits per kind, the ClamAV path with a fake scanner, the quota alert; frontend tests for the board and the pull table; Playwright scenarios for the warehouse board and the pull flow against the CI stack.
-
docs/SCHEMA.md, POLICY.md, SECURITY.md (D5 closed) and DEPLOY.md updated.
-
Phase 3: the VISUAL feed and M-Files drawings run in the worker. Migration 0004 with the VISUAL cache (batches, rows, materials, orders and order links, labor, per-batch change rows), the go-live ignored list, the resource map seeded from the old build's map (fold and ignore lines included), drawing lookups, job requests, job runs, job schedule and the worker heartbeat, plus the order-derived columns with provenance on projects and units. The work order key on a packet now includes the operation sequence, so one packet can hold two operations of the same work order.
-
The real worker: APScheduler with a settings-driven trigger that re-reads the feed settings on every fire, shop-hours and off-hours intervals, pause, LISTEN on
ps_settingsandps_job_request, one advisory lock per job,job_runsrows with counts and redacted errors, a heartbeat row and file, the stack guard before every VISUAL read, and a housekeeping job that prunes the caches at 90 days and the runs at 180. -
The
visual-feedjob: five reads through VisualKit (released work orders in the window withuntilalways passed, every tracked work order by key with no status or date filter, operations and part specs and parts and materials withmat_knownper leg, order links by base and by project, labor tickets at most every 30 minutes), COPY and MERGE into the caches with change rows, the suspect-batch guard, and the apply in one transaction: candidates by the old rules (one packet is drawing plus lot plus operation; fold and ignore; project from the base prefix; unit is project plus the three-digit lot), the go-live boundary with the ignored list and pull-in, matching on the VISUAL key across live and removed packets (a removed packet is never recreated), new drafts, drafts updated in place, change orders opened, re-aimed, withdrawn or followed on for packets past draft (minor when only target hours or the want date changed), left-behind drafts retired, work order gone after two misses, closed and cancelled observed per leg, projects and units created with customer, PO and dates from the order links and the several-open-orders rule in one function with the provenance stored, auto-release of clean drafts up to 25 per run, audit rows and NOTIFY. -
feed/fingerprint.py: a canonical hash over legs, quantity, rev, drawing and BOM (major) and target hours and want date (minor), with per-field tests and invariance tests. -
The
drawing-lookupjob: a prioritised queue, a per-run budget, a new MFilesKit lookup per run, download only when the M-Files object or file version changed, sha256 into assets, pages through pypdfium2, the decision table (attach, rev mismatch staged for Clerical Supervisor approval, not released with the drafting status, not found, lookup failed with backoff, non-numeric rev), the H-sheet note, drawing-origin change orders for a re-released file or a newer rev on an in-shop packet, and the hand drawing taken off on a new VISUAL rev. -
Clerical: the From VISUAL panel (run now, status, last ten runs, ignored work orders with pull in, unmapped resources, projects without names), the Changes to approve column and KPI, flag kinds in the Flagged column and the find bar, rev-mismatch approval with reason and signature, hand upload of a drawing or a BOM (XLSX or CSV parsed on the server) on flagged drafts with reason and signature, change-order approve, reject and hold with signature, and the project's VISUAL orders with a pin.
-
Admin: the Feed settings tab (intervals, shop hours, window, go-live date, departments, drawing recheck and budget, pause, next run, last ten runs) and the VISUAL resources editor. Every change is audited.
-
/api/feed/*,/api/jobs/*,/api/admin/feed/*, and under/api/packets/{id}:rev-approve,hand/drawing,hand/bom.GET /api/packetsgainsco=pendingandflag=<kind>. -
packetstation job run <name>andpacketstation fixtures use N. SettingsFEED_SOURCE,DRAWING_SOURCEandFIXTURE_DIR; a production stack refuses a fixture source. -
tests/fixtures/generator.pywrites a synthetic feed in the exact VisualKit contract shape with the edge cases from the plan; CI feeds the worker from it and the Playwright scenario drives a feed run, a drawing attach and a change order on an in-shop packet. -
docs/FEED.md written in full; docs/SCHEMA.md, DEPLOY.md, POLICY.md and SECURITY.md updated.
-
Integration run from a developer machine against VISUAL DEV and the vault (read-only, 2026-10-16):
visual-feedok againstVSQL\DEV / PESCOINCDEV: 994 firmed work orders in the window, 4,090 operation rows, 13,465 material lines, 100 customer orders with 102 links, 474 new drafts, 47 units and 18 projects created, 232 lettered-lot rows skipped (lots such as 6A make no unit, as in the old build), no unmapped resources, no errors.drawing-lookupok against the vault: 60 drawings looked up and fetched (the per-run budget), 213 drafts got their drawing attached, 68 flagged rev mismatch, none not found or failed. Nothing was written to VISUAL or M-Files. -
Phase 2: core domain. Migration 0003 with projects, project aliases and renumber history, units, packets and every child table (work orders, pages, BOM lines, shorts and receipts, welds, heat tags, heat table placements, stages, warehouse stage rows, transitions, Q.C. inspections and history, seals, packet log, VISUAL state), change orders with items, required departments and verifications, assets, packet documents, Q.C. documents, ITPs, user station limits and the department weld flag. Append-only triggers, soft-delete columns with partial unique indexes, server-assigned counters on packets.
-
The policy engine in Python (
server/packetstation/policy/): Principal, PacketState, the Action enum, one rule per action, custody, named preconditions, the change-order hold, and the order of checks from the plan. Every packet read returnscan,blockedwith reasons, andholder. docs/POLICY.md lists the rules and the tightenings against the old build for Seth. -
The write pipeline: one transaction per write with the packet row locked, the policy decision, compare-and-set on the expected status and department (409 "someone else already took this step" with the current state), If-Match row versions on child rows, server-assigned weld, heat tag, page and change order numbers, field-level compare-and-set on header scalars, packet version bump, packet log and audit rows, NOTIFY. Signatures through the phase 1 helper on every action the plan marks. Admin edits need an IT reason and are marked in the packet log and the audit. Filed packets are locked; filing writes an HMAC seal and Admin reopen breaks it with a reason.
-
The packet API under
/api/packets: list for the boards with the basic search, read, hand-made draft, header edit, transitions, work orders, pages, documents, move, remove, closed in VISUAL, data book date, reopen, seal, log, BOM, shorts and receipts, welds, heat tags, heat table, stage fields, checklist, clock, warehouse stage, Q.C. inspection, change orders (issue, approve, reject, hold, verify). -
/api/projectsand/api/units: create, edit with field compare-and-set, units one or several at a time, renumber with aliases and history, soft delete with a reason, number lookup through aliases. -
/api/assetsupload (type by content, 25 MB, sha256, stored by id under ASSETS_DIR, PDF page count) and/_blob/{id}served with a session, Content-Disposition and nosniff. -
Input cleaning and limits on the server (
text.py): the old cleanText rules and per-field lengths; bodies over 200 KB refused. -
Frontend: the home layout (headline, KPIs, attention, find bar with the basic search and the two-step project and unit picker, boards and list view), the Clerical screen (Changes to approve, Flagged, Going to the warehouse, Ready to close, Ready for data book, Filed; projects and units with new project and unit sheets, renumbering, move packet), the packet page (header, Drawing tab with pdf.js, Materials, Work orders with QR codes, Documents, History) with every control driven by
canandblocked, hand-made draft creation, the heat map question, send to warehouse, send straight to a department or Q.C., signature and IT reason sheets, live refresh from server events. -
Tests: the full policy matrix (every transition as every role in every status), custody, short-parts and change-order exceptions, preconditions, compare-and-set conflicts and row versions per table, server-assigned numbers under concurrent inserts, the audit and packet log rows, projects and units, assets. A Playwright scenario for the Clerical draft flow against the CI stack.
-
/api/departmentsnow returns station ids and the weld flag. -
deploy/runner: the Gitea Actions runner for docker-1 (compose file, act_runner config, install notes); registered on docker-1.
-
Phase 1: identity. Sign-in with the domain account and password against PESCO's Active Directory over LDAPS (search with the service account, then bind as the user; nested groups resolved; disabled accounts refused). Roles are the union of a person's
PS-*groups, mapped by a table derived from the department list. -
Server-side sessions: HttpOnly, SameSite=Strict cookie, idle sign-out after 15 minutes, absolute 12 hours for password sessions and 10 hours for PIN sessions, server-recorded lock after 3 idle minutes or a tab hidden for over a minute, step-up unlock with PIN or password. Origin and
X-Requested-Withcheck on every state-changing request. -
Optional Packet Station PIN, 6 to 12 digits, set by the user with their domain password, hashed with Argon2id. PIN sign-in by employee ID on registered devices only. Five wrong attempts disable the PIN; three wrong attempts at unlock or signature end the session.
-
Rate limits before any AD bind: 5 failed attempts per account per 5 minutes then a 10-minute cooldown, 30 per client address per 5 minutes.
-
Device registration by an Admin or a shop Supervisor in a password session, with a device cookie; devices listed and revocable by Admin.
-
Signatures table and the
signhelper for the sign-off actions of later phases. -
Audit rows for every identity event through the hash-chained audit log.
-
GET /api/events: server-sent events over PostgreSQL LISTEN/NOTIFY with presence. -
Account settings: AD details, PIN create or change, sessions and sign-out-others, own access log, register this device.
-
Admin: read-only AD view of users and any account, devices, PIN clearing with a reason, the group map with missing-group flags, sign-in attempts, and "Refresh from AD now", which enumerates the groups' members and creates or refreshes the users.
-
Frontend: real sign-in (password tab, PIN keypad tab on registered devices), lock screen, role switcher, Account settings, Admin shell, placeholders for the screens of later phases.
-
CLI:
packetstation ad-groups --listandpacketstation ad-refresh. -
Migration 0002: users keyed on the AD objectGUID, user_roles, sessions, devices, user_pins, signin_attempts, signatures, departments and stations seeded with the 18 departments.
-
CI: a Samba Active Directory domain controller container (
PSTEST.LOCAL) with a generated CA, seeded groups and test users; the CI compose overlay and Gitea workflow run it; a Playwright sign-in scenario runs against the stack. -
Phase 0: new repo for the Packet Station rebuild.
-
CLAUDE.md with the safety rules, connection facts, layout, commands and related projects.
-
README with the status, phase list, folder map and how to run.
-
docs/BRIEF.md (the brief, copied verbatim) and docs/PLAN.md (the approved plan, copied verbatim).
-
docs/SECURITY.md rewritten for the server build: the 20 old layers and where each now lives, the new controls, and the requirement ID table with the phase that closes each.
-
docs/DEPLOY.md with the docker-1 host facts, the two stacks, secrets layout, NPM proxy host settings and the pip index rule.
-
Stubs for docs/FEED.md, docs/POLICY.md, docs/SCHEMA.md, docs/GO-LIVE.md and docs/PAPER-FALLBACK.md.
-
.gitignore and .editorconfig.
-
Python package skeleton,
packetstationCLI (doctor,migrate,app,worker), migration runner and first migration (roles and grants). -
Multi-stage Dockerfile, compose files for the test stack and CI, Gitea Actions CI.
-
Security headers, CSP and a build version endpoint.
-
Frontend skeleton (Vite, React, TypeScript) with the PESCO dark theme ported from the old page and self-hosted fonts.
-
The image was built on docker-1 and the CI compose stack ran end to end there: roles, migration, app and worker healthchecks, doctor database checks.