Four phases shipped together. Each is a logical deploy unit on its own;
keeping the diff atomic so the rename runbook + migrations stay aligned.
Phase 1 — restore HP's formal review workflow
- Prisma: FeedbackItem, ReviewSession, ReviewSessionItem + enums
- New ApprovalType (NONE | SIMPLE | FORMAL) on PipelineStageDefinition
and PipelineStageTemplate. Stage row UI branches per type.
- feedback-service + review-session-service ported from HP (no ColorProbe)
- annotation-service auto-creates a FeedbackItem; revision-service
carries forward unresolved action items into the new revision.
- API: /api/reviews/*, /api/stages/[id]/feedback, /api/feedback/[id]
- Hooks: use-feedback, use-review-sessions
- UI: feedback-checklist, feedback-item-card, feedback-progress-bar,
create-session-dialog, session-builder, session-presenter,
session-summary, plus a new stage-review-panel
- Pages: /reviews list + detail, deliverable annotation review page
- Pipeline editor gets the approvalType select; sidebar gets Reviews
Phase 2 — full Dow Jones → L'Oréal rebrand + slug rename
- URL slug /dow-prod-tracker → /loreal-prod-tracker (next.config,
base path, redirects)
- docker-compose name + DB → loreal_prod_tracker; server path
/opt/loreal-prod-tracker; apache template renamed
- All visible strings → L'Oréal; sidebar bg #002B5C → black
- docs/RENAME_RUNBOOK.md describes the one-shot server migration
- Internal modules dow-excel-service/dow-import + OMG webhook domain
dowjones.com deliberately preserved (orthogonal to the rebrand)
Phase 3 — external /api/v1 for projects + deliverables
- API-key auth already in middleware; finished idempotency support
via new IdempotencyRecord model + src/lib/api/idempotency.ts
- Default-pipeline fallback in createProject when no template id given
- POST/GET /api/v1/projects + POST /api/v1/projects/[id]/deliverables
- docs/EXTERNAL_API.md with curl examples
Phase 4 — Box bidirectional integration
- JWT app-auth via jose (no extra deps). Config mounted as a docker
compose secret; deploy.sh stubs an empty {} so compose can start
before the operator drops the real JSON.
- Outbound: pushDeliverableToBox auto-fires on !APPROVED → APPROVED
in deliverable-status-service; "Send to client (Box)" manual button
on the approval stage row. Folder naming
{omgJobNumber}_{slug}_v{round}. 3-attempt exp backoff. BoxPushLog
audit.
- Inbound: /api/webhooks/box receives Box's signed events, matches by
OMG # + slug, creates a new Revision, routes to assignee or notifies
project owner. BoxInboundLog audit + two new NotificationType
values (BOX_UNMATCHED_FILE, NEW_FILE_AWAITING_REVIEWER).
- Naming-convention logic isolated in external-delivery-service so an
OMG-API transport can swap in later without touching matchers.
- Admin /settings/box page surfaces config status + recent activity.
Three Prisma migrations to apply on next deploy:
20260512000000_restore_review_workflow
20260512100000_idempotency_records
20260512200000_box_integration
URL rename is a one-shot — see docs/RENAME_RUNBOOK.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two smalls:
1) package.json db:seed still said seed-dow.cjs from the earlier
CJS→ESM rename — file bump missed it because I hadn't read the file
in that tool pass. With the Dockerfile now producing .mjs the seed
would have failed again for a different, dumber reason. Fixed.
2) Dow Jones wordmark is white on transparent, so it vanished into the
sidebar's light background. Added bg-[#002B5C] (Dow Jones brand
navy) to the logo header in both the desktop sidebar and the mobile
sheet. Now the logo actually reads.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The '2>/dev/null || tsx' fallback was hiding the real error from the
compiled .cjs (which is what we want to run) and then the fallback
printed 'tsx: not found' — gaslight-grade diagnostics.
Prod image has node + the compiled .cjs, so just run that. If anyone
needs to run the raw .ts in dev, 'npx tsx prisma/seed-dow.ts' still
works ad hoc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two runtime-surface fixes surfacing from the optical-dev deploy.
1) Seed's `postgres-array/index.js` kept missing even after --no-cache
rebuilds. Root cause: the Next.js standalone output traces package
manifests aggressively but sometimes leaves the `main` file body
out when the package isn't reachable from the app's import graph
(postgres-array is a transitive of pg, only reached via the seed
script, not the app runtime). Our `npm install --no-save
@prisma/adapter-pg` at build time then saw the partial install and
short-circuited. Runtime tsx resolution then blew up on `require
postgres-array`.
Fixed two ways, layered:
a) In the builder stage, after `npm run build`, esbuild the seed
into a self-contained CJS bundle at prisma/seed-dow.cjs.
`--packages=external` keeps npm packages as runtime require()s
so native .node files (via @prisma/client) work, but everything
else is bundled so the seed no longer depends on runtime module
resolution in the fragile standalone tree.
b) In the runner stage, `npm install --no-save --force` (plus
explicit `pg@8` which pulls its postgres-* deps cleanly)
overwrites any partial packages the standalone shipped with.
Belt-and-braces with the bundled seed.
c) package.json `db:seed` now prefers `node prisma/seed-dow.cjs`
and falls back to `tsx prisma/seed-dow.ts` if the .cjs isn't
there (e.g. when running the seed from a dev box where no build
happened). Both paths produce identical output.
No more runtime tsx install — dropped `npm install -g tsx@4` from
the runner image. That was always a workaround; the bundle is the
actual fix.
2) Sidebar logo not rendering — Next.js's `<Image>` with basePath +
the standalone image optimizer is finicky; the image file IS at
/app/public/navbar-logo.png in the container but Next's
`/_next/image?url=...` pipeline was returning 404 for it. Swapped
to a plain `<img>` (with the eslint-disable comment so the rule
doesn't whine). The file is ~4KB, image optimization added
nothing. Desktop + mobile sidebars both use the plain tag now.
Verified: tsc --noEmit ✓ zero errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
prisma/seed-dow.ts — idempotent seed for the Dow Jones tenant:
- Organization "Dow Jones" (dowjones.com)
- 6 ClientTeams: Brand, Events, B2B, Content, Briefing Team, Performance
- 3 placeholder Pods (Sergio, Deborah, Shared) — replace with real roster
when it's available
- Dow Pipeline Template "Dow Jones Standard" with 11 stages:
Pipeline → New → Copywriter → Client Review (Copy) → In Progress
Creative → Internal Review → Client Feedback → Final Approval →
Completed (+ On Hold, Canceled as terminal parking)
- Stage dependencies wired (optional stages bypass cleanly so
In Progress Creative reaches from New when Copywriter is skipped)
- Automation rule "Client Feedback → reopen In Progress Creative":
trigger on stage.status_changed where stageSlug=client-feedback and
newStatus=CHANGES_REQUESTED. Actions: reopen sibling stage +
increment revisionRound, send notification to assignee+producer.
- Initial admin user (DOW_ADMIN_EMAIL, default admin@dowjones.com)
with bcrypt password and mustChangePassword=true. If
DOW_ADMIN_PASSWORD env is unset a secure random is generated and
logged once for handoff.
- RBAC defaults seeded per role including CLIENT_VIEWER.
- Legacy global PipelineStageTemplate rows seeded as FK scaffolding.
New action type "reopen_sibling_stage" in action-executor.ts:
- Given event.payload.deliverableId + params.siblingSlug, finds the
sibling stage (matching either stageDefinition.slug or template.slug)
and sets it to params.reopenStatus (default IN_PROGRESS). If
params.incrementRound=true, bumps the stage's revisionRound counter
and clears completedDate. Added to validateActions' allow-list.
Wiring:
- package.json db:seed → tsx prisma/seed-dow.ts (HP seed kept at
db:seed-legacy for reference until deleted)
- prisma.config.ts migrations.seed → seed-dow.ts
- bcryptjs + @types/bcryptjs added
Verified: tsc --noEmit ✓ zero errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- basePath /dow-prod-tracker, DB name dow_prod_tracker
- docker-compose: name: dow-prod-tracker (volume isolation on shared server), ports 3002/5492
- OMG webhook env vars (secret + insecure toggle)
- NEXT_PUBLIC_AUTH_ENTRA_ENABLED feature flag (MVP uses local auth)
- Dow logo at public/navbar-logo.png
- apache/hp-prod-tracker.conf → apache/dow-prod-tracker.conf
- Text rebrand across README, SETUP, CLAUDE.md, docs, UI labels
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Token exchange now happens entirely in the browser via @azure/msal-browser
(PKCE, no client_secret — correct for Azure SPA registrations)
- Browser stays on /hp-prod-tracker/login throughout; the /api/auth/callback
URL never appears in the address bar
- New /api/auth/sso route validates the id_token (jose + Azure JWKS),
creates User/Account/Session in Prisma, and sets the authjs session cookie
- Auth.js retained only for session reading (auth()) and signOut()
- Fix dev bypass safety gate: use NODE_ENV !== production instead of
absence of AUTH_MICROSOFT_ENTRA_ID_SECRET
- Rename env vars: AUTH_MICROSOFT_ENTRA_ID_ID → AZURE_CLIENT_ID,
AUTH_MICROSOFT_ENTRA_ID_TENANT_ID → AZURE_TENANT_ID, remove AUTH_URL
- Remove /api/auth Apache proxy rule (no longer needed)
- Delete OAuthRelay.tsx, add MsalLogin.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Custom video player with hls.js for instant HLS playback with MP4
fallback. Full keyboard-driven controls matching NLE conventions:
Space/K play/pause, J/L skip 5s, arrow/comma/period frame step,
[/] speed, F fullscreen, M mute. Timecode display in HH:MM:SS:FF.
Components:
- video-player.tsx: Core player with HLS/MP4 source loading
- video-controls.tsx: Play, seek, speed, volume, fullscreen, loop
- video-timeline.tsx: Scrub bar with hover time preview + marker slots
- video-frame-display.tsx: Timecode display (HH:MM:SS:FF)
- video-upload-zone.tsx: Drag-drop upload with progress bar (XHR)
- use-video-player.ts: Player state hook with keyboard shortcuts
Review page integration:
- Auto-detects video vs image attachments per revision
- Image/Video toggle when both exist on same revision
- Upload panel extended with video + reference video zones
- VideoPlayer renders in place of ImageViewer when in video mode
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Canvas-based image viewer with zoom-to-cursor, pan, retina support, and
minimap navigation. Image upload API with PNG alpha compositing (sharp)
for CG renders with transparent backgrounds, TIFF-to-PNG conversion,
and auto-generated thumbnails. Review page accessible from stage cards
on the deliverable detail page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Implemented `stage-resolver.ts` to unify old and new pipeline stage definitions.
- Created `org-scope.ts` for organization access verification and scoping queries.
- Added role-based permissions management in `permissions.ts` and `rbac-service.ts`.
- Introduced invitation management in `invitation-service.ts` with validation schemas.
- Developed custom field and notification rule services with respective validators.
- Established pipeline template CRUD operations in `pipeline-template-service.ts`.
- Added Zustand store for managing pipeline builder state in `pipeline-builder-store.ts`.
- Implemented GET endpoint for weekly report data retrieval.
- Created components for displaying various sections of the weekly report:
- At-Risk Projects
- Completed Deliverables
- Deadline Compliance
- KPI Strip
- Pipeline Snapshot
- Upcoming Deliverables
- Report Header
- Added a custom hook for fetching weekly report data using React Query.
- Developed service functions to generate weekly report data from the database.
- Enhanced UI with responsive design and improved accessibility features.
- Added CalendarDayDetail component for displaying detailed event information for a selected day.
- Created CalendarEventPill component to represent individual events in a compact format.
- Introduced CalendarFilters component to filter events by project, stage type, and status.
- Developed CalendarGrid component to render the calendar layout and manage event interactions.
- Implemented CalendarView component to manage the overall calendar state and navigation.
- Added useCalendar hook to fetch calendar events based on specified filters.
- Created calendar-service to handle fetching events from the database with filtering capabilities.
- Updated data model to include necessary fields for calendar events and filters.
- Added system prompt and tools for AI assistant to manage calendar-related tasks.
- Implemented entity card extraction from tool results in the chat API.
- Added new EntityCard interface to define the structure of entity cards.
- Enhanced chat panel to display navigable entity cards for projects, deliverables, and users.
- Introduced status color helper for better visual representation of entity statuses.
- Updated chat message structure to include extracted entities.
- Improved chat formatting guidelines to avoid markdown tables and utilize bullet points.
- Added Tailwind Typography plugin for improved text styling in the application.
- 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.
- Updated CommandItem component to use rounded-lg for better aesthetics.
- Modified DialogOverlay and DialogContent to improve backdrop and border radius.
- Changed DropdownMenuItem, DropdownMenuCheckboxItem, and DropdownMenuRadioItem to use rounded-md for consistency.
- Enhanced SelectItem with rounded-md for a more modern look.
- Updated SheetOverlay to improve backdrop styling.
- Adjusted Toaster component border radius for a more refined appearance.
- Enhanced Table component with rounded-xl and shadow for better visual hierarchy.
- Added assignment display feature in DeliverableTable and KanbanBoard components, showing assigned users with badges.
- Updated deliverable service to include assignments in the data fetching process.
- Created a new seed script for tracker data to facilitate testing and development.
Dynamic imports for heavy components (Kanban, Gantt, CommandPalette),
skip-to-content link, ARIA landmarks/labels on sidebar, breadcrumbs,
topbar notifications, kanban board, gantt timeline, and pipeline
progress. Focus-visible ring styles for keyboard navigation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Export: multi-sheet styled workbook (Overview + Pipeline detail)
with color-coded status cells via ExcelJS.
Import: upload Excel with preview/validation step, then commit.
Supports Name, Priority, Due Date, Notes columns with flexible
column name matching. Import dialog on project detail page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Install 18 core UI primitives (button, card, dialog, table,
command, etc.) with New York style. Wire TooltipProvider in
root layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- App Router with src/ directory structure
- Design system CSS variables (Oliver/Brandtech palette, light + dark mode)
- Montserrat + Inter + JetBrains Mono font configuration
- next-themes provider for theme toggle
- Full folder structure per implementation plan
- nvm configured for Node 22
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>