---
title: "Quick Start"
description: "The quick start guide establishes the local development environment and database infrastructure required to run the Dub monorepo stack. It covers workspace dependency management, Turborepo build or..."
last_updated: "2026-10-05T05:07:35.143771+00:00"
canonical_url: "https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/technical/getting-started/quick-start"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [apps/web/scripts/dev/seed.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts)
- [apps/web/docker-compose.yml](https://github.com/blade47/dub/blob/HEAD/apps/web/docker-compose.yml)
- [apps/web/scripts/dev/seed-100k-partners.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-100k-partners.ts)
- [apps/web/scripts/dev/seed-integration.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-integration.ts)
- [apps/web/scripts/dev/seed-application-events.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-application-events.ts)
- [apps/web/scripts/dev/seed-partner-enrollment.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts)
- [apps/web/scripts/dev/data.json](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json)
- [apps/web/scripts/dev/seed-commissions.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-commissions.ts)
- [apps/web/app/ee/app.dub.co/embed/referrals/quickstart.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/app.dub.co/embed/referrals/quickstart.tsx)
- [apps/web/scripts/dev/test-partner-referrals.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/test-partner-referrals.ts)
- [apps/web/scripts/customers/annature/import-domains.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/customers/annature/import-domains.ts)
- [apps/web/scripts/dev/simulate-shopify-conversion.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/simulate-shopify-conversion.ts)
- [apps/web/app/app.dub.co/dashboard/slug/ee/settings/tracking/installation-section.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/tracking/installation-section.tsx)
- [apps/web/scripts/dev/debug-partner-search.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/debug-partner-search.ts)
- [apps/web/scripts/migrations/backfill-application-events.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/migrations/backfill-application-events.ts)
- [apps/web/scripts/dev/upsert-emoji-embeddings.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/upsert-emoji-embeddings.ts)
- [apps/web/scripts/partners/aggregate-stats-seeding.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/partners/aggregate-stats-seeding.ts)
- [apps/web/scripts/dev/benchmark-partner-search.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/benchmark-partner-search.ts)
- [packages/stripe-app/stripe-app.dev.json](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.dev.json)
- [apps/web/package.json](https://github.com/blade47/dub/blob/HEAD/apps/web/package.json)
- [packages/utils/src/constants/localhost.ts](https://github.com/blade47/dub/blob/HEAD/packages/utils/src/constants/localhost.ts)
- [apps/web/scripts/create-integration.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/create-integration.ts)
- [apps/web/scripts/dub-wrapped.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dub-wrapped.ts)
- [apps/web/scripts/restore-banned-workspace.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/restore-banned-workspace.ts)
- [apps/web/scripts/partners/backfill-partner-search.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/partners/backfill-partner-search.ts)
- [apps/web/scripts/misc/trigger-sync-embeddings.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/misc/trigger-sync-embeddings.ts)
- [apps/web/playwright.config.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/playwright.config.ts)
- [apps/web/scripts/migrations/backfill-partner-usernames.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/migrations/backfill-partner-usernames.ts)
- [turbo.json](https://github.com/blade47/dub/blob/HEAD/turbo.json)
- [apps/web/scripts/programs/bulk-star-partners.ts](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/programs/bulk-star-partners.ts)
</details>

## Overview

The quick start guide establishes the local development environment and database infrastructure required to run the Dub monorepo stack. It covers workspace dependency management, Turborepo build orchestration, Docker Compose service configuration, and various database initialization and seeding workflows. Developers can provision core fixtures, generate mock partner accounts, commission records, and referral application events, configure third-party integration secrets, and populate large-volume datasets for search indexing, vector embedding, and performance benchmarking. Sources: [apps/web/docker-compose.yml:1-46](https://github.com/blade47/dub/blob/HEAD/apps/web/docker-compose.yml#L1-L46), [apps/web/scripts/dev/seed-100k-partners.ts:1-27](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-100k-partners.ts#L1-L27), [apps/web/scripts/dev/seed.ts:1-241](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L1-L241), [apps/web/scripts/dev/benchmark-partner-search.ts:1-26](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/benchmark-partner-search.ts#L1-L26), [turbo.json:1-20](https://github.com/blade47/dub/blob/HEAD/turbo.json#L1-L20)

## Prerequisites and Monorepo Workspace Setup

### Overview

The Dub repository operates as a monorepo utilizing Turborepo build orchestration to manage package pipelines and task dependencies. Workspace package management relies on `pnpm` workspaces, linking internal packages such as `@dub/email`, `@dub/embed-react`, `@dub/tailwind-config`, `@dub/ui`, and `@dub/utils` directly into the web application workspace. Turborepo coordinates pipeline execution through `turbo.json`, enforcing build and test dependencies across workspace packages while maintaining caching and persistent service processes. Sources: [apps/web/package.json:1-184](https://github.com/blade47/dub/blob/HEAD/apps/web/package.json#L1-L184), [turbo.json:1-20](https://github.com/blade47/dub/blob/HEAD/turbo.json#L1-L20)

### Turborepo Build Pipeline Orchestration

Turborepo reads configuration from `turbo.json` to schedule execution tasks across the workspace. The build pipeline defines explicit task dependencies and output boundaries, treating global environment files (`**/.env`) as global dependencies that invalidate cache states when modified. Sources: [turbo.json:1-20](https://github.com/blade47/dub/blob/HEAD/turbo.json#L1-L20)

| Pipeline Task | Task Dependencies (`dependsOn`) | Persistent (`persistent`) | Cache Enabled (`cache`) | Output Paths / Behavior (`outputs`) |
| --- | --- | --- | --- | --- |
| `build` | `["^build"]` | *false* (default) | *true* (default) | `["!.next/cache/**", ".next/**", "dist/**"]` |
| `dev` | None | `true` | `false` | None (persistent server process) |
| `clean` | None | *false* | `false` | None (removes build artifacts) |
| `test` | `["^build"]` | *false* (default) | *true* (default) | None |

Sources: [turbo.json:1-20](https://github.com/blade47/dub/blob/HEAD/turbo.json#L1-L20)

### Web Application Package Scripts

The `apps/web` package defines scripts in `package.json` for development execution, database schema generation, testing, and OpenAPI spec generation. These scripts integrate Prisma client generation workflows directly prior to compilation, test execution, or server startup. Sources: [apps/web/package.json:5-20](https://github.com/blade47/dub/blob/HEAD/apps/web/package.json#L5-L20)

| Script Name | Command Execution String | Purpose |
| --- | --- | --- |
| `dev` | `pnpm prisma:generate && concurrently --kill-others "next dev --turbopack --port 8888"` | Generates Prisma client and starts Next.js dev server with Turbopack on port 8888 |
| `build` | `pnpm prisma:generate && next build` | Generates Prisma client and runs production Next.js build |
| `lint` | `next lint` | Executes Next.js linter checks |
| `start` | `next start` | Starts production Next.js server instance |
| `script` | `tsx ./scripts/run.ts` | Executes arbitrary TypeScript scripts via `tsx` |
| `test` | `pnpm prisma:generate && vitest -no-file-parallelism --bail=1` | Runs Vitest test suite with zero file parallelism and fails on first error |
| `test:e2e` | `playwright test` | Executes Playwright end-to-end tests |
| `test:e2e:ui` | `playwright test --ui` | Opens Playwright UI runner for end-to-end tests |
| `test:e2e:headed` | `playwright test --headed` | Runs Playwright end-to-end tests in headed browser mode |
| `generate-openapi` | `tsx ./scripts/generate-openapi.ts` | Generates OpenAPI specification artifacts |
| `prisma:generate` | `dotenv-flow -e .env -- prisma generate --schema=./prisma/schema` | Generates Prisma client from schema using environment variables |
| `prisma:push` | `dotenv-flow -e .env -- prisma db push --schema=./prisma/schema` | Pushes Prisma schema state directly to database without migrations |
| `prisma:studio` | `dotenv-flow -e .env -- prisma studio --schema=./prisma/schema --browser none` | Launches Prisma Studio GUI without spawning an automatic browser window |
| `prisma:format` | `dotenv-flow -e .env -- prisma format --schema=./prisma/schema` | Formats Prisma schema files |

Sources: [apps/web/package.json:5-20](https://github.com/blade47/dub/blob/HEAD/apps/web/package.json#L5-L20)

> [!NOTE]
> Workspace packages such as `@dub/email`, `@dub/embed-react`, `@dub/tailwind-config`, `@dub/ui`, and `@dub/utils` use workspace protocol specifiers (`workspace:*`), forcing `pnpm` to link local workspace directories rather than fetching from registry endpoints during monorepo builds. Sources: [apps/web/package.json:33-37](https://github.com/blade47/dub/blob/HEAD/apps/web/package.json#L33-L37)

### Localhost Constants and Network Fallbacks

The monorepo defines baseline constants for local execution fallbacks, including geographical coordinates and IP address defaults used during local analytics ingestion or testing. Sources: [packages/utils/src/constants/localhost.ts:1-10](https://github.com/blade47/dub/blob/HEAD/packages/utils/src/constants/localhost.ts#L1-L10)

```typescript
export const LOCALHOST_GEO_DATA = {
  continent: "NA",
  country: "US",
  city: "San Francisco",
  region: "CA",
  latitude: "37.7695",
  longitude: "-122.385",
};
export const LOCALHOST_IP = "63.141.57.109";
```

Sources: [packages/utils/src/constants/localhost.ts:1-10](https://github.com/blade47/dub/blob/HEAD/packages/utils/src/constants/localhost.ts#L1-L10)

## Local Infrastructure with Docker Compose

### Overview

The local development stack relies on Docker Compose to provision backing services, including a MySQL database configured for PlanetScale compatibility and a local mail server. Sources: [apps/web/docker-compose.yml:1-46](https://github.com/blade47/dub/blob/HEAD/apps/web/docker-compose.yml#L1-L46)

### Docker Compose Service Configuration

The `apps/web/docker-compose.yml` configuration specifies version `3.8` and defines three primary services alongside a persistent volume for database storage. Sources: [apps/web/docker-compose.yml:1-46](https://github.com/blade47/dub/blob/HEAD/apps/web/docker-compose.yml#L1-L46)

| Service Name | Image | Host Ports | Container Ports | Dependencies / Links | Purpose |
| --- | --- | --- | --- | --- | --- |
| `ps-mysql` | `mysql:8.0` | `3306:3306` | `3306` | None (Volume: `ps-mysql`) | MySQL 8.0 server instance configured with native passwords, an empty root password, and a default database named `planetscale`. |
| `planetscale-proxy` | `ghcr.io/mattrobenolt/ps-http-sim:latest` | `3900:3900` | `3900` | `ps-mysql` (depends_on, links) | PlanetScale HTTP simulator proxying requests to the MySQL backend without authentication on port 3900. |
| `mailhog` | `mailhog/mailhog:latest` | `1025:1025`, `8025:8025` | `1025`, `8025` | None | Local email testing service capturing SMTP traffic on port 1025 with a web dashboard exposed on port 8025. |

Sources: [apps/web/docker-compose.yml:5-43](https://github.com/blade47/dub/blob/HEAD/apps/web/docker-compose.yml#L5-L43)

> [!WARNING]
> The Docker Compose configuration is explicitly intended for local development only and must not be utilized in production environments. Sources: [apps/web/docker-compose.yml:1-2](https://github.com/blade47/dub/blob/HEAD/apps/web/docker-compose.yml#L1-L2)

## Core Database Seeding Workflow

### Overview

The database seeding workflow initializes the primary storage layer, loads structured test fixtures, and establishes a default entity graph containing workspaces, user roles, domains, email domains, folders, rewards, partner groups, programs, and partner accounts. Sources: [apps/web/scripts/dev/seed.ts:1-241](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L1-L241), [apps/web/scripts/dev/data.json:1-181](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L1-L181)

### Seed Data Schema and Structure

The seeding utility reads static fixture payloads defined in `data.json` and maps them into strongly typed Prisma create operations. The root structure consists of distinct entity arrays and singletons. Sources: [apps/web/scripts/dev/seed.ts:121-135](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L121-L135), [apps/web/scripts/dev/data.json:1-181](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L1-L181)

| Seed Field | Target Entity / Type | Key Properties | Purpose |
| --- | --- | --- | --- |
| `workspace` | `Project` | `id`, `name`, `slug`, `plan`, `usageLimit`, `defaultProgramId` | Defines the primary enterprise tenant entity (`Acme, Inc.`) with strict feature limits and configuration flags. Sources: [apps/web/scripts/dev/seed.ts:24-48](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L24-L48), [apps/web/scripts/dev/data.json:2-25](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L2-L25) |
| `users` | `User` & `ProjectUsers` | `id`, `name`, `email`, `emailVerified`, `role` | Provisions internal test accounts with distinct workspace access roles (`owner`, `member`, `viewer`, `billing`). Sources: [apps/web/scripts/dev/seed.ts:106-110](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L106-L110), [apps/web/scripts/dev/data.json:26-55](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L26-L55) |
| `domains` | `Domain` | `id`, `slug`, `verified` | Registers verified routing domains such as `dub.sh` under the workspace. Sources: [apps/web/scripts/dev/seed.ts:50](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L50), [apps/web/scripts/dev/data.json:56-62](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L56-L62) |
| `emailDomains` | `EmailDomain` | `id`, `slug`, `status` | Configures verified email domains such as `getacme.link`. Sources: [apps/web/scripts/dev/seed.ts:52](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L52), [apps/web/scripts/dev/data.json:63-69](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L63-L69) |
| `folders` | `Folder` | `id`, `name`, `description`, `accessLevel` | Sets up default link organization folders with specific access levels. Sources: [apps/web/scripts/dev/seed.ts:54](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L54), [apps/web/scripts/dev/data.json:70-77](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L70-L77) |
| `rewards` | `Reward` | `id`, `groupId`, `event`, `type`, `amountInCents`, `maxDuration` | Establishes payout rules for conversion events such as flat lead and sale bonuses. Sources: [apps/web/scripts/dev/seed.ts:56-68](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L56-L68), [apps/web/scripts/dev/data.json:78-99](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L78-L99) |
| `groups` | `PartnerGroup` | `id`, `name`, `slug`, `leadRewardId`, `saleRewardId`, `defaultLinks` | Categorizes partners into commission tiers with custom domain validation and default link payloads. Sources: [apps/web/scripts/dev/seed.ts:70-81](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L70-L81), [apps/web/scripts/dev/data.json:100-123](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L100-L123) |
| `program` | `Program` | `id`, `name`, `slug`, `defaultFolderId`, `defaultGroupId`, `domain` | Defines the referral program settings linking folders, groups, and domains. Sources: [apps/web/scripts/dev/seed.ts:83-104](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L83-L104), [apps/web/scripts/dev/data.json:124-136](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L124-L136) |
| `partners` | `Partner` | `id`, `name`, `email`, `country`, `user` | Generates affiliated partner profiles tied to individual user accounts. Sources: [apps/web/scripts/dev/seed.ts:111-119](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L111-L119), [apps/web/scripts/dev/data.json:137-181](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L137-L181) |

Sources: [apps/web/scripts/dev/seed.ts:24-135](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L24-L135), [apps/web/scripts/dev/data.json:1-181](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L1-L181)

### Seeding Execution Call Chain

The execution pipeline reads the local fixture file and invokes sequential database creation handlers to construct relational dependencies in proper foreign key order. Sources: [apps/web/scripts/dev/seed.ts:137-241](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L137-L241)

1. `parseJSON()` — Reads and parses `apps/web/scripts/dev/data.json` into memory as a `SeedData` structure. Sources: [apps/web/scripts/dev/seed.ts:137-141](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L137-L141)
2. `createWorkspace()` — Inserts the root tenant record into `prisma.project`. Sources: [apps/web/scripts/dev/seed.ts:144-152](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L144-L152)
3. `createUsers()` — Hashes the default password (`password`), executes `prisma.user.createMany()`, assigns workspace memberships via `prisma.projectUsers.createMany()`, queries back generated relation identifiers, and initializes `prisma.notificationPreference.createMany()`. Sources: [apps/web/scripts/dev/seed.ts:155-210](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L155-L210)
4. `createDomains()` — Populates verified routing domains through `prisma.domain.createMany()`. Sources: [apps/web/scripts/dev/seed.ts:213-231](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L213-L231)
5. `createEmailDomains()` — Commits email domain verification states to the database. Sources: [apps/web/scripts/dev/seed.ts:233-241](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L233-L241)

> [!WARNING]
> Because `createMany` batch operations do not return auto-incremented database identifiers across all database adapters, the user seeding procedure explicitly queries back created `projectUsers` records to map user identifiers before creating dependent notification preferences. Sources: [apps/web/scripts/dev/seed.ts:187-198](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L187-L198)

> [!NOTE]
> All seeded user accounts share a uniform preset password hash derived from the plaintext string `"password"` via `hashPassword("password")`. Sources: [apps/web/scripts/dev/seed.ts:163](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed.ts#L163)

## Partner and Referral Mock Seeding

### Overview

The local development environment provides specialized scripts to seed partner-specific data structures, including test affiliate accounts, referral program applications, and financial commission records. These scripts execute against the active Prisma client instance configured via `dotenv-flow/config`. Sources: [apps/web/scripts/dev/seed-application-events.ts:1-3](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-application-events.ts#L1-L3), [apps/web/scripts/dev/seed-partner-enrollment.ts:1-4](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L1-L4), [apps/web/scripts/dev/seed-commissions.ts:1-4](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-commissions.ts#L1-L4)

### Partner Enrollment and User Generation

The `seed-partner-enrollment.ts` script constructs a complete partner profile graph anchored to a designated program ID (`prog_1K2J9DRWPPJ2F1RX53N92TSGA`) and referring partner ID (`pn_1K2J9DRWPPJ2F1RX53N92TSGG`). Sources: [apps/web/scripts/dev/seed-partner-enrollment.ts:6-8](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L6-L8)

1. `prisma.program.findUnique()` — Queries the target program to retrieve its `defaultGroupId`. Sources: [apps/web/scripts/dev/seed-partner-enrollment.ts:10-17](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L10-L17)
2. `nanoid(3)` & `createId()` — Generates a unique 3-character suffix and prefixed identifiers (`user_`, `pn_`, `pge_`) for the new account. Sources: [apps/web/scripts/dev/seed-partner-enrollment.ts:24-29](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L24-L29)
3. `prisma.user.create()` — Registers the user with an email following the format `partner-{suffix}@dub-internal-test.com` and links their `defaultPartnerId`. Sources: [apps/web/scripts/dev/seed-partner-enrollment.ts:31-39](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L31-L39)
4. `prisma.partner.create()` — Establishes the core partner profile entity. Sources: [apps/web/scripts/dev/seed-partner-enrollment.ts:41-47](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L41-L47)
5. `prisma.partnerUser.create()` — Binds the user to the partner organization with an `owner` role and initializes notification preferences. Sources: [apps/web/scripts/dev/seed-partner-enrollment.ts:49-58](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L49-L58)
6. `prisma.programEnrollment.create()` — Enrolls the partner into the target program with a `pending` status. Sources: [apps/web/scripts/dev/seed-partner-enrollment.ts:60-68](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L60-L68)
7. `prisma.programApplicationEvent.create()` — Logs an immediate application event with `direct` referral source and current timestamps. Sources: [apps/web/scripts/dev/seed-partner-enrollment.ts:70-83](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L70-L83)

> [!NOTE]
> The enrollment script targets the hardcoded program identifier `prog_1K2J9DRWPPJ2F1RX53N92TSGA` and terminates execution immediately with an error log if the program record is absent from the database. Sources: [apps/web/scripts/dev/seed-partner-enrollment.ts:6](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L6), [apps/web/scripts/dev/seed-partner-enrollment.ts:19-22](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-partner-enrollment.ts#L19-L22)

### Referral Application Event Seeding

The `seed-application-events.ts` script populates historical `ProgramApplicationEvent` records for ACME program participants using randomized temporal offsets and distribution pools. Sources: [apps/web/scripts/dev/seed-application-events.ts:27-97](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-application-events.ts#L27-L97)

| Referral Source Constant | Domain Value |
| :--- | :--- |
| `direct` | Direct traffic or bookmark |
| `linkedin.com` | Professional network referral |
| `twitter.com` | Social media link |
| `marketplace` | Internal marketplace discovery |
| `acme.com` | Corporate domain referral |
| `google.com` | Search engine referral |

Sources: [apps/web/scripts/dev/seed-application-events.ts:18-25](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-application-events.ts#L18-L25)

The script queries program enrollments excluding the reserved partner ID `pn_1K2J9DRWPPJ2F1RX53N92TSGH`, calculates randomized timestamps spanning a 30-day window, determines approval status via a 70% probability threshold (`Math.random() < 0.7`), and commits the batch via `prisma.programApplicationEvent.createMany()`. Sources: [apps/web/scripts/dev/seed-application-events.ts:31-92](https://github.com/blade47/dub/scripts/dev/seed-application-events.ts#L31-L92)

### Commission Record Seeding

The `seed-commissions.ts` script inserts mock financial earnings records for testing payout dashboards and ledger reconciliations. Sources: [apps/web/scripts/dev/seed-commissions.ts:6-41](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-commissions.ts#L6-L41)

```typescript
const commissions: Prisma.CommissionCreateManyInput[] = [
  {
    id: createId({ prefix: "cm_" }),
    programId,
    partnerId,
    type: "referral",
    amount: 0,
    quantity: 1,
    earnings: 10000,
    createdAt: new Date(),
  },
  {
    id: createId({ prefix: "cm_" }),
    programId,
    partnerId,
    type: "referral",
    amount: 0,
    quantity: 1,
    earnings: 20000,
    createdAt: new Date(),
  },
];

await prisma.commission.createMany({
  data: commissions,
  skipDuplicates: true,
});
```

Sources: [apps/web/scripts/dev/seed-commissions.ts:10-36](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-commissions.ts#L10-L36)

## Third-Party Integration and External Fixtures

### Overview

Local development of external provider connections requires provisioning integration metadata and installing fixture credentials into the database via dedicated setup scripts. Environment loading is initialized through `dotenv-flow/config` across script entry points. Sources: [apps/web/scripts/dev/seed-integration.ts:5](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-integration.ts#L5), [apps/web/scripts/create-integration.ts:4](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/create-integration.ts#L4)

### Integration Metadata Creation

The `create-integration.ts` script registers third-party definitions in the database by performing an `upsert` operation on the `prisma.integration` model using `GOOGLE_ADS_INTEGRATION_ID`. Sources: [apps/web/scripts/create-integration.ts:7-9](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/create-integration.ts#L7-L9)

| Field | Value | Purpose |
| :--- | :--- | :--- |
| `id` | `GOOGLE_ADS_INTEGRATION_ID` | Primary integration identifier constant |
| `name` | `"Google Ads"` | Human-readable display name |
| `slug` | `"google-ads"` | URL-safe routing slug |
| `description` | `"Upload offline click conversions to Google Ads to optimize ad performance."` | Provider overview text |
| `developer` | `"Dub"` | Entity maintaining the integration |
| `website` | `"https://ads.google.com"` | Official external provider URL |
| `verified` | `true` | Official verification status flag |
| `projectId` | `DUB_WORKSPACE_ID` | Owning workspace context |
| `category` | `"Analytics"` | Functional taxonomy grouping |

Sources: [apps/web/scripts/create-integration.ts:11-22](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/create-integration.ts#L11-L22)

> [!NOTE]
> The `upsert` strategy ensures safe re-execution during local environment resets by updating existing record fields (`name`, `slug`, `description`, `verified`, `category`) if the integration ID already exists. Sources: [apps/web/scripts/create-integration.ts:7-30](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/create-integration.ts#L7-L30)

### Installed Integration Fixtures and Secrets

The `seed-integration.ts` script provisions workspace-level installed integration instances using `prisma.installedIntegration.upsert()` with a composite unique key constraint (`userId_integrationId_projectId`). Sources: [apps/web/scripts/dev/seed-integration.ts:8-15](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-integration.ts#L8-L15)

```typescript
await prisma.installedIntegration.upsert({
  where: {
    userId_integrationId_projectId: {
      userId: "cl7p1s07k000687rbuhpwqkqa",
      integrationId: INTERCOM_INTEGRATION_ID,
      projectId: ACME_WORKSPACE_ID,
    },
  },
  create: {
    userId: "cl7p1s07k000687rbuhpwqkqa",
    integrationId: INTERCOM_INTEGRATION_ID,
    projectId: ACME_WORKSPACE_ID,
    credentials: {
      appId: "xxx",
      accessToken: encrypt("xxx"),
    },
  },
  update: {
    //
  },
});
```

Sources: [apps/web/scripts/dev/seed-integration.ts:8-28](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-integration.ts#L8-L28)

> [!WARNING]
> Sensitive integration secrets like access tokens must be passed through the application encryption helper function (`encrypt("xxx")`) before being committed to the `credentials JSONB` payload column. Sources: [apps/web/scripts/dev/seed-integration.ts:22](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-integration.ts#L22)

### Stripe App Configuration Extension

Stripe application local development configuration is structured via extension inheritance in `packages/stripe-app/stripe-app.dev.json`, which inherits properties directly from the base `stripe-app.json` manifest. Sources: [packages/stripe-app/stripe-app.dev.json:1-3](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.dev.json#L1-L3)

## Search Benchmarks and Large-Scale Seeding

### Overview

Populating large-volume partner data, generating vector embeddings, and running latency benchmarks require specialized initialization scripts. These tools manage atomic chunked database insertions, backfill search indices across partitioned program loops, and evaluate retrieval performance. Sources: [apps/web/scripts/dev/seed-100k-partners.ts:1-7](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-100k-partners.ts#L1-L7), [apps/web/scripts/dev/upsert-emoji-embeddings.ts:1-84](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/upsert-emoji-embeddings.ts#L1-L84), [apps/web/scripts/partners/backfill-partner-search.ts:1-25](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/partners/backfill-partner-search.ts#L1-L25), [apps/web/scripts/dev/benchmark-partner-search.ts:1-26](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/benchmark-partner-search.ts#L1-L26)

### Large-Scale Partner Seeding and Search Indexing

The `seed-100k-partners.ts` script writes `User`, `Partner`, `PartnerUser`, `ProgramEnrollment`, `PartnerPlatform`, `Link`, and `ProgramPartnerTag` rows in atomic chunks defined by `CHUNK_SIZE` (2,500 partners per chunk). To prevent accidental data corruption or production exposure, safety checks enforce strict environment rules. Sources: [apps/web/scripts/dev/seed-100k-partners.ts:1-49](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-100k-partners.ts#L1-L49)

| Parameter / Constant | Value / Default | Purpose |
| :--- | :--- | :--- |
| `DEFAULT_COUNT` | `100_000` | Default number of partner records to generate |
| `MAX_COUNT` | `1_000_000` | Upper limit restriction for bulk generation |
| `DEFAULT_SEED` | `"partners-search"` | Base seed string for deterministic generation |
| `CHUNK_SIZE` | `2_500` | Atomic transaction block size for batch database inserts |
| `LOCAL_DATABASE_HOSTS` | `localhost`, `127.0.0.1`, `0.0.0.0`, `::1`, `host.docker.internal`, `mysql`, `db` | Permitted hosts for local database connection safety checks |

Sources: [apps/web/scripts/dev/seed-100k-partners.ts:37-49](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-100k-partners.ts#L37-L49)

> [!CAUTION]
> The seeding script inserts login-capable users with a known password. It refuses non-local `DATABASE_URL` connections unless `--allowRemoteDatabase` is explicitly passed, and refuses production environments (`NODE_ENV` or `VERCEL_ENV`) outright. Sources: [apps/web/scripts/dev/seed-100k-partners.ts:18-20](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/seed-100k-partners.ts#L18-L20)

Once seeded, partner enrollments must be indexed into the search provider using `backfill-partner-search.ts`. This utility pages through programs in ID order via `iterateProgramIds()` and pages through enrollments by ID rather than offset to keep per-batch costs flat. Sources: [apps/web/scripts/partners/backfill-partner-search.ts:1-70](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/partners/backfill-partner-search.ts#L1-L70)

```typescript
async function* iterateProgramIds(afterProgram?: string) {
  let cursor = afterProgram;
  let inclusive = Boolean(afterProgram);

  while (true) {
    const programs = await prisma.program.findMany({
      where: cursor ? { id: inclusive ? { gte: cursor } : { gt: cursor } } : {},
      select: { id: true },
      orderBy: { id: "asc" },
      take: PROGRAM_PAGE_SIZE,
    });

    if (programs.length === 0) {
      return;
    }

    for (const { id } of programs) {
      yield id;
    }

    cursor = programs[programs.length - 1].id;
    inclusive = false;

    if (programs.length < PROGRAM_PAGE_SIZE) {
      return;
    }
  }
}
```

Sources: [apps/web/scripts/partners/backfill-partner-search.ts:43-70](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/partners/backfill-partner-search.ts#L43-L70)

### Vector Embedding Upserts

The `upsert-emoji-embeddings.ts` script fetches emoji datasets from `EMOJIBASE_DATA_URL`, processes and deduplicates records by hexcode, and upserts them into an Upstash vector index in batches of `UPSERT_BATCH_SIZE` (500 records). Sources: [apps/web/scripts/dev/upsert-emoji-embeddings.ts:5-84](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/upsert-emoji-embeddings.ts#L5-L84)

```typescript
const EMOJIBASE_DATA_URL =
  "https://cdn.jsdelivr.net/npm/emojibase-data@16.0.3/en/data.json";
const UPSERT_BATCH_SIZE = 500;

type EmojiVectorRecord = {
  id: string;
  data: string;
  metadata: {
    emoji: string;
    label: string;
  };
};
```

Sources: [apps/web/scripts/dev/upsert-emoji-embeddings.ts:5-16](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/upsert-emoji-embeddings.ts#L5-L16)

> [!NOTE]
> Execution requires `UPSTASH_VECTOR_EMOJI_REST_URL` and `UPSTASH_VECTOR_EMOJI_REST_TOKEN` environment variables to be configured, failing immediately if either is missing. Sources: [apps/web/scripts/dev/upsert-emoji-embeddings.ts:67-74](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/upsert-emoji-embeddings.ts#L67-L74)

### Search Latency Benchmarking

The `benchmark-partner-search.ts` script measures p99 latency for relevance-ranked partner lists. It calls `getPartners` in process to bypass HTTP routing, authentication, and serialization overhead, establishing a baseline floor for API performance. Sources: [apps/web/scripts/dev/benchmark-partner-search.ts:1-9](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/benchmark-partner-search.ts#L1-L9)

| Benchmark Configuration Flag | Default Value | Limit / Constraint | Purpose |
| :--- | :--- | :--- | :--- |
| `--requests` | `1,000` | Minimum: `1,000` | Total request count for latency percentile calculation |
| `--warmup` | `50` | Non-negative integer | Initial unmeasured warmup request iterations |
| `--concurrency` | `10` | Cannot exceed `--requests` | Parallel execution concurrency bound |
| `--pageSize` | `25` | Maximum: `PARTNER_SEARCH_CANDIDATE_LIMIT` | Result pagination size per query |
| `--thresholdMs` | `1,000` | Positive integer | Maximum acceptable p99 latency threshold |
| `--sampleSize` | `100` | Max: `1,000` (`10,000` with `--searchOnly`) | Partner sampling count across the program index |
| `--maxErrorRate` | `0` | 0 to 100 percentage | Maximum allowable request error rate percentage |

Sources: [apps/web/scripts/dev/benchmark-partner-search.ts:44-56](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/benchmark-partner-search.ts#L44-L56), [apps/web/scripts/dev/benchmark-partner-search.ts:97-190](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/benchmark-partner-search.ts#L97-L190)

> [!TIP]
> Passing `--searchOnly` times the search provider's candidate query alone while skipping the local database. This permits a higher sample size ceiling (`MAX_SEARCH_ONLY_SAMPLE_SIZE` of 10,000) and enables direct provider comparison without local database bottlenecks. Sources: [apps/web/scripts/dev/benchmark-partner-search.ts:10-12](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/benchmark-partner-search.ts#L10-L12), [apps/web/scripts/dev/benchmark-partner-search.ts:54](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/benchmark-partner-search.ts#L54), [apps/web/scripts/dev/benchmark-partner-search.ts:169-178](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/benchmark-partner-search.ts#L169-L178)

## Related

- [Overview](https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/technical/getting-started/overview)
- [Project Structure](https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/technical/getting-started/project-structure)
- [Database Seeding and Testing](https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/technical/developer-tools/database-seeding-and-testing)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/llms.txt) for all pages in this wiki.
