Golden Door Asset
Software Stocks
Gemini PortfolioAgentic CRM
CRM
Intermediate

Agentic CRM

Sales pipeline with automated lead enrichment

Build Parameters
Project IDX + Firebase
4–6 hours Build

Project Blueprint: Agentic CRM - Sales Pipeline with Automated Lead Enrichment

1. The Business Problem (Why build this?)

In today's competitive sales landscape, efficiency and personalized engagement are paramount. Traditional Customer Relationship Management (CRM) systems, while essential, often fall short by demanding extensive manual data entry, providing static views of the sales pipeline, and requiring significant human effort for critical tasks like lead qualification and initial outreach. This leads to several acute pain points for sales teams:

  • Manual Data Entry Burden: Sales representatives spend an inordinate amount of time on administrative tasks – inputting lead details, logging activities, and updating deal stages. This diverts focus from actual selling.
  • Stale or Incomplete Lead Data: Prospects' information changes rapidly. Without automated enrichment, lead data quickly becomes outdated, leading to wasted effort on irrelevant contacts or missed opportunities due to lack of comprehensive intelligence.
  • Lack of Proactive Insights: Existing CRMs typically offer retrospective reporting. Sales teams need forward-looking, actionable insights to identify high-potential deals, predict revenue, and understand bottlenecks before they impact the bottom line.
  • Generic Communication: Crafting personalized emails for every prospect is time-consuming. Generic templates often fall flat, reducing engagement and conversion rates. The ability to quickly generate context-aware, personalized communications is a significant competitive advantage.
  • Disconnected Workflows: Integrating external data sources and AI capabilities into a seamless sales workflow is challenging, often requiring complex custom integrations or manual context switching.

The Agentic CRM directly addresses these challenges by infusing intelligence and automation at every stage of the sales pipeline. It transforms the CRM from a passive record-keeping system into an active, intelligent assistant that augments sales professionals, enabling them to focus on high-value interactions and accelerate deal velocity.

2. Solution Overview

Agentic CRM is designed as an intelligent sales pipeline assistant, leveraging cutting-edge AI to automate tedious tasks, enrich data, and provide generative capabilities, thereby empowering sales teams to operate with unprecedented efficiency and insight. Its core value proposition lies in its agentic nature – not just automating tasks, but intelligently acting on behalf of the user or the system itself.

The application will provide a streamlined interface for managing leads, deals, contacts, and activities, underpinned by a powerful backend that performs proactive data enrichment and AI-driven content generation.

Key Features and their Impact:

  • Automated Lead Enrichment: Upon a new lead being added (manually or via import), the system autonomously retrieves comprehensive profile information (company details, role, social presence, contact info) from external data sources. This ensures sales reps always have the most current and relevant context without manual research.
  • Kanban Deal Board: A highly intuitive, interactive board visualizing deals across customizable sales stages. This provides a clear, real-time overview of the pipeline, facilitating easy drag-and-drop updates and quick status checks.
  • Activity Logging: A robust mechanism for recording all interactions (calls, emails, meetings, automated system events) associated with leads and deals. This maintains a complete historical context, crucial for effective follow-ups and team collaboration. Automated activities (e.g., "Lead enriched successfully") reduce manual input.
  • Revenue Pipeline View: A dynamic, aggregated view of potential revenue broken down by sales stage, probability, and projected close date. This offers critical insights for forecasting, resource allocation, and identifying pipeline health.
  • Email Drafting via AI: Leveraging large language models (LLMs), the system can intelligently draft personalized sales emails based on the specific deal context, contact information, prior interactions, and user intent. This dramatically reduces the time spent on drafting communications, enabling reps to send more relevant and timely emails.

Together, these features create a cohesive platform that not only manages the sales process but actively participates in it, making sales professionals more effective, informed, and productive.

3. Architecture & Tech Stack Justification

The Agentic CRM is envisioned as a modern, scalable, and AI-first application. The chosen tech stack is designed for rapid development, high performance, real-time capabilities, and seamless integration with generative AI.

High-Level Architecture:

+------------------+        +--------------------------+        +----------------------+
|     CLIENT       |        |      BACKEND SERVICES    |        |    AI ORCHESTRATION  |
| (Next.js - React)|        | (Next.js API Routes,     |        |      (Genkit)        |
|                  |        |  Firebase Functions)     |        |                      |
|  - UI Components | <----> | - API Endpoints          | <----> | - AI Flows & Tools   |
|  - Data Display  |        | - Business Logic         |        | - Prompt Management  |
|  - User Input    |        | - Firestore Interactions |        | - LLM Interactions   |
|                  |        | - Auth Management        |        |                      |
+------------------+        +--------------------------+        +----------^-----------+
                                          |                          |       |
                                          |                          |       |
                                          V                          V       V
                                +-----------------------+    +--------------+  +--------------------+
                                |    DATABASE (Firestore) |    |  Gemini API  |  | External Enrichment|
                                | - Leads, Deals          |    |              |  |   APIs (Clearbit, |
                                | - Activities, Contacts  |    |              |  |   Hunter.io, etc.) |
                                +-----------------------+    +--------------+  +--------------------+

Tech Stack Justification:

  • Next.js (Frontend & API Routes):
    • Full-Stack Capabilities: Next.js allows for a unified development experience, handling both the frontend (React) and backend API routes within a single codebase. This simplifies project setup and maintenance.
    • Performance: Features like Server-Side Rendering (SSR) and Static Site Generation (SSG) can optimize initial load times and SEO (though less critical for an internal CRM, still beneficial).
    • Developer Experience: The React ecosystem provides a rich set of libraries and components, accelerating UI development. API Routes are excellent for handling lightweight backend logic, authentication, and proxying requests.
  • Firebase (Backend, Database, Auth, Storage, Functions):
    • Firestore (Database): A flexible, scalable NoSQL document database. Its real-time synchronization capabilities are ideal for the Kanban board, ensuring all users see up-to-the-minute deal statuses. The document-oriented model easily accommodates the varied and evolving data structures of leads, deals, and activities.
    • Firebase Authentication: Provides secure, easy-to-implement user authentication (email/password, Google, etc.), reducing development time for security infrastructure.
    • Firebase Functions: A serverless execution environment perfect for backend business logic, database triggers, and orchestrating complex workflows. Functions will be crucial for responding to Firestore changes (e.g., new lead creation triggering enrichment) and hosting Genkit flows.
    • Firebase Storage: For any potential file uploads (e.g., lead attachments, proposals), though initially not a primary feature.
    • Scalability & Managed Services: Firebase abstracts away infrastructure management, allowing developers to focus on application logic rather than server provisioning and scaling.
  • Genkit (AI Orchestration Layer):
    • Agentic AI Workflow: Genkit is the cornerstone for the "Agentic" aspect of this CRM. It provides a robust framework for building and deploying AI-powered applications, specifically for orchestrating multi-step generative AI workflows.
    • Prompt Management: Centralizes prompt definitions, versioning, and testing, ensuring consistency and quality in AI interactions.
    • Tool Integration: Allows the definition of "tools" – functions that Genkit AI models can call. This is critical for lead enrichment (calling external APIs) and for providing context to Gemini (e.g., a getDealDetails tool).
    • Observability: Genkit offers built-in tracing and logging for AI interactions, essential for debugging and optimizing complex AI flows.
    • Seamless Gemini Integration: Designed to work hand-in-hand with Google's Gemini models, simplifying API interactions and ensuring best practices for using LLMs.
  • Tailwind CSS (Styling):
    • Utility-First Approach: Enables rapid UI development by providing low-level utility classes directly in the markup. This drastically reduces the need for custom CSS and promotes consistency.
    • Customization: Highly configurable, allowing for a unique design system while retaining the benefits of utility classes.
    • Developer Experience: Eliminates the cognitive overhead of naming classes and managing cascading styles.

4. Core Feature Implementation Guide

4.1. Automated Lead Enrichment

Concept: When a new lead document is created in Firestore, a Firebase Function trigger will initiate an asynchronous Genkit flow to fetch and populate additional data from external sources.

Data Model (Firestore - leads collection):

{
  "id": "lead_123",
  "name": "Jane Doe",
  "email": "jane.doe@example.com",
  "companyName": "Acme Corp",
  "status": "New", // Enriched, Contacted, Qualified, etc.
  "createdAt": "2023-10-27T10:00:00Z",
  "updatedAt": "2023-10-27T10:00:00Z",
  "enrichmentStatus": "PENDING", // PENDING, SUCCESS, FAILED
  "enrichedData": {
    "company_domain": "acmecorp.com",
    "company_size": "50-200",
    "company_industry": "Software",
    "person_linkedin_url": "...",
    "person_title": "Sr. Sales Manager",
    "phone_numbers": ["+1-555-123-4567"],
    "summary_ai": "AI-generated summary of key lead characteristics."
  }
}

Pipeline Design:

  1. Firestore Trigger: A Firebase Function is configured to trigger onCreate on the leads collection.
  2. Function Execution: The function receives the new lead document.
  3. Genkit Flow Invocation: The function calls the Genkit enrichLeadFlow with the lead's email and company name as input.
  4. Genkit Flow (enrichLeadFlow):
    • Input: email (string), companyName (string), leadId (string).
    • Tools:
      • fetchCompanyData(domain): Calls Clearbit/Hunter.io to get company details.
      • fetchPersonData(email): Calls Clearbit/Hunter.io to get person details (LinkedIn, title, phone).
      • summarizeData(data): (Optional) Uses Gemini via Genkit defineModel to summarize raw, unstructured enrichment data into key takeaways.
    • Steps:
      • Extract domain from email.
      • Call fetchCompanyData using the domain.
      • Call fetchPersonData using the email.
      • Combine results.
      • (Optional) Use summarizeData tool with the combined raw data.
      • Return structured enrichedData.
  5. Update Firestore: Upon successful completion of the Genkit flow, the Firebase Function updates the original lead document with enrichmentStatus: 'SUCCESS' and the enrichedData payload. On failure, enrichmentStatus: 'FAILED' and an error log.
  6. Activity Logging: Add an entry to the lead's activity log: "Lead enriched successfully by AI."

Pseudo-code (Firebase Function & Genkit Flow):

// Firebase Function (functions/src/index.ts)
import * as functions from 'firebase-functions';
import { getFirestore } from 'firebase-admin/firestore';
import { runGenkitFlow } from './genkitClient'; // Helper to call Genkit flows

export const onNewLeadCreate = functions.firestore
  .document('leads/{leadId}')
  .onCreate(async (snap, context) => {
    const lead = snap.data();
    const leadId = context.params.leadId;

    if (!lead || !lead.email) {
      console.log(`Lead ${leadId} has no email, skipping enrichment.`);
      return;
    }

    await getFirestore().collection('leads').doc(leadId).update({
      enrichmentStatus: 'PENDING',
      updatedAt: new Date().toISOString(),
    });

    try {
      const enrichmentResult = await runGenkitFlow('enrichLeadFlow', {
        email: lead.email,
        companyName: lead.companyName,
        leadId: leadId,
      });

      await getFirestore().collection('leads').doc(leadId).update({
        enrichmentStatus: 'SUCCESS',
        enrichedData: enrichmentResult,
        updatedAt: new Date().toISOString(),
      });
      // Log activity
      await getFirestore().collection('activities').add({
        dealId: null, // Or associate with the lead directly if 'dealId' is null
        leadId: leadId,
        type: 'SYSTEM_ENRICHMENT',
        description: 'Lead details automatically enriched.',
        timestamp: new Date().toISOString(),
        createdBy: 'System AI',
      });
    } catch (error) {
      console.error(`Error enriching lead ${leadId}:`, error);
      await getFirestore().collection('leads').doc(leadId).update({
        enrichmentStatus: 'FAILED',
        enrichmentError: (error as Error).message,
        updatedAt: new Date().toISOString(),
      });
    }
  });


// Genkit Flow (genkit/flows/enrichLead.ts)
import { defineFlow, defineTool, runTool } from '@genkit-ai/flow';
import { z } from 'zod';
import { geminiPro } from '@genkit-ai/gemini';

// Define tools for external API calls
const clearbitApiTool = defineTool(
  {
    name: 'clearbitLookup',
    description: 'Looks up company and person data using Clearbit API.',
    inputSchema: z.object({
      email: z.string().email().optional(),
      domain: z.string().optional(),
    }),
    outputSchema: z.object({
      company: z.any().optional(),
      person: z.any().optional(),
    }),
  },
  async ({ email, domain }) => {
    // In a real scenario, handle API keys securely (e.g., Google Secret Manager)
    const apiKey = process.env.CLEARBIT_API_KEY;
    const headers = { 'Authorization': `Bearer ${apiKey}` };

    let companyData, personData;

    if (email) {
      const response = await fetch(`https://person.clearbit.com/v2/people/find?email=${email}`, { headers });
      personData = await response.json();
    }
    if (domain) {
      const response = await fetch(`https://company.clearbit.com/v2/companies/find?domain=${domain}`, { headers });
      companyData = await response.json();
    }

    return { company: companyData, person: personData };
  }
);

// Define the enrichment flow
export const enrichLeadFlow = defineFlow(
  {
    name: 'enrichLeadFlow',
    inputSchema: z.object({
      email: z.string().email(),
      companyName: z.string().optional(),
      leadId: z.string(),
    }),
    outputSchema: z.object({
      company_domain: z.string().optional(),
      company_size: z.string().optional(),
      company_industry: z.string().optional(),
      person_linkedin_url: z.string().optional(),
      person_title: z.string().optional(),
      phone_numbers: z.array(z.string()).optional(),
      summary_ai: z.string().optional(),
    }),
  },
  async (input) => {
    const domain = input.email.split('@')[1];
    const rawEnrichment = await runTool(clearbitApiTool, { email: input.email, domain });

    let companyData = rawEnrichment.company;
    let personData = rawEnrichment.person;

    // Use Gemini to summarize and extract key info
    const summaryModel = geminiPro; // Configure with specific model version if needed

    const aiSummaryResponse = await summaryModel.generate({
      prompt: `Given the following raw company and person data, extract key information and provide a concise summary. Focus on company size, industry, person's title, and LinkedIn URL.
      Company Data: ${JSON.stringify(companyData)}
      Person Data: ${JSON.stringify(personData)}
      `,
      config: { temperature: 0.2 },
    });

    const aiSummary = aiSummaryResponse.text();

    return {
      company_domain: companyData?.domain || domain,
      company_size: companyData?.metrics?.employeesRange || null,
      company_industry: companyData?.category?.sector || null,
      person_linkedin_url: personData?.linkedin?.handle ? `https://linkedin.com/in/${personData.linkedin.handle}` : null,
      person_title: personData?.title || null,
      phone_numbers: personData?.phoneNumbers || [],
      summary_ai: aiSummary,
    };
  }
);

4.2. Kanban Deal Board

Concept: A visual representation of deals moving through stages, with real-time updates and drag-and-drop functionality.

Data Model (Firestore - deals collection):

{
  "id": "deal_xyz",
  "name": "Acme Corp - Q4 Renewal",
  "leadId": "lead_123", // Link to lead document
  "contactId": "contact_456", // Link to specific contact associated with deal
  "amount": 150000,
  "stage": "Proposal Sent", // e.g., 'New', 'Qualification', 'Proposal Sent', 'Negotiation', 'Closed Won', 'Closed Lost'
  "probability": 0.7, // 0.0 - 1.0
  "expectedCloseDate": "2023-12-31T00:00:00Z",
  "createdAt": "2023-10-01T00:00:00Z",
  "updatedAt": "2023-10-27T12:30:00Z",
  "ownerId": "user_789"
}

Implementation Details:

  • Frontend (Next.js/React):
    • Data Fetching: Use onSnapshot from Firestore SDK to listen for real-time updates to the deals collection. This will automatically re-render the Kanban board when any deal changes. Query for deals relevant to the current user/view.
    • State Management: Use React Context or a library like Zustand to manage the list of deals, categorized by stage.
    • Drag-and-Drop: Integrate a library like react-beautiful-dnd or dnd-kit for intuitive drag-and-drop functionality between stages.
    • Update Logic: When a deal is dropped into a new stage, trigger a Firestore update (updateDoc) to change its stage and updatedAt fields.

Pseudo-code (React Component - simplified):

// components/KanbanBoard.tsx
import React, { useState, useEffect } from 'react';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
import { collection, query, orderBy, onSnapshot, doc, updateDoc } from 'firebase/firestore';
import { db } from '../lib/firebase'; // Your Firestore instance

const stages = ['New', 'Qualification', 'Proposal Sent', 'Negotiation', 'Closed Won', 'Closed Lost'];

interface Deal {
  id: string;
  name: string;
  amount: number;
  stage: string;
}

const KanbanBoard: React.FC = () => {
  const [dealsByStage, setDealsByStage] = useState<Record<string, Deal[]>>({});

  useEffect(() => {
    const q = query(collection(db, 'deals'), orderBy('createdAt', 'asc'));
    const unsubscribe = onSnapshot(q, (snapshot) => {
      const allDeals: Deal[] = snapshot.docs.map(doc => ({
        id: doc.id,
        ...doc.data(),
      } as Deal));

      const newDealsByStage: Record<string, Deal[]> = stages.reduce((acc, stage) => ({ ...acc, [stage]: [] }), {});
      allDeals.forEach(deal => {
        if (stages.includes(deal.stage)) {
          newDealsByStage[deal.stage].push(deal);
        }
      });
      setDealsByStage(newDealsByStage);
    });

    return () => unsubscribe(); // Cleanup listener
  }, []);

  const onDragEnd = async (result: any) => {
    const { source, destination, draggableId } = result;

    if (!destination || (source.droppableId === destination.droppableId && source.index === destination.index)) {
      return;
    }

    const sourceStage = source.droppableId;
    const destinationStage = destination.droppableId;
    const movedDeal = dealsByStage[sourceStage].find(deal => deal.id === draggableId);

    if (movedDeal) {
      const dealRef = doc(db, 'deals', draggableId);
      await updateDoc(dealRef, {
        stage: destinationStage,
        updatedAt: new Date().toISOString(),
      });
      // Firestore listener will automatically update state, so no manual state update needed here.
    }
  };

  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <div className="flex space-x-4 p-4 overflow-x-auto">
        {stages.map((stage) => (
          <Droppable droppableId={stage} key={stage}>
            {(provided) => (
              <div
                ref={provided.innerRef}
                {...provided.droppableProps}
                className="flex-shrink-0 w-80 bg-gray-100 p-3 rounded-lg shadow"
              >
                <h3 className="font-semibold text-lg mb-3">{stage} ({dealsByStage[stage]?.length || 0})</h3>
                {dealsByStage[stage]?.map((deal, index) => (
                  <Draggable key={deal.id} draggableId={deal.id} index={index}>
                    {(provided) => (
                      <div
                        ref={provided.innerRef}
                        {...provided.outerProps}
                        {...provided.dragHandleProps}
                        className="bg-white p-3 mb-2 rounded shadow-sm border border-gray-200"
                      >
                        <p className="font-medium">{deal.name}</p>
                        <p className="text-sm text-gray-600">${deal.amount.toLocaleString()}</p>
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>
        ))}
      </div>
    </DragDropContext>
  );
};

export default KanbanBoard;

4.3. Activity Logging

Concept: A chronological record of all interactions and system events related to a lead or deal.

Data Model (Firestore - activities collection):

{
  "id": "activity_abc",
  "dealId": "deal_xyz",
  "leadId": "lead_123", // Can be null if activity only relates to deal
  "type": "EMAIL_SENT", // CALL, MEETING, NOTE, SYSTEM_ENRICHMENT, SYSTEM_STAGE_CHANGE
  "description": "Sent follow-up email regarding Q4 proposal.",
  "timestamp": "2023-10-27T15:00:00Z",
  "createdBy": "user_789", // User ID or 'System AI'
  "details": { // Optional, type-specific details
    "subject": "Following up on Q4 Proposal",
    "bodySnippet": "...",
    "emailId": "msg_001"
  }
}

Implementation Details:

  • Manual Logging: Frontend provides forms to log calls, meetings, notes. On submission, a new activity document is created in Firestore.
  • Automated Logging:
    • Lead Enrichment: As shown in section 4.1, the enrichment Firebase Function adds an activity.
    • Stage Changes: A Firebase Function onUpdate for the deals collection can check if the stage field has changed. If so, it logs an activity: "Deal moved from [old stage] to [new stage]."
    • AI Email Drafting: When an AI-drafted email is sent, log it as an EMAIL_SENT activity with relevant details.

4.4. Revenue Pipeline View

Concept: A dashboard component that aggregates deal amounts by stage and probability to provide revenue forecasts.

Implementation Details:

  • Data Aggregation (Client-side):
    • The frontend component subscribes to the deals collection (similar to Kanban).
    • It then processes the deals data:
      • Group deals by stage.
      • For each stage, sum amount * probability for an "expected revenue" metric.
      • Sum amount for "potential revenue" metric.
    • Use a charting library (e.g., Recharts, Nivo) to visualize this data (e.g., bar chart showing expected revenue by stage).
  • Data Aggregation (Server-side - for complex reporting/scaling):
    • For very large datasets or complex aggregations, a scheduled Firebase Function could periodically compute and store aggregated metrics in a separate pipelineReports collection. This prevents overloading client devices with heavy computation.

Pseudo-code (Frontend Calculation):

// utils/pipelineCalculations.ts
import { Deal } from './types'; // Assume Deal interface exists

export interface PipelineSummary {
  stage: string;
  potentialRevenue: number;
  expectedRevenue: number;
  dealCount: number;
}

export function calculatePipelineSummary(deals: Deal[], stages: string[]): PipelineSummary[] {
  const summary: Record<string, { potential: number; expected: number; count: number }> = stages.reduce(
    (acc, stage) => ({ ...acc, [stage]: { potential: 0, expected: 0, count: 0 } }),
    {}
  );

  deals.forEach(deal => {
    if (stages.includes(deal.stage)) {
      summary[deal.stage].potential += deal.amount;
      summary[deal.stage].expected += deal.amount * (deal.probability || 0); // Default probability to 0
      summary[deal.stage].count += 1;
    }
  });

  return stages.map(stage => ({
    stage,
    potentialRevenue: summary[stage].potential,
    expectedRevenue: summary[stage].expected,
    dealCount: summary[stage].count,
  }));
}

4.5. Email Drafting via AI

Concept: Allow sales reps to quickly generate personalized email drafts using AI, based on rich context.

Pipeline Design:

  1. User Action: User clicks "Draft Email with AI" button on a deal/contact page in the Next.js frontend.
  2. Context Gathering: Frontend gathers relevant data:
    • dealId
    • contactId
    • User's specific prompt/intent (e.g., "Draft a follow-up email about scheduling a demo.")
    • Optional: User's preferred tone (e.g., "professional," "friendly").
  3. API Call: Frontend calls a Next.js API route (/api/ai/draft-email).
  4. Backend (Next.js API Route):
    • Validates input.
    • Fetches detailed deal, lead, contact, and activity data from Firestore using dealId and contactId.
    • Invokes the Genkit draftEmailFlow with all collected context.
  5. Genkit Flow (draftEmailFlow):
    • Input: dealDetails (object), contactDetails (object), recentActivities (array), userPrompt (string), tone (string, optional).
    • Tools:
      • getDealDetails(dealId): (If Genkit needs to fetch, though backend does it here).
      • getContactDetails(contactId): (Same as above).
    • Steps:
      • Construct a comprehensive prompt for Gemini, including all contextual data.
      • Call geminiPro model.
      • Return the drafted email (subject and body).
  6. Response: Genkit flow returns the drafted email content to the Next.js API route, which then sends it back to the frontend.
  7. Frontend Display: Display the draft in a text editor for the user to review, edit, and send.

Pseudo-code (Genkit Flow for Email Drafting):

// genkit/flows/draftEmail.ts
import { defineFlow } from '@genkit-ai/flow';
import { geminiPro } from '@genkit-ai/gemini';
import { z } from 'zod';

export const draftEmailFlow = defineFlow(
  {
    name: 'draftEmailFlow',
    inputSchema: z.object({
      deal: z.object({
        name: z.string(),
        amount: z.number(),
        stage: z.string(),
        // Add other relevant deal fields
      }),
      contact: z.object({
        firstName: z.string(),
        lastName: z.string(),
        email: z.string().email(),
        title: z.string().optional(),
        companyName: z.string(),
        // Add other relevant contact fields
      }),
      recentActivities: z.array(z.object({
        type: z.string(),
        description: z.string(),
        timestamp: z.string(),
      })).optional(),
      userPrompt: z.string(), // e.g., "Draft a follow-up email to schedule a demo for our Pro plan."
      tone: z.enum(['professional', 'friendly', 'urgent', 'formal']).default('professional'),
    }),
    outputSchema: z.object({
      subject: z.string(),
      body: z.string(),
    }),
  },
  async (input) => {
    const { deal, contact, recentActivities, userPrompt, tone } = input;

    // Construct the persona and context for the AI
    const systemInstruction = `You are a helpful sales assistant for a B2B SaaS company.
      Your goal is to draft professional, personalized, and effective sales emails.
      Adhere to a ${tone} tone.
      Always include a clear call to action based on the user's request.
      Do not include placeholders like [Your Name], just provide the content.
      Output the subject and body in JSON format.`;

    const formattedActivities = recentActivities?.map(activity =>
      `- [${new Date(activity.timestamp).toLocaleDateString()}] ${activity.type}: ${activity.description}`
    ).join('\n') || 'No recent activities found.';

    const userMessage = `Draft an email for a deal named "${deal.name}" (currently in "${deal.stage}" stage, valued at $${deal.amount.toLocaleString()}) with ${contact.firstName} ${contact.lastName} (${contact.title || 'N/A'} at ${contact.companyName}).
      Recent interactions:
      ${formattedActivities}

      User's specific request: "${userPrompt}"`;

    const prompt = [
      { role: 'system', content: systemInstruction },
      { role: 'user', content: userMessage },
    ];

    const model = geminiPro; // Or geminiProVision if images are involved

    const result = await model.generate({
      prompt: prompt,
      config: {
        responseMimeType: 'application/json', // Ask Gemini to output JSON
      },
      tools: [], // No tools needed for this specific draft, but could add e.g. a calendar booking tool
    });

    const emailDraft = JSON.parse(result.text()); // Parse the JSON output

    return {
      subject: emailDraft.subject,
      body: emailDraft.body,
    };
  }
);

5. Gemini Prompting Strategy

Effective prompting is crucial for the "Agentic" capabilities of the CRM. The strategy revolves around providing clear instructions, relevant context, few-shot examples (where applicable), and specifying desired output formats. Genkit's prompt management features will be heavily utilized to store, version, and evaluate these prompts.

General Prompting Principles:

  • Role-Playing: Clearly define the AI's persona (e.g., "You are a helpful sales assistant," "You are a data summarization bot").
  • Goal-Oriented: State the objective explicitly (e.g., "Your goal is to draft a professional email," "Extract key company information").
  • Contextual Grounding: Inject all relevant data dynamically into the prompt (deal details, contact history, lead enrichment data). This prevents hallucinations and ensures relevance.
  • Output Format Specification: Use responseMimeType: 'application/json' in Genkit's model config and explicitly describe the JSON schema within the prompt for structured outputs. For human-readable text, use Markdown.
  • Constraint Enforcement: Specify what not to do, e.g., "Do not use placeholders," "Do not include any pleasantries before the JSON."
  • Iterative Refinement: Leverage Genkit's genkit eval to test prompts against a dataset of inputs and desired outputs, continuously improving performance.

Specific Use Cases:

  1. Lead Enrichment (Internal AI summary within enrichLeadFlow):

    • Objective: Condense raw, potentially messy data from external APIs into concise, actionable summaries and extract specific fields.
    • System Prompt:
      "You are an expert data analyst. Your task is to review raw company and person data, then extract and summarize key attributes relevant for sales prospecting. Focus on company industry, size, the person's job title, and a brief, overall summary of the lead's potential interest based on available data. If a piece of data is missing, state 'N/A'."
      
    • User Prompt (dynamic):
      "Raw Company Data: {JSON.stringify(company_data)}
      Raw Person Data: {JSON.stringify(person_data)}"
      
    • Output: Could be free-form text or structured JSON for summary_ai field, e.g., {"company_summary": "...", "person_summary": "..."}.
  2. Email Drafting (draftEmailFlow):

    • Objective: Generate a personalized sales email based on deal context and user intent.
    • System Prompt: (Detailed in pseudo-code above) Emphasize tone, purpose, and JSON output for subject/body.
    • User Prompt (dynamic): (Detailed in pseudo-code above) Include deal name, stage, amount, contact details, recent activities, and user's specific request.
    • Example (Few-shot, if needed): For complex or very specific styles, an example input/output pair might be added to the prompt, though Gemini is often capable without.
    • Output: JSON { "subject": "...", "body": "..." }.
  3. Future Enhancements (e.g., Activity Summarization):

    • Objective: Summarize a long list of recent activities related to a deal or lead.
    • System Prompt:
      "You are a sales operations assistant. Your task is to provide a concise bullet-point summary of recent interactions with a prospect. Focus on the most significant events, last contact, and next steps mentioned. Keep it to 3-5 bullet points."
      
    • User Prompt (dynamic):
      "Summarize these activities for Deal: {deal.name}
      {activity_list_formatted}"
      
    • Output: Markdown bullet list.

By systematically applying these prompting strategies within Genkit, the Agentic CRM can reliably deliver intelligent automation and generative AI capabilities that significantly enhance the sales process.

6. Deployment & Scaling

The chosen tech stack provides inherent scalability and flexibility for deployment.

6.1. Deployment Strategy:

  • Next.js Frontend:
    • Vercel: Recommended for Next.js applications. Vercel provides a seamless CI/CD pipeline, global CDN, serverless functions (for Next.js API Routes), and automatic scaling. It integrates directly with GitHub.
    • Google Cloud Run: An alternative if more control or specific GCP integrations are needed. Deploy the Next.js application as a container. Cloud Run offers automatic scaling, pay-per-use, and support for custom domains.
  • Firebase Backend (Firestore, Authentication, Storage, Functions):
    • Firebase Project: These services are inherently managed and scaled by Google Cloud. Deployment involves:
      • firebase deploy --only hosting for static assets if not using Vercel.
      • firebase deploy --only functions for Firebase Functions, including Genkit flows.
  • Genkit Flows:
    • Firebase Functions: Genkit flows are typically deployed as Firebase Functions. The genkit deploy command (or equivalent configuration within firebase.json) will package and deploy the Genkit flows as Cloud Functions. This ensures they scale automatically with demand and integrate well with Firebase Triggers.

6.2. Scaling Considerations:

  • Firestore: Handles large volumes of reads and writes automatically. Ensure efficient data modeling (denormalization where appropriate, correct indexing) to avoid hot spots and optimize query performance.
  • Firebase Functions / Cloud Run: Both environments scale automatically based on incoming request load.
    • Memory/CPU: Monitor function execution times and adjust allocated memory/CPU for Genkit flows, especially as AI model calls can be resource-intensive.
    • Concurrency: Configure concurrency settings for functions to balance cost and throughput.
  • Genkit:
    • LLM Rate Limits: Be aware of Gemini API rate limits. Implement exponential backoff and retry mechanisms for API calls within Genkit flows.
    • Tool Performance: Ensure external tools/APIs called by Genkit (e.g., Clearbit) are performant and don't introduce bottlenecks. Implement caching for frequently accessed static external data.
  • Frontend (Next.js):
    • Vercel/CDN: Global CDN for static assets ensures low latency for users worldwide.
    • SSR/ISR: Strategically use Server-Side Rendering (SSR) or Incremental Static Regeneration (ISR) for pages that require fresh data on every request or periodically.

6.3. Monitoring & Observability:

  • Firebase Performance Monitoring: Track app performance, network requests, and function execution times.
  • Google Cloud Logging: Centralized logging for Firebase Functions, Genkit flows, and other GCP services. Set up log-based metrics and alerts for errors or unusual behavior.
  • Google Cloud Monitoring: Dashboards and alerts for resource utilization (CPU, memory, requests, errors) across all deployed services.
  • Genkit Tracing: Use Genkit's built-in tracing to visualize and debug the execution path of complex AI flows, identifying exactly where issues occur during prompt execution or tool calls.

6.4. Security:

  • Firebase Authentication: Secure user access with industry-standard authentication.
  • Firestore Security Rules: Implement fine-grained access control to data, ensuring users can only read/write documents they are authorized for (e.g., a sales rep can only see their own deals or deals within their team).
  • API Key Management: Store sensitive API keys (e.g., Clearbit, Gemini) in Google Cloud Secret Manager and access them via Firebase Functions or Cloud Run environment variables. Avoid hardcoding keys or exposing them in client-side code.
  • Input Validation: Strictly validate all user inputs on both the client and server to prevent injection attacks or malformed data.
  • Rate Limiting: Implement rate limiting on public-facing API routes to prevent abuse and denial-of-service attacks.

By following this comprehensive blueprint, the Agentic CRM can be built as a robust, scalable, and intelligent application, ready to transform sales operations.

Core Capabilities

  • Automated lead enrichment
  • Kanban deal board
  • Activity logging
  • Revenue pipeline view
  • Email drafting via AI

Technology Stack

Next.jsFirebaseGenkitTailwind CSS

Ready to build?

Deploy this architecture inside Project IDX + Firebase using the Gemini API.

Back to Portfolio
Golden Door Asset

Company

  • About
  • Contact
  • LLM Info

Tools

  • Agents
  • Trending Stocks

Resources

  • Software Industry
  • Software Pricing
  • Why Software?

Legal

  • Privacy Policy
  • Terms of Service
  • Disclaimer

© 2026 Golden Door Asset.  ·  Maintained by AI  ·  Updated Mar 2026  ·  Admin