42 KiB
HP CG Production Tracker — Implementation Plan
Context
The CG department creates product renders for HP. Producers currently manage projects across fragmented tools (Workfront, Excel, OMG platform) with no unified view of pipeline status, artist workload, or delivery timelines. This app replaces that fragmentation with a single purpose-built tracker — similar to Monday.com but tailored to the department's specific CG pipeline stages and dependency rules.
Confirmed Requirements
| Aspect | Decision |
|---|---|
| Platform | Web app (browser) |
| Framework | Next.js 15 (App Router, full-stack) |
| Database | PostgreSQL + Prisma ORM |
| Auth | SSO (Google / Microsoft Entra ID) via Auth.js v5 |
| Team size | 10-30 concurrent users |
| Roles | Producer (manage everything) + Artist (view assignments, update status) |
| Real-time | Not needed V1 (manual refresh) |
| Notifications | In-app only (bell icon) |
| Integrations V1 | Excel import/export |
| Revisions | Track rounds with feedback notes, version history, round count |
| Theme | Light + Dark mode with system preference detection |
| Design style | Oliver Agency / Brandtech Group — corporate-minimalist, Montserrat + Inter |
Pipeline Stages & Dependencies
Brief Intake → File Delivery → Model Prep ──→ Early Images (optional)
│ GATE
▼
Catalog Images
│ GATE
┌───────┬───────┼───────┬──────────┐
▼ ▼ ▼ ▼ ▼
Hero Packaging Photo 360 Spin Dynamic
Images Images comps Animations Spin
- Nothing starts without Brief + Model Prep complete
- Catalog Images must be approved before Hero, Packaging, Photocomps, or Animations can begin
- Early Images is optional (can be skipped)
- Stages 6-10 run in parallel once Catalog is approved
Tech Stack
Core
- Next.js 15 — App Router, React Server Components, Turbopack
- TypeScript 5.x — Full type safety
- PostgreSQL 16 + Prisma 6.x — Relational data model with type-safe queries
- Auth.js v5 +
@auth/prisma-adapter— SSO (Google + Microsoft Entra ID)
UI
- shadcn/ui — Component library (Radix + Tailwind)
- Tailwind CSS 4.x — Styling
- @tanstack/react-table v8 — Table/spreadsheet view
- @hello-pangea/dnd — Kanban drag-and-drop
- recharts — Dashboard charts
- @svar/react-gantt — Timeline/Gantt view
State & Data
- @tanstack/react-query v5 — Server state (fetching, caching, mutations)
- zustand — Client UI state (sidebar, view mode, filters)
- nuqs — URL-synced filter/sort state
Excel
- exceljs — Server-side Excel generation (export)
- xlsx (SheetJS) — Client-side Excel parsing (import)
Forms & Validation
- zod — Schema validation (API + forms + Excel rows)
- react-hook-form +
@hookform/resolvers— Form management
Utilities
- date-fns — Date formatting
- sonner — Toast notifications
- cmdk — Command palette (Cmd+K)
- lucide-react — Icons
- next-themes — Light/dark mode toggle with system preference detection
Design System
Inspired by the Oliver Agency / Brandtech Group visual identity: corporate-minimalist, clean geometry, strong typographic hierarchy, generous whitespace. Adapted for a production-tracking tool with data-dense views.
Typography
| Role | Font | Weight | Notes |
|---|---|---|---|
| Headings | Montserrat | 600, 700 | Oliver's primary brand font (Google Fonts) |
| Body / UI | Inter | 400, 500, 600 | Highly legible at small sizes for tables and data |
| Monospace | JetBrains Mono | 400 | Project codes, timestamps, technical data |
Color Palette
Light Mode
| Token | Hex | Usage |
|---|---|---|
--background |
#FFFFFF |
Page background |
--foreground |
#0A0A0A |
Primary text |
--muted |
#F5F5F5 |
Secondary backgrounds (sidebar, cards) |
--muted-foreground |
#6B7280 |
Secondary text, placeholders |
--border |
#E5E7EB |
Dividers, card borders |
--primary |
#08402C |
Primary actions (Oliver teal-green) |
--primary-foreground |
#FFFFFF |
Text on primary |
--accent |
#EE5540 |
Alerts, urgent items, notifications (Oliver flamingo) |
--accent-foreground |
#FFFFFF |
Text on accent |
--ring |
#08402C |
Focus rings |
Dark Mode
| Token | Hex | Usage |
|---|---|---|
--background |
#0A0A0A |
Page background |
--foreground |
#F5F5F5 |
Primary text |
--muted |
#171717 |
Secondary backgrounds (sidebar, cards) |
--muted-foreground |
#9CA3AF |
Secondary text |
--border |
#262626 |
Dividers, card borders |
--primary |
#0FA968 |
Primary actions (teal-green, brightened for dark bg) |
--primary-foreground |
#FFFFFF |
Text on primary |
--accent |
#F2725E |
Alerts, urgent items (flamingo, softened for dark bg) |
--accent-foreground |
#FFFFFF |
Text on accent |
--ring |
#0FA968 |
Focus rings |
Semantic Status Colors (both modes)
| Status | Light | Dark | Usage |
|---|---|---|---|
| Blocked | #DC2626 |
#EF4444 |
Blocked stages |
| Not Started | #6B7280 |
#9CA3AF |
Pending work |
| In Progress | #2563EB |
#60A5FA |
Active work |
| In Review | #D97706 |
#FBBF24 |
Awaiting approval |
| Approved | #16A34A |
#4ADE80 |
Completed/approved |
| Skipped | #9CA3AF |
#6B7280 |
Optional stages skipped |
Design Principles
- Corporate-minimalist — Clean lines, no decorative elements, content-first
- Dense but breathable — Tables and boards show lots of data with consistent spacing (8px grid)
- Strong hierarchy — Montserrat bold headings, clear size steps (14/16/20/24/32px)
- Restrained color — Mostly neutral with teal-green for primary actions, flamingo reserved for urgency/alerts
- Photography-free — Icons and data visualization only, no stock imagery
Component Styling
- Cards —
bordercolor border, subtle shadow in light mode (shadow-sm), no shadow in dark mode - Buttons — Primary: teal-green bg, white text, no border-radius excess (
rounded-md). Secondary: ghost/outline style - Tables — Alternating row shading using
muted, sticky headers, compact row height (40px) - Sidebar —
mutedbackground, 256px width, collapsible to 64px icon-only - Navigation — Horizontal topbar with breadcrumbs, sticky at top
- Status badges — Pill-shaped, semantic color bg with matching text, uppercase small font
- Kanban cards — White/dark card on muted board bg, left border accent by status color
Theme Toggle
next-themeswithattribute="class"strategy for Tailwind dark mode- Three options: Light / Dark / System
- Toggle in topbar settings area
- Persisted in
localStorage, respectsprefers-color-schemeon first visit
Data Model (Prisma)
Key Entities
Organization → has many Users, Projects User → role (ADMIN/PRODUCER/ARTIST), SSO accounts, assignments, notifications Project → projectCode, status, priority, dates → has many Deliverables Deliverable → name, status, priority, dueDate → has many DeliverableStages (auto-created: all 10) PipelineStageTemplate → seed data for 10 stages + dependency rules (isCriticalGate, isOptional) PipelineStageDependency → which stages depend on which (seed data) DeliverableStage → instance per deliverable, tracks status/dates/revisionRound → has Assignments, Revisions, Comments StageAssignment → links User to DeliverableStage with optional role ("Lead"/"Support") Revision → round number, status, feedback notes, internal notes, attachments (JSON) Comment → threaded (parentId), per stage Notification → type, title, message, link, isRead
Dependency Enforcement Logic
- When a deliverable is created → auto-create 10 DeliverableStage records. Stages with unmet prerequisites start as
BLOCKED - Before a stage moves to
IN_PROGRESS→ check all prerequisite stages areAPPROVED(orSKIPPEDif optional) - When a critical gate is
APPROVED→ automatically unblock downstream stages (BLOCKED → NOT_STARTED)
Application Architecture
Folder Structure (abbreviated)
src/
├── app/
│ ├── (auth)/login/ # SSO login page
│ ├── (app)/ # Authenticated routes
│ │ ├── dashboard/ # KPI dashboard
│ │ ├── projects/ # Project list + CRUD
│ │ │ └── [projectId]/ # Project detail + views
│ │ │ ├── table/ # Spreadsheet view
│ │ │ ├── board/ # Kanban view
│ │ │ ├── timeline/ # Gantt view
│ │ │ └── deliverables/[deliverableId]/ # Pipeline stages
│ │ ├── my-work/ # Artist's assignments
│ │ ├── notifications/ # Notification history
│ │ └── settings/ # User + org settings
│ └── api/ # REST API routes
│ ├── auth/[...nextauth]/
│ ├── projects/ # CRUD + nested deliverables/stages
│ ├── users/ # List org users
│ ├── notifications/ # List + mark read
│ ├── import/excel/ # Upload + parse
│ ├── export/excel/ # Generate + download
│ └── dashboard/stats/ # KPI aggregations
├── components/
│ ├── ui/ # shadcn/ui primitives
│ ├── layout/ # Sidebar, topbar, breadcrumbs, notification bell
│ ├── views/ # Table, Board, Timeline, Dashboard view components
│ ├── deliverables/ # Pipeline progress visualizer
│ ├── stages/ # Stage cards, status badges, dependency graph
│ ├── revisions/ # Revision timeline, forms
│ └── excel/ # Import dialog, export button, column mapper
├── lib/
│ ├── auth.ts # Auth.js config
│ ├── prisma.ts # Singleton client
│ ├── pipeline/
│ │ ├── dependency-engine.ts # Pure dependency validation functions
│ │ └── stage-machine.ts # State transitions
│ ├── services/ # Business logic (project, deliverable, stage, revision, notification, excel, dashboard)
│ └── validators/ # Zod schemas
├── hooks/ # TanStack Query hooks per entity
├── stores/ # Zustand (UI state, filter state)
└── types/ # Shared TypeScript types
Key Patterns
- Thin API routes → delegate to service layer for all business logic
- Service layer → encapsulates Prisma queries + business rules (testable, reusable)
- Dependency engine as pure functions →
canStageStart()returns{ allowed, reason }, used both server-side and potentially client-side - URL-synced filters via
nuqs→ views are shareable/bookmarkable - Server Components for initial data fetch, TanStack Query for client-side mutations/cache
Four Main Views
-
Table View — TanStack Table + shadcn/ui. Server-side pagination. Multi-column sort, faceted filters (status, stage, artist, priority, date). Column visibility toggle. URL-persisted state.
-
Board View — Kanban with drag-and-drop. Group by Status or by Stage. Drag triggers PATCH with dependency validation; blocked moves snap back with toast error.
-
Timeline View — Gantt chart (SVAR). Deliverables as rows, stages as task bars. Dependency arrows. Color-coded by status. Day/week/month zoom. Read-only V1.
-
Dashboard View — KPI cards (active projects, in-progress, overdue, avg revisions). Charts: deliverables by stage, delivery trend, on-time rate, artist workload. Overdue alerts list.
Phased Build Plan
Phase 1: Foundation
- Project scaffolding (Next.js, TS, Tailwind, ESLint, Prettier)
- Design system setup (Tailwind theme tokens, Montserrat + Inter fonts, light/dark CSS variables)
next-themesintegration with light/dark/system toggle- Prisma schema + migrations + seed (pipeline templates + dependencies)
- Auth.js SSO (Google + Microsoft) with domain validation
- shadcn/ui component installation + theme customization to match design system
- App shell layout (sidebar, topbar, breadcrumbs, theme toggle)
- Project CRUD (API + pages + forms)
- Deliverable CRUD (API + pages, auto-create 10 stages)
- User management (list, role assignment)
Phase 2: Core Pipeline & Views
- Dependency engine + stage state machine
- Stage status management with dependency enforcement
- Artist assignment system + "My Work" page
- Table View (full TanStack Table implementation)
- Board View (Kanban with drag-and-drop)
- Timeline View (Gantt chart)
- Pipeline progress visualizer component
- TanStack Query hooks + optimistic updates
Phase 3: Advanced Features
- Revision tracking (rounds, feedback, history timeline)
- Threaded comment system on stages
- Notification system (in-app bell + full page, auto-generated on key events)
- Dashboard view (KPIs, charts, overdue alerts)
- Excel import (upload, preview, column mapping, validation, transactional commit)
- Excel export (multi-sheet styled workbook)
- Deadline tracking (approaching/overdue detection + notifications)
Phase 3b: Reference Image Comparison (Markup Review)
- Reference image upload — attach reference/approved images to any revision round. Stored via the existing
attachmentsJSON field onRevision, with file upload to local storage (Phase 1) or S3/Cloud (production). Supports PNG, JPG, WebP up to 10MB. - Current render upload — upload the current WIP render alongside the reference for direct comparison. Each revision round can have a "reference" image and a "current" image.
- A-B comparison slider — draggable vertical divider overlaying reference (left) and current (right) images. User drags to reveal/hide each side. Built as a
<ImageCompareSlider>component using pointer events + CSS clip-path. No external dependency needed. - Toggle mode — click/tap to flip between reference and current image (full-frame swap with crossfade transition). Keyboard shortcut:
Spaceto toggle. Useful on smaller screens where the slider is impractical. - Side-by-side mode — display both images at equal size in a horizontal split. Synced zoom/pan so both images move together. Default on wide screens.
- Zoom & pan — scroll-to-zoom with pinch support. Pan by click-drag when zoomed. Zoom level synced across both images in all comparison modes.
- Image gallery per revision — revision rounds accumulate images over time. Gallery shows all uploaded images for the stage across rounds, with round number labels. Quick-select any past round's image as the reference for comparison.
- Context in StageDetailSheet — new "Compare" tab in the stage detail sheet (alongside existing Revisions and Comments tabs). Comparison tools live here. Selecting a revision round auto-loads its images.
- Lightweight markup overlay (optional enhancement) — basic annotation tools (arrow, rectangle, freehand, text pin) drawn on top of the current image. Annotations saved as JSON on the revision. Not a full drawing app — just enough to point at problems.
Data Model Changes
// Extend Revision.attachments JSON schema:
{
referenceImage?: { url: string, filename: string, size: number, uploadedAt: string },
currentImage?: { url: string, filename: string, size: number, uploadedAt: string },
annotations?: Array<{ type: "arrow"|"rect"|"freehand"|"pin", points: number[], text?: string, color: string }>
}
New API Endpoints
POST /api/stages/:stageId/revisions/:revisionId/upload — multipart form upload (reference or current image)
DELETE /api/stages/:stageId/revisions/:revisionId/upload — remove an uploaded image
New Components
src/components/revisions/
├── image-compare-slider.tsx — A-B slider with drag handle
├── image-toggle.tsx — Toggle/crossfade between two images
├── image-side-by-side.tsx — Synced side-by-side with zoom/pan
├── image-upload-zone.tsx — Drag-and-drop upload for reference/current
├── revision-image-gallery.tsx — Browse images across revision rounds
├── compare-tab.tsx — Orchestrator: mode selector + comparison view
└── markup-overlay.tsx — Lightweight annotation layer (optional)
PNG Transparency Handling
CG renders are typically PNGs with transparent backgrounds and semi-transparent drop shadows. When two transparent PNGs are layered in comparison modes (slider, toggle, overlay), the shadows multiply and produce incorrect visual results — making review unreliable.
Solution: server-side alpha compositing on upload.
- On the upload endpoint, detect if the image is a PNG with an alpha channel (check IHDR color type via
sharpor raw buffer inspection). - If alpha is present, composite the image onto a solid white (#FFFFFF) background using
sharp.flatten({ background: '#FFFFFF' })before storing. - Store the flattened version as the comparison-ready image. Optionally keep the original transparent PNG as a separate
originalUrlfor download purposes. - JPG and WebP uploads (no alpha) skip this step — no processing needed.
- This happens once at upload time, not at render time — avoids per-view processing cost and ensures all comparison modes work correctly without CSS hacks.
// Upload processing pipeline (pseudo):
const img = sharp(buffer);
const metadata = await img.metadata();
if (metadata.format === 'png' && metadata.hasAlpha) {
buffer = await img.flatten({ background: '#FFFFFF' }).png().toBuffer();
}
UX Notes
- Images are almost never reviewed in isolation — the reference comparison is the primary review workflow. The compare tab should be the default/first tab when images exist.
- Default to slider mode on desktop, toggle mode on mobile.
- Reference images persist across rounds (the approved reference doesn't change until a new one is set). Current images update each round.
- Empty state: prompt to upload a reference image with a clear CTA. Show how comparison works with a placeholder illustration.
Phase 4: Polish
- Command palette (Cmd+K search)
- Bulk operations (multi-select in table → bulk status/assignment/priority)
- Loading skeletons, error boundaries, empty states
- Responsive design (mobile sidebar, stacked Kanban)
- Performance (query optimization, virtual scrolling, dynamic imports)
- Accessibility audit
- Edge cases (concurrent edits, rate limiting, session expiry)
- Documentation + deployment config
Spreadsheet Analysis — Learnings from Master CG Tracker
Source:
assets/temp/Master_CG Tracker (1).xlsx— 20 sheets, ~1,000 rows of real production data spanning FY25Q2 through FY26Q2. This is the live tracker the team uses today. Everything below describes gaps between the spreadsheet's reality and our current data model/plan.
1. Missing Project-Level Fields
The spreadsheet tracks several project attributes we don't yet model:
| Field | Spreadsheet Column | Notes |
|---|---|---|
| Business Unit | BU |
D&P, Poly, ACS, CPS, BPS, Gaming, Print. Every sheet uses this as a primary grouping/filter. Should be an enum. |
| Form Factor | Form Factor |
NB (Notebook), DT (Desktop), X360, AIO, TBD. Product hardware category. |
| Code Name | Code Names |
HP internal product code names (Trekker, Salute, Quadro, Coda, Agusta, etc.). The primary human-readable identifier producers use. |
| NPI or Refresh | NPI or Refresh |
Whether the project is for a New Product Introduction or a Refresh of existing content. Affects scope and cost. |
| Fiscal Quarter | Qtr |
FY25Q2, FY25Q3, FY25Q4, FY26Q1, FY26Q2. HP fiscal year runs Nov–Oct (Q1=Nov-Jan, Q2=Feb-Apr, Q3=May-Jul, Q4=Aug-Oct). Everything is organized by quarter. |
| Requestor | Requestor |
The HP stakeholder who requested the work. Distinct from Producer (internal PM) and Artist. Often multi-person. |
| Workfront ID | WF / WF/OMG / WF Link |
Reference number from Workfront (HP's work management tool). Critical cross-system link. |
| OMG Code | OMG Code |
Reference from the OMG platform. Format varies: "OMG1798463", "OMG 2116699", plain "1952931". Needs normalization. |
| BMT ID | BMT ID |
Another external tracking ID used for billing/reconciliation. |
Action: Add businessUnit, formFactor, codeName, npiOrRefresh, quarter, requestor, workfrontId, omgCode, bmtId to the Project model. businessUnit as an enum, others as optional strings.
2. Missing Deliverable-Level Fields
| Field | Spreadsheet Column | Notes |
|---|---|---|
| CMF/SKU | CMF/Sku / CMF |
Color-Material-Finish identifier. Often multi-valued with \r\n separators (e.g., "Glacier Silver\r\nMica Silver\r\nStarlit Blue"). One deliverable can cover multiple CMF variants. |
| Asset Count | #Asset / #Assets |
Number of individual images/renders. Ranges from 1 to 72. Critical for workload estimation and cost calculation. |
| Requested Due Date | Requested Due Date / Req Due Date |
Date HP requested delivery — distinct from planned delivery date. |
| Planned Delivery Date | Planned Delivery Date / Delivery Date |
Date the team plans to actually deliver. |
| Actual Delivery Date | Inferred from Remark ("Delivered on...") |
When work was actually delivered. Not a dedicated column in the spreadsheet but should be in the app. |
| WF Input Date | WF Input Date / WF Request date |
When the brief was entered into Workfront. |
| Script Status | Script Status |
For animations: "Received", "N.R" (Not Required). Relevant for Annotated Spin and Dynamic Spin types. |
Action: Add cmfSku (text, supports multi-line), assetCount (int), requestedDueDate, plannedDeliveryDate, actualDeliveryDate, wfInputDate to Deliverable. Add scriptStatus as optional string for animation deliverables.
3. Financial Tracking — Entirely Missing Domain
The spreadsheet has substantial financial data that our plan doesn't address at all:
Per-project costs:
- Single
Costscolumn on WIP/Delivered sheets (values: $550 to $174,900) Projected Revenueper quarter columnAmounton Spins sheet with cost-split breakdowns across quarters
Granular cost breakdown (LeighRecon + NPI Forecast sheets):
| Cost Component | Description | Typical Values |
|---|---|---|
| Model Prep | 3D model preparation | $1,490 per model |
| Core | Primary render set | $2,730–$7,800 |
| Alt Color | Additional color variants | $420–$3,780 |
| Alt Name Plate/Output | Nameplate/branding variants | varies |
| Retouching (Optical) | Post-production retouching | varies |
| DAM Upload | Digital Asset Management delivery | $40–$640 |
| Estimated Total | Sum of above | $180–$14,030 |
Quarterly financial summaries (Summary sheet):
- Forecasted Amount vs Actual Billings per quarter
- Q3 total: $521,052 across three project categories
- Q4 projected: $634,748
Forecast sheets (FY25Q2–FY26Q1):
- Per-BU breakdown: Model Prep count/cost, Asset count/cost, Total, Due Date
- Used for capacity and revenue planning
Action: This is a Phase 3+ feature but the data model needs to accommodate it from the start. Add a ProjectFinancials model or cost fields on Project/Deliverable. Consider a CostBreakdown JSON field for the granular stage-type costs. Add estimatedCost, actualCost, projectedRevenue to Project.
4. Team Structure — Artist Specializations
The Project_Count sheet reveals the actual team structure:
| Department | Count | Names |
|---|---|---|
| CG Stills | 15 | Leivur, Prateek, Bharat, Aditya, Jinesh, Nizam, Soham, Ankit, Ameya, Juan, Krishnand, Yash, Eric, Xavier |
| CG Model Prep | 4 | Anantha Krishnan, Arun Prakash, Nijil Rajithan, Mayur |
| CG Animation | 8 | Sandeep Sidhu, Babon Ghosh, Hujef Bagwan, Ankit Kumar Gupta, Sonu Kumar, Pankaj Duragkar, Niteen, Ameya Kandekar |
| CG Producer | 7 | Leigh Human, Neha Sayana, Gaurav Singh, Vivek Singh, Manan Aggarwal, Iqbal, Abir |
Current gap: The schema has a flat Role enum (ADMIN/PRODUCER/ARTIST). In practice, artists have distinct specializations that determine which stages they can be assigned to. Model Prep artists don't do Hero renders. Animation artists don't do Catalog stills.
Action: Add department or specialty field to User (enum: CG_STILLS, CG_MODEL_PREP, CG_ANIMATION, CG_PRODUCER). This enables smart assignment suggestions and workload views filtered by capability.
5. Per-Asset Creation ETA — Reference Data
The Project_Count sheet contains baseline production times:
| Asset Type | ETA (Working Days) |
|---|---|
| Model Prep (Simple) | 2 WDs |
| Model Prep (Moderate) | 3–5 WDs |
| Model Prep (Complex) | 6–9 WDs |
| Catalog | 1 WD |
| Hero | 2 WDs |
| Photocomp | 3 WDs |
| Spill | 3 WDs |
| 360 Spin | 3.5 WDs |
| Dynamic Spin | 7 WDs |
| Annotated Spin | 10 WDs |
Current gap: The PipelineStageTemplate has no duration/ETA data. These reference times are used for capacity planning ("Kick off by (T-8W)" column in NPI Forecast calculates 8-week lead time from due date).
Action: Add estimatedDays (Float) to PipelineStageTemplate seed data. This feeds into timeline views, workload forecasting, and auto-calculated kickoff dates.
6. Additional Deliverable Types
The plan defines 10 pipeline stages, but the spreadsheet reveals types not cleanly mapped:
| Spreadsheet Type | Current Pipeline Stage? | Notes |
|---|---|---|
| Catalog | Yes — "Catalog Images" | Core type |
| Hero image / Hero imagery | Yes — "Hero Images" | Core type |
| Photocomp | Yes — "Photocomps" | Core type |
| 360 Spin | Yes — "360 Spin Animations" | Core type |
| Dynamic Spin | Yes — "Dynamic Spin" | Core type |
| Packaging | Yes — "Packaging Images" | Core type |
| Annotated Spin | No | Video with callouts/annotations. 10 WD ETA. Appears frequently in Print Animations and Spins sheets. |
| Spill images | No | Product "spill" renders. 3 WD ETA. Appears in Project_Count. |
| Animations (general) | Partially — mapped to Dynamic/360 | Some sheets lump all animations together. |
Action: Evaluate whether "Annotated Spin" and "Spill" should be added as pipeline stages 11 and 12, or whether they're sub-types of existing stages. The Project_Count sheet counts them separately alongside Hero, Catalog, Photocomp, etc. — suggesting they're first-class deliverable types.
7. Agency / External Vendor Tracking
The Hero Project (CPS) sheet has an Agency column with values "O" (Oliver) and "Pix". Some work is outsourced to external agencies rather than done by the internal team.
Action: Add optional agency field (string) to Deliverable or Project. Enables filtering "internal vs external" workload.
8. Status Vocabulary Gap
The spreadsheet uses informal, organic status language that doesn't map 1:1 to our StageStatus enum:
| Spreadsheet Status | Closest App Status | Notes |
|---|---|---|
| WIP | IN_PROGRESS | Direct mapping |
| In Progress | IN_PROGRESS | Direct mapping |
| Delivered | APPROVED | Implies completed + handed off |
| TBA | NOT_STARTED | To Be Assigned/Announced |
| On Hold | ON_HOLD (exists on Project only) | Need stage-level hold? |
| Brief Pending | BLOCKED | Waiting for brief intake |
| Under review | IN_REVIEW | Direct mapping |
| R1 Pending Kiran's approval | IN_REVIEW | Review round 1 with specific reviewer |
| Clays with Kiran for review | IN_REVIEW | Model prep review checkpoint |
| DAM | Custom — post-approval | DAM upload is tracked as a final step |
| DAM Done | APPROVED | DAM upload completed |
| "5 images delivered rest WIP" | Partial delivery | Not supported by current enum |
Key insight: The "Kiran / ID reviews" column appears across most sheets — this is a mandatory Industrial Design review checkpoint that sits between certain stages. It's not a formal pipeline stage but is tracked pervasively.
Action: Consider adding DELIVERED to StageStatus (distinct from APPROVED). The APPROVED → DELIVERED distinction matters for tracking when work is signed off vs when assets are actually uploaded to DAM. The "ID Review" checkpoint may warrant being a formal pipeline stage or a flag on the Model Prep / Early Images stages.
9. Date Handling Complexity
The spreadsheet tracks up to 5 different dates per item:
- WF Input Date — when brief entered Workfront
- Requested Due Date — HP's desired delivery date
- Planned Delivery Date — team's planned delivery
- Kick off by (T-8W) — calculated start date (8 weeks before due)
- Actual Delivery Date — when actually delivered (inferred from remarks)
Current model: Deliverable has a single dueDate. DeliverableStage has startDate, completedDate, dueDate.
Action: Expand Deliverable date fields as described in Section 2. The "T-8W" kickoff calculation can be derived from dueDate + estimatedDays reference data.
10. Quarterly Organization & Fiscal Calendar
Everything in the spreadsheet is organized by HP's fiscal quarter:
- FY starts in November (not January or April)
- Q1 = Nov–Jan, Q2 = Feb–Apr, Q3 = May–Jul, Q4 = Aug–Oct
- Sheets are named by quarter:
Q4_WIP_Projects,Q2_2026,FY26Q1 Forecast $ - Projects carry a
Qtrcolumn: "FY26Q2", "FY25Q4", "25Q4", "Q4"
Action: Add quarter to Project (string like "FY26Q2"). Build a fiscal quarter utility (lib/fiscal-quarter.ts) that converts dates to/from HP's fiscal calendar. Dashboard and reporting views should group by fiscal quarter.
11. Excel Import Column Mapping
When importing from this spreadsheet, the column mapper must handle:
- Inconsistent headers across sheets (e.g.,
WF,WF/OMG,WF Link,WF/OMGall mean Workfront reference) - Blank/unnamed columns used as spacers (cols 11, 22-26 in Q4_WIP)
- Merged cells (25 merge regions in Q4_WIP alone)
- Multi-line cell content with
\r\nseparators (CMF, Requestor, Remarks fields) - Excel serial date numbers (45895, 45947, etc.) — need conversion
- Inconsistent quarter format ("Q4", "FY25Q4", "25Q4", "FY26Q2")
- Inconsistent OMG code format ("OMG1798463", "OMG:1968117", "OMG 2116699", plain "2233567")
- Cost values as strings with embedded formatting ("Total $24980\r\nCost split\r\n70% for FYQ4...")
- Multiple data tables per sheet (Project_Count has 3 side-by-side datasets)
Action: The Excel import Phase 3 feature needs robust header fuzzy-matching, date serial conversion, multi-line cell parsing, and cost string extraction. Build a lib/excel/column-aliases.ts mapping known header variations to canonical field names.
12. Summary of Data Model Changes Needed
New enums:
BusinessUnit: D_AND_P, POLY, ACS, CPS, BPS, GAMING, PRINT
NpiOrRefresh: NPI, REFRESH
ArtistDepartment: CG_STILLS, CG_MODEL_PREP, CG_ANIMATION, CG_PRODUCER
Project — new fields:
businessUnit BusinessUnit?
formFactor String?
codeName String?
npiOrRefresh NpiOrRefresh?
quarter String?
requestor String?
workfrontId String?
omgCode String?
bmtId String?
estimatedCost Float?
actualCost Float?
projectedRevenue Float?
Deliverable — new fields:
cmfSku String? (multi-line text)
assetCount Int?
requestedDueDate DateTime?
plannedDeliveryDate DateTime?
actualDeliveryDate DateTime?
wfInputDate DateTime?
scriptStatus String?
agency String?
costBreakdown Json? (Model Prep, Core, Alt Color, etc.)
User — new field:
department ArtistDepartment?
PipelineStageTemplate — new field:
estimatedDays Float?
StageStatus enum — consider adding:
DELIVERED (distinct from APPROVED — work delivered to DAM)
New pipeline stages to evaluate:
Stage 11: Annotated Spin (10 WDs, post-Catalog gate)
Stage 12: Spill Images (3 WDs, post-Catalog gate)
13. Deep Dive: Q2_2026 Sheet — Additional Findings
The Q2_2026 sheet (75 data rows) is the most current active-work tracker. A row-by-row review reveals patterns the header-level analysis missed:
13a. Business Units Are Far More Diverse Than Expected
The initial BU enum listed 7 values. The actual data shows 12+ distinct BU values:
| BU in Data | Notes |
|---|---|
| CPS | Consumer Personal Systems |
| ACS | Advanced Computing Solutions (ZBook, Workstations) |
| BPS | Business Personal Systems (EliteBook, ProBook, ProDesk) — dominates the sheet |
| Peripheral / Peripherals | Inconsistent naming — headsets, cables |
| Printer OPS | Office Printing Solutions |
| Printer HPS | Home Printing Solutions |
| NPI | New Product Introduction (used as a BU?) |
| Pan PS | Pan Personal Systems (keyboards, mice, adapters) |
| Hybrid Systems | Keyboards/peripherals |
| RPOS | Retail Point of Sale |
| D&P | Displays & Peripherals |
| Poly | Poly (conferencing headsets/video) |
Action: BusinessUnit enum needs expansion. Consider whether "Printer OPS" and "Printer HPS" should be separate from a general "PRINT", and whether "NPI" is truly a BU or a project classification. Use a string field with suggested values rather than a strict enum, given the evolving nature.
13b. Form Factors Go Well Beyond PC Categories
| Form Factor | Count in Q2 | Description |
|---|---|---|
| NB | ~25 | Notebook |
| DT | ~8 | Desktop |
| X360 | 1 | Convertible |
| Printer | ~10 | Printers (OPS + HPS) |
| Headset | 3 | Poly headsets |
| Accessories | 2 | Cables, peripherals |
| Display | 2 | Monitors |
| KB | 2 | Keyboards |
| KBM | 1 | Keyboard-Mouse combo |
| Mouse | 3 | Mice |
| Adapter | 3 | Power adapters |
| Cable | 1 | Cables |
| SFF | 2 | Small Form Factor desktop |
| CS | 1 | Clamshell? |
| Tablet | 1 | Tablets |
| Various | 2 | Multiple form factors |
| TBD / "No clarity" | 3 | Not yet determined |
Action: formFactor must be a free-text string, not an enum. Too many values and they evolve with product lines.
13c. The "WF" Column Is a Project Description, Not Just an ID
Examples from the data:
"[CPS] Finley Catalog""ZBook 8 G2i - MerinoW 14in and 16in Hero Imagery""BPS Imagine 26 Lifestyle Photocomps""Nacho14 _Catalog_HeroImagery_SimpleSpin_LifestyleComposites"
This is essentially the project name/description from Workfront — a human-readable label, not a numeric ID. The actual WF ID is sometimes embedded in a link, sometimes absent.
Action: Map this to the Project.name field. The workfrontId field should capture any numeric WF reference separately.
13d. Additional Deliverable Types Found
| Type in Data | Current Stage? | Notes |
|---|---|---|
| Lifestyle | No | Lifestyle composite images. Distinct from Photocomp. 4–26 assets per project. |
| Pkg | Partially — "Packaging Images" | Abbreviated. Appears for adapters, printers, peripherals — not just PC packaging. |
| Screen Swap | No | Updating screen content in existing renders. Lightweight task (16 assets, no model prep). |
| TBD | N/A | Type not yet determined during planning phase. |
Action: "Lifestyle" composites are a distinct deliverable type (different from Photocomp). "Screen Swap" is a lightweight task type. Both should be considered for the pipeline template. The "Pkg" abbreviation confirms Packaging is used broadly beyond PC products.
13e. Multiple Artists Per Deliverable — Varied Separator Formats
The Artist field uses multiple delimiter styles:
"Juan | Amit"— pipe with spaces"Ankit/Bharat"or"AnkitBharat"— slash or concatenated"Ameya, Nizam, Eric"— commas"O+Pix+OV"— external agencies with plus signs
External agency codes appear directly in the Artist field:
- Pix — external agency
- OV — Oliver agency
- O — Oliver abbreviation
Action: The assignment system needs to support multiple artists per deliverable and distinguish internal artists from external agencies. Consider StageAssignment for internal artists and a separate agency field (or tag) for external vendors. The import parser needs multi-delimiter splitting for the Artist field.
13f. The "ID | CMF" Column Tracks Two Reviewer Roles
This column consistently contains two types of contacts:
- ID (Industrial Designer):
"ID: Steve.lai","ID: Boberoi","ID: Chi Miles, FredHuang" - CMF (Color Material Finish designer):
"CMF: MatthewWilliams","CMF: Matt Williams"
These are HP-side reviewers who must approve renders at specific checkpoints. The "Kiran / ID reviews" column tracks when this review is scheduled or completed.
Action: Consider modeling ID and CMF reviewers as project-level contacts (not app users). Add idReviewer and cmfReviewer optional string fields to Project or Deliverable. These are external HP stakeholders, not system users.
13g. Richer Status Vocabulary Than Initially Mapped
The Q2_2026 data reveals workflow-specific statuses not in the initial mapping:
| Status | Meaning | Frequency |
|---|---|---|
| Clays | Clay renders posted for review (pre-lighting) | 3 rows |
| Lighting / Lighting WIP | Lighting stage in progress | 2 rows |
| Model Prep | Specifically in model preparation | 2 rows |
| Under Prep | Model prep in progress | 1 row |
| To be started | Queued but not begun | 5 rows |
| Share Quote | Cost estimate pending client approval | 3 rows |
| Quotes TBD | Estimating phase | 2 rows |
| In-Planning | Project still being scoped | 2 rows |
| Catalogs in progress | Dependent on catalog stage completing first | 1 row |
| Aug Due | Far-future delivery, placeholder | 2 rows |
| HOLD | On hold (different capitalization from "On Hold") | 1 row |
| TBI | To Be Initiated | 1 row |
Key insight: Many of these are sub-statuses within IN_PROGRESS that describe which part of the work is active (clay modeling → lighting → compositing → review). The current StageStatus enum captures the macro state but loses this workflow detail.
Action: Add an optional subStatus or workflowStep free-text field to DeliverableStage to capture granular progress ("Clays posted", "Lighting WIP", "Pending ID review"). This preserves the informal status language producers actually use while keeping the formal enum for filtering and reporting.
13h. Cross-Quarter Overflow
The Q2_2026 sheet contains items from 4 different quarters:
- FY26Q1 (rows 46–50): Carryover items still in progress
- FY26Q2 (majority): Current quarter
- FY26Q3 (row 38): Next-quarter item already briefed
- FY26Q4 (row 39): Future item already in pipeline
Action: Projects carry a primary quarter but may appear across multiple quarter views. Filtering by quarter should use the project's assigned quarter, not date-based inference. Consider a "target quarter" vs "actual delivery quarter" distinction.
13i. Date Format Inconsistency in Input Data
The same column (Requested Due Date) contains:
- Excel serial numbers:
46071,46143,46244 - Text strings:
"TBD","13th Feb","20/03","28/02","13/07","14/11" - Mixed
DD/MMformat (notMM/DD— important for parsing)
Action: The Excel import parser needs to handle mixed date formats in the same column. Parse strategy: try Excel serial → try DD/MM/YYYY → try text date → store as null + flag for manual review. Date locale is DD/MM (European/international), not MM/DD.
13j. The Requestor Field Contains Complex Contact Lists
Examples:
- Simple:
"Nancy","Corey Hilton" - Multi-person:
"SH: Nancy, alejandra.duarte@hp.com\r\nkristine.el-zokm@hp.com, lily.psimaris@hp.com" - Roles embedded:
"SH: Oliva Amy, Connor Rock,\r\nGautam Khanna, ID: Steve.lai" - Combined:
"PM: Anna Kuo, Sunny Chou,\r\nSH: Alejandra Duarte"
Roles mentioned: SH (Stakeholder), PM (Project Manager), ID (Industrial Designer).
Action: The requestor field should be a text field supporting multi-line input. Do not try to normalize this into structured contacts for V1 — the variety is too high. Consider structured HP contacts as a Phase 5+ feature.
Verification Plan
- Auth flow: Log in via Google/Microsoft SSO → verify session contains role + org → verify unauthorized domains are rejected
- Pipeline dependencies: Create a deliverable → verify stages 6-10 are BLOCKED → approve Model Prep → verify still blocked → approve Catalog → verify stages 6-10 become NOT_STARTED
- CRUD: Create project → add deliverables → assign artists → update statuses → delete → verify cascade
- Views: Switch between Table/Board/Timeline/Dashboard → verify data consistency → test filters/sorts persist in URL
- Revisions: Submit revision on a stage → request changes → submit round 2 → approve → verify round count
- Excel: Import a sample spreadsheet → map columns → preview → commit → verify data created. Export → verify multi-sheet workbook with correct data
- Notifications: Assign an artist → verify notification appears → mark read → verify count decreases