dow-prod-tracker/UPGRADE_PLAN.md
Leivur Djurhuus 9d5acf1683 feat: add Smart Search Panel with semantic search capabilities
- Implemented Smart Search Panel component for enhanced project and deliverable search functionality.
- Introduced useSemanticSearch and useOllamaHealth hooks for managing search queries and AI availability.
- Developed embedding-service to generate and store vector embeddings for projects and deliverables.
- Created semantic-search-service to handle vector search, structural query detection, and LLM summarization.
- Added support for hybrid search combining structural filters and semantic queries.
- Integrated UI components for displaying search results and user interactions.
2026-03-06 16:13:36 -06:00

72 KiB
Raw Blame History

HP CG Production Tracker — Upgrade Plan (Phase 5+)

This document covers all planned upgrades beyond the Phase 14 foundation. Each feature area includes scope, implementation approach, new/modified files, and dependencies. Features are grouped by domain and ordered within each phase by priority.


Table of Contents

  1. Phase 5: Visual Review & Annotation System
  2. Phase 6: Workload & Resource Management
  3. Phase 7: Automation & Workflow Engine
  4. Phase 8: Asset Intelligence & AI Review Integration
  5. Phase 9: Advanced Reporting & Analytics
  6. Phase 10: Collaboration Enhancements
  7. Phase 11: Quality of Life & Polish
  8. Phase 12: Docker Deployment
  9. Data Model Changes Summary
  10. New API Routes Summary
  11. New Pages Summary
  12. Third-Party Libraries

Phase 5: Visual Review & Annotation System

The cornerstone upgrade. Transforms the tracker from a status management tool into a true visual production platform. Every CG deliverable ultimately produces an image — reviewing those images with precision is the core workflow.

5.1 — Image Viewer with High-Fidelity Zoom

What: Full-screen image viewer with smooth pan/zoom up to 200%+ for pixel-level inspection. Supports common CG output formats (PNG, TIFF, EXR preview, JPEG).

Why: HP's quality bar for CG renders is extremely high. Producers and artists need to inspect fine details (texture seams, aliasing, color banding) at pixel level without downloading files to a separate app.

Implementation:

  • Canvas-based viewer component using <canvas> with WebGL acceleration for large images
  • Zoom controls: scroll wheel, pinch gesture (touch), toolbar buttons, keyboard shortcuts (+/-)
  • Zoom levels: fit-to-view, 50%, 100% (1:1 pixel), 150%, 200%, and free zoom
  • Pan via click-drag when zoomed in; minimap overlay showing viewport position on full image
  • Pixel coordinate display in status bar (x, y) with color value readout (RGB/Hex)
  • Preload adjacent revisions for instant switching
  • Support for high-DPI displays (retina) with proper pixel ratio handling

Key files:

  • src/components/review/image-viewer.tsx — Core canvas viewer component
  • src/components/review/zoom-controls.tsx — Zoom toolbar + keyboard handler
  • src/components/review/minimap.tsx — Navigation minimap overlay
  • src/hooks/use-image-viewer.ts — Pan/zoom state management hook

Dependencies: None (uses native Canvas API + WebGL)


5.2 — Pixel-Accurate Annotations

What: Draw annotations directly on images — circles, rectangles, arrows, freehand, and text labels. Each annotation is anchored to image coordinates (not screen coordinates) so they remain accurate at any zoom level. Annotations are linked to comments.

Why: "See the artifact on the left edge of the product, 3rd shelf" is ambiguous. Clicking on the exact pixel and drawing a circle around it eliminates miscommunication between producers, artists, and HP reviewers.

Implementation:

  • SVG overlay layer on top of the canvas viewer (annotations render in SVG for crisp scaling, image renders in canvas for performance)
  • Annotation tools: rectangle, ellipse, arrow, freehand path, text label, pin (point marker)
  • Color picker for annotation stroke (default: accent red for visibility)
  • Annotations stored as JSON in the database with image-space coordinates
  • Each annotation is linked to a Comment record — clicking an annotation highlights the associated comment in the sidebar, and vice versa
  • Annotation visibility toggle (show/hide all, show/hide per revision round)
  • Undo/redo stack for annotation drawing session

Data model additions:

model Annotation {
  id              String   @id @default(cuid())
  commentId       String
  comment         Comment  @relation(fields: [commentId], references: [id], onDelete: Cascade)
  revisionId      String
  revision        Revision @relation(fields: [revisionId], references: [id], onDelete: Cascade)
  type            AnnotationType  // RECTANGLE, ELLIPSE, ARROW, FREEHAND, TEXT, PIN
  data            Json            // { x, y, width, height, points[], text, color, strokeWidth }
  imageX          Float           // anchor point in image coordinates
  imageY          Float
  createdById     String
  createdBy       User     @relation(fields: [createdById], references: [id])
  createdAt       DateTime @default(now())
}

enum AnnotationType {
  RECTANGLE
  ELLIPSE
  ARROW
  FREEHAND
  TEXT
  PIN
}

Key files:

  • src/components/review/annotation-layer.tsx — SVG overlay with tool switching
  • src/components/review/annotation-tools.tsx — Toolbar with tool selection
  • src/components/review/annotation-renderer.tsx — Renders individual annotation shapes
  • src/lib/services/annotation-service.ts — CRUD for annotations
  • src/lib/validators/annotation.ts — Zod schemas
  • src/hooks/use-annotations.ts — TanStack Query hook

Dependencies: Requires 5.1 (Image Viewer)


5.3 — Side-by-Side Version Comparison

What: Compare two revisions of the same deliverable using multiple comparison modes: side-by-side, overlay with opacity slider, horizontal/vertical wipe (swipe divider), and onion skin.

Why: CG revision changes are often subtle — slightly adjusted lighting, minor geometry fixes, color grading tweaks. Direct visual comparison makes it obvious what changed between rounds.

Implementation:

  • Dual-pane viewer sharing a synchronized zoom/pan state (pan one, both move)
  • Comparison modes:
    • Side-by-side: Two viewers, synced zoom/pan, with version labels
    • Overlay: Single viewer, second image overlaid with adjustable opacity (0-100%)
    • Wipe: Draggable vertical or horizontal divider revealing one image on each side
    • Onion skin: Alternating between images at adjustable interval (useful for animation)
  • Dropdown selectors for left/right revision (default: previous round vs. current round)
  • Annotations from both versions shown with version-colored borders
  • Keyboard shortcuts: 1/2/3/4 to switch modes, left/right arrows to cycle revisions

Key files:

  • src/components/review/comparison-viewer.tsx — Dual-pane orchestrator
  • src/components/review/wipe-divider.tsx — Draggable split control
  • src/components/review/overlay-controls.tsx — Opacity slider + mode toggles
  • src/app/(app)/projects/[projectId]/deliverables/[deliverableId]/review/page.tsx — Review page

Dependencies: Requires 5.1 (Image Viewer)


5.4 — Revision History Timeline & Version Control

What: A dedicated panel within the review viewer that provides full version history for every deliverable stage. Browse all revision rounds (v1, v2, v3...) with thumbnails, see comments and annotations tied to each version, track the decision history per round, and navigate between any version with a single click.

Why: The core review loop in CG production is iterative — an artist submits, a producer requests changes, the artist resubmits, and the cycle repeats multiple times. Without a clear version timeline, it's easy to lose track of what feedback was given on which round, what changed between versions, and who approved what and when. This is the connective tissue between annotations (5.2), comparison (5.3), and review sessions (5.5) — it provides the longitudinal view across all revision rounds.

Implementation:

  • Collapsible sidebar panel in the review viewer (right side or bottom drawer)
  • Vertical timeline layout with each revision round as a node:
    • Thumbnail preview of that round's submitted image (auto-generated via 8.2)
    • Round number + status badge (Submitted, Changes Requested, Approved, Rejected)
    • Submitted by (artist name + avatar) and submission timestamp
    • Annotation count for that round (clickable to filter annotation layer)
    • Comment thread summary — first line of feedback + total comment count
    • Decision record — who approved/rejected, when, with what note
    • File metadata — resolution, file size, format (useful for tracking resubmission quality)
  • Click any round to load that version in the image viewer with its annotations
  • "Latest" badge on the most recent round; "Current" badge on the one being viewed
  • Diff indicators between rounds: visual markers showing which rounds had changes requested vs. approved, building a clear progression narrative
  • Keyboard navigation: up/down arrows to move through rounds, Enter to load
  • Filtering: show all rounds, show only rounds with feedback, show only decision points
  • Timeline integrates with comparison viewer (5.3): selecting two rounds from the timeline opens them in side-by-side/overlay/wipe mode
  • Export revision history as PDF report (round-by-round summary with thumbnails, feedback notes, decisions, and timestamps) for stakeholder documentation

Comment threading per version:

  • Comments on the existing deliverable stage are already threaded (Phase 3)
  • This feature extends the comment display to be grouped by revision round in the timeline panel — each round's node expands to show its associated comments and annotations
  • New comments can be posted against any historical round (not just the latest), enabling back-references like "the fix from v2 introduced a new issue visible at..."
  • Comments from external review links (10.3) and review sessions (5.5) also appear in the timeline, attributed to the round they were made on

Annotation history per version:

  • Each annotation is already linked to a revisionId (5.2)
  • The timeline panel shows annotation counts per round and toggles annotation visibility per round on the image viewer
  • "Show all annotations" mode overlays annotations from all rounds with color-coded borders (e.g., v1 = blue, v2 = orange, v3 = green) for seeing the full feedback history at once
  • "Show resolved" toggle to distinguish between addressed and still-open annotations

Decision audit trail:

  • Every approve/reject/changes-requested decision is logged with: who, when, note
  • Displayed inline in the timeline at the relevant round
  • Links to approval chain records (7.2) when multi-level approval is configured
  • Exportable as part of the revision history PDF

No new data model required — uses existing Revision (roundNumber, status, feedbackNotes, internalNotes, attachments, timestamps), Comment (threaded, per stage), and Annotation (per revision) models. The timeline is a read-only aggregation view over existing data.

Key files:

  • src/components/review/revision-timeline.tsx — Main timeline panel component
  • src/components/review/revision-node.tsx — Individual round node with expandable details
  • src/components/review/revision-comments.tsx — Per-round comment thread display
  • src/components/review/revision-annotations-summary.tsx — Annotation count + filter toggles
  • src/components/review/revision-history-export.tsx — PDF export generator
  • src/hooks/use-revision-history.ts — TanStack Query hook aggregating revisions + comments + annotations
  • Update src/app/(app)/projects/[projectId]/deliverables/[deliverableId]/review/page.tsx — Integrate timeline panel

Dependencies: Requires 5.1 (Image Viewer) + 5.2 (Annotations). Enhanced by 5.3 (Comparison) and 8.2 (Preview Generation for thumbnails).


5.5 — Review Sessions & Playlists

What: Curate a set of deliverables/revisions into a review session. Walk through them sequentially with per-item approve/request-changes/reject actions. Shareable via link.

Why: Producers regularly review batches of deliverables with HP stakeholders. A structured review session replaces scattered email threads and ensures every item gets a documented decision.

Implementation:

  • Review Session entity containing ordered list of items (deliverable stage + revision)
  • Session states: DRAFT -> IN_PROGRESS -> COMPLETED
  • Presenter mode: full-screen, navigate with arrow keys, decision buttons prominent
  • Each item shows: image viewer, annotation layer, comment sidebar, decision buttons
  • Summary view: grid of thumbnails with approve/reject status badges
  • Shareable link with optional expiry and access control (internal only vs. external)
  • Auto-generate session from filters (e.g., "all Catalog Images in Review for Project X")

Data model additions:

model ReviewSession {
  id              String              @id @default(cuid())
  name            String
  status          ReviewSessionStatus @default(DRAFT)
  createdById     String
  createdBy       User                @relation(fields: [createdById], references: [id])
  organizationId  String
  organization    Organization        @relation(fields: [organizationId], references: [id])
  shareToken      String?             @unique
  expiresAt       DateTime?
  items           ReviewSessionItem[]
  createdAt       DateTime            @default(now())
  updatedAt       DateTime            @updatedAt
}

model ReviewSessionItem {
  id                 String           @id @default(cuid())
  sessionId          String
  session            ReviewSession    @relation(fields: [sessionId], references: [id], onDelete: Cascade)
  deliverableStageId String
  deliverableStage   DeliverableStage @relation(fields: [deliverableStageId], references: [id])
  revisionId         String?
  revision           Revision?        @relation(fields: [revisionId], references: [id])
  sortOrder          Int
  decision           ReviewDecision?
  decisionNote       String?
  decidedById        String?
  decidedBy          User?            @relation(fields: [decidedById], references: [id])
  decidedAt          DateTime?
}

enum ReviewSessionStatus {
  DRAFT
  IN_PROGRESS
  COMPLETED
}

enum ReviewDecision {
  APPROVED
  CHANGES_REQUESTED
  REJECTED
}

Key files:

  • src/app/(app)/reviews/page.tsx — Review sessions list
  • src/app/(app)/reviews/[sessionId]/page.tsx — Session presenter view
  • src/components/review/session-builder.tsx — Create/edit session with item picker
  • src/components/review/session-presenter.tsx — Full-screen walkthrough mode
  • src/components/review/session-summary.tsx — Thumbnail grid with decisions
  • src/lib/services/review-session-service.ts — Business logic
  • src/hooks/use-review-sessions.ts — TanStack Query hooks
  • API routes: /api/reviews/, /api/reviews/[sessionId]/, /api/reviews/[sessionId]/items/

Dependencies: Requires 5.1 + 5.2 (Image Viewer + Annotations). Enhanced by 5.4 (Revision Timeline).


5.6 — Feedback Action Items (Artist Checklist)

What: Every annotation and review comment automatically becomes an actionable to-do item on a checklist for the assigned artist. Artists see a clear, prioritized list of everything they need to address for each revision round, and can check items off as they work through them. When all items are resolved, the stage is ready for resubmission.

Why: Without this, artists must mentally parse through comment threads and scan annotations to build their own list of what needs fixing. Items get missed, context gets lost, and producers have to manually verify whether feedback was addressed. A structured checklist makes the feedback-to-fix loop explicit, trackable, and auditable.

How it works — the full feedback loop:

  1. Reviewer creates feedback — draws annotation or writes comment with actionable note
  2. System auto-creates a FeedbackItem — linked to the annotation/comment, assigned to the stage's artist(s), categorized by severity
  3. Artist sees checklist — organized by priority, with direct links to the annotation on the image
  4. Artist works through items — checks each off as addressed, optionally adds a resolution note ("Fixed — adjusted specular intensity by 15%")
  5. Artist submits new revision — any unchecked items carry forward as still-open on the next round with a warning
  6. Reviewer verifies — can see which items were marked resolved, compare before/after, and either confirm resolution or reopen

Where the checklist appears (3 locations):

1. Review Viewer — Feedback Panel (primary)

  • Dedicated collapsible panel in the review viewer, alongside the revision timeline (5.4)
  • Full checklist for the current revision round with:
    • Checkbox + item summary (auto-generated from annotation/comment text)
    • Severity indicator: Critical (red), Major (orange), Minor (yellow), Suggestion (blue)
    • Thumbnail crop of the annotated region (click to zoom to that spot on the image)
    • "Resolve" action with optional note field
    • Status: Open, In Progress, Resolved, Verified (by reviewer), Reopened
  • Filter by: status (open/resolved), severity, annotation type
  • Progress bar at top: "4 of 7 items resolved"
  • Grouped by revision round — see current round's items and carried-forward items from previous rounds

2. My Work Page — Feedback Summary (artist's home base)

  • Each assignment card on the existing My Work page gets a feedback badge: "5 open items"
  • Expandable section within each assignment showing the checklist inline
  • Click any item to deep-link directly to the review viewer, zoomed to that annotation
  • Aggregate counters at top of My Work page: "12 open feedback items across 3 assignments"
  • Sort/filter assignments by: most feedback items, highest severity items first, oldest unresolved items

3. Stage Card on Deliverable Detail — Progress Indicator (producer view)

  • Compact progress indicator on the stage card: "4/7 feedback items resolved"
  • Color-coded: red if critical items are open, green if all resolved
  • Hover popover showing breakdown by severity
  • Producers can see at a glance which stages have outstanding feedback before approving

Auto-creation rules:

  • When an annotation is created → auto-create FeedbackItem linked to that annotation
  • When a comment is posted and contains actionable language → auto-create FeedbackItem (optional: reviewer can toggle "Mark as action item" checkbox when posting a comment, default ON for annotations, default OFF for comments to avoid noise from discussion threads)
  • Reviewers can also manually create standalone feedback items (not tied to an annotation) for general notes like "Overall color temperature feels too warm"
  • Bulk creation: reviewer can batch-create items from a review session (5.5) where each "changes requested" decision auto-generates items from that session's annotations

Severity levels:

  • Critical — Must fix before resubmission (blocks approval). E.g., wrong product shown, missing required element
  • Major — Should fix, significant quality issue. E.g., visible artifacts, wrong lighting
  • Minor — Nice to fix, small quality issue. E.g., minor texture seam, slight color shift
  • Suggestion — Optional improvement, not required for approval. E.g., "Consider slightly warmer fill light"

Data model additions:

model FeedbackItem {
  id                  String            @id @default(cuid())
  deliverableStageId  String
  deliverableStage    DeliverableStage  @relation(fields: [deliverableStageId], references: [id], onDelete: Cascade)
  revisionId          String
  revision            Revision          @relation(fields: [revisionId], references: [id], onDelete: Cascade)
  annotationId        String?
  annotation          Annotation?       @relation(fields: [annotationId], references: [id], onDelete: SetNull)
  commentId           String?
  comment             Comment?          @relation(fields: [commentId], references: [id], onDelete: SetNull)
  summary             String            // short description of what needs to be done
  severity            FeedbackSeverity  @default(MAJOR)
  status              FeedbackStatus    @default(OPEN)
  sortOrder           Int               @default(0)
  assignedToId        String?
  assignedTo          User?             @relation("FeedbackAssignee", fields: [assignedToId], references: [id])
  createdById         String
  createdBy           User              @relation("FeedbackCreator", fields: [createdById], references: [id])
  resolvedById        String?
  resolvedBy          User?             @relation("FeedbackResolver", fields: [resolvedById], references: [id])
  resolvedAt          DateTime?
  resolutionNote      String?
  verifiedById        String?
  verifiedBy          User?             @relation("FeedbackVerifier", fields: [verifiedById], references: [id])
  verifiedAt          DateTime?
  carriedFromId       String?           // if carried forward from a previous round
  carriedFrom         FeedbackItem?     @relation("FeedbackCarryForward", fields: [carriedFromId], references: [id])
  carriedTo           FeedbackItem[]    @relation("FeedbackCarryForward")
  createdAt           DateTime          @default(now())
  updatedAt           DateTime          @updatedAt

  @@index([deliverableStageId])
  @@index([revisionId])
  @@index([assignedToId])
  @@index([status])
  @@map("feedback_items")
}

enum FeedbackSeverity {
  CRITICAL
  MAJOR
  MINOR
  SUGGESTION
}

enum FeedbackStatus {
  OPEN
  IN_PROGRESS
  RESOLVED
  VERIFIED
  REOPENED
}

Key files:

  • src/components/review/feedback-checklist.tsx — Main checklist panel in review viewer
  • src/components/review/feedback-item.tsx — Individual checklist item with resolve action
  • src/components/review/feedback-progress-bar.tsx — Progress bar (4/7 resolved)
  • src/components/review/feedback-create-dialog.tsx — Manual item creation
  • src/components/my-work/feedback-summary.tsx — Inline checklist on My Work page
  • src/components/stages/feedback-indicator.tsx — Compact badge for stage cards
  • src/lib/services/feedback-service.ts — CRUD, auto-creation logic, carry-forward
  • src/lib/validators/feedback.ts — Zod schemas
  • src/hooks/use-feedback-items.ts — TanStack Query hook
  • API routes: /api/feedback/, /api/feedback/[itemId]/, /api/stages/[stageId]/feedback/

Automation integration (Phase 7):

  • Auto-rule: "When all Critical + Major feedback items are resolved → notify producer that stage is ready for re-review"
  • Auto-rule: "When a new revision is submitted with unresolved Critical items → warn artist and block submission" (configurable)
  • Auto-rule: "When feedback item is unresolved for >3 days → escalate notification"

Dependencies: Requires 5.2 (Annotations) + 5.4 (Revision Timeline). Enhanced by 7.1 (Automation triggers). Integrates with existing My Work page and deliverable detail page.


Phase 6: Workload & Resource Management

Gives producers visibility into team capacity so they can make informed assignment decisions and prevent burnout/bottlenecks.

6.1 — Capacity Planning View

What: Visual overview of each artist's assignment load across all projects, broken down by week. Shows allocated vs. available capacity with overallocation warnings.

Implementation:

  • New page: /workload — grid with artists as rows, weeks as columns
  • Each cell shows number of active assignments + status breakdown (colored segments)
  • Configurable capacity threshold per user (default: 5 concurrent assignments)
  • Overallocation highlighted in red when assignments exceed threshold
  • Click a cell to drill down into specific assignments for that artist/week
  • Filter by project, stage type, date range
  • Data sourced from existing StageAssignment + DeliverableStage records

Data model additions:

// Add to User model:
maxCapacity     Int     @default(5)    // max concurrent assignments

Key files:

  • src/app/(app)/workload/page.tsx — Capacity planning page
  • src/components/workload/capacity-grid.tsx — Artist x Week grid
  • src/components/workload/capacity-cell.tsx — Individual cell with status bars
  • src/components/workload/capacity-detail-popover.tsx — Drill-down assignment list
  • src/lib/services/workload-service.ts — Aggregation queries
  • API route: /api/workload/

6.2 — Utilization Heatmaps

What: Color-coded heatmap showing team utilization over time. Instantly spot who's overloaded, who's underutilized, and how load trends over weeks/months.

Implementation:

  • Heatmap component integrated into workload page as an alternate visualization
  • Color scale: light green (low load) -> yellow (moderate) -> red (overallocated)
  • Toggle between absolute count and percentage of capacity
  • Time range: 4-week, 8-week, 12-week, custom
  • Export to image/PDF for stakeholder reports

Key files:

  • src/components/workload/utilization-heatmap.tsx — Heatmap visualization (recharts)
  • src/components/workload/heatmap-legend.tsx — Color scale legend

Dependencies: Requires 6.1 (Capacity Planning data)


6.3 — Skill-Based Assignment Suggestions

What: Tag users with specialties (modeling, texturing, lighting, compositing, animation). When assigning an artist to a stage, suggest best-fit artists based on skill match, current workload, and availability.

Implementation:

  • New Skill model and many-to-many with User
  • Predefined skill set relevant to CG pipeline: Modeling, Texturing, UV Mapping, Lighting, Rendering, Compositing, Animation, Rigging, Photography, Retouching
  • Each pipeline stage template maps to recommended skills
  • Assignment dialog shows suggested artists sorted by: skill match -> lowest current load
  • Visual indicator showing each suggestion's match score and current utilization

Data model additions:

model Skill {
  id        String      @id @default(cuid())
  name      String      @unique
  users     UserSkill[]
  stages    StageSkillRequirement[]
}

model UserSkill {
  userId    String
  user      User    @relation(fields: [userId], references: [id], onDelete: Cascade)
  skillId   String
  skill     Skill   @relation(fields: [skillId], references: [id], onDelete: Cascade)
  level     SkillLevel @default(INTERMEDIATE)

  @@id([userId, skillId])
}

model StageSkillRequirement {
  stageTemplateId  String
  stageTemplate    PipelineStageTemplate @relation(fields: [stageTemplateId], references: [id])
  skillId          String
  skill            Skill @relation(fields: [skillId], references: [id])
  importance       Int   @default(1)  // 1=nice-to-have, 2=important, 3=required

  @@id([stageTemplateId, skillId])
}

enum SkillLevel {
  JUNIOR
  INTERMEDIATE
  SENIOR
  LEAD
}

Key files:

  • src/app/(app)/settings/skills/page.tsx — Skill management page (admin)
  • src/components/assignments/skill-match-suggestions.tsx — Suggested artists list
  • src/lib/services/skill-service.ts — Matching algorithm
  • API routes: /api/skills/, /api/users/[userId]/skills/

Dependencies: Requires 6.1 (capacity data for load-aware suggestions)


Phase 7: Automation & Workflow Engine

Reduces manual overhead by automating repetitive status changes, notifications, and escalations based on configurable triggers.

7.1 — Trigger-Based Automations

What: Configurable "when X happens, do Y" rules that execute automatically. Eliminates manual status bumping and notification sending for predictable workflows.

Example rules:

  • When all Catalog Images are APPROVED -> auto-advance Hero/Packaging/Photocomps/360/Dynamic to NOT_STARTED
  • When a deliverable is 2 days past due -> notify the assigned PM
  • When an artist submits a revision -> auto-set stage to IN_REVIEW
  • When a review session is completed -> update all approved items' stages to APPROVED

Implementation:

  • Automation rules stored in database, configurable per organization
  • Rule structure: Trigger (event type + conditions) -> Actions (status change, notification, assignment)
  • Event bus: when a stage/revision/assignment changes, evaluate matching rules
  • Built-in rule templates for common CG pipeline workflows
  • Admin UI to create, edit, enable/disable rules
  • Execution log for audit trail (what fired, when, what it did)

Data model additions:

model AutomationRule {
  id              String              @id @default(cuid())
  name            String
  description     String?
  organizationId  String
  organization    Organization        @relation(fields: [organizationId], references: [id])
  isEnabled       Boolean             @default(true)
  trigger         Json                // { event, conditions[] }
  actions         Json                // { type, params }[]
  createdById     String
  createdBy       User                @relation(fields: [createdById], references: [id])
  executions      AutomationExecution[]
  createdAt       DateTime            @default(now())
  updatedAt       DateTime            @updatedAt
}

model AutomationExecution {
  id          String          @id @default(cuid())
  ruleId      String
  rule        AutomationRule  @relation(fields: [ruleId], references: [id], onDelete: Cascade)
  triggeredBy Json            // the event that triggered it
  result      Json            // what actions were taken
  status      ExecutionStatus
  executedAt  DateTime        @default(now())
}

enum ExecutionStatus {
  SUCCESS
  PARTIAL_FAILURE
  FAILURE
}

Supported trigger events:

  • stage.status_changed — with conditions on stage type, old/new status
  • revision.submitted — new revision uploaded
  • review.decision_made — approve/reject in review session
  • deadline.approaching — N days before due date
  • deadline.passed — due date exceeded
  • assignment.created — artist assigned to stage

Supported actions:

  • update_stage_status — change a stage's status
  • send_notification — create notification for specified users/roles
  • create_assignment — auto-assign a user
  • send_webhook — POST to external URL (future AI review integration point)

Key files:

  • src/app/(app)/settings/automations/page.tsx — Automation rules management
  • src/components/automations/rule-builder.tsx — Visual rule editor
  • src/components/automations/execution-log.tsx — Audit log viewer
  • src/lib/services/automation-service.ts — Rule evaluation engine
  • src/lib/automation/event-bus.ts — Event dispatcher
  • src/lib/automation/action-executor.ts — Action runner
  • API routes: /api/automations/, /api/automations/[ruleId]/, /api/automations/[ruleId]/executions/

Note: The existing dependency engine (src/lib/pipeline/dependency-engine.ts) already handles stage unblocking. The automation engine extends this with user-configurable rules beyond the hardcoded pipeline dependencies.


7.2 — Multi-Level Approval Chains

What: Define approval workflows requiring sign-off from multiple stakeholders in sequence. For example: Artist Lead -> Producer -> Client Contact.

Implementation:

  • Approval chain template per organization (configurable per stage type)
  • Each step has: approver role/user, required or optional, auto-advance on approve
  • Status tracking per step: PENDING -> APPROVED / REJECTED
  • When all required steps are approved, the stage is marked APPROVED
  • If any step is rejected, stage goes back to IN_PROGRESS with feedback
  • Visual progress indicator showing which approval steps are complete
  • Email/in-app notification at each step to the next approver

Data model additions:

model ApprovalChain {
  id              String              @id @default(cuid())
  name            String
  organizationId  String
  organization    Organization        @relation(fields: [organizationId], references: [id])
  stageType       String?             // null = applies to all stages
  steps           ApprovalStep[]
  createdAt       DateTime            @default(now())
}

model ApprovalStep {
  id              String          @id @default(cuid())
  chainId         String
  chain           ApprovalChain   @relation(fields: [chainId], references: [id], onDelete: Cascade)
  stepOrder       Int
  approverRole    Role?           // role-based (any PRODUCER)
  approverUserId  String?         // specific user
  approverUser    User?           @relation(fields: [approverUserId], references: [id])
  isRequired      Boolean         @default(true)
  autoAdvance     Boolean         @default(true)
  approvalRecords ApprovalRecord[]
}

model ApprovalRecord {
  id                  String           @id @default(cuid())
  deliverableStageId  String
  deliverableStage    DeliverableStage @relation(fields: [deliverableStageId], references: [id])
  stepId              String
  step                ApprovalStep     @relation(fields: [stepId], references: [id])
  decision            ReviewDecision
  note                String?
  decidedById         String
  decidedBy           User             @relation(fields: [decidedById], references: [id])
  decidedAt           DateTime         @default(now())
}

Key files:

  • src/app/(app)/settings/approvals/page.tsx — Approval chain configuration
  • src/components/approvals/chain-builder.tsx — Visual chain editor (drag to reorder steps)
  • src/components/approvals/approval-progress.tsx — Step-by-step progress indicator
  • src/lib/services/approval-service.ts — Chain evaluation and advancement
  • API routes: /api/approval-chains/, /api/stages/[stageId]/approve/

7.3 — Project Templates

What: Save a full project configuration (deliverable list, stage settings, default assignments, automation rules) as a reusable template. One-click project creation for repeat HP SKU types.

Why: HP product shoots often follow the same structure — same deliverable types, same pipeline, same team assignments. Templates eliminate 15-20 minutes of manual setup per project.

Implementation:

  • "Save as Template" action on any existing project
  • Template captures: deliverable names/types, stage configurations, default assignments (by role, not specific user), automation rules, priority defaults
  • "New Project from Template" in project creation dialog
  • Template library page with preview, edit, duplicate, delete
  • Org-level templates (shared) + personal templates

Data model additions:

model ProjectTemplate {
  id              String                    @id @default(cuid())
  name            String
  description     String?
  organizationId  String
  organization    Organization              @relation(fields: [organizationId], references: [id])
  createdById     String
  createdBy       User                      @relation(fields: [createdById], references: [id])
  isShared        Boolean                   @default(true)
  configuration   Json                      // full template config
  deliverables    ProjectTemplateDeliverable[]
  createdAt       DateTime                  @default(now())
  updatedAt       DateTime                  @updatedAt
}

model ProjectTemplateDeliverable {
  id              String              @id @default(cuid())
  templateId      String
  template        ProjectTemplate     @relation(fields: [templateId], references: [id], onDelete: Cascade)
  name            String
  type            String?
  priority        Priority            @default(MEDIUM)
  defaultAssignments Json?            // [{ role, stageType }]
  sortOrder       Int
}

Key files:

  • src/app/(app)/templates/page.tsx — Template library
  • src/components/templates/template-card.tsx — Template preview card
  • src/components/templates/template-builder.tsx — Create/edit template
  • src/lib/services/template-service.ts — Template CRUD + instantiation
  • API routes: /api/templates/, /api/templates/[templateId]/instantiate/

Phase 8: Asset Intelligence & AI Review Integration

Ensures uploaded assets meet HP's strict quality standards through automated validation and future AI-powered review. The AI Review Engine is being developed as a separate service and will connect via API.

8.1 — File Validation on Upload

What: Automatically validate uploaded files against spec requirements: resolution, color space, file format, file size, aspect ratio. Reject non-conforming files with clear error messages before they enter the review pipeline.

Implementation:

  • Validation rules configurable per stage type (e.g., Catalog Images require 4000x4000px minimum, sRGB color space, PNG or TIFF)
  • Server-side validation using sharp for image metadata extraction
  • Client-side pre-validation for instant feedback (file type, basic dimensions)
  • Validation report: pass/fail per check with details
  • Override option for producers (with reason logged) when files are intentionally non-standard
  • Batch validation for multi-file uploads

Data model additions:

model AssetSpec {
  id              String   @id @default(cuid())
  organizationId  String
  organization    Organization @relation(fields: [organizationId], references: [id])
  stageType       String       // which pipeline stage this spec applies to
  name            String
  rules           Json         // { minWidth, minHeight, maxFileSize, allowedFormats[], colorSpace, dpi }
  isActive        Boolean      @default(true)
  validationResults AssetValidationResult[]
  createdAt       DateTime     @default(now())
  updatedAt       DateTime     @updatedAt
}

model AssetValidationResult {
  id              String   @id @default(cuid())
  revisionId      String
  revision        Revision @relation(fields: [revisionId], references: [id], onDelete: Cascade)
  specId          String
  spec            AssetSpec @relation(fields: [specId], references: [id])
  passed          Boolean
  results         Json     // [{ check, expected, actual, passed }]
  overrideById    String?
  overrideBy      User?    @relation(fields: [overrideById], references: [id])
  overrideReason  String?
  validatedAt     DateTime @default(now())
}

Key files:

  • src/app/(app)/settings/asset-specs/page.tsx — Spec configuration (admin)
  • src/components/upload/file-validator.tsx — Validation UI with pass/fail report
  • src/lib/services/asset-validation-service.ts — Validation engine
  • src/lib/validators/asset-specs.ts — Zod schemas for spec rules
  • API routes: /api/asset-specs/, /api/revisions/[revisionId]/validate/

New dependency: sharp (image processing — already commonly used in Next.js)


8.2 — Thumbnail & Preview Generation

What: Auto-generate web-optimized thumbnails and preview images from uploaded high-resolution assets. Enables fast browsing without downloading 100MB+ source files.

Implementation:

  • On upload: generate 3 sizes — thumbnail (200px), preview (1200px), full (original)
  • Use sharp for server-side image processing
  • Store generated previews alongside originals (same storage, different paths)
  • Lazy loading with blur placeholder (LQIP — low quality image placeholder)
  • Support TIFF/EXR to JPEG/WebP conversion for browser viewing
  • Background job queue for processing (avoid blocking upload response)

Key files:

  • src/lib/services/preview-service.ts — Image processing pipeline
  • src/lib/jobs/generate-previews.ts — Background processing job
  • src/components/common/optimized-image.tsx — Image component with lazy load + LQIP

8.3 — AI Review Engine Integration Point

What: API integration layer for the external AI Review Engine. When connected, the AI engine analyzes uploaded renders for quality issues (noise, artifacts, color accuracy, composition) and returns structured feedback.

Why: HP demands exceptional quality consistency. Manual review catches most issues but human reviewers have throughput limits and can miss subtle problems. The AI engine acts as a first-pass QC layer.

Implementation:

  • Webhook endpoint that the AI Review Engine calls with analysis results
  • Structured result format: overall score, per-check scores, flagged regions (coordinates), severity levels, suggested actions
  • AI review results displayed alongside human review in the annotation viewer
  • AI-flagged regions rendered as annotations with a distinct style (dashed border, AI icon)
  • Configuration: which stages trigger AI review, confidence thresholds, auto-block on fail
  • Dashboard widget showing AI review pass rates and common issue categories

Data model additions:

model AIReviewResult {
  id                  String   @id @default(cuid())
  revisionId          String
  revision            Revision @relation(fields: [revisionId], references: [id], onDelete: Cascade)
  overallScore        Float    // 0-100
  passed              Boolean
  checks              Json     // [{ name, score, severity, details }]
  flaggedRegions      Json     // [{ x, y, width, height, issue, severity }]
  engineVersion       String
  processingTimeMs    Int
  createdAt           DateTime @default(now())
}

Key files:

  • src/app/api/webhooks/ai-review/route.ts — Incoming webhook from AI engine
  • src/components/review/ai-review-overlay.tsx — AI annotations on image viewer
  • src/components/review/ai-review-summary.tsx — Score card + issue list
  • src/lib/services/ai-review-service.ts — Result processing + storage
  • API routes: /api/webhooks/ai-review/, /api/revisions/[revisionId]/ai-review/

Dependencies: External AI Review Engine (separate project). This phase only builds the integration layer — the engine itself is developed independently.


8.4 — AI-Powered Natural Language Search (pgvector)

What: A chat-style search panel where producers can ask questions in plain English and get back relevant projects, deliverables, and pipeline stages with direct links. For example: "Which Envy projects are running behind?" or "Show me deliverables similar to the Q3 packaging work."

Why: As the tracker grows to hundreds of projects and thousands of deliverables, finding the right information becomes harder. Traditional filters work for structured queries (status = overdue), but producers often think in terms of meaning and context. Natural language search bridges that gap without requiring producers to learn complex filter combinations.

Approach: Use PostgreSQL's pgvector extension to add vector search directly to our existing database — no external vector database service needed. Use Ollama to run embedding and summarization models locally — zero API costs, no data leaves the network, and no dependency on external AI services. This keeps the architecture simple, self-contained, and free to operate.

Implementation:

  1. Database setup

    • Enable pgvector extension on PostgreSQL (CREATE EXTENSION vector)
    • Add raw SQL migration for embedding columns (Prisma doesn't natively support vector types — use Unsupported("vector(768)") in schema, raw SQL for queries)
    • Add embedding Vector(768) column to projects, deliverables, and deliverable_stages tables (768 dimensions for nomic-embed-text model)
  2. Embedding generation service

    • On create/update of a project or deliverable, generate a text representation by concatenating key fields: name, description, status, priority, assignees, deliverable names, notes, business unit, code name, etc.
    • Call the local Ollama API (POST http://ollama:11434/api/embeddings) using the nomic-embed-text model to convert that text into a 768-dimensional vector
    • Store the vector in the embedding column
    • One-time backfill script to generate embeddings for all existing records
    • Service layer hook to regenerate embeddings when records change
  3. Search API

    • New endpoint: /api/search/semantic/
    • Accepts a natural language query string
    • Converts the query to an embedding using the same model
    • Runs cosine similarity search via pgvector: SELECT *, embedding <=> $1 AS distance FROM projects ORDER BY distance LIMIT 10
    • Hybrid routing: detect structural queries (dates, statuses, priorities) and route to standard Prisma filters; route meaning-based queries to vector search
    • Results include entity type, ID, name, status, and relevance score
  4. LLM summarization layer (optional enhancement)

    • Pass the top search results + the user's original question to a local Ollama LLM (POST http://ollama:11434/api/generate) using qwen3.5:9b
    • Generate a natural language summary: "There are 3 Envy projects currently behind schedule. The most critical is Envy 16 Refresh with 4 overdue deliverables..."
    • Return both the AI summary and the structured result list
    • Runs entirely on-premises — no project data ever leaves the network
  5. Frontend: Producer Search Chat

    • Extend the existing cmdk command palette with a "smart search" mode, or add a dedicated slide-out chat panel accessible from the top nav
    • Input: free-text query field
    • Output: AI summary (if enabled) at the top, followed by clickable result cards for matching projects/deliverables that link directly into the tracker
    • Show relevance scores and highlight why each result matched
    • Conversation history within the session for follow-up questions

Data model additions:

// Add to existing models (raw SQL migration — Prisma Unsupported type)
// projects table:    embedding  Unsupported("vector(768)")?
// deliverables table: embedding  Unsupported("vector(768)")?

model SearchLog {
  id          String   @id @default(cuid())
  userId      String
  user        User     @relation(fields: [userId], references: [id])
  query       String
  resultCount Int
  clickedId   String?  // which result the user opened (for relevance tuning)
  createdAt   DateTime @default(now())

  @@index([userId])
  @@map("search_logs")
}

Key files:

  • src/lib/services/embedding-service.ts — Generate and store embeddings
  • src/lib/services/semantic-search-service.ts — Vector search + hybrid routing
  • src/app/api/search/semantic/route.ts — Search API endpoint
  • src/components/search/smart-search-panel.tsx — Chat-style search UI
  • src/hooks/use-semantic-search.ts — React Query hook for search
  • prisma/migrations/xxx_add_pgvector.sql — Raw SQL migration for pgvector setup
  • scripts/backfill-embeddings.ts — One-time backfill script

New dependencies:

  • pgvector PostgreSQL extension (installed on the database, not an npm package)
  • Ollama service (Docker container — ollama/ollama image)
  • Ollama models: nomic-embed-text (embeddings, ~274MB), qwen3.5:9b (summarization) — pulled automatically on first container start
  • Note: qwen3.5:9b has been downloaded to the local dev machine and is ready for testing. This is our chosen summarization model going forward.
  • No paid API services — everything runs locally

Practical notes:

  • Zero ongoing AI costs — all models run on-premises via Ollama
  • No project data ever leaves the network — important for HP production data
  • Ollama exposes a simple REST API (http://ollama:11434) — the embedding service just makes HTTP calls, no SDK needed
  • Embeddings are fast even on CPU (~10-50ms per record); summarization benefits from GPU but works on CPU with a few extra seconds per query
  • If vector search needs ever outgrow pgvector's performance at scale, migration to a dedicated vector database like Pinecone is straightforward — the embedding generation and search API layers stay the same, only the storage backend changes
  • Search logs enable future relevance tuning and usage analytics
  • See Phase 12: Docker Deployment for the full containerized deployment strategy including Ollama

Phase 9: Advanced Reporting & Analytics

Builds on the existing dashboard with deeper insights for project management and stakeholder reporting.

9.1 — Velocity & Throughput Metrics

What: Track deliverables completed per week, average time per stage, and identify pipeline bottlenecks.

Implementation:

  • Time tracking derived from stage status change timestamps (already captured in updatedAt)
  • Metrics: throughput (deliverables completed/week), cycle time (brief intake to final approval), stage dwell time (average time spent in each stage), bottleneck detection (stages with longest average dwell)
  • Trend charts over configurable time windows (4/8/12/26 weeks)
  • Filterable by project, stage type, artist, priority
  • Compare periods (this month vs. last month)

Key files:

  • src/components/dashboard/velocity-chart.tsx — Throughput trend line
  • src/components/dashboard/cycle-time-chart.tsx — Average cycle time breakdown
  • src/components/dashboard/bottleneck-chart.tsx — Stage dwell time comparison
  • src/lib/services/analytics-service.ts — Metric aggregation queries

9.2 — Burndown Charts

What: Per-project burndown showing remaining deliverables over time with projected completion date based on current velocity.

Implementation:

  • Chart shows: ideal burndown line, actual burndown line, projection line
  • Scope changes (added deliverables) shown as step-ups in the remaining count
  • Confidence interval on projection based on velocity variance
  • Warning when projected completion exceeds deadline

Key files:

  • src/components/dashboard/burndown-chart.tsx — Burndown visualization
  • src/components/dashboard/projection-engine.ts — Velocity-based projection math

9.3 — Client-Facing Dashboard (Read-Only Portal)

What: Simplified, read-only view for HP stakeholders to check project status without needing full app access. Accessible via secure share link.

Implementation:

  • New route group: src/app/(portal)/ — minimal layout, no sidebar, branded header
  • Share link generation with token-based auth (no account required)
  • Configurable visibility: which projects, which data fields are exposed
  • Shows: project status overview, deliverable progress grid, latest revision thumbnails, timeline, pending decisions
  • No edit capabilities — view only
  • Optional password protection + expiry on share links
  • Mobile-optimized layout

Data model additions:

model PortalLink {
  id              String    @id @default(cuid())
  token           String    @unique
  organizationId  String
  organization    Organization @relation(fields: [organizationId], references: [id])
  projectIds      String[]     // which projects are visible
  createdById     String
  createdBy       User      @relation(fields: [createdById], references: [id])
  password        String?      // bcrypt hashed, optional
  expiresAt       DateTime?
  lastAccessedAt  DateTime?
  accessCount     Int       @default(0)
  isActive        Boolean   @default(true)
  createdAt       DateTime  @default(now())
}

Key files:

  • src/app/(portal)/[token]/page.tsx — Portal landing page
  • src/app/(portal)/[token]/projects/[projectId]/page.tsx — Project detail view
  • src/components/portal/portal-header.tsx — Branded header with HP/Oliver logos
  • src/components/portal/project-overview.tsx — Status summary grid
  • src/lib/services/portal-service.ts — Token validation + scoped data access
  • src/middleware.ts — Portal route auth handling
  • API routes: /api/portal/, /api/portal/[token]/

9.4 — SLA Tracking

What: Define target turnaround times per stage type. Measure actual vs. target and flag SLA breaches in real-time.

Implementation:

  • SLA configuration per organization per stage type (e.g., Model Prep: 3 business days, Catalog Images: 5 business days)
  • Real-time SLA status: on-track (green), at-risk (yellow, >75% elapsed), breached (red)
  • SLA dashboard widget showing compliance rate and breach trends
  • Notification when an SLA is at risk (configurable threshold)
  • Historical SLA compliance reports (filterable by project, stage, artist, date range)
  • Business-hours-aware calculation (exclude weekends, optionally holidays)

Data model additions:

model SLATarget {
  id               String       @id @default(cuid())
  organizationId   String
  organization     Organization @relation(fields: [organizationId], references: [id])
  stageType        String
  targetHours      Int          // business hours
  warningThreshold Float        @default(0.75)  // warn at 75% of target
  isActive         Boolean      @default(true)
  createdAt        DateTime     @default(now())
}

Key files:

  • src/app/(app)/settings/sla/page.tsx — SLA target configuration
  • src/components/dashboard/sla-compliance-chart.tsx — Compliance rate visualization
  • src/components/stages/sla-indicator.tsx — Inline SLA status badge
  • src/lib/services/sla-service.ts — SLA calculation engine (business hours aware)

Phase 10: Collaboration Enhancements

Deepens the communication layer to reduce dependency on email and Slack for project-related discussions.

10.1 — Rich @Mentions with Deep Linking

What: @mention users in comments with autocomplete. Mentioned users receive notifications with deep links directly to the relevant deliverable/stage/comment.

Implementation:

  • @ trigger in comment input opens user autocomplete dropdown
  • Mentions stored as structured data: { userId, displayName, position } within comment text
  • Notification created for each mentioned user with direct link to the comment
  • Mentioned user's name rendered as a clickable link to their profile
  • Support @mentioning roles (e.g., @producers) to notify all users with that role

Key files:

  • src/components/comments/mention-input.tsx — Comment input with @mention autocomplete
  • src/components/comments/mention-renderer.tsx — Renders mention inline with link
  • Update src/lib/services/comment-service.ts — Extract mentions + create notifications

10.2 — Project Activity Feed

What: Unified chronological stream of all activity on a project: status changes, comments, uploads, assignments, approvals. Single source of truth for "what happened."

Implementation:

  • Activity log entries auto-generated on every state change (already partially done via notifications — extend to a dedicated activity model)
  • Filterable by: event type, user, deliverable, date range
  • Compact view (one-liner per event) and expanded view (with details)
  • Infinite scroll with cursor-based pagination

Data model additions:

model ActivityEntry {
  id              String       @id @default(cuid())
  projectId       String
  project         Project      @relation(fields: [projectId], references: [id], onDelete: Cascade)
  deliverableId   String?
  deliverable     Deliverable? @relation(fields: [deliverableId], references: [id])
  stageId         String?
  userId          String
  user            User         @relation(fields: [userId], references: [id])
  type            ActivityType
  summary         String       // human-readable: "Jane moved Catalog Images to IN_REVIEW"
  metadata        Json?        // structured event data for rich rendering
  createdAt       DateTime     @default(now())
}

enum ActivityType {
  STATUS_CHANGE
  COMMENT_ADDED
  REVISION_SUBMITTED
  ASSIGNMENT_CHANGED
  APPROVAL_DECISION
  FILE_UPLOADED
  DEADLINE_CHANGED
  PRIORITY_CHANGED
  PROJECT_CREATED
  DELIVERABLE_CREATED
}

Key files:

  • src/components/activity/activity-feed.tsx — Feed component with filters
  • src/components/activity/activity-entry.tsx — Individual entry renderer
  • src/lib/services/activity-service.ts — Logging + querying
  • API route: /api/projects/[projectId]/activity/

What: Generate watermarked, time-limited URLs for external stakeholders (e.g., HP brand team) to view specific deliverables without creating an account.

Implementation:

  • Generate unique token-based URL for specific deliverable/revision
  • Watermark overlay on images showing: reviewer email/name, date, "CONFIDENTIAL"
  • Configurable expiry (24h, 48h, 7 days, 30 days)
  • Access logging (who viewed, when, from what IP)
  • Revoke link capability
  • Comment capability for external reviewers (optional, requires email verification)

Key files:

  • src/app/(external)/review/[token]/page.tsx — External review page
  • src/components/review/watermark-overlay.tsx — Dynamic watermark renderer
  • src/lib/services/external-link-service.ts — Token generation + validation
  • API routes: /api/external-links/, /api/external-links/[token]/

Note: Overlaps with 5.5 Review Sessions share functionality and 9.3 Client Portal. These should share the underlying token/auth infrastructure but serve different use cases (bulk review vs. individual deliverable vs. project overview).


Phase 11: Quality of Life & Polish

Incremental UX improvements that make the daily workflow faster and more pleasant.

11.1 — Saved Filters & Custom Views

What: Let users save their current filter/sort/column configuration as a named view. Quick-switch between saved views. Share views with team.

Implementation:

  • "Save View" button in table/board/timeline toolbar
  • View stores: filters, sort order, column visibility, column order, grouping
  • Personal views (private) and shared views (visible to org)
  • Quick access via dropdown in view toolbar
  • Pin favorite views for one-click access
  • URL-encode view ID so saved views are linkable

Data model additions:

model SavedView {
  id              String       @id @default(cuid())
  name            String
  userId          String
  user            User         @relation(fields: [userId], references: [id], onDelete: Cascade)
  organizationId  String
  organization    Organization @relation(fields: [organizationId], references: [id])
  projectId       String?      // null = cross-project view
  viewType        ViewType     // TABLE, BOARD, TIMELINE
  configuration   Json         // { filters, sort, columns, groupBy }
  isShared        Boolean      @default(false)
  isPinned        Boolean      @default(false)
  createdAt       DateTime     @default(now())
  updatedAt       DateTime     @updatedAt
}

enum ViewType {
  TABLE
  BOARD
  TIMELINE
}

Key files:

  • src/components/views/saved-view-picker.tsx — Dropdown with saved views
  • src/components/views/save-view-dialog.tsx — Save/edit view dialog
  • src/lib/services/saved-view-service.ts — CRUD
  • API routes: /api/views/, /api/views/[viewId]/

11.2 — Extended Command Palette Actions

What: Extend the existing Cmd+K palette with quick-actions beyond navigation: "approve and advance," "assign to me," "mark blocked," "start review session."

Implementation:

  • Add action commands alongside existing search/navigation commands
  • Context-aware actions: show relevant actions based on current page/selected item
  • Recent commands history
  • Fuzzy search across all command types
  • Keyboard shortcut hints shown inline

Key files:

  • Update src/components/layout/command-palette.tsx — Add action commands
  • src/lib/commands/action-registry.ts — Registry of available actions + handlers

11.3 — Offline Indicator & Optimistic Updates

What: Detect when connectivity drops, show indicator, queue changes locally, and sync when connection resumes. Extends existing TanStack Query optimistic updates.

Implementation:

  • Network status detection via navigator.onLine + periodic ping
  • Visual indicator in topbar when offline (amber banner)
  • TanStack Query already supports optimistic updates — extend to queue failed mutations
  • Sync queue with retry logic when back online
  • Conflict resolution: last-write-wins with toast notification if server state diverged

Key files:

  • src/components/layout/offline-indicator.tsx — Banner component
  • src/hooks/use-network-status.ts — Network detection hook
  • src/lib/sync/mutation-queue.ts — Offline mutation queue

11.4 — Batch Upload with Auto-Matching

What: Drag-and-drop multiple files onto a project and auto-match to deliverables by file naming convention (e.g., SKU-12345_catalog_v2.png matches Catalog Images deliverable).

Implementation:

  • Drop zone on project detail page accepting multiple files
  • Naming convention parser: configurable regex patterns per organization
  • Preview table showing: file name, matched deliverable, matched stage, confidence
  • Manual override for mismatches or unmatched files
  • Bulk upload with progress indicator
  • Auto-create revisions for matched files

Key files:

  • src/components/upload/batch-upload-zone.tsx — Drag-and-drop area
  • src/components/upload/file-matcher.tsx — Auto-match preview table
  • src/lib/services/file-matching-service.ts — Naming convention parser + matcher
  • src/lib/validators/naming-convention.ts — Configurable pattern schemas

Phase 12: Docker Deployment

Containerize the entire application stack for consistent, one-command deployment to any server. Eliminates "works on my machine" issues, simplifies onboarding, and makes the Ollama AI layer a natural part of the infrastructure rather than a separate install.

12.1 — Docker Compose Stack

What: A docker-compose.yml that defines the complete application as three services: the Next.js app, PostgreSQL with pgvector, and Ollama with pre-configured models. One docker compose up starts everything.

Architecture:

┌─────────────────────────────────────────────────────┐
│                  docker-compose.yml                  │
│                                                      │
│  ┌────────────┐  ┌────────────┐  ┌────────────────┐ │
│  │    app      │  │     db     │  │     ollama     │ │
│  │  Next.js    │  │ PostgreSQL │  │  nomic-embed   │ │
│  │  Port 3000  │  │  + pgvector│  │  qwen3.5:9b    │ │
│  │             │──│  Port 5432 │  │  Port 11434    │ │
│  │             │  │            │  │                │ │
│  └────────────┘  └────────────┘  └────────────────┘ │
│        │                │                │           │
│   [app-network]    [db-volume]    [ollama-volume]    │
└─────────────────────────────────────────────────────┘

Services:

Service Image Purpose
app Custom (Dockerfile) Next.js production build, serves the tracker
db pgvector/pgvector:pg17 PostgreSQL 17 with pgvector extension pre-installed
ollama ollama/ollama:latest Local AI model server for embeddings and summarization

Implementation:

  1. Dockerfile (Next.js app)

    • Multi-stage build: node:20-alpine for deps + build, minimal final image
    • Stage 1: Install dependencies (npm ci)
    • Stage 2: Build the Next.js app (npm run build)
    • Stage 3: Production image with only next start and built output
    • Runs prisma generate during build, prisma migrate deploy on startup
    • Final image size target: ~200-300MB
  2. docker-compose.yml

    • Three services (app, db, ollama) on a shared internal network
    • app depends on db and ollama with health checks
    • db uses pgvector/pgvector:pg17 image with pgvector ready out of the box
    • ollama uses official image with a startup script to pull models on first run
    • Named volumes for database data (pgdata) and Ollama models (ollama-models)
    • Environment variables sourced from .env file
    • Only app exposes a port to the host (3000); db and ollama are internal only
  3. docker/ollama-entrypoint.sh (model bootstrap script)

    • Starts the Ollama server
    • Checks if required models are already pulled (cached in volume)
    • If not, pulls nomic-embed-text and qwen3.5:9b automatically
    • Subsequent starts skip the pull — models persist in the Docker volume
  4. docker/db-init.sql (database initialization)

    • CREATE EXTENSION IF NOT EXISTS vector; — ensures pgvector is enabled
    • Runs automatically on first database creation via PostgreSQL's init script mechanism
  5. .env.example (deployment template)

    # Database
    DATABASE_URL=postgresql://postgres:your_password@db:5432/hp_prod_tracker
    POSTGRES_PASSWORD=your_password
    POSTGRES_DB=hp_prod_tracker
    
    # NextAuth
    NEXTAUTH_URL=http://your-server:3000
    NEXTAUTH_SECRET=generate-a-random-secret
    
    # Ollama (internal — no need to change)
    OLLAMA_HOST=http://ollama:11434
    OLLAMA_EMBED_MODEL=nomic-embed-text
    OLLAMA_LLM_MODEL=qwen3.5:9b
    

Key files:

  • Dockerfile — Multi-stage Next.js production build
  • docker-compose.yml — Full stack orchestration
  • docker/ollama-entrypoint.sh — Model bootstrap script
  • docker/db-init.sql — pgvector extension initialization
  • .env.example — Environment variable template with documentation
  • .dockerignore — Exclude node_modules, .next, .git, etc.

12.2 — Health Checks & Startup Orchestration

What: Ensure services start in the correct order and the app only accepts traffic once all dependencies are healthy.

Implementation:

  • db health check: pg_isready command — app waits until database accepts connections
  • ollama health check: curl http://localhost:11434/api/tags — confirms Ollama is running and responsive
  • app startup script: runs prisma migrate deploy first (applies any pending migrations), then starts Next.js
  • Docker Compose depends_on with condition: service_healthy ensures correct order: db starts first, then ollama, then app
  • Restart policy: restart: unless-stopped on all services for automatic recovery

12.3 — Production Deployment Workflow

What: Documented step-by-step process for deploying to a server.

Deployment steps:

# 1. Clone the repository
git clone <repo-url> hp-prod-tracker
cd hp-prod-tracker

# 2. Configure environment
cp .env.example .env
# Edit .env with production values (database password, NextAuth secret, server URL)

# 3. Start everything
docker compose up -d

# 4. First run: wait for Ollama to download models (~5GB, one-time)
docker compose logs -f ollama  # Watch progress, Ctrl+C when done

# 5. Seed the database (if fresh install)
docker compose exec app npx prisma db seed

# 6. Verify
curl http://localhost:3000  # Should return the app

Updating the application:

git pull
docker compose up -d --build  # Rebuilds only the app container
# Prisma migrations run automatically on startup

GPU support for Ollama (optional):

  • Install nvidia-container-toolkit on the host
  • Add deploy.resources.reservations.devices to the ollama service in compose
  • Significantly speeds up LLM summarization; embeddings are fast regardless
  • CPU-only is fully functional — GPU is a performance optimization, not a requirement

Backup strategy:

  • Database: docker compose exec db pg_dump -U postgres hp_prod_tracker > backup.sql
  • Ollama models: cached in volume, re-pulled automatically if lost — no backup needed
  • Application: stateless — the Docker image is rebuilt from source on each deploy

12.4 — Development Environment with Docker

What: A docker-compose.dev.yml override for local development that mounts source code and enables hot reloading while keeping the database and Ollama in containers.

Implementation:

  • Override file extends the production compose with dev-specific settings
  • app service: mounts ./src as a volume, runs next dev instead of next start
  • db service: exposes port 5432 to host for Prisma Studio / direct access
  • ollama service: same as production (models don't need hot reload)
  • Developers can choose: run everything in Docker, or run only db + ollama in Docker and run the Next.js app natively with npm run dev

Usage:

# Full Docker development
docker compose -f docker-compose.yml -f docker-compose.dev.yml up

# Or: only infrastructure in Docker, app runs natively
docker compose up db ollama
npm run dev

Key files:

  • docker-compose.dev.yml — Development overrides
  • docker/dev-entrypoint.sh — Dev startup script (skip build, run dev server)

Data Model Changes Summary

Phase New Models Modified Models
5 Annotation, ReviewSession, ReviewSessionItem, FeedbackItem Comment (add annotations + feedback relations)
6 Skill, UserSkill, StageSkillRequirement User (add maxCapacity, skills)
7 AutomationRule, AutomationExecution, ApprovalChain, ApprovalStep, ApprovalRecord, ProjectTemplate, ProjectTemplateDeliverable
8 AssetSpec, AssetValidationResult, AIReviewResult, SearchLog Revision (add validation/AI relations), Project + Deliverable (add embedding columns)
9 PortalLink, SLATarget
10 ActivityEntry
11 SavedView

Total new models: 22


New API Routes Summary

Phase Routes
5 /api/annotations/, /api/reviews/, /api/reviews/[id]/items/, /api/feedback/, /api/feedback/[id]/, /api/stages/[id]/feedback/
6 /api/workload/, /api/skills/, /api/users/[id]/skills/
7 /api/automations/, /api/automations/[id]/executions/, /api/approval-chains/, /api/stages/[id]/approve/, /api/templates/, /api/templates/[id]/instantiate/
8 /api/asset-specs/, /api/revisions/[id]/validate/, /api/webhooks/ai-review/, /api/revisions/[id]/ai-review/, /api/search/semantic/
9 /api/portal/, /api/portal/[token]/, /api/analytics/velocity/, /api/analytics/sla/
10 /api/projects/[id]/activity/, /api/external-links/
11 /api/views/

Total new API routes: ~26


New Pages Summary

Phase Pages
5 Review page (per deliverable), Review sessions list, Session presenter
6 Workload/capacity page, Skills management (settings)
7 Automations management (settings), Approval chains (settings), Template library
8 Asset specs (settings), Smart search panel (chat UI)
9 Client portal (external), SLA configuration (settings)
10 Activity feed (per project), External review page
11 — (enhancements to existing pages)

Total new pages: ~13


Third-Party Libraries

Library Purpose Phase
sharp Server-side image processing (validation, thumbnails, previews) 8
fabric.js or native Canvas/SVG Annotation drawing on canvas (evaluate during 5.2) 5
bcryptjs Password hashing for portal links 9

Philosophy: Minimize new dependencies. Most features build on the existing stack (React, TanStack Query, shadcn/ui, recharts, Prisma). Canvas/SVG APIs are native browser capabilities. Only add libraries when they provide substantial value over a custom solution.


Implementation Priority & Dependencies

Phase 5 (Visual Review) ─── standalone, highest impact
   |
   |-- 5.1 Image Viewer <-- foundation for everything
   |-- 5.2 Annotations <-- requires 5.1
   |-- 5.3 Comparison <-- requires 5.1
   |-- 5.4 Revision History Timeline <-- requires 5.1 + 5.2, enhanced by 5.3
   |-- 5.5 Review Sessions <-- requires 5.1 + 5.2, enhanced by 5.4
   +-- 5.6 Feedback Action Items <-- requires 5.2 + 5.4, integrates with My Work

Phase 6 (Workload) ─── standalone, high impact for producers
   |
   |-- 6.1 Capacity Grid <-- foundation
   |-- 6.2 Heatmaps <-- requires 6.1
   +-- 6.3 Skill Matching <-- requires 6.1

Phase 7 (Automation) ─── standalone, reduces manual work
   |
   |-- 7.1 Trigger Rules <-- foundation
   |-- 7.2 Approval Chains <-- standalone within phase
   +-- 7.3 Templates <-- standalone within phase

Phase 8 (Asset Intelligence) ─── requires Phase 5 for full value
   |
   |-- 8.1 File Validation <-- standalone
   |-- 8.2 Preview Generation <-- standalone
   |-- 8.3 AI Integration <-- requires external engine + 8.1 + 8.2
   +-- 8.4 Semantic Search <-- standalone, requires pgvector extension

Phase 9 (Reporting) ─── benefits from Phase 6 + 7 data
Phase 10 (Collaboration) ─── benefits from Phase 5
Phase 11 (QoL) ─── standalone incremental improvements, can be interleaved

Phase 12 (Docker) ─── can be done at any time, benefits from 8.4 for Ollama
   |
   |-- 12.1 Docker Compose Stack <-- foundation
   |-- 12.2 Health Checks <-- requires 12.1
   |-- 12.3 Production Workflow <-- requires 12.1 + 12.2
   +-- 12.4 Dev Environment <-- requires 12.1

Estimated Scope

Phase New Models New Routes New Pages Components
5 5 6 3 ~32
6 3 3 2 ~8
7 6 6 3 ~10
8 4 5 2 ~13
9 2 4 2 ~8
10 1 2 2 ~6
11 1 1 0 ~8
12 0 0 0 0 (infra only)
Total 22 ~27 ~14 ~85

Document version: 1.1 — Created 2026-03-01, updated 2026-03-06 Updates: Added 8.4 (AI semantic search with Ollama + pgvector), Phase 12 (Docker deployment) To be updated as features are refined and priorities shift.