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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions