Skip to main content
doc0blade47/dubdocumentation home
Sign in

Partner Search Namespace Creation

Last updated Oct 12, 2026
Relevant source files

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

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, apps/web/lib/api/partners/search/providers/turbopuffer.ts:123-136


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

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

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

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

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

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

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

Sources: apps/web/app/(ee)/api/cron/partners/delete/route.ts:131-163, apps/web/lib/api/links/bulk-delete-links.ts:47-73, apps/web/lib/api/partners/queue-partner-search-sync.ts:44-124, apps/web/lib/api/partners/search/provider.ts:12-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

Sources: apps/web/app/(ee)/api/cron/partners/delete/route.ts:20-183, apps/web/lib/api/links/bulk-delete-links.ts:23-78, apps/web/lib/api/partners/queue-partner-search-sync.ts:44-83, apps/web/lib/api/partners/search/provider.ts:12-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, apps/web/lib/api/partners/search/provider.ts:5-20

Was this page helpful?