Redbook Web

Modern web application for managing RFC (Request for Change) quality issue tickets, replacing the legacy WPF Redbook application.


Overview

Redbook Web is a React/TypeScript single-page application that provides a modern interface for creating, editing, and tracking quality issues (RFCs). It connects to the PSI.UniData.API for data access to the UniData REDBOOK.1287 table.

FeatureDescription
Production URLhttps://redbook.progressivesurface.com
API Backendhttps://api.progressivesurface.com/api/redbook
AuthenticationAzure AD (PSI credentials)
DeploymentAzure App Service (Linux) + Private Endpoint
RepositoryC:\GIT\redbook-web

Features

Current (Phase 1) ✅

  • RFC CRUD: Create, read, update, delete quality issues
  • Search: Filter by project, status, date range, department, text
  • Department Status Grid: Track which departments have addressed an issue — names loaded live from UniData at runtime; grid layout and MV slot order match ProApp XAML exactly
  • Corrective Action Fields: Audit cause (free-text), containment, preventative actions
  • Project Search: Search-as-you-type combobox with 300ms debounce; calls /api/redbook/lookups/projects?q=
  • ECN/NCN Display: View linked engineering changes and non-conformances
  • Lookups from UniData: Employees, accounts, cost centers, audit types, departments (with slot index)

Planned (Phase 2-4)

  • ECN/NCN linking UI (add/remove links)
  • Copy RFC to multiple projects
  • Excel export
  • PDF reports
  • QR code generation

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    REDBOOK WEB FRONTEND                          │
│  React + TypeScript + TailwindCSS + React Query                 │
│  Azure Static Web Apps                                           │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼ HTTPS + JWT
┌─────────────────────────────────────────────────────────────────┐
│                    PSI.UNIDATA.API                               │
│  /api/redbook/* endpoints                                        │
│  Windows Service on PS-PROXY                                     │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼ U2 Toolkit
┌─────────────────────────────────────────────────────────────────┐
│                    UNIDATA (MRP-PROD)                           │
│  REDBOOK.1287 table                                              │
└─────────────────────────────────────────────────────────────────┘

UniData Field Mapping

The API maps these UniData fields from REDBOOK.1287. Note: These position numbers reflect the API’s internal mapping and may differ from the raw UniData field positions documented in Redbook Data Dictionary.

FieldUniData PositionDescription
RFC.NOKeyUnique identifier
JOB.NO1Project number
PROBLEM2Problem description
DRAWING.NO3Related drawing
PART.NO4Related part number
ENTERED.BY6Creator initials
ENTERED.DATE7Creation date
PROBLEM.TYPE8Problem category code
ROOT.CAUSE9Root cause code
SOLUTION10Solution text
PRIORITY12Priority (1-4)
STATUS13Open/Closed
AUDIT.TYPE21Audit category
AUDIT.CAUSE22Audit cause
ACCOUNT25Customer account
RESP.DEPT26Primary responsibility (cost center)
WASTE.MTL27Material cost
WASTE.ENG28Engineering hours
WASTE.MFG29Manufacturing hours
WASTE.CSS30Customer service hours
ACTIVITY35Activity log
FIRSTACTION.DATE38First action date

Lookup Data Sources

The application loads dropdown data from these UniData tables:

LookupTableQueryFields
EmployeesEMPLOYEE.PUBLIC.1287WITH ACTIVE = 'Y'LAST.NAME, FIRST.NAME, DEPT.NO
AccountsACCOUNT.1287WITH DELETED # 'Y' AND WITH JSHOP.GRP = 'J'NAME
Cost CentersCOCESELECT COCECCEN (key), DESC
Audit TypesStatic-01=Internal, 02=External Customer, 03=External Registrar
PrioritiesStatic-1=Critical, 2=High, 3=Medium, 4=Low
Departments/api/redbook/lookups/departmentslive from APIcode, name, slot (0-based MV index)
Projects/api/redbook/lookups/projects?q=search-as-you-type, ≥2 chars, max 25code, description, customerName

API Endpoints

RFC Operations

MethodEndpointDescription
GET/api/redbook/rfc/{rfcNo}Get single RFC
POST/api/redbook/rfcCreate new RFC
PUT/api/redbook/rfc/{rfcNo}Update RFC
DELETE/api/redbook/rfc/{rfcNo}Delete RFC
POST/api/redbook/searchSearch RFCs
GET/api/redbook/by-project/{projectNo}Get RFCs for project

Lookup Endpoints

MethodEndpointDescription
GET/api/redbook/dev/lookups/allAll lookups in one call
GET/api/redbook/dev/lookups/employeesActive employees
GET/api/redbook/dev/lookups/accountsJob Shop accounts
GET/api/redbook/dev/lookups/cost-centersCost centers (COCE)
GET/api/redbook/dev/lookups/audit-typesAudit types
GET/api/redbook/dev/lookups/prioritiesPriority levels
GET/api/redbook/dev/lookups/departmentsDepartment codes with slot index
GET/api/redbook/lookups/projects?q=Project search (≥2 chars, max 25 results)
GET/api/redbook/dev/lookups/projects?q=Project search (service-account session)

Project Structure

redbook-web/
├── frontend/
│   ├── src/
│   │   ├── api/
│   │   │   └── client.ts           # API client with all endpoints
│   │   ├── auth/
│   │   │   └── AuthProvider.tsx    # Azure AD authentication
│   │   ├── components/
│   │   │   ├── rfc/
│   │   │   │   ├── DepartmentStatusGrid.tsx
│   │   │   │   ├── CorrectiveActionForm.tsx
│   │   │   │   ├── ProjectSearch.tsx   # async combobox with debounce
│   │   │   │   └── index.ts
│   │   │   └── LoadingSpinner.tsx
│   │   ├── hooks/
│   │   │   ├── useRfc.ts           # RFC CRUD hooks
│   │   │   └── useLookups.ts       # Lookup data hooks
│   │   ├── pages/
│   │   │   ├── HomePage.tsx        # Search/list view
│   │   │   ├── RfcDetailPage.tsx   # View RFC details
│   │   │   ├── RfcCreatePage.tsx   # Create new RFC
│   │   │   └── RfcEditPage.tsx     # Edit existing RFC
│   │   ├── types/
│   │   │   └── redbook.ts          # TypeScript interfaces
│   │   └── App.tsx
│   ├── package.json
│   └── vite.config.ts
└── README.md

Development

Prerequisites

  • Node.js 18+
  • npm or pnpm
  • Access to PSI.UniData.API (local or production)

Local Development

cd C:\GIT\redbook-web\frontend
npm install
npm run dev

The app runs at http://localhost:5173 and connects to the local API at http://localhost:5000.

Environment Variables

Create .env.local for local development:

VITE_API_URL=http://localhost:5000
VITE_AZURE_CLIENT_ID=your-client-id
VITE_AZURE_TENANT_ID=your-tenant-id

Deployment

Azure App Service (Private Endpoint)

The frontend is deployed to Azure App Service with:

  • Custom domain: redbook.progressivesurface.com
  • Private endpoint: redbook-web-pe at 10.160.140.12 (PS-ProdData subnet)
  • Public network access: Disabled (internal only, VPN required)
  • SSL: Wildcard certificate (*.progressivesurface.com)
  • Auth: Azure AD (EasyAuth)
  • CI/CD: GitHub Actions on self-hosted runner (ps-cicd-runner)

Build and Deploy

Pushes to main or master trigger automatic deployment via GitHub Actions:

npm run build
# Deploys via self-hosted runner → az webapp deploy

Comparison with WPF App

FeatureWPF AppWeb App
PlatformWindows desktopWeb browser
AuthenticationWindows domainAzure AD
Data accessPSI Local Service (WCF)REST API (U2 Toolkit)
PerformanceSlow (WCF overhead)Fast (~200-300ms)
DeploymentManual installAuto-deploy
Mobile accessNoYes

Parity Harness

A four-layer test harness validates that the REST API (PSI.UniData.API) produces the same redbook data as the legacy WCF backend (PSILocalService), enabling safe incremental migration.

Architecture

LayerTechnologyPurpose
Layer 1 — Headless.NET 8 console (PSI.Redbook.Headless)Calls both backends, writes normalized Observation JSON
Layer 2 — VM TestsxUnit net48 (PSI.Redbook.View.Tests)Unit-tests WPF ViewModel behavior (pending Task 11a)
Layer 3 — UI SmokeManual / future PlaywrightEnd-to-end comparison of rendered UI
Layer 4 — XAML AuditStatic analysisDocuments all bound VM properties in the ProApp XAML

Running Layer 1 Locally

cd C:\GIT\PSI.All\parity\orchestrator
 
# Run a scenario against both backends
python -m orchestrator run \
  --yaml ..\scenarios\get_rfc_by_id.yaml \
  --out ..\out \
  --wcf-endpoint http://ps-proxy/PSILocalService/PSILocalService.svc \
  --rest-base https://api.progressivesurface.com \
  --wcf-user <user> \
  --wcf-password <password>

Scenario Files

Scenario YAMLs live in PSI.All/parity/scenarios/ (moved from redbook-web/harness/scenarios/ in April 2026 to avoid cross-repo CI checkout). Current scenarios:

ScenarioWhat it tests
get_rfc_by_idFetch single RFC by number
get_rfc_list_by_projectRFC list for a project via GetRedbookItems
search_recent_rfcsRFC appears in project search results

CI

PSI.All/.github/workflows/parity.yml runs on the self-hosted, windows, dotnet-framework runner:

  • Layer 2 VM tests — every qualifying PR; currently 0 passed / 1 skipped (pending Task 11a)
  • Layer 1 parity — nightly Mon–Fri and on manual dispatch; requires PARITY_* secrets


Department Slot Order

Department status writes/reads use 0-based MV slot indices (matching ProApp RFCResponsibleDeptsEnum) as dictionary keys — not dept codes. This matters because two departments share code 180 (HR = slot 13, Accounting = slot 14). The 16-slot order is:

SlotCodeName
0150Purchasing
1160RCV/STK
2170Quality
3115Proposal
4140Sales
5110EElec Engineering
6110MMech Engineering
7102Machine/Weld
8125Job Shop
9130Process Dev
10106Mech Assembly
11108Elec Assembly
12120Customer Service
13180Human Resources
14180Accounting
15160ZProduction Planning

Last updated: 2026-04-29 — dept slot order fix (Plan 3), parity orchestrator moved to PSI.All