---
title: "Partner Search Namespace Creation"
description: "The POST -> CreateNamespace flow handles the full, permanent deletion lifecycle of a partner from a program within Dub. It coordinates database record cleanup, cascades deletion to associated links..."
last_updated: "2026-10-12T07:00:10.106935+00:00"
canonical_url: "https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/technical/how-it-works/partner-search-namespace-creation"
---

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

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

- [apps/web/app/ee/api/cron/partners/delete/route.ts](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/app/(ee)/api/cron/partners/delete/route.ts)
- [apps/web/lib/api/links/bulk-delete-links.ts](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/links/bulk-delete-links.ts)
- [apps/web/lib/api/partners/queue-partner-search-sync.ts](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/queue-partner-search-sync.ts)
- [apps/web/lib/api/partners/search/provider.ts](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/provider.ts)
- [apps/web/lib/api/partners/search/providers/turbopuffer.ts](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/providers/turbopuffer.ts)
</details>

## Overview

The `POST -> CreateNamespace` flow handles the full, permanent deletion lifecycle of a partner from a program within Dub. It coordinates database record cleanup, cascades deletion to associated links, dispatches search synchronization jobs to keep index state consistent, and initializes the Turbopuffer search provider namespace when communicating with vector and full-text search backends.

Sources: [apps/web/app/(ee)/api/cron/partners/delete/route.ts:19-23](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/app/(ee)/api/cron/partners/delete/route.ts#L19-L23), [apps/web/lib/api/partners/search/providers/turbopuffer.ts:123-136](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/providers/turbopuffer.ts#L123-L136)

---

### Step-by-Step Execution Flow

#### Step 1: Handle Partner Deletion Request (`POST`)

The execution begins at the cron API route endpoint `POST` inside `apps/web/app/(ee)/api/cron/partners/delete/route.ts`. Wrapped with `withCron`, the handler parses the request body using a Zod schema (`inputSchema`) to extract `workspaceId`, `programId`, `partnerId`, and `userId`. It checks if the partner enrollment exists and validates that the partner is eligible for permanent deletion by inspecting associated link statistics, active commissions, and payouts. If valid, it purges dependent records (such as submitted leads, fraud events, messages, and discovered partners), invokes bulk link deletion, deletes the program enrollment, and updates workspace partner usage quotas.

Sources: [apps/web/app/(ee)/api/cron/partners/delete/route.ts:20-160](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/app/(ee)/api/cron/partners/delete/route.ts#L20-L160)

#### Step 2: Bulk Delete Links (`bulkDeleteLinks`)

When a partner enrollment contains active short links (`links.length > 0`), the route invokes `bulkDeleteLinks` in `apps/web/lib/api/links/bulk-delete-links.ts`. This function processes links in batches of 100 (`DELETE_LINKS_BATCH_SIZE`). For each batch, it identifies and deletes associated discount codes, removes link records in a Prisma transaction while decrementing project total links counters, and asynchronously cleans up external caches (Redis `linkCache`, Tinybird analytics, R2 storage assets, and partner search index synchronization queues).

Sources: [apps/web/lib/api/links/bulk-delete-links.ts:23-78](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/links/bulk-delete-links.ts#L23-L78)

#### Step 3: Queue Partner Search Sync for Links (`queuePartnerSearchSyncForLinks`)

Inside the asynchronous cleanups of `bulkDeleteLinks`, if any deleted links were associated with a partner (`link.partnerId`), `queuePartnerSearchSyncForLinks` is invoked. It maps the deleted links by their `programId` and `partnerId` pairs to ensure updates are grouped by program rather than flooded per link, preparing payloads for synchronization.

Sources: [apps/web/lib/api/partners/queue-partner-search-sync.ts:100-125](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/queue-partner-search-sync.ts#L100-L125)

#### Step 4: Queue Partner Search Sync (`queuePartnerSearchSync`)

Both the link-level sync queue and the main cron route (after deleting the program enrollment itself) call `queuePartnerSearchSync`. This function verifies whether a partner search provider is active. If configured, it divides enrollment and partner IDs into batches and dispatches them to `partnerSearchSyncJob` with a default delay (`PARTNER_SEARCH_SYNC_DELAY_SECONDS` of 5 seconds) to ensure database mutations have fully committed before background workers query them back.

Sources: [apps/web/lib/api/partners/queue-partner-search-sync.ts:44-83](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/queue-partner-search-sync.ts#L44-L83)

#### Step 5: Get Partner Search Provider (`getPartnerSearchProvider`)

When search operations or background sync jobs need to communicate with the vector and search backend, they invoke `getPartnerSearchProvider` in `apps/web/lib/api/partners/search/provider.ts`. This function checks for the presence of `TURBOPUFFER_API_KEY`. If present, it caches and returns an instance of the Turbopuffer search provider, avoiding repeated TLS handshake and connection pool setup costs across invocations.

Sources: [apps/web/lib/api/partners/search/provider.ts:12-20](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/provider.ts#L12-20)

#### Step 6: Create Turbopuffer Partner Search Provider (`createTurbopufferPartnerSearchProvider`)

Invoked by the provider factory, `createTurbopufferPartnerSearchProvider` constructs the search client interface. It sets up methods for candidate searching (`searchCandidates`), counting (`countCandidates`), bulk upserts (`upsert`), and document deletions (`delete`). Each write operation automatically chunks payloads (`WRITE_BATCH_SIZE` of 500) and wraps requests in transient retry logic.

Sources: [apps/web/lib/api/partners/search/providers/turbopuffer.ts:345-421](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/providers/turbopuffer.ts#L345-L421)

#### Step 7: Create Namespace (`createNamespace`)

Underpinning the search provider operations, `createNamespace` initializes a connection to the Turbopuffer SDK using the API key and configured region (`aws-us-east-1`). It binds to the canonical multi-tenant namespace (defined as `partner-search-v4`) which aggregates all program documents while maintaining strict filter-level isolation via `programId`.

Sources: [apps/web/lib/api/partners/search/providers/turbopuffer.ts:34-34, 123-136](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/providers/turbopuffer.ts#L34-L34, L123-L136)

---

### Sequence Diagram

```mermaid
sequenceDiagram
    participant Cron as POST /api/cron/partners/delete
    participant Links as bulkDeleteLinks
    participant QueueLinks as queuePartnerSearchSyncForLinks
    participant QueueSync as queuePartnerSearchSync
    participant Provider as getPartnerSearchProvider
    participant TPProvider as createTurbopufferPartnerSearchProvider
    participant Namespace as createNamespace

    Cron->>Links: bulkDeleteLinks(links)
    activate Links
    Links-->>Cron: { deletedCount }
    deactivate Links

    Cron->>QueueSync: queuePartnerSearchSync({ enrollmentIds })
    activate QueueSync
    QueueSync->>Provider: getPartnerSearchProvider()
    activate Provider
    Provider->>TPProvider: createTurbopufferPartnerSearchProvider()
    activate TPProvider
    TPProvider->>Namespace: createNamespace(namespaceName)
    activate Namespace
    Namespace-->>TPProvider: TurbopufferNamespace client
    deactivate Namespace
    TPProvider-->>Provider: PartnerSearchProvider
    deactivate TPProvider
    Provider-->>QueueSync: Provider instance
    deactivate Provider
    QueueSync-->>Cron: Job dispatched
    deactivate QueueSync

    Note over Links, QueueLinks: Async link-level cleanup (waitUntil)
    Links->>QueueLinks: queuePartnerSearchSyncForLinks(partnerLinks)
    activate QueueLinks
    QueueLinks->>QueueSync: queuePartnerSearchSync({ partnerIds, programId })
    QueueSync-->>QueueLinks: Job dispatched
    deactivate QueueLinks
```

Sources: [apps/web/app/(ee)/api/cron/partners/delete/route.ts:131-163](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/app/(ee)/api/cron/partners/delete/route.ts#L131-L163), [apps/web/lib/api/links/bulk-delete-links.ts:47-73](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/links/bulk-delete-links.ts#L47-L73), [apps/web/lib/api/partners/queue-partner-search-sync.ts:44-124](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/queue-partner-search-sync.ts#L44-L124), [apps/web/lib/api/partners/search/provider.ts:12-20](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/provider.ts#L12-20), [apps/web/lib/api/partners/search/providers/turbopuffer.ts:123-136, 345-352](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/providers/turbopuffer.ts#L123-L136, L345-L352)

---

### Flowchart

```mermaid
flowchart TD
    A[POST Cron Request] --> B[Validate Partner & Dependencies]
    B --> C{Can Delete?}
    C -- No --> D[Log & Respond: Skipped]
    C -- Yes --> E[Purge Related DB Records]
    E --> F{Has Links?}
    F -- Yes --> G[bulkDeleteLinks]
    F -- No --> H[Delete Enrollment & Update Usage]
    G --> H
    H --> I[queuePartnerSearchSync]
    I --> J{Search Provider Configured?}
    J -- No --> K[No-op / Skip Queue]
    J -- Yes --> L[getPartnerSearchProvider]
    L --> M[createTurbopufferPartnerSearchProvider]
    M --> N[createNamespace]
    N --> O[Dispatch Sync Job to QStash]
    O --> P[Record Audit Log & Respond Success]
```

Sources: [apps/web/app/(ee)/api/cron/partners/delete/route.ts:20-183](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/app/(ee)/app/(ee)/api/cron/partners/delete/route.ts#L20-L183), [apps/web/lib/api/links/bulk-delete-links.ts:23-78](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/links/bulk-delete-links.ts#L23-L78), [apps/web/lib/api/partners/queue-partner-search-sync.ts:44-83](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/queue-partner-search-sync.ts#L44-L83), [apps/web/lib/api/partners/search/provider.ts:12-20](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/provider.ts#L12-20), [apps/web/lib/api/partners/search/providers/turbopuffer.ts:123-136, 345-352](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/providers/turbopuffer.ts#L123-L136, L345-L352)

---

### Key Observations

> [!IMPORTANT]
> **Resilience and Non-Blocking Queueing:** The search sync queueing mechanism (`queuePartnerSearchSync`) is designed to never throw errors that would fail the core partner deletion mutation. If QStash publishing fails, it falls back to the outbox pattern.

> [!NOTE]
> **Connection Caching:** The Turbopuffer search provider instance is cached per process (`cachedSearchProvider`), ensuring that high-frequency background jobs and searches reuse established HTTP connection pools and avoid redundant TLS handshakes.

Sources: [apps/web/lib/api/partners/queue-partner-search-sync.ts:40-43](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/queue-partner-search-sync.ts#L40-L43), [apps/web/lib/api/partners/search/provider.ts:5-20](https://github.com/blade47/dub/blob/7c93d97abf0ecd37fb669c6a68a1f7ef9109daea/apps/web/lib/api/partners/search/provider.ts#L5-L20)

## Sitemap

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