PSI Explorer Web

Unified web portal for PSI manufacturing intelligence. A React application providing project management, BOM visualization, Gantt job analytics, PLC fleet analysis, lead time tracking, and AI-powered machine intelligence via real-time UniData connectivity.


Overview

PSI Explorer Web is a React single-page application that displays BOM (Bill of Materials) data from the AFTEC ERP system via the PSI.UniData.API gateway.

| Feature | Description | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | Tree View | Hierarchical expandable BOM display | | Table View | Flat sortable/filterable table with CSV export | | Part Details | Click any part to see inventory and specs | | PLC Fleet | Fleet-wide PLC dashboard with project drill-down to per-project analysis, I/O verification, scorecards, intent, history, similar projects, and CSV export | | Ask the Fleet | AI chat panel powered by Azure OpenAI + MCP tools for natural language machine queries | | Machine Explorer | CS/field service focused machine intelligence portal — split-view layout with persistent AI chat panel + 6 tabs: Overview, Active Work, Service History, Parts & BOM, Drawings, Controls. Photo gallery from MultiMedia + K: drive. Deep-linkable via #machine/{job}/{tab} | | PC Fleet | Dell PC fleet dashboard — 640+ PCs across machines, age/warranty tracking, Windows version badges, upgrade letter generation | | Gantt Charts | Job-level Gantt analytics for 2,327 jobs — sortable table, drill-down heatmap (Year>Quarter>Month>Week), velocity chart, multi-job compare, single-job viewer with employee/handoff/redbook/ECN/inventory popups | | Lead Time | Root cause analysis across 2,500+ projects (216 columns) with 8 analysis views, P2/P98/P50 dept milestones, idle time tracking | | Performance | Full BOM loads in ~200-300ms | | Authentication | Azure AD (MSAL.js) or anonymous dev mode |

PropertyValue
Live SiteBomExplorer.progressivesurface.com
RepositoryProgressiveSurface/psi-explorer-web
APIapi.progressivesurface.com
HostingAzure App Service (Express.js)
AccessInternal only (VPN required)

Deployment

Production Configuration

SettingValue
App Servicepsi-explorer-web
Resource GroupPS-WEBAPPS
Custom Domainexplorer.progressivesurface.com
Private Endpointbom-explorer-web-pe
Internal IP10.160.0.17
Public AccessDisabled
HTTPS OnlyEnabled
SSL CertificateWildcard from Key Vault (ps-certificates-kv)
VNet IntegrationPS-WebApps subnet

Network Architecture

User (VPN) → DNS (10.160.0.5) → 10.160.0.17 → Azure App Service
                                     ↓
                               Private Endpoint
                               (PS-SERVERS subnet)

The app is internal-only - users must be on VPN or the corporate network to access it.

Production Stack

| Component | Technology | | --------- | ---------------------------------- | ------------------------------------------------- | | Frontend | React 18 SPA (Vite build) | | Server | Express.js (server.js) | | Hosting | Azure App Service (Linux, Node 20) | | API | PSI.UniData.API at api.progressivesurface.com |

CI/CD

The application auto-builds and deploys via GitHub Actions:

  1. npm install - Install dependencies
  2. npm run build - Build React app (outputs to dist/)
  3. Deploy to Azure App Service
  4. Express server serves static files from dist/

Environment Configuration

Development (.env or defaults):

VITE_API_URL=/api          # Proxied through Vite dev server
VITE_USE_DEV_ENDPOINTS=true

Production (.env.production):

VITE_API_URL=https://api.progressivesurface.com/api
VITE_USE_DEV_ENDPOINTS=true

CORS Configuration

The PSI.UniData.API must include this origin in its CORS allowed list (appsettings.json):

"Cors": {
  "AllowedOrigins": [
    "https://explorer.progressivesurface.com"
  ]
}

Features

Tree View

  • Expandable/collapsible hierarchy
  • Color-coded GT codes (Purchased=green, Manufactured=blue)
  • Auto-expands first two levels
  • Click part to view details

Table View

  • Sort by any column
  • Filter by part number, description, or GT code
  • CSV export with one click
  • Shows all BOM items flat

Part Detail Card

  • Part number and description
  • GT code and UOM
  • Lead times (Mfg, Purchase, Cumulative)
  • Inventory (On Hand, On Order, Available, Allocated)
  • BOM indicator

Statistics

  • Total parts count
  • Max BOM depth
  • Load time (ms)
  • Database calls made

Ask the Fleet (AI Chat)

Any PSI employee can ask questions about any machine in plain English — no AI tools, no configuration, no training. Click “Ask the Fleet” in the bottom-right corner (or press Ctrl+K) and type a question. This is the first production application consuming the PSI Machine Intelligence MCP Server.

What it does: The AI can call any combination of MCP tools — project lookup, BOM explosion, PLC analysis, fault diagnosis, inventory checks, drawing searches, vendor data, cost analysis — and returns streaming answers with rich result cards. Clicking a part number or job number in the response navigates directly to that item in PSI Explorer.

PLC analysis data: When users ask about PLC programs, the AI uses pre-converted L5X files and analysis JSON from the PLC Fleet Catalog — covering 507 Allen-Bradley Logix 5000 projects, plus 414 SLC 500, 248 CNC, and 252 robot programs across 1,391 projects fleet-wide. See L5X Tools for the conversion pipeline.

Example questions:

  • “What is project 2399? Who’s on the team?”
  • “Show me the BOM for job 2386”
  • “Diagnose the low air pressure fault on 2399”
  • “Check inventory for part 069995”
  • “Compare projects 2399 and 2386”
  • “What machines are similar to 2224?”

How it works:

User (browser) → ChatPanel (React)
    → POST /api/chat (SSE stream)
    → Express chat-engine (async generator agentic loop)
        → Azure OpenAI GPT 5.2 (with MCP tool definitions)
            ↔ MCP Client (@modelcontextprotocol/sdk)
                → PS-PROXY:3100 (MCP Server)
                    → UniData API, file shares, PLC analyzers
        ← Streaming text + tool result events (SSE)
    ← Rich cards, markdown, clickable navigation

The Express.js backend connects to PS-PROXY:3100 as an MCP client at startup, discovers all available tools, and converts their schemas to the OpenAI tool format. When a user sends a message, the chat engine runs an agentic loop: it sends the conversation + tool definitions to GPT 5.2, streams text back as SSE events, and when the model calls tools, it executes them via MCP and feeds the results back to the model. This loop repeats until the model produces a final text response.

Key implementation details:

  • SSE streaming with async generators for clean backpressure handling
  • Rich tool result cards — project cards, BOM summaries, fault trace chains, inventory status with color coding
  • Dual provider support — Azure OpenAI (primary) or Claude via Azure AI Foundry, auto-selected by env vars
  • Conversation persistence in localStorage (client) and in-memory Map (server)
  • Context-aware suggested questions when the chat is empty

Backend files: server/mcp-client.js, server/chat-engine.js, server/chat-routes.js Frontend: src/components/chat/ (ChatPanel, ChatInput, ChatMessage, ToolResultCard, SuggestedQuestions)

Environment variables (set one provider):

VariableDescription
AZURE_OPENAI_ENDPOINTAzure OpenAI endpoint URL
AZURE_OPENAI_API_KEYAzure OpenAI API key
AZURE_OPENAI_API_VERSIONAPI version (default: 2025-04-01-preview)
AZURE_OPENAI_MODELModel deployment name (default: gpt-5.2-chat)
ANTHROPIC_FOUNDRY_API_KEYAlternative: API key from Azure AI Foundry (for Claude)
CLAUDE_MODELClaude model ID (default: claude-sonnet-4-6)
MCP_SERVER_URLMCP server URL — must use FQDN on Azure (default: http://ps-proxy:3100/mcp, production: http://ps-proxy.ad.ptihome.com:3100/mcp)

PLC Fleet Dashboard

Top-level nav page for fleet-wide PLC analysis across all 88 archived Allen-Bradley projects. Provides fleet aggregates and per-project drill-down — click any job number or enter one directly to open the full project PLC view.

Fleet-level views:

  • Fleet Stats — total projects, rungs, modules, tags
  • Scorecard Summary — fleet averages across 4 dimensions (complexity, safety, reuse, documentation), distribution bar (good/fair/poor), sortable project table with pagination and CSV export
  • Processor Distribution — horizontal bar chart of processor types across fleet
  • Module Distribution — top 10 most-used I/O modules
  • Fleet Reuse & Adoption — horizontal bar charts showing top routines, UDTs, and tag prefixes by adoption rate across fleet
  • Recent Changes — nightly scan results with job-level change entries
  • Fleet Search — search tags, modules, or programs across all projects (regex)
  • Project Comparison — side-by-side controller/tag/module/program diff between any two projects

Per-project drill-down (8 sub-tabs):

Sub-TabWhat It Shows
ModulesI/O module table with slot, catalog #, name, type badge, firmware version, RPI (color-coded if slow), IP address, status (FAULT/INHIBITED/OK). Risk highlighting on fault/inhibited rows. Filter by name, catalog, type, vendor, productType. Sortable by all columns. CSV export.
TagsController tags with data type badge, constant flag (lock icon), dimensions, tag type, access. Type dropdown filter. Quick filter chips (All/Faults/Timers/Counters). “Used by” cross-reference chips showing which routines output each tag (from intent data). Paginated (50/page). CSV export.
ProgramsExpandable program tree with routine details. Search filter (programs + routines by name). Intent analysis: routine descriptions, functional area badges, complexity indicators, key states, outputs, expandable safety dependencies. Program-level safety features. Click any routine to view its full source — ladder logic rung text with syntax highlighting (XIC/XIO, OTE/OTL, TON/CTU, JSR, MOV/EQU), line numbers, search within routine, and copy-to-clipboard.
HistoryVersion timeline with date, engineer, confidence badge, summary. Inline change deltas: +/- tags (green/red), ~modified (amber), +/- modules, +/- rungs. Click to expand and see actual tag/module names.
Scorecard4-dimension quality score (Complexity, Safety, Reuse, Documentation) with progress bars, overall score, individual findings with confidence levels. Null-safe rendering — displays available dimensions even if MCP returns partial data.
I/O VerifyCross-references PLC modules with project BOM. Two-pass matching (description substring + parts search fallback). Shows matched/unmatched modules, BOM items not in PLC, spare parts summary with stock status (None/Low/OK). CSV export.
CompareSide-by-side comparison with another project: controller diff, tag/module/program counts, tags unique to each, summary.
SimilarFind projects with the same machine type or customer. Shows ranked list with job number, description, machine type, and status. Uses find_similar_machines MCP tool.

Controller summary bar (shown on all sub-tabs): Processor type, firmware version, source file, creation date, last modified date, safety program badge (green if present, amber if missing), security badge (if secured).

Files: src/components/plc/ — PlcFleetPage.tsx, PlcTab.tsx, ModuleInventory.tsx, TagBrowser.tsx, ProgramTree.tsx, VersionTimeline.tsx, Scorecard.tsx, IoVerify.tsx, ProjectCompare.tsx

Data source: PLC Fleet Archive via MCP Server at PS-PROXY:3100. Analysis JSONs generated nightly from K: drive ACD files. See PLC Code Intelligence for the full vision.

Machine Explorer

Top-level nav page (#machine / #machine/{jobNumber}) designed for CS managers and field service engineers servicing machines post-ship. Split-view layout with persistent AI chat panel on the right.

Target users: CS managers on customer calls, field service engineers preparing for site visits, spare parts/aftermarket support. Not primarily for in-build project management.

Layout: Split view — machine content area (left, ~65%) with header + lifecycle timeline + 6 tabs. Persistent AI chat panel (right, ~35%) auto-scoped to the current machine, powered by Azure OpenAI + MCP tools.

Navigation: Enter a job number (e.g. 2399) for direct navigation, an S-prefixed serial number (e.g. S3501) to look up a machine by serial, or any free-text query (customer, description, quote) to search. The S prefix is required for serial lookup because job and serial numbers overlap in the 2400–3600 range — bare numerics are always treated as job numbers. Deep-link URLs: #machine/{job}/{tab} where tab is one of: overview, active-work, service-history, parts-bom, drawings, controls. Browser back/forward preserves tab state.

Header: Machine photo (from MultiMedia + K: drive, click to open fullscreen gallery), then two prominent identity blocks side-by-side — PROJECT {job} and MACHINE S{serial} — followed by customer, description, status badge, warranty status, robot badge, machine type, ship date (formatted), team members, quick links (copy K: drive path, copy video path, BOM link). The 4–5 digit number is the project number; the actual machine is identified by its serial (rendered with an S prefix). AI executive summary (“What is this machine?”) below the header.

Lifecycle timeline: Horizontal bar: Order → Engineering → Manufacturing → Ship → Field Service. Uses department P2/P98 dates from Azure SQL + project info dates. Current phase highlighted.

Photo gallery: Near-fullscreen lightbox with carousel navigation, keyboard arrows, photo counter, source labels. Photos aggregated from two sources: MultiMedia Lo Res Project Files (\\ad.ptihome.com\DFS\DATA\MultiMedia\Photo\Lo Res Project Files\{job}) and K: drive (K:\PROJECT\{job}\photos\).

AI Chat Panel: Persistent right panel reusing chat-engine.js backend. Machine context (job, customer, type, serial, team) injected as system message on first query. Suggested question chips for CS use cases. Rich responses with clickable links to parts, drawings, RFCs. Collapsible. Chat history persists across tab switches.

Tabs (6 total):

TabData SourceWhat It Shows
Overviewget_ai_assessment + get_rfcs (MCP) + Azure SQL handoff_extractions + machine_dna_features + lessons_learned + list_project_files”What is this machine?” AI summary, Watch Out / known issues & risks, Resources grid (design review video, vendor manuals, drawings, K: drive), Quick Stats (RFCs, open issues, resolved, WOs), Lessons Learned
Active Workget_rfcs (MCP, filtered to open) + Azure SQL purchase_ordersOpen RFCs / service issues (cards with severity, age, expandable detail), Open Quotes (placeholder for future), Open Purchase Orders (table)
Service Historyget_rfcs (MCP) + Azure SQL redbooks + ecn_detail + ncn_detailOpen items section (prominent red cards at top), Summary bar (total issues, quality cost, avg resolution), Searchable/filterable closed history timeline merging RFCs + Redbooks + ECNs + NCNs
Parts & BOMget_bom + get_part_details + get_part_manufacturer + get_part_vendors + get_inventory_status + get_drawing_metadata + assess_obsolescence_risk (MCP)BOM table with search, part detail panel (manufacturer, vendor, inventory with serial numbers, engineering files), obsolescence risk (real ERP INC/OBS flags)
Drawingsget_electrical_drawing_index (MCP)Drawing index with search/filter, category breakdown, sortable table, PDF links
Controlsget_plc_analysis + get_ai_assessment (MCP)Full PlcTab — modules, tags, programs, history, scorecard, I/O verify, compare, similar. Fault catalog and safety assessment moved here from former Quality tab

Backend:

  • server/machine-routes.js — 39 Express routes proxying MCP tools (original 13 + Phase 5 diagnostics/tracing/photos)
  • server/analytics-routes.js — 11 Azure SQL routes querying PSI_Analytics (labor, departments, workforce, redbooks, ECNs, NCNs, Machine DNA, purchase orders, change orders, handoff, budget vs actual)
  • server/analytics-db.js — Azure SQL connection via Azure AD managed identity (no credentials needed)
  • server/chat-engine.js — Extended with machineContext parameter for scoped conversations
  • server/chat-routes.jsPOST /api/chat accepts optional machineContext object

Frontend files:

  • src/components/machine/ — MachineExplorerPage, MachineSearch, MachineHeader, PhotoGallery, MachineChatPanel, OverviewTab, ActiveWorkTab, ServiceHistoryTab, ControlsTab, SupplyChainTab, DrawingsTab, LifecycleTimeline
  • src/components/shared/ErrorBoundary.tsx — React error boundary wrapping each tab
  • src/hooks/useMachine.ts — 32 React Query hooks (lazy-loaded per active tab)
  • src/hooks/useAnalytics.ts — 11 React Query hooks for Azure SQL analytics
  • src/services/machineApi.ts — typed API client (38 endpoints)
  • src/services/analyticsApi.ts — typed API client (11 endpoints)
  • src/services/chat.ts — SSE streaming chat client with machineContext support
  • src/types/machine.ts — TypeScript interfaces (MachineTab: 6 tabs)
  • src/lib/dateUtils.ts — shared date formatting (“Dec 5, 2024” format)
  • src/lib/navigation.ts — programmatic navigation utility

Testing:

  • src/components/machine/__tests__/null-safety.test.tsx — 24 tests verifying all components render without crashing when data is undefined/null/partial. Runs in CI on every push.

Removed tabs (files retained in codebase, accessible via AI chat panel):

  • Quality → replaced by Service History + Controls (fault catalog/safety moved)
  • Manufacturing → data available via AI panel
  • Commissioning → data folded into Overview (risks, handoff) + AI panel
  • Fleet Context → data available via AI panel

PC Fleet Dashboard

Top-level nav page (#pc-fleet) for tracking Dell PCs deployed inside PSI machines running PRIMS/CITS HMI software. Accessed via the Monitor icon in the left navigation bar.

What it tracks: 640+ PCs across the fleet (619 with Dell service tags), joined with project data to show customer and machine context alongside PC hardware status.

Two views:

  • Machine-centric view (default) — groups PCs by project, shows PC replacement timeline (original → retrofit replacements), highlights current vs. replaced PCs
  • Flat view — every PC as a sortable row for fleet-wide analysis

Key features:

  • Age color coding (green <5yr, amber 5-8yr, red 8-10yr, dark red >10yr)
  • Windows version badges (Win 11/10/7/XP with color severity)
  • Dell warranty status with dates and service levels
  • Text search, OS filter, warranty filter, age range filter
  • Summary cards (current PC count, warranty breakdown, legacy OS count, average age)
  • Generate Upgrade Letter — personalized customer template for PC replacement proposals

Data flow: PRIMS Installations spreadsheet → load_prims_standalone.pypsi_ingest.db → Dell Command Warranty enrichment → publish_ingest_tables.pypsi_analytics.db passthrough copy → sync_table_to_azure.py → Azure SQL → /api/analytics/pc-fleet endpoint → React page.

Production source of truth: PSI Explorer’s analytics routes query Azure SQL PSI_Analytics directly. The SQLite files on PS-PROXY (psi_ingest.db, psi_analytics.db) are upstream pipeline stages used to build and publish that Azure SQL data, not the app’s live database.

Files: src/components/pc-fleet/PcFleetPage.tsx, server/analytics-routes.js (pc-fleet endpoint)

Full documentation: PC Fleet Management


Tech Stack

TechnologyPurpose
React 18UI framework
ViteBuild tool and dev server
TypeScriptType safety
TailwindCSSStyling
React QueryData fetching and caching
MSAL ReactAzure AD authentication
Lucide ReactIcons
Express.jsProduction server
openaiAzure OpenAI GPT 5.2 (chat engine, primary)
@anthropic-ai/foundry-sdkClaude API via Azure AI Foundry (chat engine, alternative)
@modelcontextprotocol/sdkMCP client for PS-PROXY tool access

Project Structure

psi-explorer-web/
├── package.json
├── server.js               # Express production server (+ chat routes + MCP init)
├── vite.config.ts          # Dev server, proxy config
├── tailwind.config.js      # TailwindCSS theme
├── tsconfig.json
├── .env.example            # Environment template
├── .env.production         # Production API config
├── index.html
├── server/
│   ├── mcp-client.js       # MCP connection to PS-PROXY:3100
│   ├── chat-engine.js      # Agentic loop (Azure OpenAI / Claude + MCP)
│   ├── chat-routes.js      # Express routes for /api/chat
│   ├── plc-routes.js       # Express routes for /api/plc (MCP proxy)
│   ├── machine-routes.js   # Express routes for /api/machine (26 MCP proxies)
│   ├── analytics-routes.js # Express routes for /api/analytics (10 Azure SQL routes)
│   └── analytics-db.js     # Azure SQL connection pool (PSI_Analytics)
├── src/
│   ├── main.tsx            # Entry point
│   ├── App.tsx             # Main application (+ ChatPanel)
│   ├── index.css           # Tailwind imports
│   ├── vite-env.d.ts       # Environment types
│   ├── components/
│   │   ├── BomTree.tsx     # Hierarchical tree view
│   │   ├── BomTable.tsx    # Flat table with sorting
│   │   ├── BomStats.tsx    # Summary statistics
│   │   ├── JobSearch.tsx   # Search input
│   │   ├── PartCard.tsx    # Part detail panel
│   │   ├── chat/
│   │   │   ├── ChatPanel.tsx          # Floating panel (toggle/Ctrl+K)
│   │   │   ├── ChatInput.tsx          # Text input + send
│   │   │   ├── ChatMessage.tsx        # Message bubbles + markdown
│   │   │   ├── ToolResultCard.tsx     # Rich tool result cards
│   │   │   └── SuggestedQuestions.tsx  # Context-aware question chips
│   │   ├── machine/
│   │   │   ├── MachineExplorerPage.tsx  # Page shell (search + detail + tabs)
│   │   │   ├── MachineSearch.tsx        # Search + recent machines
│   │   │   ├── MachineHeader.tsx        # Identity banner
│   │   │   ├── OverviewTab.tsx          # Dashboard cards + scorecard + Machine DNA
│   │   │   ├── ControlsTab.tsx          # PlcTab reuse wrapper
│   │   │   ├── QualityTab.tsx           # RFCs + AI assessment + Redbooks/ECNs/NCNs
│   │   │   ├── ManufacturingTab.tsx     # Labor charts + dept summary + workforce
│   │   │   ├── SupplyChainTab.tsx       # BOM + part details + obsolescence
│   │   │   ├── DrawingsTab.tsx          # Drawing index + search/filter
│   │   │   ├── CommissioningTab.tsx     # Readiness + AI checklist + handoff
│   │   │   └── FleetTab.tsx             # Lineage + siblings + comparison + radar
│   │   └── plc/
│   │       ├── PlcFleetPage.tsx   # Fleet dashboard + project drill-down
│   │       ├── PlcTab.tsx         # Per-project sub-tab orchestrator
│   │       ├── ModuleInventory.tsx # Modules table (health, risk, FW)
│   │       ├── TagBrowser.tsx     # Tag table (search, type filter, used-by)
│   │       ├── ProgramTree.tsx    # Program tree (intent, search, safety)
│   │       ├── VersionTimeline.tsx # History timeline (change deltas)
│   │       ├── Scorecard.tsx      # Quality scorecard display
│   │       ├── IoVerify.tsx       # BOM ↔ PLC module matching
│   │       └── ProjectCompare.tsx # Cross-project comparison
│   ├── hooks/
│   │   ├── useBom.ts       # BOM React Query hooks
│   │   ├── usePlc.ts       # PLC React Query hooks (analysis, history, changes, compare, fleet)
│   │   ├── useMachine.ts   # Machine Explorer React Query hooks (20 hooks)
│   │   ├── useAnalytics.ts # Analytics React Query hooks (10 hooks, Azure SQL)
│   │   ├── useBomModuleMatch.ts  # BOM ↔ PLC module matching hook
│   │   └── useChat.ts      # Chat state + localStorage persistence
│   ├── lib/
│   │   ├── bomModuleMatch.ts     # Pure BOM ↔ module matching logic
│   │   ├── plcExportUtils.ts     # CSV export for PLC tables (modules, tags, scorecards, I/O verify)
│   │   ├── plcScorecard.ts       # Scorecard scoring algorithms
│   │   └── navigation.ts         # Programmatic nav utility (navigateToMachine)
│   ├── services/
│   │   ├── api.ts          # REST API client (BOM + parts)
│   │   ├── plcApi.ts       # PLC API client (analysis, history, fleet, intent)
│   │   ├── machineApi.ts   # Machine Explorer API client (26 endpoints)
│   │   ├── analyticsApi.ts # Analytics API client (10 endpoints, Azure SQL)
│   │   └── chat.ts         # SSE streaming client for /api/chat
│   ├── auth/
│   │   └── msalConfig.ts   # Azure AD config
│   └── types/
│       ├── bom.ts          # BOM TypeScript interfaces
│       ├── plc.ts          # PLC TypeScript interfaces (analysis, history, scorecard, intent)
│       ├── machine.ts      # Machine Explorer interfaces (info, summary, assessment, rfcs, etc.)
│       ├── analytics.ts    # Analytics interfaces (labor, redbooks, ECNs, NCNs, DNA, etc.)
│       └── chat.ts         # Chat TypeScript interfaces
└── dist/                   # Build output (served by Express)

Running Locally

Prerequisites

Install and Run (Development)

cd C:\GIT\psi-explorer-web
 
# Install dependencies
npm install
 
# Start dev server (with Vite proxy)
npm run dev

Access at http://localhost:5173

Run Production Build Locally

# Build the app
npm run build
 
# Start Express server
npm start

Access at http://localhost:8080

Network Access

To access from other machines in development:

  1. Set host: true in vite.config.ts (already configured)
  2. Add machine names to allowedHosts
  3. Run npm run dev
  4. Access via http://PCNAME:5173

Key Components

server.js (Production Server)

Express server for Azure App Service deployment. Initializes MCP client at startup and registers chat API routes:

import express from "express"
import { connect as connectMcp } from "./server/mcp-client.js"
import chatRoutes from "./server/chat-routes.js"
 
const app = express()
app.use(express.json())
app.use(express.static("dist"))
app.use(chatRoutes) // /api/chat (POST), /api/chat/tools (GET)
 
// Health check, SPA fallback...
 
async function start() {
  await connectMcp() // Connect to PS-PROXY:3100/mcp
  app.listen(PORT)
}
start()

BomTree.tsx

Recursive tree component with expand/collapse:

function BomTreeItem({ node, onSelectPart, depth }) {
  const [expanded, setExpanded] = useState(node.expanded)
 
  return (
    <div style={{ paddingLeft: depth * 20 }}>
      <div onClick={() => onSelectPart(node.partNumber)}>
        {node.hasChildren && <ChevronIcon expanded={expanded} />}
        {getGTCodeIcon(node.gtCode)}
        <span>{node.partNumber}</span>
        <span>{node.description}</span>
      </div>
      {expanded &&
        node.children.map((child) => (
          <BomTreeItem key={child.wbsNumber} node={child} depth={depth + 1} />
        ))}
    </div>
  )
}

useBom.ts

React Query hooks for data fetching:

export function useBomByJob(jobNumber: string | null) {
  return useQuery({
    queryKey: ["bom", "job", jobNumber],
    queryFn: async () => {
      const response = await bomApi.getByJob(jobNumber)
      return {
        ...response,
        tree: buildBomTree(response.items), // Convert flat to tree
      }
    },
    enabled: !!jobNumber,
    staleTime: 5 * 60 * 1000, // Cache for 5 minutes
  })
}

api.ts

API client with dev/prod endpoint switching:

const API_BASE_URL = import.meta.env.VITE_API_URL || "/api"
const USE_DEV_ENDPOINTS = import.meta.env.VITE_USE_DEV_ENDPOINTS === "true" || true
 
export const bomApi = {
  getByJob: async (jobNumber: string): Promise<BomResponse> => {
    const endpoint = USE_DEV_ENDPOINTS ? `/bom/dev/job/${jobNumber}` : `/bom/job/${jobNumber}`
    return fetchApi(endpoint)
  },
}

Data Types

BomItem

interface BomItem {
  level: number
  wbsNumber: string
  parentPartNumber: string | null
  partNumber: string
  description: string
  gtCode: string
  quantity: number
  onHand: number
  onOrder: number
  available: number
  hasChildren: boolean
  isPurchased: boolean
  isManufactured: boolean
  jobNumber: string
}

BomTreeNode

interface BomTreeNode extends BomItem {
  children: BomTreeNode[]
  expanded: boolean
}

Building for Production

npm run build

Output in dist/ folder. The postinstall script automatically runs the build.

Package Scripts

{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "start": "node server.js",
    "postinstall": "npm run build"
  }
}

GT Code Colors

GT CodeTypeColor
PU, VMPurchasedGreen
FA, MOManufacturedBlue
ASAssemblyPurple
Other-Gray

Screenshots

Tree View

▼ 841782 - Torit Dust Coll. Retrofit          Qty: 1  [RETROFIT]
  ▼ 806038 - W/o 95188 Retrofit Electrical    Qty: 1  [RETROFIT]
    ▸ 003419 - 800mr-pt16rs Pilot Light       Qty: 1  [LT]
    ▸ 003054 - 700-p400-a1 Relay 4p 120vac    Qty: 1  [RELAY]
    ▸ 005756 - V130la10a Varistor             Qty: 1  [VARISTOR]

Statistics Bar

┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 📦 40      │ │ 📊 2       │ │ ⏱️ 0.2s    │ │ 🔗 16      │
│ Total Parts│ │ Max Depth  │ │ Load Time  │ │ DB Calls   │
└────────────┘ └────────────┘ └────────────┘ └────────────┘

Lead Time Analysis

Root cause analysis module for understanding why PSI lead times increased 50-68% since 2022. Accessible via the “Lead Time” tab. Analyzes 216+ data columns across 2,569 projects spanning 24 years (2001–2025), including P2/P98/P50 substantial engagement milestones, department idle time, engineering cascade effects, and ECN-driven complexity metrics.

Key Findings

The deep-dive analysis (March 2026) identified these root causes:

  • Idle time is the real problem: Work hours grew 25% but calendar time grew 68%. The gap is idle time — departments waiting for upstream work, materials, or decisions. Engineering and Machine Shop are 89-91% idle.
  • Engineering cascade proven: Engineering completion (P98) drives downstream department start (P2) with r=0.70–0.83 correlation. Late engineering finish cascades through the entire project.
  • ECN as complexity proxy: ECN count is the strongest single predictor of engineering hours (r=0.72) and quality rework (r=0.82). High-ECN projects take 20% longer and consume 54% more labor.
  • Vendor lead times doubled: Work order cycle times went from 65 to 117 days.
  • Quote inflation masks the problem: Planned lead times grew +90 days, making OTD% unreliable as a root cause metric.

Eras

Projects are grouped into business eras for comparison:

EraYearsDescription
Baseline2017–2021Steady-state operations
Overload2022–2023Too many concurrent projects
Current2024–presentPost-correction period

Views (8 tabs)

ViewDescription
Root CausesHeadline idle time analysis: work vs idle stacked bars per era, department queue ratio cards (8 depts), engineering cascade correlation badges, ECN trend summary, era comparison stats
ExplorerSortable/filterable project table with human-readable column names, CSV export, click-to-detail popup
CorrelationTop 25 metrics correlated with Days Late (or Lead Time / On Time), with scatter plot + plain-English explanation panel and correlation strength badge
Era ComparisonSide-by-side era cards with delta-vs-baseline indicators for 13 metrics including idle %, work hours, P2P98 spans, WO cycle time, and ECN count
Dept HeatmapYear-over-year heatmap for 8 departments with 6 metric options: Budget %, Hours, Span, P2P98 Span, Idle %, ECN Count. Color logic varies by metric (absolute thresholds, YoY delta, percentile).
Dept FlowEngineering cascade visualization: upstream→downstream scatter plots (4 pairs), “Everything Starts Later” table, engineering span growth charts, ECN impact on cascade, capacity vs OTD (de-emphasized)
Findings11 data-driven findings ranked by evidence strength (Definitive / Strong / Contributing / Contradicted), with leadership-friendly expanded cards (What we think / How we tested / What the data shows / Uncertainty / Recommendations)
TimelineSummary mode: median dept activity bars per ship year. Individual mode: Gantt-style per-project bars with P2/P98 substantial engagement (solid core) and First/Last tails (faded), P50 midpoint markers, idle % tooltips

P2/P98/P50 Milestones

Department engagement dates computed from daily labor hours (tslabor2):

MilestoneDefinition
P2 (Substantial Start)Date when 2% of cumulative labor hours reached — trims early check-ins
P50 (Work Midpoint)Date when 50% of cumulative labor hours reached
P98 (Substantial End)Date when 98% of cumulative labor hours reached — trims late punch-list entries
Queue RatioP2P98 calendar span ÷ (total hours / 8). Ratio of 1.0 = working every day; 10x = 90% idle

Key UI Features

  • Human-readable labels: All 216+ raw CSV column names mapped to plain English
  • View descriptions: Each tab shows a plain-English explanation of what the view shows
  • Expandable glossary: Key terms (P2/P98, Queue Ratio, Idle %, Cascade, OTD, ECN, etc.) defined inline
  • Era year ranges: Every era chip, card, and label shows the year range
  • Filter bar: Era toggle chips, search by job/customer, OTD filter, internal project toggle
  • OTD de-emphasis: OTD % is shown but flagged as unreliable for root cause analysis due to quote inflation (Finding F11)
  • Graceful degradation: Views fall back to First/Last dates when P2/P98 data is unavailable

Data Pipeline

Project data is built by build_comprehensive_dataset.py (Python, runs nightly at 1 AM ET on PS-PROXY) from UniData tables including tslabor2, purchaseorders, pohist, bom_receipts, gantt_job_revisions, ecn data, and redbook records. Output: \\ad.ptihome.com\DFS\Schedule\SS123\LEADTIME\comprehensive_dataset.csv (2,569 rows × 216+ columns). Served via PSI.UniData.API (/api/leadtime/dev/projects and /api/leadtime/dev/scorecard) with 5-minute cache and auto-refresh on file change.


Gantt Charts

Job-level Gantt analytics page accessible via the “Gantt” tab (#gantt). Replaces a monolithic 36K-line vanilla JS page with modular React components. Covers 2,327 jobs (1,329 new builds, 998 retrofits) with weekly labor data by work center, section-level aggregation, and Goldratt TOC velocity metrics.

Views

ViewDescription
Job Table13-column sortable table (Job, Description, Actual/Quoted hours, Ship, BL Ship, Redbook, ECN, WOs, Revenue, Throughput, T/hr). Type filter (All/New Builds/Retrofits/Active), year filter tabs, search. Checkbox selection for multi-job compare.
OverviewDrill-down heatmap (Year > Quarter > Month > Week) with section/operation rows. RGBA color-scaled cells. Breadcrumb navigation + zoom buttons. Velocity strip (8 TOC KPI cards: WIP, Throughput Rate, Implied Lead Time, Avg Cycle Time, WIP Hours, Revenue, Throughput, Avg T/hr). Recharts velocity chart (shipped/WIP/new starts). Click any column header for period detail overlay with capacity bars and job breakdown.
CompareMulti-job comparison heatmap. Select 2+ jobs via checkboxes, then compare. Bucket tabs (TOTAL + per-section). Two modes: by-job (one row per job) and by-op (hierarchical with work center sub-rows). 15-color cycling palette. Month span headers.

Single Job Viewer

Click any job row to open the full Gantt viewer. Replaces the former standalone viewer.html.

ComponentDescription
Stats BarActual/Planned/Quoted hours, WO count, weeks, work centers, peak IP inventory, redbook count, ECN count, revenue, throughput, T/hr, date range, order/ship/BL ship dates
Handoff PillsSection-to-section handoff indicators (overlap/gap/direct/incomplete) with colored dots
Gantt GridWeeks x operations table with RGBA heatmap cells, section headers, milestone markers, redbook week tinting, cutoff/overrun dimming. 4 sticky left columns (Work Center, Actual, Plan, Quoted). Inventory GL bucket rows, handoff rows, redbook/ECN rows, total row.
Popups (5 types)Employee: expandable rows with WO breakdown + cross-job links + time off. Redbook: issues with ID, date, type, problem/cause/solution. ECN: parts with status badges, dates, hours. Inventory: parts list with BOM level badges (L0-L5) and dollar amounts. Handoff: from/to section comparison with overlap/gap status and per-week detail.

Data Source

Pre-generated JSON files from batch_gantt.py (built nightly by Python scripts in C:\GIT\JobPlanningBom\scripts\gantt\). Data is uploaded to Azure Blob Storage (psiganttdata storage account, gantt-data container) via CI workflow (hourly Mon-Fri during business hours) and manual scripts/upload-gantt-data.ps1. The Express server reads from blob storage first (via @azure/storage-blob SDK, 5-minute cache), falling back to local filesystem. Jobs summary served via /api/gantt/jobs, per-job detail via /api/gantt/job/{number}. In development, Vite middleware serves files directly from ./gantt-data/ (populated by scripts/sync-gantt-data.mjs).

Files

  • src/components/gantt/ — GanttPage, GanttStatsBar, GanttFilters, JobTable, OverviewPanel, OverviewBreadcrumb, OverviewHeatmap, VelocityStrip, VelocityChart, PeriodDetailOverlay, ComparePanel, CompareHeatmap, CompareLegend, JobViewer, JobViewerStats, JobViewerTable, JobViewerPopups (17 components)
  • src/hooks/useGantt.ts — React Query hooks (useGanttJobs, useGanttJobDetail)
  • src/lib/ganttUtils.ts — Pure utility functions (filtering, sorting, aggregation, velocity, compare)
  • src/types/gantt.ts — TypeScript interfaces (GanttJobSummary, GanttJobDetail, 25+ sub-types)

Recent Changes

  • 2026-03-19 - Gantt Charts: Full React rebuild of the 36K-line vanilla JS gantt page. 17 modular components replacing monolithic index.html + viewer.html. Job table with type/year/search filters and checkbox selection. Drill-down overview heatmap (Year>Quarter>Month>Week) with section/operation rows and RGBA color scaling. 8-card Goldratt TOC velocity strip + Recharts velocity chart (shipped/WIP/starts). Period detail overlay with capacity bars and WIP risk. Multi-job compare panel (by-job and by-op modes, 15-color palette). Full single-job viewer with stats badges, handoff pills, Gantt grid (weeks x ops), and 5 popup types (employee, redbook, ECN, inventory, handoff). React Query hooks with staleTime caching. Vite middleware plugin for dev-time JSON serving.
  • 2026-03-16 - Machine Explorer Redesign: Transformed from engineering debug panel to CS/field service portal. Split-view layout with persistent AI chat panel (machine-scoped conversations via Azure OpenAI + 61 MCP tools). 6 CS-focused tabs replacing 8 engineer-focused tabs: Overview (“What is this machine?”, Watch Out risks, Resources, Lessons Learned), Active Work (open RFCs, open POs), Service History (open items prominent, searchable timeline), Parts & BOM, Drawings, Controls. Photo gallery lightbox from MultiMedia + K: drive (29 photos for job 2337). Lifecycle timeline (Order→Ship). Error boundaries on all tabs. 24 null-safety tests. Azure SQL managed identity auth (no credentials needed). 39 MCP backend routes, 11 analytics routes. Tab data badges. Date formatting throughout.
  • 2026-03-12 - Machine Explorer Phase 1: New top-level #machine/{job} page with 360° machine intelligence view. 13 Express backend routes proxying MCP tools. Search with recent history, header banner (identity, team, PLC stats), Overview tab (health cards, I/O, programs, modules, scorecard dimensions, findings, available data), Controls tab (full PlcTab reuse), Quality tab (RFCs + AI fault catalog + safety assessment + design quality). Hash-based deep linking. 5 placeholder tabs for future phases.
  • 2026-03-02 - Lead Time Deep Dive Revamp: Dashboard→Root Causes (idle time bars, queue ratio cards, cascade badges, ECN trends), Capacity&OTD→Dept Flow (cascade scatter plots, “Everything Starts Later” table, span growth, ECN impact), Hypotheses→Findings (11 findings with evidence grouping), P2/P98/P50 substantial engagement milestones on Timeline (three-segment bars + midpoint markers), Dept Heatmap (3 new metrics: P2P98 Span, Idle %, ECN Count), Era Comparison expanded to 13 metrics, OTD de-emphasized per F11 finding, data pipeline expanded to 216+ columns.
  • 2026-03-03 - PLC bug fixes + routine source viewer: Scorecard crash fix (null guards when MCP returns partial data), click-to-view routine source code on Programs tab (full ladder logic rung text with syntax highlighting, search, copy).
  • 2026-03-02 - PLC Fleet 1.5 UX: CSV export on all PLC tables (modules, tags, scorecards, I/O verify), sortable fleet scorecard table with pagination, sortable module inventory, fault/timer/counter quick filter chips on tags, fleet reuse & adoption dashboard (routine/UDT/tag prefix adoption bars), Similar Projects sub-tab, E2E tests converted from mocks to real MCP endpoints.
  • 2026-03-02 - PLC Fleet page: project drill-down (click any job or enter number), clickable jobs on scorecard/search/changes, per-project Compare sub-tab. Sub-tab enhancements: module health columns (FW, status, risk highlighting), history change deltas (tag/module/rung diffs), program search filter + key states/outputs/safety features, tag const/dims columns + used-by cross-reference, controller summary badges (dates, safety, security).
  • 92af620 - PLC Code Intelligence Phases A-C: Scorecards (4-dimension scoring, fleet averages), Intent Deduction (100K rungs parsed, 2923 routines summarized), I/O Verify sub-tab (BOM ↔ PLC module matching with spare parts). 46 MCP tools.
  • a549ce1 - Lead Time UI round 2: leadership polish — bigger text, correlation explanation panels, redesigned hypothesis cards, smart heatmap coloring (YoY delta + percentile), capacity chart fixes, timeline summary mode
  • a4352af - Lead Time UI: rename Recovery→Current, human-readable labels everywhere, Machine Shop + Weld in dept heatmap, new Gantt timeline view, ViewHeader with glossary, fix dollar formatting on labor hour columns
  • Ask the Fleet - AI chat panel: Claude + 42 MCP tools, streaming SSE, rich tool cards, navigation integration, Ctrl+K shortcut
  • 1c01405 - Dashboard collapse (details hidden by default), timeline overhaul (zoom/pan/tooltips/keyboard nav), capacity & floor plan diagnostics
  • 0f2ddf8 - Add monthly labor burn chart to project detail Hours tab (cumulative dept hours from WIPLEDGER.HRS with budget reference lines)
  • e26affb - Fix status codes, array direction, add close/ship date exclusions
  • 56bd1fe - Add recency gate to active project filter
  • e82636a - Update API URL to https://api.progressivesurface.com
  • e9c4cb6 - Add Azure App Service deployment configuration (Express server)
  • d4316c4 - Initial commit: PSI Explorer Web React application