Predecessors are real references now
- data.predecessors holds work-package ids, replacing a free-text SOP phase label
that couldn't express "WP04 waits on WP02" and gated nothing. The SOP phase
survives beside it as the descriptive "Sequence phase" field.
- readiness() has two gates: constraints clear AND every predecessor Closed. The
banner, sticky bar, left rail, dashboard Gates column and the ready counters all
reflect the second one.
- Enforced server-side by enforce_release_gates() on every path that sets a status
— the plain upsert included, since that's how the browser and the offline outbox
save. /issue and /status would otherwise have been ways around it.
- Cycles are refused directly and through a chain, with a message naming the
package that already waits on this one. The Creator's picker also hides itself
and its own descendants, so a cycle is hard to build in the first place.
- A deleted predecessor does not block: it would freeze everything downstream of a
package someone removed.
- The gate is refusable, on purpose. Planners release ahead of upstream close-out,
so an explicit reason (data.gateOverride) allows it, gets a gate_overridden audit
event naming what was skipped, and prints on the package. A blank reason is not
an override, and changing the predecessor set clears it. The dashboard won't
release a blocked package at all — it points at the form where the reason is
captured.
Critical constraints reopened after release
- Reopening a SOP-critical constraint on a released package emails the owner, PM,
CM and the package's distribution list (minus whoever did it) and writes a
constraint_reopened audit event.
- Detected by diffing the incoming constraints against the stored ones inside the
normal upsert rather than via a new endpoint: the sync outbox only replays
POST /api/wps, so a dedicated route would be lost offline. It fires only on a
real cleared→open transition, so re-saving an already-open constraint doesn't
re-announce, and never before release or for a non-critical constraint.
- Bodies carry the constraint name, WP number and a link — never package contents.
Verified: 139 API checks on one fresh database (44 permissions + 22 password reset
+ 34 search/localization + 39 gates/notifications), including every bypass path,
cycle shapes, the deleted-predecessor case, blank-reason overrides, and the four
recipients confirmed both in the outbox and on the wire against a local SMTP sink.
27 driven UI checks against the real Creator page in headless Chrome covering the
picker, the override prompt (accept and cancel), override invalidation, the cycle
exclusions and the dashboard refusal. Screenshots reviewed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Site comments (8/3)
- BIM card: LOD removed, IFF # added next to the coordination status, and required
once that status is "Signed off (IFF)" — an unnumbered sign-off isn't traceable.
A LOD already stored on a package is preserved and shown as legacy, not blanked.
- The blue "from SOP types" subtext under a field is now a SOP chip on the label
with the detail in a tooltip. The chip stays visible rather than hover-only:
field tablets have no hover, and "this came from the SOP" is the part that
matters. The hint elements stay in the DOM (hidden) so the code writing to them
keeps working; an observer mirrors their text into the tooltip.
- Specification Section is no longer typed per package. Each WP type carries a
spec section on the SOP; the field is read-only in the Creator and follows the
type, with the SOP's spec folder linked underneath. This reads both spec
comments as one intent — stop typing it, derive it.
- Assignees and Distribution are multi-selects over the SOP project team, showing
each person's job function, with the CM pre-added to Distribution (removable per
package) and a free-text option for people with no account. The stored display
strings are unchanged so print/export/dashboard keep working; account ids ride
alongside for the notification work in wave 3.
Localization + time
- Per-user locale/timezone (Language & time in the user menu), an app-wide default
in the admin console, then the browser. Timezones are validated against the
server's zoneinfo and the picker is fed from it. Calendar dates are formatted
from their parts so a due date never reads a day early in another zone.
- Every displayed timestamp now goes through the shared helpers.
Top-bar chrome
- Project switcher beside the logo and a centered global search, injected into
either generation of top bar; skipped in an iframe so the embedded Creator
doesn't get a second one. Ctrl/Cmd-K focuses search.
- GET /api/search covers work packages, projects and SOPs, scoped to the caller's
projects, hiding archived packages, with LIKE wildcards escaped.
Fixed along the way: showForm() cleared every card's inline display, which undid
applyKind() — so the Package Type and BIM cards reappeared on an install-only
project. Split out applyKindVisibility() and re-apply it there.
Verified: 100 API checks on a fresh database (44 permissions + 22 password reset +
34 search/localization), 24 driven UI checks against the real Creator page in
headless Chrome (SOP chips, both people pickers, spec auto-fill, critical tags,
BIM suppression), and the chrome harness on both bar styles. Screenshots reviewed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Work Package form was capped at a 1000px column, which wasted most of a
desktop screen, and the only way to reach another package was to scroll to the
Saved table at the bottom.
- Put the form in a wide two-column shell (max 1760px); ctx-bar, mode-wrap and
the release banner widened to match.
- Above 1200px the two-up field grids flow to 3-4 columns instead of stretching
two fields across the whole card. Narrow layouts are unchanged.
- New sticky left rail listing every saved package, grouped by status in field
order, with WP number, subject, readiness dot and type. Click to open it in
the form; the package being edited is highlighted. Filter box, + New and
Dashboard shortcuts, collapsible (state persisted), hidden under 1100px where
the Saved table still covers navigation.
- The rail re-renders from renderSavedList(), so saves, deletes, splits,
archive/restore and the project pull all keep it current.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Brings the Work Package Suite from a browser-local prototype to a
multi-tenant, SQL-backed deployment hardened for customer IP.
Auth & access control
- Local username/password login (bcrypt + JWT in an HttpOnly cookie),
admin-managed users, per-project membership, and project-scoped API access.
- Admin console: change user roles, view the audit trail, manage settings.
Security hardening
- CSP / HSTS / X-Frame-Options / nosniff headers in nginx; Secure cookie via
X-Forwarded-Proto; CSRF Origin check; attribute-safe output escaping.
- Login lockout, token_version session revocation, stronger password policy,
fail-closed secret loading, encrypted (AES-256) database backups.
Persistence & schema
- SOPs and Work Packages are now DB-backed and shared across users, written
through a durable client sync outbox that queues offline edits.
- Alembic migrations applied automatically on container start.
New capabilities
- Phase 2 dashboard (progress, gating, pagination, archive).
- Phase 3 PWA "Field View" with offline caching and auth fallback.
- WP owner assignment with OPTIONAL email notifications, OFF by default and
toggled from the admin console. SMTP password is read only from the
SMTP_PASSWORD env var (never stored); emails carry a WP number + deep link,
never customer IP.
Also: IBM Carbon restyle, Help section, and DEPLOYMENT.md brought up to date.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the whole-project BIM 'mode' with an opt-in capability + a
per-package kind, so a single project can produce both model and
install packages (and install-only projects are unaffected).
SOP tool:
- Step 4 "Include BIM / VDC work packages" checkbox (state.bimEnabled).
Enabling adds BIM package types + BIM release gates (flagged bim) plus
BIM roles/sources/process steps alongside the construction defaults;
disabling strips the bim-flagged items.
- Generated SOP carries bimEnabled and a per-type / per-constraint bim flag.
- Required sign-off role titles stay editable (no longer force-renamed).
Work Package Creator:
- Shows a Package Type selector (Install IWP / BIM EWP) only when the
SOP has bimEnabled; kind is saved per package and labeled in the output.
- WP types and release gates are filtered by kind (BIM types+gates for
EWP, install types+gates for IWP).
- EWP reveals the BIM Details card and hides controls.dev Assets /
Materials / Kitting-MIMO; IWP shows those plus the "Enabled by - BIM
package" traceability link.
Supersedes the earlier whole-project BIM mode.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SOP tool:
- "Load BIM / VDC template" (Step 4): one click sets BIM deliverable
types, install-phase disciplines, BIM release-gate constraints (with
EN06 citations), the BIM process sequence, reference sources, BIM
sign-off roles, and MWP##-[Area]-[PHASE] numbering. Tags the SOP mode
as 'bim'.
- Step 3 required sign-off role titles are now editable (default
Superintendent/Foreman); the BIM template sets them to BIM Coordinator
and Construction Lead (CRS).
- Step 7: capture a project-homepage link for the chosen tracking and
commissioning platforms.
Work Package Creator:
- BIM mode (SOP.mode==='bim'): hides controls.dev Assets, Material List,
and Kitting/MIMO; shows a BIM Details card (LOD, model area, clash /
coordination status, linked scan).
- Project tracking/commissioning links are copied onto every WP and
shown in the WP output.
- "Enabled by - BIM package(s)" field links a field IWP back to the BIM
package that enabled it (EWP -> IWP traceability).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gate the suite behind a self-contained login (no external IdP):
- User model with bcrypt-hashed passwords; admin/user roles
- /api/auth endpoints: login, logout, me, change-password, and
admin-only user management (list/create/delete/reset/enable)
- Stateless JWT session in an HttpOnly, SameSite=Lax, auto-Secure
cookie; middleware refuses every /api data route without a session
- login.html + auth-guard.js: login page and per-page guard with a
top-right "name / Admin / Sign out" pill
- Admin Console now gated on admin role (passphrase gate removed) with
a User administration card
- manage_users.py CLI to bootstrap the first admin
- Rebuilt help.js into a searchable, multi-topic help center
- Local-dev convenience: app serves html/ so the site + API share one
origin under uvicorn (inactive in the prod container)
- Docs/env: AUTH_SECRET_KEY, requirements (bcrypt, PyJWT), README
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Help: shared help.js injects a Help modal (workflow + key concepts) and the
.help-tip tooltip component. "❔ Help" added to the suite header and home nav.
- Tooltips: ⓘ hover hints on the trickiest fields (WP number auto-build,
disciplines, scope/split, constraints, materials-by-discipline, discipline
strategy, split threshold).
- WP creator: sticky section-nav jump chips at the top and an always-visible
sticky save bar (Save Draft / Save & View) showing live release readiness.
- Dashboard: metric cards (Release-ready / On hold / Overdue / Total) and the
status chips are now clickable filters for the board.
- Consistent colored status pills in the dashboard board and the saved list.
Theme unification (home Carbon vs tools palette) intentionally left for a
separate pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Cost codes: drop everything after 4990 (material/quality/admin codes removed).
- WP creator: add "Duplicate" (asks how many copies; each a clean Draft with
unique number/subject, approvals & closeout cleared). When embedded the WP
toolbar now shows only New + Duplicate.
- Condense duplicated toolbars: the embedded creator's Usage Data, Load Example/
Sample SOP, Comments, View SOP and Dashboard buttons are hidden; the suite's
top-right "Usage Logs" and "Load Sample" are the single instances.
- Load Sample is context-aware: SOP tab loads the sample SOP, WP/Dashboard tab
loads the example Work Package in the creator.
- Dashboard moved to a nav-tab next to SOP Configuration / Work Package Creation.
- Remove "Prime Controls" branding from the embedded WP menu.
- Remove "Bill Clarida" from the example WP distribution and the step-comments
name placeholder.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Projects become the top-level container; SOPs and Work Packages belong to one.
Backend:
- New projects table + CRUD (/api/projects).
- sops.project_id (FK, cascade) and work_packages.project_id added;
list/latest/metrics endpoints accept a project_id filter.
Front end (now under html/):
- project-data.js: shared API-first ProjectData adapter with localStorage
fallback + active-project helpers.
- Home page: removed "About This Suite"; added a Project picker (create /
use sample / select). Tool cards stay hidden until a project is active and
carry &project=<id>; hero shows the active project.
- Suite reads ?project, resolves it, shows it in the header, and prefills the
SOP project fields; passes &project into the WP-creator iframe.
- WP creator stamps projectId onto saved packages.
SOP/WP localStorage is not yet namespaced per project (next step).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>