Skip to content

Instantly share code, notes, and snippets.

@mihairaulea
Created August 9, 2023 22:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mihairaulea/ed0695ee908198c3a5bff7c07939c492 to your computer and use it in GitHub Desktop.
Save mihairaulea/ed0695ee908198c3a5bff7c07939c492 to your computer and use it in GitHub Desktop.
Blueprint for the data layer used to store cold email marketing campaigns
// ALL table are mongodb collections
// does capping this collection give it hashmap-like props? ask mongodb expert
// db.createCollection("userData", {capped: true, size: 100000000})
// table
let userData = new Map();
// table
let emailIdToUserId = new Map();
// table
let emailIdToCampaignId = new Map();
// table
let emailIdToProfileId = new Map();
// table
let contactedIdsForUserId = new Map();
// generates campaign data for a user
function createCampaign({
userId,
// could have also been called batchId
campaignId,
emailSubject,
emailText,
replyToEmail,
elasticSearchQuery,
noOfEmailsToSend,
sendEmailApi
}) {
let campaignData = new Object();
// this is not 100% necessary, but better safe than sorry
campaignData.userId = userId;
// this is again not necessary, because the campaignId is what points to this
// we reach this by going through campaign = campaigns.get(userId) -> campaign.get(campaignId)
campaignData.campaignId = campaignId;
// this will be a template-style text that our other systems will personalize
campaignData.emailSubject = emailSubject;
// same as subject
campaignData.emailText = emailText;
// this will be used by the smtp server
campaignData.replyToEmail = replyToEmail;
// this will be used by the data layer, along with the idsContacted to filter and select the data
// used to personalize and get the emails to send to
campaignData.elasticSearchQuery = elasticSearchQuery;
// this is needed because not all entries have an email address. for later.
//campaignData.initialDataSet = getNumberOfHits(elasticSearchQuery);
// all 4 get updated on events
campaignData.noEmailsSent = noOfEmailsToSend;
campaignData.noEmailsOpened = 0;
campaignData.noOfEmailsClicked = 0;
campaignData.emailsOpened = [];
campaignData.emailsClicked = [];
// this is populated by the resend.com smtp server
// for tests, mock this
campaignData.emailsSendAndProfileIds = sendEmailApi(emailSubject, emailText, replyToEmail, elasticSearchQuery);
campaignData.emailsSendIds.forEach((emailIdAndProfileId) => {
// used to update the campaign statistics on each email event(opened, clicked)
emailIdToUserId.set(emailIdAndProfileId.emailId, userId);
emailIdToCampaignId.set(emailIdAndProfileId.emailId, campaignId);
emailIdToProfileId.set(emailIdAndProfileId.emailId, emailIdAndProfileId.profileId);
});
// this can be safely performed in a batch
if(contactedIdsForUserId.has(userId)!=true)
contactedIdsForUserId.set(userId, new Map());
contactedIdsForUserId.get(userIds).set( emailIdAndProfileId.map(t => t.profileId), true );
let campaignsDataEntry = userData.get(userId);
campaignsDataEntry.set(campaignId, campaignData);
}
// we use this to present the user with the performance of their campaigns
// and also enable them to re-target users
function getCampaigns(userId) {
return userData.get(userId);
}
// used for retargeting from the UI
function getEmailsOpenedForRetargetingFromCampaign(userId, campaignId) {
return userData.get(userId).get(campaignId).emailsOpened;
}
// used for retargeting from the UI
function getEmailsClickedForRetargetingFromCampaign(userId, campaignId) {
return userData.get(userId).get(campaignId).emailsClicked;
}
// EVENTS
// we need to be able to get the userId and campaignId just with this emailId
function emailOpened(emailId) {
// first get the campaign data
userData.get( emailIdToUserId.get(emailId) ).get( emailIdToCampaignId.get(emailId) ).emailsOpened.push(emailId);
}
function emailClicked(emailId) {
userData.get( emailIdToUserId.get(emailId) ).get( emailIdToCampaignId.get(emailId) ).emailsOpened.push(emailId);
}
// data source
// --- CONTACTED IDS
// the contacted ids is used by the lead data layer to exclude people already contacted in
// a. search
// b. when launching a campaign
// this is created/added to when the campaign starts
// this will be used on every id returned from the elasticsearch query
function hasIdBeenContacted(userId, contactedId) {
return contactedIdsForUserId.get(userId).has(contactedId) == true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment