Developer Setup

Developer Setup (IDE + Hot-Reload)

For developers who want to run Next.js locally with IDE integration, debugging, and hot-reload. Databases run in Docker with ports exposed to your host machine. This is separate from the Windows installer — it’s for working on the platform itself.

If you want the packaged customer experience, use the installer instead — see the repo README.md Quick Start.

Prerequisites

Tool Version
Git Latest
Docker Desktop 4.40+
Node.js 20+
pnpm 9+

Option A: Automated script

git clone https://github.com/OpenDigitalProductFactory/opendigitalproductfactory.git
cd opendigitalproductfactory
.\scripts\fresh-install.bat

The script will:

Then start the dev server:

pnpm --filter web dev      # http://localhost:3000

Option B: Manual setup

git clone https://github.com/OpenDigitalProductFactory/opendigitalproductfactory.git
cd opendigitalproductfactory
pnpm install

Note: the repo .npmrc sets package-import-method=copy, so installs copy files out of the pnpm store instead of hardlinking. This is deliberate: with many concurrent git worktrees sharing one store on the same volume, hardlinks let a single mutated node_modules file corrupt the store and every sibling worktree. Copies cost more disk and install time per worktree — don’t revert this to speed up an install.

Create environment files:

# 1. Root .env — used by Docker Compose for container credentials
cp .env.docker.example .env

# 2. App-level .env file — used by Next.js and local Prisma commands
cp .env.example apps/web/.env.local

Then edit .env and apps/web/.env.local to replace the <generate with: ...> placeholders with real values. On Windows PowerShell:

# Generate AUTH_SECRET (base64)
[Convert]::ToBase64String((1..32 | ForEach-Object { [byte](Get-Random -Max 256) }))
# Generate CREDENTIAL_ENCRYPTION_KEY (hex)
-join ((1..32) | ForEach-Object { "{0:x2}" -f (Get-Random -Max 256) })

INNGEST_SIGNING_KEY and INNGEST_EVENT_KEY each need their own 64-hex-character value (openssl rand -hex 32). Compose refuses to start without them. The portal and the inngest service share them, so after changing either one, recreate both services together.

Or use the automated script (Option A) which handles this automatically.

If you have an older install with packages/db/.env, Prisma still treats it as a legacy fallback, but new installs should not need it.

Start databases (with ports exposed to host):

If you are in a linked git worktree, run scripts/seed-worktree-mcp.ps1 on Windows or scripts/seed-worktree-mcp.sh on macOS / Linux before any Compose command. The seeder writes an ignored .env value like COMPOSE_PROJECT_NAME=dpf-<topic> so worktree containers and volumes cannot join the root dpf project.

docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d postgres

This exposes PostgreSQL on port 5432 to your host machine.

Run migrations and seed:

pnpm --filter @dpf/db exec prisma generate       # Generate Prisma client
pnpm --filter @dpf/db exec prisma migrate deploy # Apply all migrations
pnpm --filter @dpf/db seed                       # Seed roles, agents, taxonomy, admin user

Build the promoter image (required for Build Studio feature deployment):

docker build -f Dockerfile.promoter -t dpf-promoter .

Build the document engine image (optional, for office document conversion). An install made with the installer does not need this step: a Customizable install pins the dpf-doctools image published for the release tag its clone descends from (the git describe baked into the portal as DPF_PLATFORM_VERSION), by digest, and builds Dockerfile.doctools from the clone only when no published image is reachable. That pin is stored in self_upgrade.doctoolsImage and resolved again after every upgrade. Build it by hand only for a bare pnpm dev portal, or to test changes to the image. The portal runs it one-shot; compose never starts it. The smoke test exercises it offline and read-only:

docker build -f Dockerfile.doctools -t dpf-doctools .
bash tools/doctools/smoke.sh dpf-doctools

The portal only runs a digest-pinned image. To point a dev portal at a local build, set DPF_DOCTOOLS_IMAGE in the dev portal’s own environment to its image id (docker image inspect -f '' dpf-doctools). The docker-gated converter test uses the same reference and is skipped without it:

DPF_DOCTOOLS_TEST_IMAGE="$(docker image inspect -f '' dpf-doctools)"   pnpm --filter web exec vitest run lib/documents/conversion/convert.docker.test.ts

Start the dev server:

pnpm --filter web dev      # http://localhost:3000

Login: admin@dpf.local / changeme123

Running Tests

pnpm typecheck         # TypeScript across all workspaces
pnpm test              # Vitest unit tests (web + db + mobile)
pnpm test:e2e          # Playwright end-to-end against running portal
pnpm test:e2e:demo     # Headed sandbox-preview demo

Branching

After install-dpf.ps1 runs in Customizable mode, your clone sits on a per-install branch named dpf/<instance-id>. That branch is the shared workspace for Build Studio and VS Code on this install — leave it where it is.

For feature work, create short-lived topic branches off main:

git fetch origin
git checkout -b feat/my-thing origin/main
# ... work, commit ...
git push -u origin feat/my-thing
gh pr create --base main

Branch prefixes by intent: feat/*, fix/*, chore/*, doc/*, clean/*. One concern per branch. See CONTRIBUTING.md for the full PR workflow.