Files
Project-SDE-WP-Suite/ONBOARDING.md
n.siegfried 3c40b58ff8 Add multi-project support: projects entity, picker home page, project context
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>
2026-06-15 15:39:45 -07:00

12 KiB

Project Handoff & History

A curated record of where this project is, the decisions behind it, and what's left — so a teammate (or a fresh Claude Code session) can pick up cleanly. This is a summary of the working sessions, not a verbatim chat transcript.

Last updated: 2026-06-15.

TL;DR — current status

The Work Package Suite is an internal tool for Prime Controls construction projects: configure a project SOP, then author Work Packages against it.

  • Front end: static HTML/CSS/JS, no build step. Two tools surfaced from the home page — SOP Configuration and Work Package Creator — both living in one app (work-package-suite.html) as two tabs. The Creator is embedded via <iframe> (wp-creation-index.html).
  • Back end (NEW, Phase 1 done): a Python/FastAPI API + PostgreSQL under server/ for shared storage of SOPs, Work Packages, and comments.
  • Hosting target: internal, behind the company firewall. NGINX serves the static site and proxies /api/ to the Python API. No outbound internet calls.
  • Next up (Phase 2, NOT started): rewire the front end to read/write the API instead of browser localStorage.

Architecture

browser → NGINX ──serves──> static site (index.html, work-package-suite.html, …)
                └─proxy /api/─> Python API (FastAPI, uvicorn/gunicorn :8000) → PostgreSQL

Today the front end still stores data in localStorage; Phase 2 moves it to the API. The API is already built and testable on its own.

Key decisions (and why)

Decision Choice Rationale
Tool structure One app, two tabs (SOP + WP Creator) Shared state; SOP flows straight into the Creator. Standalone SOP tool was deleted as a duplicate.
WP Creator integration Embedded as an <iframe> The real Creator is a separate, complex app; iframing avoids JS global collisions and reuses it as-is.
Discipline on WP types Removed everywhere Per request — WP types now carry Enabled / Special Rules / WO Complete Approval only. Also removed the derived Discipline field + trade-code in the Creator.
Hosting Internal NGINX, behind firewall Company requirement. Considered IIS (dropped) and SharePoint (can't host a multi-file app).
Database PostgreSQL Site admin is provisioning it; good JSON support for SOP/WP documents. Code uses SQLAlchemy, so it's portable.
Identity Name field only Trust the internal network; users type their name. No login.
Client data model Server-backed (Phase 2 goal) SOPs/WPs/comments shared across users; localStorage becomes a draft cache.
Comments transport API → Postgres Replaces an earlier Power Automate plan; comments now persist to SQL directly.

Timeline (by commit)

Commit What it delivered
c583daa Initial import of the WP Suite files.
2af4b58 Consolidated to two tools (one app, two tabs); restored Rev 0 features — white header, single title, Step Comments in header, usage logs, sample data, APM in Team + Sign-offs, drag-and-drop sequencing, pre-loaded deletable sources, two-card home page, embedded WP Creator.
d2dc6ff Removed discipline from WP types and the Creator; removed external Google-Fonts call (firewall hardening); added Export/Import + a central-feedback hook + DEPLOYMENT.md.
7186d46 First pass wiring feedback through an IIS reverse proxy to Power Automate.
3d4402c Switched that reverse proxy from IIS to NGINX.
a33b777 Phase 1 backend: FastAPI + SQLAlchemy + PostgreSQL (server/); NGINX now proxies /api/ to it; comments persist to SQL; docs rewritten.

Repo map

How to run / deploy

  • API + database: see server/README.md (Postgres setup, dev uvicorn, prod gunicorn + systemd). API docs at /api/docs.
  • Front end + proxy: see DEPLOYMENT.md and nginx-wp-suite.conf.
  • Locally the API runs against a SQLite file with zero config, so it can be tried without Postgres.

What's done vs. pending

Done

  • Two-tool consolidation, all Rev 0 feature restorations, discipline removal.
  • Firewall hardening (no external calls).
  • Export/Import feedback on every surface.
  • Phase 1 backend (API + schema) + NGINX proxy + deploy docs.
  • Discipline strategy, sizing, split & dashboard (branch feat/wp-discipline-split-dashboard) — see below.

Discipline strategy, WP sizing, Split-by-Discipline & Dashboard

Discipline came back — but as a project policy set in the SOP, not a fixed field. The Governance step (SOP config, step 5) now also captures:

  • Disciplines (default Mechanical / Electrical / Tech) — comma list.
  • Discipline strategy (governance.discMode): single (one discipline per WP), multi (one WP bundles disciplines, scope split per discipline), or choice (planner decides per package — build big, split later).
  • Split threshold (governance.sizeHoursMax) — the Creator warns when a package's est. hours exceed it.
  • governance.instanceSuffix = letter (instances get A/B/C suffixes).

In the WP Creator (wp-creation-app.js):

  • A Disciplines picker (hidden unless the SOP defines disciplines). Pick 2+ and the single flat work-step list becomes per-discipline scope sections, each with its own steps and its own status (e.g. Issued — Electrical while Mechanical is still In Progress). Overall WP status rolls up to the least-advanced discipline.
  • ⎘ Split by Discipline turns a multi-discipline package into one instance per discipline: WP01-…WP01A (Mech), WP01B (Elec), WP01C (Tech). Each instance is a single-discipline WP linked to the master via instanceOf / parentNumber; the master is kept as a roll-up (split:true, children:[]).
  • New per-WP fields on the saved object: disciplines, scope ({discipline: [steps]}), discStatus, instanceOf, instanceLabel, parentNumber, split, children.

The Dashboard (📊 in the Creator header; home card Work Package Dashboard; deep-link work-package-suite.html?view=dashboard or …?view=dashboard#…): metrics (total / release-ready / on-hold / overdue / est vs actual hrs), breakdowns by status & discipline, a gating panel (what's blocking each package), and a filterable board with view / edit / issue per package. Masters are excluded from counts so split hours aren't double-counted.

Data source today is localStorage via the WPData adapter in wp-creation-app.js — swap list()/issue()/setStatus() to fetch('/api/wps…') in Phase 2 and the UI is unchanged.

Backend (server/) gained the matching endpoints: POST /api/wps/{id}/issue (refuses if constraints are open — the AWP gate), POST /api/wps/{id}/status, and GET /api/wps/metrics. work_packages gained parent_id and issued_at columns.

Migration caveat: tables are still auto-created on startup, so the new parent_id / issued_at columns appear on a fresh DB only. Before there's real data this is fine; once there is, add Alembic (see open question #2) and migrate rather than relying on create_all.

Multi-project support

Note on layout: the IT admin moved all static files into html/ and added a Docker/NGINX deployment (Dockerfile, docker-compose.yml, nginx/). Front-end paths below are under html/. server/ stayed at the repo root.

The suite is now multi-project. Projects are the top-level container; every SOP and Work Package belongs to one.

  • Backend: new projects table + CRUD (/api/projects). sops gained project_id (FK, cascade) and work_packages gained project_id; list/latest/ metrics endpoints accept a project_id filter.
  • Project layer: html/project-data.js — a shared, API-first ProjectData adapter (list/get/save/remove hit /api/projects) that falls back to a localStorage mirror (wp_projects) when the API is unreachable, plus active-project helpers (getActive/setActive, stored in wp_active_project / wp_active_project_obj).
  • Home page (html/index.html): "About This Suite" removed; a Project picker added. With no projects it offers Create Project / Use Sample Project; otherwise a dropdown to select. The tool cards stay hidden until a project is active and then carry &project=<id>; the hero shows the active project.
  • Suite (html/work-package-suite-app.js): reads ?project=<id>, resolves it via ProjectData, shows it in the header, and prefills the SOP project fields (step 1) from the project record when empty. Passes &project into the WP-creator iframe.
  • WP creator: stamps projectId onto every saved package (for API sync).

Not yet done (the next fork): SOP/WP localStorage is still global, not namespaced per project — selecting a different project locally still shows the same wp_suite_sop / wp_iwp_v1 data. The intended end state is per-project data via the API (GET /api/sops/latest?project_id=…, GET /api/wps?project_id=…). Decide whether to (a) namespace the local keys by project id with a migration of existing un-namespaced data into a "default" project, or (b) jump straight to the API for SOP/WP reads. See the open question below.

Pending — Phase 2: wire the front end to the API

  • SOP: on SOP Complete, POST /api/sops; on load, GET /api/sops/latest to hydrate the Creator (currently uses localStorage key wp_suite_sop).
  • WP Creator: save packages via POST /api/wps; list/load via GET /api/wps (currently localStorage). It reads the active SOP from GET /api/sops/latest.
  • Comments already post to /api/feedback → the API; the list views could be switched from localStorage to GET /api/comments.
  • Keep localStorage as an offline draft cache / fallback.

Open questions for whoever continues

  1. Projects: the DB supports many SOPs, but the UI assumes one active SOP ("latest"). Do we need a project picker?
  2. Migrations: tables are auto-created on startup. Before real data, decide on Alembic for future schema changes.
  3. Power App view: if still wanted, point it at the Postgres comments / work_packages tables via the on-prem data gateway (no app change needed).
  4. Backups / retention for the Postgres database (ask the site admin).

Continuing with Claude Code

Open this repo in Claude Code and start with: "Read ONBOARDING.md and DEPLOYMENT.md, then help me with Phase 2 — wiring the front end to the API." The commit messages above are a reliable trail of what changed and why.