Skip to content

Build Modular Calendar & Reminder Feature Module (With Email Support) #13

@abhishek-nexgen-dev

Description

@abhishek-nexgen-dev

📅 Calendar & Reminder Feature (FastKit-Style)

🧩 Description

  • Create a modular calendar/reminder feature that lets users:

  • Add, update, and delete events/tasks

  • Set reminder times

  • Automatically receive email reminders via NodeMailer

  • Easily plug this feature into any Express project without writing boilerplate

This module should be:

  • Class-based

  • Pluggable

  • Email-ready with customizable mail templates

  • Ready for production-scale use with date-based job scheduling

🧱 Why This Is Important

  • 🧘 Most apps need event scheduling (personal dashboards, health, team tools)

  • ⏰ Reminder emails improve engagement and reduce forgetfulness

  • 🔌 Clean, modular design makes it easy to reuse or extend

🟢 Difficulty Level: Intermediate → Advanced

Familiarity with:

  • NodeMailer

  • Express + TypeScript

  • Async services & scheduling (e.g., node-cron or setTimeout)

  • Zod/Joi validation

  • Date/time manipulation (date-fns, dayjs)

✅ Tasks

📁 Folder Structure

src/
└── features/
    └── Calendar/
        └── v1/
            ├── Calendar.controller.ts
            ├── Calendar.service.ts
            ├── Calendar.validators.ts
            ├── Calendar.constant.ts
            ├── Calendar.model.ts
            ├── Calendar.reminder.ts       # Email scheduler logic
            ├── Calendar.demo.ts
            └── README.md

📘 Model (Calendar.model.ts)

export interface ICalendarEvent {
  id: string;
  title: string;
  description?: string;
  startTime: Date;
  endTime: Date;
  remindBeforeInMinutes?: number; // e.g. 10 min before
  email: string; // whom to send reminder
  status?: 'pending' | 'completed';

// Other 
}

📜 Validators (Calendar.validators.ts)

Use Zod or Joi:

const createEventSchema = z.object({
  title: z.string().min(2),
  startTime: z.string().datetime(),
  endTime: z.string().datetime(),
  remindBeforeInMinutes: z.number().optional(),
  email: z.string().email(),
});

✅ Export validation middleware.

⚙️ Service (Calendar.service.ts)

class CalendarService {
  async createEvent(data: ICalendarEvent): Promise<ICalendarEvent> {}
  async getAllEvents(): Promise<ICalendarEvent[]> {}
  async updateEvent(id: string, updates: Partial<ICalendarEvent>): Promise<ICalendarEvent> {}
  async deleteEvent(id: string): Promise<boolean> {}
}

📦 Controller (Calendar.controller.ts)

Bind-safe controller:

class CalendarController {
  createEvent(req, res): Promise<void>;
  getEvents(req, res): Promise<void>;
  updateEvent(req, res): Promise<void>;
  deleteEvent(req, res): Promise<void>;
}

✅ Uses:

  • TryCatch.wrap()

  • SendResponse.success() / .error()

🔔 Reminder Handler (Calendar.reminder.ts)

This file:

  • Schedules email reminders based on startTime - remindBeforeInMinutes

  • Uses NodeMailer or SendGrid for sending

  • Optionally logs to Logger.ts

class ReminderScheduler {
  static schedule(event: ICalendarEvent): void {
    const delay = event.startTime.getTime() - Date.now() - (event.remindBeforeInMinutes || 10) * 60000;
    if (delay <= 0) return;

    setTimeout(() => {
      EmailSender.sendReminder(event.email, event.title, event.startTime);
    }, delay);
  }
}

📧 Email Sender (in utils/Email.ts or local helper)

import nodemailer from 'nodemailer';

export class EmailSender {
  static async sendReminder(to: string, title: string, startTime: Date) {
    const transport = nodemailer.createTransport({ /* SMTP config */ });

    await transport.sendMail({
      to,
      subject: `Reminder: ${title}`,
      html: `<p>This is a reminder for your event: <strong>${title}</strong> scheduled at ${startTime}.</p>`,
    });
  }
}

🧾 Constants (Calendar.constant.ts)

export const CALENDAR_MESSAGES = {
  CREATED: "Event created and reminder scheduled.",
  UPDATED: "Event updated.",
  DELETED: "Event deleted.",
  NOT_FOUND: "Event not found.",
};

📘 README.md

Include:

  • How to create events

  • Example of reminder config

  • How reminder emails work

  • Customizing NodeMailer transport

  • How to use controller directly in routes

🧪 Demo Code (Calendar.demo.ts)

router.post('/calendar/eventCreate', validateCreateEvent, calendarController.createEvent);
router.get('/calendar', calendarController.getEvents);
router.put('/calendar/:id', validateUpdateEvent, calendarController.updateEvent);
router.delete('/calendar/:id', calendarController.deleteEvent);

🎯 Expected Outcome

[x] Plug-n-play calendar/reminder module

[x] Clean separation of controller, service, validators, scheduler

[x] Auto-schedule emails on event creation

[x] Built-in NodeMailer support

[x] Easy to customize timing, templates, provider

🙋🏻‍♂️ Looking For

Contributors for:

  • Adding recurring events support (daily, weekly)

  • Adding cron-based implementation (node-cron)

  • Supporting SMS (Twilio)

  • Frontend sample

  • Email templates (tsx)

📦 Bonus Ideas

  • Add “mark as completed” status

  • Add calendar ICS export

  • Add Google Calendar sync in future

  • Export reminders in CSV

Metadata

Metadata

Assignees

No one assigned
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions