Adds PipelineBranchKind (NONE/APPROVED/DECLINED) on stage definitions
so producers can tag the two routes downstream of a FORMAL-approval
stage. The engine then picks exactly one branch per decision:
• Approve → APPROVED-branch children auto-open, DECLINED-branch
siblings auto-SKIPPED (grayed out, unreachable)
• Request Changes → DECLINED-branch children auto-stamped APPROVED
(passive record of the decline), APPROVED-branch siblings auto-
SKIPPED, then the existing rework edge fires as before
Also fixes a quiet bug in pipeline-template-service.addStage where
approvalType was being dropped from new stages (whitelist didn't
include it).
UI: dropdown on the stage edit sheet + branch-kind badges on the
deliverable detail page. SKIPPED rendering already grays things out.
Smoke test extended: 65/65 passing including the user's split-on-
decision case, N-way split, regression assertion that untagged
pipelines still open all children, and an idempotency check.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The leading digits in the inbound filename convention identify the
deliverable, not the project. Adds Deliverable.omgJobNumber (unique
per org), flips inbound-ingest-service to resolve the deliverable
directly by that number (no more project hop), points box-outbound's
folder name at the deliverable's OMG, and surfaces the field in the
deliverable form + detail page.
Schema:
- NEW Deliverable.omgJobNumber String?
- @@index([omgJobNumber]) + @@unique([organizationId, omgJobNumber])
- Migration 20260512400000_deliverable_omg_number
Inbound matcher:
- Skips project lookup, resolves deliverable directly.
- Slug capture from the filename becomes a sanity-check warning
instead of a hard requirement (OMG # is authoritative now).
- Unmatched message reads "No deliverable found with OMG # X".
Outbound:
- buildDeliveryNaming now takes deliverable.omgJobNumber.
- "Missing OMG number on deliverable" failure case replaces the
old project-level check.
UI:
- Deliverable form dialog: new "OMG Deliverable #" input with a
one-line hint explaining the inbound matching convention.
- Deliverable detail metadata: shows "OMG Deliverable #" alongside
the existing "OMG Project #" (relabelled from "OMG Job #").
Project.omgJobNumber is kept as-is — still used for OMG webhook
project upserts; just no longer drives the file matcher.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reshapes the Revision model around how producers + clients actually
work: one upload per round (image OR video, no references), per-stage
version chain V0.1 → V0.2 → V1 → V1.1 → V1.2 → V2 …, holding pen for
inbound files received while a previous version is in client approval,
and per-pipeline filename matching for inbound ingest.
Schema:
- Revision: drop roundNumber + multi-key attachments. Add major/minor/
sentToClient/sentAt/asset (single image-or-video object) + unique
(deliverableStageId, major, minor).
- PipelineTemplate: add inboundFilenameRegex (per-pipeline matcher).
- NEW HoldingPenFile model + HoldingPenSource enum (MANUAL/API/BOX).
- Empty prod DB → clean ALTER TABLE migration, no backfill.
Send-to-client semantics:
- The latest internal revision IS the V{n} — promote in place
(major+=1, minor=0, sentToClient=true). Chain reads V0.1, V0.2, V1,
V1.1, V1.2, V2, ...
- sendToClient is the ONLY Box-push trigger. Auto-on-APPROVED removed
from deliverable-status-service. APPROVED is now an internal "done
iterating" state, separate from "shipped to client".
Three input channels, one matcher:
- NEW src/lib/services/inbound-ingest-service.ts — consolidates Box
webhook, /api/v1/upload, and manual upload-by-filename. One regex
resolver, one project/deliverable matcher, one routing + notification
fan-out.
- box-inbound-service is now a thin wrapper that fetches Box metadata
and delegates.
- external-delivery-service.parseInboundFileName takes an optional
regex override. Default: ^(\d+)_([a-z0-9-]+)(?:_v(\d+))?(?:\.[a-z0-9]+)?$
captures (1) OMG #, (2) slug, (3) optional version.
- buildDeliveryNaming now uses {omg}_{slug}_V{major} for Box folders.
Holding pen:
- When a deliverable is IN_REVIEW (a V{n} is awaiting client decision)
and a new file arrives via any channel, it lands in HoldingPenFile —
NOT in the active chain. Producer manually promotes (creates the
next minor on the chosen stage) or discards.
- Held files render in a new HoldingPenPanel on the deliverable detail
page when present. Source pill (MANUAL/API/BOX), parsed identifiers,
target-stage picker, Promote + Discard buttons.
Per-pipeline regex UI:
- NEW InboundMatchingRules section in the pipeline editor. Live regex
compile, sample-filename match test with echoed captures, save with
server-side regex-compile validation.
Upload simplification:
- storeRevisionAsset replaces the old processAndStoreImage +
processAndStoreVideo + multi-key attachment merge. MIME-detects kind,
preserves PNG alpha flatten + TIFF→PNG + thumbnail for images, and
keeps the async HLS transcode pipeline for videos.
- The single revision upload route drops the `type=` parameter.
- Three legacy components deleted: image-gallery, image-upload-zone,
video-upload-zone. NEW asset-upload-zone (unified drop zone).
New API:
- POST /api/stages/:stageId/revisions/:revisionId/send-to-client
- GET /api/deliverables/:id/holding-pen
- POST /api/deliverables/:id/holding-pen/:fileId (promote)
- DELETE /api/deliverables/:id/holding-pen/:fileId (discard)
- POST /api/v1/upload (multipart; same matcher as Box webhook)
UI label rollup:
- src/lib/format-revision-label.ts is the single source of truth.
Sent revisions render `V{major}`; internal `V{major}.{minor}`.
- Revision node/timeline, session presenter/builder/summary, revision
list, stage review panel — all read the helper.
- Comparison toolbar simplified to cross-revision picker (no more
reference-vs-current within a single revision).
The deliverable annotation review page is a temporary stub (links back
to the deliverable detail page where the in-row controls live). The
full annotation overlay + comparison surface will be rebuilt against
the single-asset model in a follow-up.
Run on next deploy:
docker compose -p loreal-prod-tracker exec app npx prisma migrate deploy
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Edit Project dialog's Owner/Project Manager field is now a dropdown
of real users on the system instead of a text box — so the value is
a FK to a real User row rather than a hand-typed string that drifts
from the roster.
Schema:
- Project.requestorUserId (nullable FK → User) + relation
"ProjectOwner" on both sides. Migration 20260425000000_project_owner_fk.
- Existing freeform `requestor` column stays put. It's now the
FALLBACK for ingest-sourced rows where the upstream Owner name
doesn't match a user on the system yet; the UI prefers the linked
user's display name when one exists.
Plumbing:
- createProjectSchema accepts requestorUserId.
- project-service listProjects + getProject both include
requestorUser { id, name, email } so the UI doesn't need a second
round-trip.
UI:
- ProjectFormDialog swaps the Input for a Select populated by
useUsers(). "— Unassigned —" at the top clears the link. When a
project has a legacy freeform requestor and no linked user, the
dialog shows it as a hint ("Currently unlinked (from intake):
<name> — pick a user from the list to replace") so admins can
see what came in from the XLSX/webhook and bind it.
- Project detail view + list view both prefer
requestorUser.name ?? requestorUser.email ?? requestor for the
"Owner" column. Sort key on the list uses the same chain.
New first-class attachments concept on the deliverable detail page,
replacing the "stash a Figma URL in the notes" workaround. Two kinds
share one row:
- FILE — uploaded via the existing /data/uploads volume, served
through /api/uploads/deliverables/:id/:filename. 100MB cap.
Images render a thumbnail inline; PDFs/docs get a file icon
+ download link. Blob cleaned up on delete.
- LINK — external URL (Figma / Drive / Dropbox / ad-hoc). Figma URLs
detected against the file/proto/design/board path pattern
and get an in-line iframe preview via Figma's embed host.
Other URLs open in a new tab with an external-link icon.
Schema:
- DeliverableAttachment model + migration. Cascade-deletes with the
parent deliverable. Optional stageDefinitionId tag scopes an asset
to a specific stage (null = whole deliverable).
- Extended serving route's MIME allowlist: PDF, Office docs, CSV,
text, ZIP, AI/PSD. Was tight to video/image-only before.
Plumbing:
- attachment-service with listAttachments / createLink /
createFile / delete. Visibility-scoped (assertProjectVisible via
deliverable.projectId).
- POST /api/deliverables/:id/attachments — content-type discriminates
multipart (file) vs JSON (link). DELETE at the nested route.
- useAttachments / useCreateLinkAttachment / useUploadFileAttachment /
useDeleteAttachment hooks; invalidate ["attachments", deliverableId].
UI panel renders above Pipeline Stages so assets are always in sight.
Read-only for CLIENT_VIEWER; all other roles can upload/paste/delete.
Producers can now drag cards on both boards. Three distinct write
paths, each with validation appropriate to what it's moving:
Projects board (status lens only):
- Drop updates Project.status via PATCH /api/projects/:id.
- Stage lens stays read-only — Project.stage is derived from the
dominant deliverable stage, there's no single write target.
Deliverables board (status lens):
- Drop updates Deliverable.status directly.
Deliverables board (stage lens) — the interesting one:
- Drop hits new POST /api/deliverables/:id/transition endpoint,
validated by new stage-transition-service.
- Forward transitions: current → APPROVED, optional intermediates
→ SKIPPED, target → IN_PROGRESS. If a REQUIRED intermediate
isn't already done, the drop is rejected ("walk through it
first") — toast shows the blocking stage name.
- Rework (backward) transitions: only allowed if the pipeline
template declares an explicit rework path from current → target.
Otherwise rejected. No cross-pipeline drops possible because the
target slug is looked up inside the deliverable's own pipeline.
Schema:
- New PipelineStageRework self-join on PipelineStageDefinition —
per-template declaration of "from stage X you can push back to
stage Y". Migration 20260423000000_pipeline_stage_reworks.
- Seed populates Dow's canonical rework paths: Client Review
(Copy) → Copywriter, Internal Review → In Progress Creative,
Client Feedback → In Progress Creative, Final Approval → In
Progress Creative, Completed → In Progress Creative.
Pipeline template editor UI (where producers would add their own
rework paths) is deferred; the seed covers Dow out of the box.
Hooks: added useUpdateProjectById, useUpdateDeliverableById,
useTransitionDeliverable — all take ids at mutation time so the
boards don't need one hook per card.
Briefs are pre-project requests. Three intake paths land in one place:
1. Manual — "New Brief" dialog on /briefs
2. REST — POST /api/briefs (auth'd)
3. Webhook — POST /api/webhooks/briefs (HMAC-signed)
Once triaged, "Promote to Project" flips Brief.status → CONVERTED,
creates the Project, and links them via convertedProjectId so the
audit trail stays intact.
Schema:
- New BriefStatus enum + Brief model, indexed on org/status/team
- Unique on (organizationId, externalId) so webhook replays are
idempotent — same upstream id = update, not insert
- Migration 20260422000000_briefs, hand-written SQL
Webhooks — now three total, each with its own secret and header:
- /api/webhooks/omg (projects — existing, unchanged)
- /api/webhooks/deliverables (NEW — keyed on project OMG # + name)
- /api/webhooks/briefs (NEW — keyed on externalId)
Extracted a shared HMAC verifier at src/lib/webhooks/hmac.ts so the
two new routes don't copy-paste the crypto code from the OMG route.
Deliverables webhook looks up the parent project by OMG job number
(the canonical key from the projects webhook); returns 404 with a
hint if the project hasn't been created yet. Brief webhook source
records "webhook:<system>" so we can tell where briefs come from.
UI:
- /briefs page: filterable/searchable table, inline status dropdown
per row, New Brief dialog, Promote to Project dialog
- Sidebar nav entry for Briefs above Projects
Env: added DELIVERABLE_WEBHOOK_SECRET / ALLOW_INSECURE and
BRIEF_WEBHOOK_SECRET / ALLOW_INSECURE alongside the existing OMG
pair in .env.example.
Sourced from Dow Jones_Team List_042027.xlsx (2026-04-21 handover).
- 20 users across Performance (9), Events (6), Shared (5)
- Roles mapped from Dow titles: Ops/Business/Creative Director → ADMIN;
Sr/Project Manager + Copy Lead + QC Manager → PRODUCER; Designers +
Motion + Copywriters → ARTIST
- ClientTeam memberships created per roster: performance/events users
get their one team; Shared users get both (so non-admin cross-team
roles like Copy Lead-ACD and QC Content Manager can actually see
work across both pods)
- Pods realigned team-first: performance-pod / events-pod /
leadership-pod (replaces the Sergio/Deborah/Shared placeholders)
- department field stores the Dow title verbatim for display
You flagged three concrete gaps after the deploy went live — all
addressed in this commit, plus the API + how-to docs you asked for.
A) Create Project dialog was still HP-centric
Placeholders like "HP Envy x360 Renders" / "HP-2026-001" / "NPI /
Refresh" / "Form Factor" etc. bore no relation to Dow's actual XLSX
columns and the form had no ClientTeam selector — so any
admin-created project was orphaned from the visibility layer.
- src/lib/validators/project.ts: added clientTeamId + omgJobNumber;
status enum now includes PIPELINE and CANCELED
- src/components/projects/project-form-dialog.tsx: rewritten around
the Dow XLSX schema. Three tabs (Details / Dates / References)
instead of four. Placeholders reference real Dow values
(Celena / Yzabella etc. for Owner, 2337959 for OMG #, Brand / Events
etc. for Team, Copywriting/Display/... for Category). ClientTeam
selector populated from /api/client-teams with a "no teams — add
one in Settings" fallback. Category is a typed enum dropdown with
the 8 XLSX values. Risk/Priority wording mirrors the XLSX labels
(Priority = URGENT). Dropped HP-only fields from the UI
(formFactor, codeName, npiOrRefresh, businessUnit placeholder,
agency, Financial tab, Workfront ID placeholder). Legacy fields
are still in the Zod schema for back-compat but not rendered.
B) Users invisible because only the admin was seeded
The plan flagged "real Dow/Oliver roster — open question" and we
never got the list, so the seed only created admin@dowjones.com.
prisma/seed-dow.ts now also creates the 9 placeholder resources
from the Resources.html prototype (Alice Chen, Ben Marsh, Cara Wu,
Dan Koch, Eva Stone, Frank Osei, Grace Lee, Hiro Tanaka, Isla Reeve),
distributed round-robin across the three placeholder pods. Each has
role + department + maxCapacity set but no passwordHash, so they
show up in the UI immediately but can't log in until an admin
invites them via Settings → Team (which issues a reset link).
Swap for the real roster whenever Zia delivers it — the emails are
@example.com so they're safe to delete.
C) Resource Manager page (matching Resources.html)
New capacity planner UI — daily hours-per-job grid.
- Schema: new ResourceBooking model { userId, date, jobNumber,
hours, note, organizationId, createdById }. Migration at
prisma/migrations/20260421000000_resource_bookings.
- Validator (src/lib/validators/booking.ts): create + list schemas
with date-only coercion.
- Service (src/lib/services/booking-service.ts): week window
helpers, create/list/delete + known-job-numbers lookup for the
popover autocomplete.
- API: GET/POST /api/resources/bookings, DELETE
/api/resources/bookings/[id], GET /api/resources/job-numbers.
Writes gated to ADMIN + PRODUCER; reads open to any signed-in
member of the org (capacity view is a shared studio-level thing,
not per-team visibility).
- Hook (src/hooks/use-bookings.ts) with TanStack Query wiring +
week-scoped cache keys.
- Page (src/app/(app)/resources/page.tsx) ports the Resources.html
design to the app's Tailwind + shadcn primitives: Resource × Day
grid grouped by department, week navigator, click-to-assign
popover with job-number autocomplete + hour chips (1/2/3/4/6/8 +
custom), capacity bar per cell, week total column with over-cap
warning, collapsible role bands. Matches the prototype's
color-hashed job chips so the same job number gets a consistent
color across the grid.
- Sidebar nav: added "Resources" entry next to Workload.
D) Docs — full README + API reference + how-to
- API.md: complete REST + webhook reference. Three auth modes
documented (session cookie / X-API-Key / OMG HMAC). XLSX upload
header map with the Dow XLSX column correspondences. OMG webhook
has the speculative payload shape + a working bash example that
signs + sends a request. Common flows at the bottom: bootstrap
from zero, OMG publishes a status change, update a job from an
external script.
- HOWTO.md: end-to-end runbook. Mental model, local dev, prod
deploy pointers, first-login ritual, add-users flow (UI + API),
client teams + pods config, XLSX ingest (UI + curl + idempotency
notes), OMG webhook wiring (secret gen through verification),
producer daily workflow, client-viewer experience, resource
planning walk-through, RBAC matrix, common-problems table, and
"change the model" pointer map for future edits.
- README.md: top intro now points at API.md / HOWTO.md / DEPLOY.md.
Verified: npx 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>
Replace 2 stale migration files with a single baseline migration
capturing the full 40+ model schema. The database was freshly reset
via clean-slate, making this the ideal time to establish migration
history. Dockerfile now runs prisma migrate deploy before app start.
Updated SETUP.md and ROADMAP.md to reference prisma migrate dev
instead of db push.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add timestampSeconds and frameThumbnailUrl fields to Annotation model
- New VideoAnnotationLayer component: auto-pause on draw tool activation,
SVG annotation overlay on paused video, time-filtered visibility,
All/Timed toggle, timecode display in toolbar
- New VideoTimelineMarkers: orange=unresolved, green=resolved, clustered
markers on scrub bar with click-to-seek and hover scale
- Thread timestampSeconds through validator, service, and API layers
- Feedback item cards show timestamp badges for video annotations
- VideoPlayer gains renderOverlay, timelineMarkers, pause/seek in state
- Fix "Processing" overlay shown when MP4 is available (FFmpeg fallback)
- Add revision polling when video status is "processing"
- Configure proxyClientMaxBodySize: 500mb for large video uploads
- Fix pre-existing Prisma JSON type error in upload-service.ts
- Update ROADMAP with lawn reference learnings and A7.3 progress
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three related bugs fixed:
1. Form save buttons silently failing — valueAsNumber on empty number inputs
produced NaN, which Zod rejected without visible errors on hidden tabs.
Replaced with setValueAs that converts empty strings to undefined.
2. Unique constraint violation on deliverable stage creation — dynamic pipeline
stages without matching global template slugs all fell back to
globalTemplates[0], creating duplicate (deliverableId, templateId) pairs.
Changed constraint from @@unique([deliverableId, templateId]) to
@@unique([deliverableId, stageDefinitionId]).
3. Stage names showing wrong template — all UI components read
stage.template.name exclusively, ignoring stageDefinition from the dynamic
pipeline system. Updated 13 components, 6 services, and all relevant Prisma
queries to prefer stageDefinition over template for display.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Implemented SessionPresenter and SessionSummary components for managing review sessions.
- Created AlertDialog component for modal dialogs.
- Developed hooks for managing review sessions, including fetching, creating, updating, and deleting sessions.
- Added service functions for review session operations in the backend.
- Introduced validation schemas for review session inputs using Zod.
Replace FeedbackSeverity enum (Critical/Major/Minor/Suggestion) with a
simple isActionItem boolean. Annotations default to action items (things
the artist must fix). Any item can be toggled to an info callout (context
that doesn't need action). Progress bar and carry-forward only count
action items. Screenshot paste limited to 5MB with user notification.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
A4 — Revision History Timeline:
- Collapsible right panel with vertical timeline of all revision rounds
- Each node shows thumbnail, status badge, timestamp, annotation count,
comment summary, and decision record
- Keyboard navigation (up/down arrows), auto-scroll to active round
- Filter by rounds with feedback, "Compare from here" action
- Enriched revision data hook aggregating annotations + comments
A5 — Feedback Checklist:
- FeedbackItem model with severity (Critical/Major/Minor/Suggestion),
status flow (Open → In Progress → Resolved → Verified), and
carry-forward between revision rounds
- Auto-creation from annotations (non-blocking, post-transaction)
- Checklist panel in review page with progress bar, severity grouping,
resolve-with-note flow, verify/reopen actions
- FeedbackIndicator badge on stage cards in deliverable detail page
- CRUD API routes + TanStack Query hooks
- Prisma schema additions (requires db push)
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`.
- Add PATCH endpoint to handle date overrides and clear manual overrides in the stage API.
- Introduce hooks for overriding stage dates and clearing overrides.
- Enhance the stage dependency engine to allow reopening from terminal states.
- Update stage status transitions to support reopening stages.
- Implement scheduling logic to auto-schedule stages based on due dates, considering manual overrides.
- Create a new component for managing stage dates with a popover interface.
- Add database migration for new fields related to manual scheduling and schedule conflicts.
- Document the executive overview and producer guide for the HP CG Production Tracker.
- Add event bus for dispatching automation events with handlers.
- Create rule engine to evaluate events against defined triggers.
- Introduce chat provider to interface with Claude API and Ollama fallback.
- Define tool schemas for Claude-compatible operations.
- Implement tool executor to map tool calls to service layer functions.
- Develop automation service for CRUD operations on rules and event handling.
- 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.
- Implemented `CapacityCell`, `CapacityDetailPopover`, and `CapacityGrid` components for displaying user workload and capacity.
- Created `UtilizationHeatmap` component to visualize team member utilization over weeks.
- Added hooks for managing skills (`useSkills`, `useCreateSkill`, `useDeleteSkill`, `useUserSkills`, `useSetUserSkill`, `useRemoveUserSkill`, `useStageSuggestions`) and workload (`useWorkload`, `useUpdateCapacity`).
- Developed services for skill management (`skill-service.ts`) and workload management (`workload-service.ts`) to interact with the database.
- Introduced logic for calculating user workload, including active assignments and capacity overload detection.
- Enhanced UI with tooltips and badges for better user experience.
- 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.
- Implement PPTXSchemaValidator for validating PowerPoint presentation XML files against XSD schemas.
- Create RedliningValidator to check tracked changes in Word documents, ensuring proper author tracking.
- Introduce recalc.py script to recalculate Excel formulas using LibreOffice, including error handling for Excel-specific errors.
- Add UI components for collapsible sections and tabs using Radix UI.
- Implement stage validation schema using Zod for managing project stages.