Browse documentation

Plans

RankFlow AI — Directory Profile System: Complete Plan

Document: Directory Profile Creation & Management System

docs/directory-profile-plan.md
On this page

Document: Directory Profile Creation & Management System
Version: 1.0.0
Date: 2026-06-13
Status: Post-Pivot (replaces individual landing page / subdomain model)
Scope: Complete workflow for creating, approving, publishing, and refreshing directory profile pages for each client.


What Changed (vs. Landing Page System)#

Before (Landing Page) After (Directory Profile)
Individual subdomain (client.rankflow.in) Profile on unified directory (directory.com/clinics/city/client)
3-5 landing page templates 1-2 profile layouts (standard + premium)
Custom domain support (CNAME) No custom domains — all profiles on directory domain
Site editor (AI chat-based editing) Doctor approval gate (content queued for approval)
Static Site Generation (SSG) per client ISR on dynamic route (/clinics/[city]/[slug])
Wildcard DNS (*.rankflow.in) Single domain DNS (directory.com)
Page traffic analytics Profile view analytics + click-to-call tracking
"Page offline if you cancel" Profile removed after 30-day grace period
Content: hero, services, FAQ, map, reviews Content: hero, bio, services, FAQ, reviews, map, contact, related clinics

What was removed:

  • ❌ Subdomain assignment
  • ❌ Custom domain setup
  • ❌ Site editor (AI chat-based website editing)
  • ❌ Landing page templates (3-5 variants)
  • ❌ A/B testing for landing pages
  • ❌ Wildcard DNS management
  • ❌ SSG per-client build pipeline
  • ❌ "Ownership lock-in" retention model

What was added:

  • ✅ Directory profile creation (/clinics/[city]/[slug])
  • ✅ Profile approval gate (doctor reviews AI content before publish)
  • ✅ Related clinics (internal linking for SEO juice)
  • ✅ City pages (SEO-optimized, unique content per city)
  • ✅ Specialty pages (SEO-optimized, unique content per specialty)
  • ✅ Directory homepage (search, featured, categories)
  • ✅ Profile view analytics
  • ✅ 30-day grace period on cancellation

1. Profile Content Collection During Onboarding#

The Problem#

The onboarding form currently collects business info but doesn't explicitly collect the depth of content needed for a rich directory profile. A generic profile (just name + address + phone) won't rank. We need 500+ words of unique content per profile.

The Solution: Structured Content Collection#

Step 2b of onboarding (after basic business info): Expanded content collection with smart defaults and AI suggestions.

Fields to Collect (with AI-suggested defaults)#

Field Required AI Suggestion Client Can Edit
Business name
Specialty Dropdown (30 specialties)
City Dropdown (500+ Indian cities)
Years of experience "Enter years"
Services AI suggests 5-10 based on specialty
Unique selling points (USPs) AI suggests 3-5 based on specialty + city
Education/qualifications "Enter degrees"
Languages spoken AI suggests based on city
Patient types AI suggests (children, adults, seniors, families)
Insurance accepted AI suggests common insurers in city
Photo AI: "Upload a photo of yourself or your clinic"
Logo AI: "Upload your clinic logo"
Clinic photos (3-5) AI: "Upload 3-5 photos of your clinic"
Hours AI suggests standard hours
Payment methods AI suggests (cash, UPI, card, insurance)

AI Suggestion Logic:

// Pseudo-code for AI suggestion
function suggestServices(specialty: string, city: string): string[] {
  const serviceMap = {
    "dentist": ["Root Canal Treatment", "Dental Implants", "Teeth Whitening", "Braces & Orthodontics", "Dental Crowns", "Pediatric Dentistry"],
    "cardiologist": ["ECG & Echocardiography", "Heart Health Checkups", "Hypertension Management", "Chest Pain Evaluation", "Cardiac Risk Assessment"],
    // ... 30 specialties
  };
  return serviceMap[specialty] || ["General Consultation", "Health Checkup", "Diagnostic Services"];
}

function suggestUSPs(specialty: string, city: string): string[] {
  const uspTemplates = [
    "Over {years} years of experience in {specialty}",
    "Advanced diagnostic equipment for accurate {specialty} care",
    "Personalized treatment plans for every patient",
    "Accepts all major health insurance in {city}",
    "Same-day appointments available",
    " multilingual staff (speaks {languages})"
  ];
  // AI picks 3-5 most relevant
}

UI Design:

┌──────────────────────────────────────────────────────┐
│  Step 2: Tell Us About Your Clinic                  │
│                                                      │
│  Specialty *          [ Dentist ▼ ]                 │
│                                                      │
│  Services (AI-suggested)                             │
│  ☑ Root Canal Treatment                             │
│  ☑ Dental Implants                                  │
│  ☑ Teeth Whitening                                  │
│  ☐ Braces & Orthodontics   [ + Add Custom ]         │
│                                                      │
│  Years of Experience  [ 15 ] years                  │
│                                                      │
│  What Makes You Special? (AI-suggested)             │
│  ☑ Over 15 years of experience in dentistry         │
│  ☑ Advanced diagnostic equipment                    │
│  ☑ Same-day appointments available                  │
│  [ + Add Your Own ]                                 │
│                                                      │
│  [ Back ]        [ Save & Continue → ]              │
└──────────────────────────────────────────────────────┘

Key principle: AI suggests. Client edits. Doctor approves. Never publish without approval.


2. AI Content Generation Pipeline#

Step 1: Bio Generation (300–500 words)#

Input: Business name, specialty, city, services, USPs, years of experience, education, languages, patient types

Output: Professional, MCI-compliant bio

AI Prompt:

You are a medical content writer for an Indian healthcare directory.
Write a 300-500 word professional bio for {businessName}, a {specialty} in {city}.

Constraints:
- NO promotional claims (no "best", "top", "most trusted", "leading")
- NO guaranteed outcomes (no "100% success", "painless", "immediate results")
- Informational tone only — describe services, experience, and patient care approach
- Include: specialty, city, years of experience, key services, patient types, languages
- Mention MCI registration implicitly (e.g., "registered medical practitioner")
- End with a call to action: "Schedule a consultation" or "Book an appointment"

Structure:
1. Opening paragraph (2-3 sentences): Who they are, specialty, city, experience
2. Services paragraph: 3-5 key services with brief descriptions
3. Patient care philosophy: Approach to patient care, patient types
4. Closing: Languages, hours, booking CTA

Output: Plain text, no markdown, no HTML.

Example Output:

Dr. Smith Dental Clinic is a dental practice located in Kochi, Kerala, serving patients of all ages for over 15 years. The clinic provides comprehensive dental care including root canal treatment, dental implants, teeth whitening, and orthodontic services.

The clinic offers a range of services designed to address common dental concerns. Root canal treatment is performed using modern techniques to preserve natural teeth. Dental implant procedures help restore missing teeth with permanent solutions. Teeth whitening services are available for patients seeking cosmetic improvements. Pediatric dentistry services cater to children and adolescents.

The practice focuses on patient comfort and preventive care. The team believes in educating patients about oral health to prevent future dental issues. Same-day appointments are available for urgent dental concerns. The clinic accepts all major health insurance providers in Kochi.

Dr. Smith and the team speak English, Malayalam, and Hindi. The clinic is open Monday through Saturday, 9:00 AM to 7:00 PM. Patients can schedule appointments by phone or WhatsApp.

Cost: ~$0.03 per bio (Claude Haiku, ~400 words)


Step 2: Service Descriptions (50–100 words each)#

Input: Service name, specialty, city

Output: Brief description of the service

AI Prompt:

Describe the dental service "{serviceName}" in 50-100 words for a patient in {city}.
Constraints: Informational only. No promotional language. No pricing (unless asked). Include what the service involves and who it's for.

Example Output (Root Canal Treatment):

Root canal treatment is a dental procedure used to treat infected or damaged tooth pulp. The procedure involves removing the infected tissue, cleaning the root canal, and sealing the tooth to prevent further infection. This treatment helps save the natural tooth and eliminates pain caused by the infection. It is recommended for patients with deep cavities, cracked teeth, or persistent tooth pain.

Cost: ~$0.01 per service (Claude Haiku, ~75 words)


Step 3: FAQ Generation (10 Q&A pairs)#

Input: Specialty, city, services, common patient questions

Output: 10 Q&A pairs

AI Prompt:

Generate 10 FAQ questions that patients in {city} commonly ask about {specialty} services.
For each question, provide a 2-3 sentence informational answer.

Constraints:
- Questions should be practical and patient-focused
- Answers should be informational, not promotional
- Include cost-related questions where appropriate (give ranges, not exact prices)
- Include questions about insurance, appointment booking, and first visits
- No "best doctor" or "why choose us" questions

Output format:
Q1: [Question]
A1: [Answer]
...
Q10: [Question]
A10: [Answer]

Example Output:

Q1: What is the cost of root canal treatment in Kochi?
A1: The cost of root canal treatment in Kochi typically ranges from ₹3,000 to ₹8,000 depending on the tooth and complexity. Molars generally cost more than front teeth. Most dental insurance plans cover a portion of the cost.

Q2: How long does a dental implant procedure take?
A2: A dental implant procedure typically takes 3-6 months from start to finish. The initial implant placement takes 1-2 hours, followed by a healing period of 2-3 months. The final crown is placed after the implant has integrated with the jawbone.

Q3: Does teeth whitening damage enamel?
A3: Professional teeth whitening performed by a dentist is safe and does not damage enamel. The bleaching agents are carefully applied to minimize sensitivity. Some patients may experience temporary sensitivity for 24-48 hours after the procedure.

... (7 more)

Cost: ~$0.05 per FAQ set (Claude Haiku, ~10 Q&A pairs)


Step 4: Schema Generation (JSON-LD)#

Input: All profile data (name, address, phone, hours, services, reviews, FAQs)

Output: JSON-LD schema object

No AI needed — structured data generation via code:

function generateSchema(profile: DirectoryProfile): JsonLdObject {
  return {
    "@context": "https://schema.org",
    "@graph": [
      {
        "@type": "LocalBusiness",
        "@id": `${profile.canonicalUrl}#business`,
        "name": profile.businessName,
        "description": profile.bio.substring(0, 300),
        "url": profile.canonicalUrl,
        "telephone": profile.phone,
        "email": profile.email,
        "address": {
          "@type": "PostalAddress",
          "streetAddress": profile.address,
          "addressLocality": profile.city,
          "addressRegion": profile.state,
          "addressCountry": "IN"
        },
        "geo": {
          "@type": "GeoCoordinates",
          "latitude": profile.latitude,
          "longitude": profile.longitude
        },
        "openingHoursSpecification": profile.hours.map(h => ({
          "@type": "OpeningHoursSpecification",
          "dayOfWeek": h.day,
          "opens": h.opens,
          "closes": h.closes
        })),
        "image": profile.photoUrl,
        "aggregateRating": {
          "@type": "AggregateRating",
          "ratingValue": profile.avgRating,
          "reviewCount": profile.reviewCount
        },
        "hasMap": profile.mapUrl,
        "priceRange": "₹₹"
      },
      {
        "@type": "Physician",
        "@id": `${profile.canonicalUrl}#physician`,
        "name": profile.doctorName,
        "medicalSpecialty": profile.specialty,
        "worksFor": { "@id": `${profile.canonicalUrl}#business` }
      },
      {
        "@type": "FAQPage",
        "mainEntity": profile.faqs.map(faq => ({
          "@type": "Question",
          "name": faq.question,
          "acceptedAnswer": { "@type": "Answer", "text": faq.answer }
        }))
      },
      {
        "@type": "BreadcrumbList",
        "itemListElement": [
          { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://directory.com/" },
          { "@type": "ListItem", "position": 2, "name": `Clinics in ${profile.city}`, "item": `https://directory.com/clinics/${profile.citySlug}` },
          { "@type": "ListItem", "position": 3, "name": profile.businessName, "item": profile.canonicalUrl }
        ]
      }
    ]
  };
}

Cost: $0 (code generation)


Step 5: Content Compliance Filter (MCI Check)#

Before any content is shown to the doctor for approval, it passes through a compliance filter:

const FORBIDDEN_WORDS = [
  "best", "top", "most trusted", "leading", "no.1", "number one",
  "guaranteed", "100% success", "painless", "immediate results",
  "miracle", "cure all", "magic", "secret"
];

const FORBIDDEN_PATTERNS = [
  /best\s+(dentist|doctor|clinic|surgeon)/i,
  /top\s+(dentist|doctor|clinic|surgeon)/i,
  /most\s+(trusted|experienced|qualified)/i,
  /\d+%\s+(success|guarantee)/i,
  /guaranteed\s+(results|cure|outcome)/i,
];

function checkCompliance(content: string): ComplianceResult {
  const violations = [];
  
  FORBIDDEN_WORDS.forEach(word => {
    if (content.toLowerCase().includes(word)) {
      violations.push({ type: "FORBIDDEN_WORD", word, severity: "ERROR" });
    }
  });
  
  FORBIDDEN_PATTERNS.forEach(pattern => {
    if (pattern.test(content)) {
      violations.push({ type: "FORBIDDEN_PATTERN", pattern: pattern.source, severity: "ERROR" });
    }
  });
  
  // Check for medical disclaimers
  if (!content.includes("This information is for educational purposes")) {
    violations.push({ type: "MISSING_DISCLAIMER", severity: "WARNING" });
  }
  
  return { passed: violations.filter(v => v.severity === "ERROR").length === 0, violations };
}

If compliance fails: Content is sent back to AI with instructions: "Rewrite to remove promotional claims. Use informational tone only."


3. Profile Approval Gate#

The Problem#

Clients (doctors) want to review content before it goes live. But they don't want to spend hours editing. They want to "approve with minor tweaks" or "reject with feedback."

The Solution: Three-Option Approval#

┌──────────────────────────────────────────────────────┐
│  📝 Review Your Directory Profile                    │
│                                                      │
│  Your AI Copilot has generated your profile content. │
│  Review and approve before it goes live.            │
│                                                      │
│  ── Bio ────────────────────────────────────────────│
│  Dr. Smith Dental Clinic is a dental practice...     │
│  [ Edit Bio ]                                        │
│                                                      │
│  ── Services ───────────────────────────────────────│
│  ☑ Root Canal Treatment                            │
│  ☑ Dental Implants                                   │
│  ☑ Teeth Whitening                                  │
│  [ Edit Services ]                                   │
│                                                      │
│  ── FAQs ────────────────────────────────────────────│
│  Q: What is the cost of root canal treatment?        │
│  A: The cost typically ranges from ₹3,000...        │
│  [ Edit FAQs ]                                       │
│                                                      │
│  [ ❌ Reject & Request Changes ]                     │
│  [ ✏️ Approve with Edits ]                          │
│  [ ✅ Approve as Is ]                               │
│                                                      │
│  ⏰ Auto-approve in 48 hours if no action           │
└──────────────────────────────────────────────────────┘

Approval Options#

Option Action Timeline
✅ Approve as Is Profile goes live immediately Instant
✏️ Approve with Edits Client makes edits, then approves Within 24 hours
❌ Reject & Request Changes Client provides feedback, AI regenerates 24-48 hours
Auto-approve If no action within 48 hours, profile auto-publishes 48 hours

Approval Flow#

AI generates content → Compliance check → 
  → Doctor reviews → 
    → [Approve] → Publish immediately
    → [Edit + Approve] → Save edits → Publish
    → [Reject] → Collect feedback → AI regenerates → Loop
    → [No action] → Auto-approve after 48 hours

Notification Sequence#

Time Channel Message
T+0 (content ready) WhatsApp + Email "Your directory profile is ready for review. Approve here: [link]"
T+24h (no action) WhatsApp reminder "Reminder: Your profile is ready for approval. Auto-publishes in 24 hours."
T+48h (auto-approve) WhatsApp "Your profile has been published on India's trusted healthcare directory. View: [link]"
T+48h (rejected) WhatsApp + Email "Your feedback has been received. AI is regenerating your profile. New draft in 2 hours."

4. Profile Publishing Workflow#

Onboarding Steps (Revised)#

Step 1: Business Info [C]          → Name, category, address, phone, hours
Step 2: Content Collection [C]     → Services, USPs, experience, photos, media
Step 3: Consent & Compliance [C]   → DPDPA consent, MCI acknowledgment
Step 4: Payment [C]                → Plan selection, payment, trial start
Step 5: Directory Profile Creation [S] → AI generates bio, services, FAQs, schema
Step 6: Doctor Approval [C]        → Review profile content, approve/edit/reject
Step 7: Profile Publish [S]        → Publish on directory, update GBP, submit citations
Step 8: GBP Connect [C]            → OAuth connect, sync data
Step 9: Social Connect [C]         → Instagram, Facebook connect
Step 10: Citations [S]             → Submit 30 directory listings
Step 11: First Posts [S]           → First GBP post + social posts
Step 12: Welcome [S]               → WhatsApp + email welcome report

[C] = Client action | [S] = System automated

Profile Publish Checklist#

Before a profile goes live, the system verifies:

  • Content passes MCI compliance check
  • Doctor approval received (or auto-approve timer expired)
  • All required fields populated (name, address, phone, hours, bio, services)
  • At least 1 photo uploaded (or placeholder used)
  • Schema markup is valid JSON-LD
  • Meta title and description are within limits (70 chars, 160 chars)
  • URL slug is unique within city
  • City page exists (or is created)
  • GBP websiteUri is updated to directory profile URL
  • XML sitemap is updated
  • ISR revalidation is triggered

5. Monthly Content Refresh#

What Gets Refreshed#

Content Refresh Frequency Method
Bio Monthly AI rewrites with same constraints
3 FAQs Monthly AI generates new questions based on trends
Service descriptions Monthly AI refreshes 2-3 services
Reviews Real-time Google review sync + new review replies
Hours On change Client updates via dashboard
Photos On change Client uploads via dashboard
Schema On content change Regenerated automatically

Refresh Workflow#

1st of every month (Inngest cron job):
  → Fetch all PUBLISHED profiles
  → For each profile:
    a. Generate new bio (Claude Haiku, ~400 words)
    b. Pick 3 services to refresh
    c. Generate 3 new FAQs (replace oldest 3)
    d. Regenerate schema if content changed
    e. Set status to PENDING_REVIEW (if plan requires approval)
    f. Send WhatsApp: "Your profile content has been refreshed. Review changes: [link]"
    g. Trigger ISR revalidation after approval
  → Log all refreshes
  → Send admin report

Client Approval for Refresh#

Plan Refresh Approval
Starter Auto-approve (no doctor review)
Standard Doctor reviews changes, approves in 24h
Premium Doctor reviews changes, approves in 24h
Enterprise Doctor reviews changes, approves in 24h + custom content

6. Client Dashboard Integration#

/dashboard/profile — Profile Management#

┌──────────────────────────────────────────────────────┐
│  📋 My Directory Profile                              │
│                                                      │
│  Status: ✅ LIVE                                     │
│  URL: directory.com/clinics/kochi/dr-smith-dental  │
│  Views: 1,247 (last 30 days)                         │
│  Click-to-Call: 89 (last 30 days)                    │
│                                                      │
│  [ 👁️ View Live Profile ]  [ 📋 Edit Content ]      │
│                                                      │
│  ── Content Status ─────────────────────────────────│
│  Bio          ✅ Published (refreshed 2 days ago)     │
│  Services     ✅ Published (8 services)             │
│  FAQs         ✅ Published (10 FAQs)                  │
│  Reviews      ✅ 47 Google reviews synced             │
│  Photos       ✅ 5 photos uploaded                  │
│                                                      │
│  ── Pending Changes ─────────────────────────────────│
│  📝 New bio draft waiting for approval               │
│  [ Review Changes ]                                  │
│                                                      │
│  ── GBP Link ────────────────────────────────────────│
│  Google Business Profile linked ✅                    │
│  Website URL: directory.com/clinics/kochi/...       │
│  [ Update GBP ]                                      │
│                                                      │
│  ── Share Profile ────────────────────────────────────│
│  [ Copy Link ]  [ Share on WhatsApp ]  [ QR Code ]  │
└──────────────────────────────────────────────────────┘

Profile Editing (Limited)#

Clients can edit:

  • ✅ Contact info (phone, hours, address)
  • ✅ Photos (upload, replace, reorder)
  • ✅ Services (add, remove, reorder)
  • ✅ Bio (edit with compliance check)
  • ✅ FAQs (edit, add, remove)

Clients CANNOT edit:

  • ❌ URL slug (SEO-critical, fixed after publish)
  • ❌ City (would change the URL structure)
  • ❌ Schema markup (auto-generated)
  • ❌ Meta tags (auto-generated)
  • ❌ Related clinics (auto-generated)

7. Fallback Mechanisms#

Scenario 1: Client Already Has a Website#

Old behavior: Offered to host their landing page on our subdomain or inject schema into their existing site.

New behavior: No change needed. The directory profile is SEPARATE from their existing website. They keep their website. We create a directory profile. Their GBP can link to EITHER (or both — but we recommend the directory profile for higher DA).

Client: "I already have a website: drsmith.com"
RankFlow: "Great! Your existing website stays as-is. We'll also create a premium directory profile for you on India's trusted healthcare directory. Your Google Business Profile will link to the directory profile for better rankings. You can keep both."

Scenario 2: Client Wants to Leave#

Old behavior: "Page goes offline, citations deleted, rankings collapse."

New behavior:

Day 0: Client cancels
Day 1: Profile status → PAUSED (still visible but marked "listing no longer active")
Day 7: WhatsApp reminder: "Your profile will be removed in 23 days. Reconnect to keep it live."
Day 30: Profile status → ARCHIVED (returns 404, removed from sitemap)
Day 30: Citations on external directories (Justdial, Practo, etc.) → Gradually removed or updated
Day 30: GBP website URL → Client can update to their own website

Key difference: The directory profile is removed, but the external citations may remain (depending on directory policies). The client loses the directory authority but retains their GBP and any citations that don't require ongoing maintenance.


8. Technical Implementation#

Database Schema (Prisma)#

See directory-website-architecture.md Section 5 for the complete DirectoryProfile schema.

Key API Endpoints (tRPC)#

See directory-website-architecture.md Section 6 for the complete API specification.

Content Generation Job (Inngest)#

// src/jobs/profile-content-generation.ts
import { inngest } from "@/lib/inngest";

export const generateProfileContent = inngest.createFunction(
  { id: "generate-profile-content" },
  { event: "profile/content.generate" },
  async ({ event, step }) => {
    const { practiceId } = event.data;
    
    // Step 1: Fetch practice data
    const practice = await step.run("fetch-practice", async () => {
      return db.practice.findUnique({ where: { id: practiceId } });
    });
    
    // Step 2: Generate bio
    const bio = await step.run("generate-bio", async () => {
      return ai.generate({
        task: "directory_profile_bio",
        model: "claude-sonnet",
        input: { practice },
      });
    });
    
    // Step 3: Generate service descriptions
    const services = await step.run("generate-services", async () => {
      return Promise.all(practice.services.map(service => 
        ai.generate({ task: "directory_profile_service", model: "claude-haiku", input: { service } })
      ));
    });
    
    // Step 4: Generate FAQs
    const faqs = await step.run("generate-faqs", async () => {
      return ai.generate({
        task: "directory_profile_faq",
        model: "claude-sonnet",
        input: { practice },
      });
    });
    
    // Step 5: Compliance check
    const compliance = await step.run("check-compliance", async () => {
      return checkCompliance(bio + services.join(" ") + faqs.join(" "));
    });
    
    if (!compliance.passed) {
      // Retry with feedback
      await step.run("retry-with-feedback", async () => {
        return ai.generate({
          task: "directory_profile_bio",
          model: "claude-sonnet",
          input: { practice, feedback: compliance.violations },
        });
      });
    }
    
    // Step 6: Save to database
    await step.run("save-profile", async () => {
      return db.directoryProfile.create({
        data: {
          practiceId,
          status: "PENDING_REVIEW",
          bio,
          services: { create: services },
          faqs: { create: faqs },
          schemaMarkup: generateSchema({ practice, bio, services, faqs }),
        },
      });
    });
    
    // Step 7: Send approval notification
    await step.run("send-approval-request", async () => {
      return sendWhatsApp({
        to: practice.phone,
        message: `Your directory profile is ready for review. Approve here: ${approvalUrl}`,
      });
    });
    
    return { profileId, status: "PENDING_REVIEW" };
  }
);

ISR Revalidation#

// src/app/api/revalidate/route.ts
import { revalidatePath } from "next/cache";

export async function POST(request: Request) {
  const { profileId, citySlug, slug } = await request.json();
  
  // Revalidate the profile page
  revalidatePath(`/clinics/${citySlug}/${slug}`);
  
  // Revalidate the city page
  revalidatePath(`/clinics/${citySlug}`);
  
  // Revalidate the specialty page (if applicable)
  // revalidatePath(`/specialty/${specialty}`);
  
  return Response.json({ revalidated: true, profileId });
}

9. Cost Analysis#

Content Generation Cost (Per Profile)#

Content Model Cost Quantity Total
Bio Claude Sonnet ~$0.03 1 $0.03
Service descriptions Claude Haiku ~$0.01 8 $0.08
FAQs Claude Sonnet ~$0.05 1 set $0.05
Schema Code $0 1 $0
City page content Claude Sonnet ~$0.02 1 $0.02
Total per profile ~$0.18

Monthly Refresh Cost (Per Profile)#

Content Cost Quantity Total
Bio rewrite ~$0.02 1 $0.02
Service refresh (3 services) ~$0.01 3 $0.03
FAQ refresh (3 new) ~$0.03 1 $0.03
Total per profile/month ~$0.08

At Scale (500 clients)#

Metric Monthly Cost
Initial content generation (500 profiles) ~$90
Monthly refresh (500 profiles) ~$40
Total content cost per month ~$40
Per client per month ~$0.08

Compare to old model:

  • Old model: 500 subdomains × Vercel hosting + 500 SSG builds + wildcard DNS + custom domain support = ~$200-300/month
  • New model: 1 domain × Vercel hosting + ISR caching = ~$50-100/month
  • Savings: ~$150-200/month at 500 clients

10. Success Metrics#

Profile Quality Metrics#

Metric Target Measurement
Average bio length 400+ words Count words per profile
Average services per profile 5+ Count services
Average FAQs per profile 10+ Count FAQs
Compliance pass rate 100% Automated check on every piece of content
Doctor approval rate 80%+ Approved / (Approved + Rejected)
Average approval time <24 hours Time from "content ready" to "approved"
Profile view count (month 1) 50+ per profile Analytics tracking
Profile view count (month 6) 200+ per profile Analytics tracking

SEO Metrics#

Metric Target Measurement
Directory DA (Month 1) 10+ Moz/Ahrefs
Directory DA (Month 6) 25+ Moz/Ahrefs
Directory DA (Month 12) 35+ Moz/Ahrefs
Profiles indexed by Google 100% Google Search Console
Average profile ranking (Month 3) Top 10 for "[specialty] in [city]" Rank tracking
Average profile ranking (Month 6) Top 5 for "[specialty] in [city]" Rank tracking
Internal links per profile 3-6 Related clinics
Backlinks to directory (Month 6) 50+ Ahrefs/Moz
Backlinks to directory (Month 12) 200+ Ahrefs/Moz

11. Summary#

This directory profile system replaces the individual landing page model with a unified, high-authority approach that is:

  • Better SEO: One compounding domain vs. 100 zero-authority subdomains
  • Simpler tech: No wildcard DNS, no per-client builds, no custom domains
  • Better for clients: They get rankings, not a website they don't want
  • More maintainable: One codebase, one design system, one SEO strategy
  • Future-proof: The directory becomes a standalone, monetizable asset

Key workflows:

  1. Onboarding collects structured content (Step 2b)
  2. AI generates bio, services, FAQs, schema (Steps 5-6)
  3. Doctor approves via three-option gate (Step 6)
  4. Profile publishes on directory + GBP updates + citations submit (Step 7)
  5. Monthly refresh regenerates content + doctor re-approves (ongoing)

Next step: Begin development of the directory profile creation pipeline (Week 3-4 of the new architecture timeline).