Backlink Opportunity Database
Status: [To Build]
A curated, admin-managed database of directories, listing sites, social bookmarking platforms, and press release sites where clients can self-serve build backlinks. An AI agent matches each tenant’s domain, region, and business type to the most relevant entries and surfaces them directly in the existing backlinks list as sourceType: "directory_opportunity" or "competitor_gap" rows.
Concept
The existing pipeline handles cold outreach (DM sends emails on behalf of the client). This feature handles self-serve link building — a curated list of sites the client can go to themselves and submit their business, with step-by-step instructions for each.
| Cold Outreach Pipeline | Opportunity Database | |
|---|---|---|
| Who acts | DM sends emails | Client submits themselves |
| Discovery | AI researches arbitrary domains | Pre-seeded + agent-filtered from DB |
| Output | CampaignEmail for DM to send | Steps panel on detail page |
| Status flow | prospecting → outreach_sent → agreed → published | opportunity → in_progress → completed |
| UI surface | Same backlinks list + detail | Same backlinks list + detail |
Both types live on the same /seo/backlinks page. sourceType determines which detail panels are shown.
Directory Database Structure
Categories (from spreadsheet)
| Category | Subcategories |
|---|---|
| Business Directories / Listing Sites | Automotive, Creative Services, Education & Training, Events & Entertainment, Finance & Accounting, Food & Hospitality, Healthcare/Medical, Home Services & Construction, IT & Software/SaaS, Legal, Marketing Tech, Real Estate, Travel & Tourism, Other |
| Social Bookmarking Sites | General, News Aggregators & Trend Curators, Image & Visual Content, Tech & Developer-Focused, Professional & Academic, Business & Marketing, Social Media/Community Sharing Platforms |
| Press Release | Automotive, E-commerce & Retail, Education & EdTech, Entertainment & Media, Environment & Sustainability, Finance & Fintech, Healthcare & Medical, Legal & Regulatory, Manufacturing & Industrial, Nonprofits & Social Impact, Real Estate, Technology, Travel & Hospitality, Other |
Additional planned categories:
- Forum & Community Sites (Reddit, Quora, Stack Overflow, niche forums)
- Review Platforms (G2, Capterra, Trustpilot, Google Business Profile)
- Resource / Wiki Sites (Wikipedia citations, AboutUs, Crunchbase)
Data Model
BacklinkDirectory
Table: backlink_directory
Managed by superadmins. Tenant-agnostic.
| Field | Type | Notes |
|---|---|---|
id | String (cuid) | PK |
name | String | Display name, e.g. “HealthGrades” |
url | String | Submission/listing URL |
category | String | business_directory | social_bookmarking | press_release | forum | review_platform | resource_site |
subcategory | String | Industry/topic subcategory from the table above |
domainRating | Int? | 0–100; used in “What You Gain” panel |
linkType | String | dofollow | nofollow (default: nofollow) |
isFree | Boolean | Whether free submission is available |
isPaid | Boolean | Whether there’s a paid tier (not mutually exclusive with isFree) |
paidPriceUsd | Int? | Approximate paid listing cost in USD |
regions | String[] | ["IN", "US", "GLOBAL"] — applicable countries/regions |
difficulty | String | easy | medium | hard — effort to get listed |
estimatedMinutes | Int? | Approximate time to complete submission |
steps | Json | Ordered array of { order, title, description, url? } |
isActive | Boolean | Toggle visibility across all tenants (default: true) |
createdAt | DateTime | |
updatedAt | DateTime |
Indexes:
[category, subcategory]— agent filtering[regions]— region-based filtering[isActive]
Steps JSON shape
type DirectoryStep = {
order: number
title: string
description: string
url?: string // direct link to the page to visit for this step
}Example:
[
{ "order": 1, "title": "Go to the submission page", "description": "Visit the business listing form.", "url": "https://example-directory.com/add-listing" },
{ "order": 2, "title": "Create an account", "description": "Sign up with your business email. Use the same domain as your website." },
{ "order": 3, "title": "Fill in business details", "description": "Enter your business name, website URL, description (150–300 words), and select your category." },
{ "order": 4, "title": "Submit for review", "description": "Click Submit. Approval typically takes 2–5 business days. You'll receive a confirmation email." }
]Backlink model extensions
Three new fields added to the existing Backlink model:
| Field | Type | Notes |
|---|---|---|
sourceType | String | outreach | directory_opportunity | competitor_gap (default: outreach) |
directoryId | String? | FK → BacklinkDirectory (null for outreach and agent-discovered competitor_gap) |
steps | Json? | Copied from BacklinkDirectory.steps at opportunity-creation time; self-contained so edits to the directory don’t retroactively change the backlink |
Why copy steps onto the Backlink row: The directory entry may be edited or deactivated. Each Backlink row preserves the instructions that were current when it was created.
Status values by sourceType:
sourceType | outreachStatus values |
|---|---|
outreach | prospecting → outreach_sent → responded → agreed → published (also: rejected, no_response) |
directory_opportunity | opportunity → in_progress → completed | not_applicable |
competitor_gap | opportunity → in_progress → completed | not_applicable |
Agent: opportunity-matcher
Queue: agent__opportunity_matcher
Credit type: backlink_opportunity_match
Trigger: On-demand (DM or client initiates) or post-onboarding setup chain
Input: { tenantId } — agent loads tenant domain, region, business category, and client context internally.
Process:
- Directory filtering: Query
BacklinkDirectorywhereisActive = trueandregionscontains the tenant’s region (or"GLOBAL"). Filter by subcategory match against the tenant’s business type. - Deduplication: Skip directories where a
Backlinkrow already exists for this tenant (directoryIdmatch). - Relevance scoring: LLM scores each filtered directory 1–10 based on client context + business type. Drops entries scoring < 4.
- Competitor gap discovery: Crawl competitor domains (from
Tenant.competitors) and find listing sites they appear on that are not in theBacklinkDirectoryDB — propose these assourceType: "competitor_gap"rows. - Backlink row creation: For each result, insert a
Backlinkrow withsourceType,directoryId,steps(copied),relevanceScore,outreachStatus: "opportunity",domainRating,linkType.
Output: N new Backlink rows; no email, no campaign created.
Manage Portal — Directory Management
Route: /templates/backlink-directories (or /settings/backlink-directories)
| Screen | Description |
|---|---|
| Directory list | Table of all BacklinkDirectory entries; filter by category/region/active; toggle active inline |
| Add directory | Form: name, URL, category, subcategory, DR, link type, free/paid, regions, difficulty, estimated minutes, steps builder |
| Edit directory | Same form; changes do NOT retroactively update existing Backlink.steps copies |
| Bulk CSV import | Upload CSV matching the spreadsheet format; maps columns to model fields |
| Steps builder | Drag-and-drop ordered list of steps; each step has title + description + optional URL |
Seeding Plan
The spreadsheet defines ~3 category groups × ~10 subcategories. Initial seed data will cover approximately:
- 200–300 Business Directory entries (one per major industry subcategory × top 15–20 directories)
- 50–80 Social Bookmarking entries (top bookmarking/aggregator sites per subcategory)
- 30–50 Press Release sites (free + paid tiers)
Seed file: packages/db/prisma/seed/backlink-directories.ts
Format: array of BacklinkDirectory objects matching the model fields above.