Prisma's generated client calls fileURLToPath(import.meta.url) to locate
its query engine binary. In CJS output that's undefined, and the require
of the seed bundle blew up before running a line of actual seed code.
ESM output (.mjs) runs natively on Node 22, import.meta.url resolves
correctly, everything else about the bundle (external npm packages,
inlined generated client) stays the same.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause nailed down: the Next.js standalone tree ships package
manifests for the pg driver chain (postgres-array, postgres-bytea etc.)
without the corresponding source files. npm's 'version already
satisfies, skipping' logic fires on every subsequent install — --force,
--no-save, explicit pg@8, all of them. The manifest is there, npm says
done.
Fix: rm -rf every package in the chain first, then fresh install. Plus
a fail-fast check at the end (test -f postgres-array/index.js) so a
silent regression surfaces as FATAL in the build log instead of hours
later at seed time.
Sorry for the runaround. This should've been the first move.
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>
`npm install --no-save tsx` in the runner stage was reporting success
but the tsx binary kept vanishing from node_modules/.bin after the
Next.js standalone node_modules reshuffled its tree. The seed then
failed with "sh: tsx: not found" even after a clean rebuild.
Install tsx globally instead (npm install -g tsx@4 → /usr/local/bin/tsx),
which is PATH-resolvable regardless of any local node_modules churn.
Other seed-adjacent deps stay local (prisma CLI, dotenv, adapter-pg,
bcryptjs) because the seed script explicitly imports them and wants
them resolved from the app's local node_modules.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Caught on the first real deploy to optical-dev. Two separate bugs.
Dockerfile — runner stage was missing tsx + @prisma/adapter-pg + bcryptjs
The Next.js standalone bundle covers the app, but prisma/seed-dow.ts
is a separate .ts file executed via tsx (not bundled). Runner only
explicitly installed prisma + dotenv, so `npm run db:seed` failed with
"sh: tsx: not found" and deploys couldn't run the one-time seed.
→ Added tsx, @prisma/adapter-pg (seed uses PrismaPg directly), and
bcryptjs (seed hashes the admin's temp password) to the
`npm install --no-save` line in the runner stage. Adds ~15 MB to
the final image — worth it for a working seed path.
/api/health was 503 pre-seed, which made deploy.sh unwillingly block itself
The probe in deploy.sh uses `curl -sf` and treats any non-2xx as
"not ready". The health endpoint flipped the entire `healthy` flag to
false when `organizations` or `pipeline_templates` counted zero —
meaning a freshly-migrated-but-not-yet-seeded app was classified as
unhealthy, deploy.sh gave up at Step 6, and we never got to Step 7
(Apache config) or Step 8 (UFW). End result: the URL 404'd because
Apache wasn't proxying anything to the container.
→ Split liveness from readiness:
- GET /api/health (default) — DB reachable, pgvector installed,
AUTH_SECRET set, DEV_BYPASS off. Empty tables are reported as
"warn" but do NOT 503. This is what deploy.sh waits on.
- GET /api/health?strict=1 — same checks PLUS org + templates
present. Use post-seed to verify everything landed.
- Added a "mode" field ("liveness" | "strict") so which mode was
used is visible in the response.
- Pre-seed content-level checks now return status: "warn" with a
hint to run `npm run db:seed`, instead of hard-failing.
Net effect for a fresh deploy:
./deploy.sh → builds, runs migrations, reports healthy once DB +
env are good, configures Apache, DONE. Then you can
`docker compose -p dow-prod-tracker exec app npm run db:seed`
at your leisure.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The standalone Next.js output doesn't include prisma (devDependency)
or dotenv (only used by prisma.config.ts, not app runtime). Install
them explicitly in the runner stage for prisma migrate deploy.
Pin prisma@7.4.2 to avoid npx downloading a non-existent version.
Co-Authored-By: Claude Opus 4.6 (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>
FFmpeg in Docker for transcoding, thumbnail extraction, and metadata
parsing. Videos stored in /data/uploads (mounted volume), served via
streaming API route with Range headers and HLS segment caching. Upload
flow: stream-write MP4 → ffprobe metadata → thumbnail → async HLS
transcode → update revision status to ready.
New files:
- video-service.ts: FFmpeg/ffprobe wrapper (HLS, thumbnails, metadata)
- /api/uploads/[...path]: streaming file server with Range support
Modified:
- upload-service.ts: video handling, 500MB limit, async HLS pipeline
- upload route: accepts video/referenceVideo types
- Dockerfile: ffmpeg + /data/uploads directory
- docker-compose.yml: uploads_data volume
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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.