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>
27 lines
1.5 KiB
Cheetah
27 lines
1.5 KiB
Cheetah
# ── L'Oréal Prod Tracker — Next.js standalone ───────────────────────────
|
|
# This is a TEMPLATE — deploy.sh renders ${APP_HOST_PORT} into the sibling
|
|
# apache/loreal-prod-tracker.conf (gitignored) before telling Apache to
|
|
# Include that rendered file. Edit this .tmpl, then rerun deploy.sh.
|
|
#
|
|
# APP_HOST_PORT is auto-picked by deploy.sh from 3002 upward if that port is
|
|
# already in use on the host. The rendered .conf always points at whatever
|
|
# port Docker actually bound — no drift between the reverse proxy and the
|
|
# container.
|
|
|
|
# Large uploads: video files up to 500 MB (overrides the global 100 MB limit)
|
|
<Location /loreal-prod-tracker>
|
|
LimitRequestBody 524288000
|
|
</Location>
|
|
|
|
# WebSocket passthrough (Next.js real-time features)
|
|
RewriteCond %{HTTP:Upgrade} websocket [NC]
|
|
RewriteCond %{HTTP:Connection} upgrade [NC]
|
|
RewriteRule ^/loreal-prod-tracker/(.*) ws://127.0.0.1:${APP_HOST_PORT}/loreal-prod-tracker/$1 [P,L]
|
|
|
|
# Chat + AI endpoints: long timeout for streaming responses
|
|
ProxyPass /loreal-prod-tracker/api/chat http://127.0.0.1:${APP_HOST_PORT}/loreal-prod-tracker/api/chat timeout=300
|
|
ProxyPassReverse /loreal-prod-tracker/api/chat http://127.0.0.1:${APP_HOST_PORT}/loreal-prod-tracker/api/chat
|
|
|
|
# All other routes (must come after more-specific paths above)
|
|
ProxyPass /loreal-prod-tracker http://127.0.0.1:${APP_HOST_PORT}/loreal-prod-tracker
|
|
ProxyPassReverse /loreal-prod-tracker http://127.0.0.1:${APP_HOST_PORT}/loreal-prod-tracker
|