Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions backend/apps/cloud/src/common/templates/en/subscribe-reminder.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Hey there,<br /><br />

You signed up for Swetrix a couple of days ago and set up your project — nice!
But it looks like you haven't started your free trial yet.<br /><br />

The trial is 14 days, no credit card required, and gives you full access to
everything Swetrix offers — unlimited features, no restrictions.<br /><br />

<a href="{{subscribeUrl}}" target="_blank">Start your free trial</a><br /><br />

Here's what you get:<br />
<ul>
<li>Web analytics that don't require cookie banners</li>
<li>Error tracking and session analysis</li>
<li>Custom events, funnels, and goals</li>
<li>Privacy-first reCAPTCHA alternative</li>
</ul>

If you have any questions or need help, just reply to this email.<br /><br />

Andrii Romasiun<br />
Founder, Swetrix
1 change: 1 addition & 0 deletions backend/apps/cloud/src/mailer/letter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ export enum LetterTemplate {
OrganisationInvitationUnregistered = 'organisation-invitation-unregistered',
SocialIdentityLinked = 'social-identity-linked',
NoEventsAfterSignup = 'no-events-after-signup',
SubscribeReminder = 'subscribe-reminder',
}
5 changes: 5 additions & 0 deletions backend/apps/cloud/src/mailer/mailer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ const metaInfoJson = {
en: () => 'Need help setting up Swetrix?',
},
},
[LetterTemplate.SubscribeReminder]: {
subject: {
en: () => 'Your Swetrix trial is waiting for you',
},
},
}

interface Params {
Expand Down
46 changes: 45 additions & 1 deletion backend/apps/cloud/src/task-manager/task-manager.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ export class TaskManagerService {
const users = await this.userService.find({
where: {
isActive: true,
// we don't want to send the reminder for people who for example used it long time ago, then removed their projects and now are kinda counted as "new users"
planCode: Not(PlanCode.none),
created: Between(weekAgo, twoDaysAgo),
noEventsReminderSentOn: IsNull(),
},
Expand Down Expand Up @@ -1163,6 +1163,50 @@ export class TaskManagerService {
})
}

@Cron(CronExpression.EVERY_DAY_AT_10AM)
async remindUsersToSubscribe() {
const weekAgo = dayjs.utc().subtract(1, 'week').toDate()
const twoDaysAgo = dayjs
.utc()
.subtract(NO_EVENTS_REMINDER_DELAY_DAYS, 'days')
.toDate()

const users = await this.userService.find({
where: {
isActive: true,
planCode: PlanCode.none,
hasCompletedOnboarding: true,
created: Between(weekAgo, twoDaysAgo),
subscribeReminderSentOn: IsNull(),
},
select: ['id', 'email'],
})

if (_isEmpty(users)) {
return
}

const subscribeUrl = `${this.configService.get('CLIENT_URL')}/subscribe`
const sentOn = dayjs.utc().format('YYYY-MM-DD HH:mm:ss')

await mapLimit(users, REPORTS_USERS_CONCURRENCY, async (user) => {
try {
await this.mailerService.sendEmail(
user.email,
LetterTemplate.SubscribeReminder,
{ subscribeUrl },
)
await this.userService.update(user.id, {
subscribeReminderSentOn: sentOn,
})
} catch (reason) {
this.logger.error(
`[CRON WORKER](remindUsersToSubscribe) Failed to process user ${user.id}: ${reason}`,
)
}
})
}

@Cron(CronExpression.EVERY_2_HOURS)
async deleteOldShareInvitations() {
const minDate = dayjs.utc().subtract(PROJECT_INVITE_EXPIRE, 'h').toDate()
Expand Down
4 changes: 4 additions & 0 deletions backend/apps/cloud/src/user/entities/user.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ export class User {
@Column({ type: 'timestamp', nullable: true })
noEventsReminderSentOn: Date

// the date when the "you haven't subscribed yet" reminder email was sent
@Column({ type: 'timestamp', nullable: true })
subscribeReminderSentOn: Date

@Column('varchar', { length: 15, nullable: true })
subID: string

Expand Down
1 change: 1 addition & 0 deletions backend/migrations/mysql/2026_03_10_subscribe_reminder.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `user` ADD COLUMN `subscribeReminderSentOn` timestamp DEFAULT NULL;