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>
Until now the only way to set up Dow's six client teams + production pods
was via the seed script. Now admins manage them from the Settings UI.
Validators (Zod):
- src/lib/validators/client-team.ts: create/update/membership schemas;
slug regex enforced (lowercase + dashes only — keeps it stable for the
XLSX/webhook ingest path which resolves teams by slug).
- src/lib/validators/pod.ts: create/update + setHomePod schemas.
Services:
- src/lib/services/client-team-service.ts: list/create/update/delete +
addMember/removeMember. delete blocks if the team still has projects
(forces an explicit move first). Auto-derives slug from name when not
provided.
- src/lib/services/pod-service.ts: list/create/update/delete + setUserHomePod.
delete is non-cascading on members — sets User.homePodId=null instead
of deleting people. Lead-user assignment is org-scope-validated.
API routes (gated by new permissions CLIENT_TEAM_MANAGE / POD_MANAGE
seeded for ADMIN in Phase 3):
- GET/POST /api/client-teams
- PATCH/DELETE /api/client-teams/[teamId]
- POST/DELETE /api/client-teams/[teamId]/members
- GET/POST /api/pods
- PATCH/DELETE /api/pods/[podId]
- POST/DELETE /api/pods/[podId]/members
GET endpoints are open to any signed-in user — they need the lists for
filter dropdowns and to know their own team. Project-row visibility is
still enforced via Phase 2's visibility helpers, untouched.
Hooks:
- src/hooks/use-client-teams.ts and src/hooks/use-pods.ts — TanStack
Query wrappers with cache invalidation on mutations.
Settings pages:
- src/app/(app)/settings/client-teams/page.tsx — create teams, manage
memberships, see project counts. Hides external (CLIENT_VIEWER) users
with a "client" badge so admins know who's who.
- src/app/(app)/settings/pods/page.tsx — create pods, set lead, add/remove
members. Filters out external users from the pod-eligible list.
- src/app/(app)/settings/page.tsx — added Client Teams + Pods cards to
the index, reordered to surface user-management first.
Verified: tsc --noEmit ✓ zero errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploy fixes (critical — Phase 0 string-rebrand didn't touch numeric ports):
- deploy.sh APP_PORT 3001 → 3002 (health check was hitting HP's app!)
- apache/dow-prod-tracker.conf — all proxy/websocket rules 3001 → 3002
(traffic to /dow-prod-tracker would have been served by HP's container)
- deploy.sh: added COMPOSE_PROJECT=dow-prod-tracker and `-p $COMPOSE_PROJECT`
on every `docker compose` invocation (down, up, exec, logs, ps). This is
the CLAUDE.md belt-and-braces rule — without it, a future move of the
deploy dir to `deploy/` would collapse the compose project name to
`deploy` and collide with any other app in a sibling `deploy/` dir on
the shared server. The `name:` field in compose covers us today, -p
covers us tomorrow.
- apache conf header comment rewritten to explain the port convention and
where to keep it in sync.
Admin add-user flow (answers the open question):
- createInvitation now creates/upserts the placeholder User row
(email + role + organizationId + isExternal + mustChangePassword=true)
in addition to the Invitation bookkeeping row. It stores a 24-byte
password-reset token on BOTH the User (passwordResetToken) and the
Invitation (token) — same token, so the existing /reset-password/[token]
page accepts the invite URL without a separate accept endpoint.
- Role enum now includes CLIENT_VIEWER. isExternal auto-derives from role
but can be overridden. When admin invites a CLIENT_VIEWER, the placeholder
user lands correctly pre-flagged for external handling.
- POST /api/org/invitations now returns {acceptUrl} — the full
/reset-password/<token> link admin can hand over out-of-band while SMTP
is unwired.
- revokeInvitation also clears the reset token on the placeholder user so
a leaked URL can't be used to claim the account after revocation.
- Deleted /api/invitations/accept (SSO-era — the accept IS the password
reset now) and removed acceptInvitationSchema from the validator.
Team settings UI (src/app/(app)/settings/team/page.tsx):
- Role dropdown now has "Client (read-only)" alongside Admin/Producer/Artist.
- After a successful invite, a banner shows the accept URL with a Copy
button so admin can paste it into Teams/email. Dismissible.
- Current-members list renders CLIENT_VIEWER with an amber badge.
Plumbing verified: tsc --noEmit ✓ zero errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Shared canonical path: both ingest channels transform inputs into a single
DowRow shape (src/lib/validators/dow-import.ts) and write via the single
upsertProjectFromDow() function (src/lib/services/dow-excel-service.ts),
so the XLSX importer and the webhook cannot drift. Upserts on
Project.omgJobNumber (unique) — idempotent under replay.
XLSX ingest (Phase 4):
- New src/lib/validators/dow-import.ts — Zod schema with STATUS_MAP,
RISK_MAP, header normalizer, team-slug normalizer, preview + commit
result types.
- New src/lib/services/dow-excel-service.ts:
- parseDowTracker(buffer): locates "Job Tracker " (or "Job Tracker"),
scans first 5 rows to find the header row with 4+ matched columns,
skips the example/instructions row at header+1, substring-matches
headers (handles "Creative Team Member Deliverable is Assigned to"
→ assignee), collects row-level errors without aborting the batch.
- upsertProjectFromDow(row, organizationId): auto-creates
ClientTeam if missing (seed covers the 6 canonical teams, but stay
forgiving); on create, generates N deliverables from outputCount +
pipeline stages from the default Dow pipeline template with
BLOCKED/NOT_STARTED status derived from stage dependencies; on
update, only overwrites fields that are set so producer-edited data
isn't clobbered by blanks.
- previewDowImport() and commitDowImport() wrap the flow for the API.
- Rewrote src/app/api/projects/bulk-import/route.ts for the Dow schema.
POST ?commit=true|false, multipart file=<xlsx>. commit=false returns
{preview, totalRows, validRows, errors[], rows[]} (first 25 samples);
commit=true returns {imported, created, updated, deliverablesCreated,
errors[]}. Batch never aborts on a single bad row.
OMG webhook (Phase 5):
- New src/app/api/webhooks/omg/route.ts — POST-only. HMAC-SHA256
signature verification via X-OMG-Signature: sha256=<hex> against
OMG_WEBHOOK_SECRET, timing-safe compare. OMG_WEBHOOK_ALLOW_INSECURE
escape hatch for stub testing. Looks up the Dow org by canonical
domain dowjones.com. Transforms the (speculative, documented)
OMG payload into DowRow then calls upsertProjectFromDow. Unknown
fields from payload.raw land on Project.customFields JSON so OMG
can add fields without us losing data. Logs every event (never
the raw payload — PII).
- middleware.ts: /api/webhooks/ added to the unauthenticated-allowed
path list (alongside /api/auth and /api/health) — HMAC auth happens
inside the handler.
Verified: tsc --noEmit ✓ zero errors.
Co-Authored-By: Claude Opus 4.7 (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>
- 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.
- 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.
Services, API routes, hooks, and UI components for:
- Revision rounds with submit/review/approve/request-changes flow
- Threaded comments with replies on each stage
- Stage detail sheet accessible from deliverable detail page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Assignment service: assign/unassign users to stages, get user's work
- API routes: POST/DELETE /api/stages/:id/assignments, GET /api/my-work
- My Work page with assignments grouped by project
- StageStatusBadge component with semantic status colors
- Zod validator for assignment input
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Deliverable service auto-creates 10 pipeline stages on creation
- Stages start as BLOCKED/NOT_STARTED based on dependency rules
- Dependency engine: canStageStart() validates all prerequisites
- Stage machine: enforces valid status transitions
- Critical gate approval auto-unblocks downstream stages
- API routes for deliverables (nested under projects) and stages
- Zod validators for deliverable create/update
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Zod validation schemas for create/update project
- Service layer with listProjects, getProject, createProject,
updateProject, deleteProject
- API routes: GET/POST /api/projects, GET/PATCH/DELETE /api/projects/:id
- TanStack Query hooks for all project operations
- Project list page with card grid, status/priority badges
- Project create dialog with form validation
- QueryProvider + API utility helpers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>