Phase 7+8: logo swap + deploy README
Logo: - src/components/layout/sidebar.tsx — replaced text wordmark with the Dow navbar-logo.png in both desktop (collapsed-aware) and mobile sidebar variants. Logo links to /dashboard. Sized at h-7 (28px) — fits the 400×48 source aspect ratio comfortably. Deploy docs: - DEPLOY.md — focused deployment guide for optical-dev.oliver.solutions. Highlights the CLAUDE.md shared-server safety rules (compose `name:` field + `-p` flag), env var checklist, first-time setup, update flow, the seven-step verification list, rollback, and common-issue triage. This is the doc you hand a new ops person along with the deploy.sh. - README.md — top intro rewritten for the actual Dow product (Excel/ Planner replacement, 11-stage pipeline, OMG + XLSX ingest, per-team visibility) instead of the inherited HP CG copy. Points at DEPLOY.md. Verified: tsc --noEmit ✓ zero errors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4361d4cd2a
commit
a4107ae23d
3 changed files with 237 additions and 17 deletions
206
DEPLOY.md
Normal file
206
DEPLOY.md
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
# Deploying dow-prod-tracker
|
||||
|
||||
Target: **`https://optical-dev.oliver.solutions/dow-prod-tracker`**, hosted on the
|
||||
shared Oliver Agency dev box alongside `hp-prod-tracker`.
|
||||
|
||||
Run the deploy script from the repo root on the server:
|
||||
|
||||
```bash
|
||||
cd /srv/dow-prod-tracker # or wherever you cloned it
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
The first run will install Docker, Compose, Apache and UFW if missing, prompt
|
||||
you to fill in `.env` from `.env.example`, then bring everything up. Subsequent
|
||||
runs are idempotent — safe to re-run for updates.
|
||||
|
||||
---
|
||||
|
||||
## Why this deploy is different from the rest
|
||||
|
||||
The shared server runs multiple apps from sibling deploy directories. **Two
|
||||
things must hold or those apps will silently corrupt each other** (this has
|
||||
bitten us before — see CLAUDE.md):
|
||||
|
||||
1. **`docker-compose.yml` MUST pin a top-level `name:` field.**
|
||||
We pin `name: dow-prod-tracker`. Without this, Compose defaults the project
|
||||
name to the parent directory name. If two apps both live under `deploy/`,
|
||||
they collapse onto the same project and fight over containers
|
||||
(`deploy-db-1`) and volumes (`deploy_pgdata`). Deploying one would silently
|
||||
evict the other and destroy its data.
|
||||
|
||||
2. **Every `docker compose` invocation in `deploy.sh` passes `-p
|
||||
dow-prod-tracker` as belt-and-braces.**
|
||||
This is redundant with `name:` today, but if anyone moves the `name:` line
|
||||
out of the compose file, or runs commands by hand from a different cwd,
|
||||
the `-p` flag is the safety net.
|
||||
|
||||
The deploy script also enforces:
|
||||
|
||||
| Concern | Value | Where |
|
||||
|---|---|---|
|
||||
| Compose project name | `dow-prod-tracker` | `name:` in `docker-compose.yml` + `-p` in `deploy.sh` |
|
||||
| App port (host) | `3002` | `docker-compose.yml` ports + `deploy.sh` `APP_PORT` + `apache/dow-prod-tracker.conf` |
|
||||
| DB port (host) | `5492` | `docker-compose.yml` ports |
|
||||
| DB name | `dow_prod_tracker` | `docker-compose.yml` env + `.env` `DATABASE_URL` |
|
||||
| App URL path | `/dow-prod-tracker` | `next.config.ts` `basePath` |
|
||||
| Apache reverse proxy | `→ 127.0.0.1:3002/dow-prod-tracker` | `apache/dow-prod-tracker.conf` |
|
||||
|
||||
If you change any of these, change them in **all** the listed locations or
|
||||
the deploy will silently fail (or, worse, route Dow traffic to HP's app).
|
||||
|
||||
`hp-prod-tracker` runs on **port 3001**. Don't reuse it.
|
||||
|
||||
---
|
||||
|
||||
## .env.production checklist
|
||||
|
||||
Required env vars on the server:
|
||||
|
||||
```
|
||||
DATABASE_URL=postgresql://postgres:<DB_PASSWORD>@db:5432/dow_prod_tracker?schema=public
|
||||
DB_PASSWORD=<long random>
|
||||
AUTH_SECRET=<openssl rand -base64 32>
|
||||
|
||||
# Auth — local credentials in MVP. Flip to true post-MVP once Entra is wired.
|
||||
NEXT_PUBLIC_AUTH_ENTRA_ENABLED=false
|
||||
|
||||
# Entra (only required when NEXT_PUBLIC_AUTH_ENTRA_ENABLED=true)
|
||||
AZURE_CLIENT_ID=
|
||||
AZURE_TENANT_ID=
|
||||
AZURE_REDIRECT_URI=https://optical-dev.oliver.solutions/dow-prod-tracker/login
|
||||
|
||||
# OMG webhook receiver
|
||||
OMG_WEBHOOK_SECRET=<openssl rand -hex 32> # share with Shashank
|
||||
OMG_WEBHOOK_ALLOW_INSECURE=false
|
||||
|
||||
# AI chat (optional — chat features degrade gracefully if absent)
|
||||
ANTHROPIC_API_KEY=
|
||||
OLLAMA_HOST=http://10.24.42.219:11434
|
||||
OLLAMA_CHAT_MODEL=gemma4:latest
|
||||
OLLAMA_EMBED_MODEL=nomic-embed-text
|
||||
|
||||
# Cron + API key (used for scheduled tasks + machine-to-machine API access)
|
||||
CRON_SECRET=<openssl rand -hex 32>
|
||||
API_KEY=<openssl rand -hex 32>
|
||||
|
||||
# Initial admin (optional — overrides the default admin@dowjones.com / random pw)
|
||||
DOW_ADMIN_EMAIL=admin@dowjones.com
|
||||
DOW_ADMIN_PASSWORD= # leave blank → seed prints a random one
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## First-time setup on a fresh server
|
||||
|
||||
```bash
|
||||
# 1. Clone
|
||||
sudo mkdir -p /srv && sudo chown $USER:$USER /srv
|
||||
cd /srv
|
||||
git clone git@bitbucket.org:zlalani/dow-prod-tracker.git
|
||||
cd dow-prod-tracker
|
||||
|
||||
# 2. Configure
|
||||
cp .env.example .env
|
||||
$EDITOR .env # fill in real secrets
|
||||
|
||||
# 3. Deploy (installs deps, builds, runs migrations, configures Apache + UFW)
|
||||
./deploy.sh
|
||||
|
||||
# 4. Seed the Dow tenant + initial admin (one-time)
|
||||
docker compose -p dow-prod-tracker exec app npm run db:seed
|
||||
# → save the printed admin email + temp password
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Updating an existing deployment
|
||||
|
||||
```bash
|
||||
cd /srv/dow-prod-tracker
|
||||
./deploy.sh # pulls, rebuilds, restarts
|
||||
```
|
||||
|
||||
The Prisma migration in `prisma/migrations/20260420000000_init/` runs on
|
||||
container startup (via the standalone Next.js entrypoint). New migrations land
|
||||
automatically.
|
||||
|
||||
---
|
||||
|
||||
## Verification — must pass before declaring deploy done
|
||||
|
||||
1. **Volume isolation** — both apps' volumes must be distinct:
|
||||
```bash
|
||||
docker volume ls | grep -E "hp-prod-tracker|dow-prod-tracker"
|
||||
```
|
||||
Expect to see `hp-prod-tracker_pgdata`, `hp-prod-tracker_uploads_data`,
|
||||
`dow-prod-tracker_pgdata`, `dow-prod-tracker_uploads_data` — four distinct
|
||||
volumes.
|
||||
|
||||
2. **HP unaffected** — hit HP's URL in a browser and confirm it loads. If it
|
||||
fails, the new deploy collided with it (don't continue — fix first).
|
||||
|
||||
3. **Health check** — `curl https://optical-dev.oliver.solutions/dow-prod-tracker/api/health`
|
||||
should return 200.
|
||||
|
||||
4. **Login** — open the URL in a browser, sign in with the seed admin
|
||||
credentials, get redirected to `/change-password?first=1`, set a real
|
||||
password, land on `/dashboard`.
|
||||
|
||||
5. **XLSX ingest** — upload `Dow Jones_Studio Tracker_Example_*.xlsx` via
|
||||
`POST /api/projects/bulk-import?commit=false` (curl or via the UI button).
|
||||
Expect a preview JSON with normalized rows + any row errors. Then commit
|
||||
with `?commit=true` and spot-check a project in psql:
|
||||
```bash
|
||||
docker compose -p dow-prod-tracker exec db \
|
||||
psql -U postgres -d dow_prod_tracker \
|
||||
-c "select \"omgJobNumber\", name, status, \"clientTeamId\" from projects limit 5;"
|
||||
```
|
||||
|
||||
6. **OMG webhook** — when Shashank confirms the payload shape, share
|
||||
`OMG_WEBHOOK_SECRET` and have OMG POST to
|
||||
`https://optical-dev.oliver.solutions/dow-prod-tracker/api/webhooks/omg`
|
||||
with header `X-OMG-Signature: sha256=<hex hmac of body>`.
|
||||
|
||||
7. **Per-team visibility** — invite a test user as `CLIENT_VIEWER`, assign
|
||||
them to one client team only (Settings → Client Teams), accept the invite
|
||||
link, sign in, confirm they only see that team's projects.
|
||||
|
||||
---
|
||||
|
||||
## Rollback
|
||||
|
||||
If a deploy goes wrong:
|
||||
|
||||
```bash
|
||||
cd /srv/dow-prod-tracker
|
||||
git log --oneline -5 # find previous good commit
|
||||
git checkout <previous-commit>
|
||||
./deploy.sh --skip-pull # rebuild from that commit
|
||||
```
|
||||
|
||||
If the database itself is in a bad state (rare — Prisma migrations are
|
||||
forward-only), restore from the latest postgres dump in `/srv/backups/`
|
||||
(set up your own cron for these — not yet automated).
|
||||
|
||||
---
|
||||
|
||||
## Common issues
|
||||
|
||||
**"port is already allocated"** — something else is on 3002 or 5492. Check
|
||||
with `sudo ss -tlnp | grep -E '3002|5492'`. If it's a stale dow-prod-tracker
|
||||
container from a botched deploy, `docker compose -p dow-prod-tracker down`
|
||||
will release it.
|
||||
|
||||
**Apache returns 502** — the app container isn't running or its health check
|
||||
is failing. `docker compose -p dow-prod-tracker logs app --tail 50`.
|
||||
|
||||
**"Project with that OMG number already exists in a different organization"**
|
||||
— a previous import landed projects under a different org (e.g. dev seed).
|
||||
Either delete those projects, or recreate the org with the canonical
|
||||
`dowjones.com` domain (the seed and webhook both look up the org by domain).
|
||||
|
||||
**`/api/webhooks/omg` returns 401** — signature mismatch. Verify both ends
|
||||
share the exact `OMG_WEBHOOK_SECRET` and that OMG sends the header as
|
||||
`X-OMG-Signature: sha256=<hex>`. For local stub testing only, set
|
||||
`OMG_WEBHOOK_ALLOW_INSECURE=true` in `.env` and restart.
|
||||
13
README.md
13
README.md
|
|
@ -1,8 +1,17 @@
|
|||
# Dow Jones Studio Tracker
|
||||
|
||||
A purpose-built production tracking tool for the HP CG department — replacing the fragmented workflow of Workfront, Excel spreadsheets, and the OMG platform with a single, unified web application.
|
||||
A production tracking tool for the Dow Jones studio team at Oliver Agency —
|
||||
replacing Excel/Planner with a single web app: per-team-scoped project visibility,
|
||||
the 11-stage Dow pipeline (Pipeline → New → Copywriter → Client Review → In
|
||||
Progress Creative → Internal Review → Client Feedback → Final Approval →
|
||||
Completed + On Hold + Canceled), and ingest from both the OMG webhook and the
|
||||
Studio Tracker XLSX.
|
||||
|
||||
Built for producers and CG artists who need real-time visibility into where every deliverable stands across every stage of the pipeline.
|
||||
Forked from `hp-prod-tracker`, customized for Dow Jones. See [DEPLOY.md](./DEPLOY.md)
|
||||
for deployment to `optical-dev.oliver.solutions/dow-prod-tracker`.
|
||||
|
||||
Built for producers and creative team members who need real-time visibility into
|
||||
where every deliverable stands across every stage of the pipeline.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { usePathname } from "next/navigation";
|
||||
import {
|
||||
LayoutDashboard,
|
||||
|
|
@ -175,14 +176,16 @@ export function Sidebar() {
|
|||
isCollapsed ? "justify-center px-2" : "px-4"
|
||||
)}>
|
||||
{!isCollapsed && (
|
||||
<div className="flex flex-col">
|
||||
<span className="font-heading text-[11px] font-black tracking-[0.15em] uppercase text-[var(--foreground)]">
|
||||
Dow Jones Studio
|
||||
</span>
|
||||
<span className="text-[9px] font-semibold tracking-[0.12em] uppercase text-[var(--muted-foreground)]">
|
||||
by Oliver Agency
|
||||
</span>
|
||||
</div>
|
||||
<Link href="/dashboard" className="flex items-center" aria-label="Dow Jones Studio Tracker">
|
||||
<Image
|
||||
src={`${process.env.NEXT_PUBLIC_BASE_PATH ?? ""}/navbar-logo.png`}
|
||||
alt="Dow Jones Studio Tracker"
|
||||
width={400}
|
||||
height={48}
|
||||
className="h-7 w-auto"
|
||||
priority
|
||||
/>
|
||||
</Link>
|
||||
)}
|
||||
<Button
|
||||
variant="ghost"
|
||||
|
|
@ -229,13 +232,15 @@ export function MobileSidebar() {
|
|||
<Sheet open={isMobileOpen} onOpenChange={setMobileOpen}>
|
||||
<SheetContent side="left" className="w-60 p-0">
|
||||
<SheetTitle className="sr-only">Navigation</SheetTitle>
|
||||
<div className="flex h-14 flex-col justify-center border-b px-4">
|
||||
<span className="font-heading text-[11px] font-black tracking-[0.15em] uppercase text-[var(--foreground)]">
|
||||
Dow Jones Studio
|
||||
</span>
|
||||
<span className="text-[9px] font-semibold tracking-[0.12em] uppercase text-[var(--muted-foreground)]">
|
||||
by Oliver Agency
|
||||
</span>
|
||||
<div className="flex h-14 items-center border-b px-4">
|
||||
<Image
|
||||
src={`${process.env.NEXT_PUBLIC_BASE_PATH ?? ""}/navbar-logo.png`}
|
||||
alt="Dow Jones Studio Tracker"
|
||||
width={400}
|
||||
height={48}
|
||||
className="h-7 w-auto"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
<div className="flex h-[calc(100vh-3.5rem)] flex-col">
|
||||
<NavLinks onNavigate={() => setMobileOpen(false)} />
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue