Skip to Content
Course content

246: Building a Simple CRM Backend

Click on the "Edit" button in the top corner of the screen to edit your slide content.

When people first hear "CRM backend," they usually panic and think they need to set up a PostgreSQL database, configure a complex Rails migration, and build a REST API before they can even track a single customer. I see this all the time. There is a persistent belief that the "CRM" part of the name implies a specific infrastructure rather than a specific logic.

The "Database First" Trap vs. Domain Modeling

If you start by worrying about tables and foreign keys, you'll likely over-engineer your data structure before you even understand how your specific business process works. You don't need a database to build a CRM; you need a way to model the relationship between a person, their company, and the history of your conversations with them.

Look at this approach. Instead of thinking about "Rows in a table," let's think about "Objects in Ruby." If we are building a CRM for a freelance consultant, the core entity isn't a "record"—it's a Contact. A Contact has a name, an email, and a list of Interactions. By building this in plain Ruby first, we can iterate on the logic in seconds rather than waiting for migrations to run.

class Interaction
  attr_reader :date, :note

  def initialize(date, note)
    @date = date
    @note = note
  end
end

class Contact
  attr_reader :name, :email, :interactions

  def initialize(name, email)
    @name = name
    @email = email
    @interactions = []
  end

  def add_interaction(note)
    # I like using Time.now here so the user doesn't have to manually input dates
    @interactions << Interaction.new(Time.now, note)
  end
end

From Individual Objects to a Managed System

Now, having a Contact class is great, but a CRM isn't just a collection of people; it's a system for finding and managing those people. You don't want to be manually managing an array of objects in your main script. You need a coordinator—a manager class that handles the "registry" of your clients.

I usually implement this using a Hash. Why? Because looking up a contact by a unique ID in a Hash is significantly faster than iterating through an Array of objects to find a matching name. It's a small detail that makes a huge difference as your "database" grows from ten people to a thousand.

class CRM
  def initialize
    @contacts = {}
    @next_id = 1
  end

  def add_contact(name, email)
    contact = Contact.new(name, email)
    id = @next_id
    @contacts[id] = contact
    @next_id += 1
    id
  end

  def find_contact(id)
    @contacts[id] || raise("Contact with ID #{id} not found!")
  end

  def list_all_contacts
    @contacts.map { |id, contact| "#{id}: #{contact.name} (<#{contact.email}>)" }
  end
end

# Quick test drive:
my_crm = CRM.new
client_id = my_crm.add_contact("Alice Smith", "alice@example.com")
my_crm.find_contact(client_id).add_interaction("Discussed Q3 pricing")
puts my_crm.list_all_contacts

Notice how the CRM class encapsulates the storage. The rest of your application doesn't need to know that you're using a Hash internally. If you decide later that you want to save this to a JSON file or move it to a real SQL database, you only have to change the code inside the CRM class. The way you call add_contact or find_contact stays exactly the same. That's the power of decoupling your business logic from your storage mechanism.




📋 Practical Task

Implementing a Lead Priority Scoring System

In a real CRM, not all contacts are created equal. Some are "hot leads" and some are just "cold" contacts. Your task is to extend the CRM backend we just built to include a priority scoring system.

Modify the Contact class and the CRM class to implement the following:

  • Add a priority_score attribute to the Contact class (defaulting to 0).
  • Add a method Contact#update_score(points) that adds or subtracts points from the priority score.
  • Add a method CRM#high_priority_contacts that returns an array of all contacts with a score of 10 or higher.

Testing your work: Create a CRM instance, add three different contacts, give two of them scores above 10, and verify that high_priority_contacts only returns those two.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.