Files
cal-diy-oidc/agents/rules/data-repository-methods.md
T
Benny Joo ab21c7f805 refactor: Cal.diy (#28903)
* feat: Cal.diy — community-driven MIT-licensed fork of Cal.com

This squashed commit contains all Cal.diy changes applied on top of calcom/cal.com main:

- Rebrand Cal.com to Cal.diy across the entire codebase
- Remove Enterprise Edition (EE) features, license checks, and AGPL restrictions
- Switch license from AGPL-3.0 to MIT
- Remove docs/ directory (migrated to Nextra at cal.diy)
- Remove dead code: org tests, EE tips, platform nav, premium username, SAML/SSO, etc.
- Clean up .env.example for self-hosted Cal.diy
- Update Docker image references to calcom/cal.diy
- Update README, CONTRIBUTING.md, and issue templates for Cal.diy community fork
- Add PR welcome bot for Cal.diy contributors
- Fix API v2 breaking changes oasdiff ignore entries
- Replace Blacksmith CI runners with default GitHub Actions

3893 files changed, 20789 insertions(+), 411020 deletions(-)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: remove org-specific /organizations/:orgId endpoints from API v2 atoms controllers (#1701)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: revert Cal.diy Inc to Cal.com, Inc. in license files, copyright notices, and package metadata (#1702)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* rip out org related comments in api v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-15 09:52:36 -03:00

5.3 KiB

title, impact, impactDescription, tags
title impact impactDescription tags
Repository Method Naming Conventions HIGH Improves code discoverability and reusability data, repository, naming, conventions, methods

Repository Method Naming Conventions

Impact: HIGH

Repository methods should follow consistent naming conventions to improve discoverability and promote code reuse across different features.

Rule 1: Don't include the repository's entity name in method names

Method names should be concise and avoid redundancy since the repository class name already indicates the entity type.

// Good - Concise method names
class BookingRepository {
  findById(id: string) { ... }
  findByUserId(userId: string) { ... }
  create(data: BookingCreateInput) { ... }
  delete(id: string) { ... }
}

// Bad - Redundant entity name in methods
class BookingRepository {
  findBookingById(id: string) { ... }
  findBookingByUserId(userId: string) { ... }
  createBooking(data: BookingCreateInput) { ... }
  deleteBooking(id: string) { ... }
}

Rule 2: Use include or similar keywords for methods that fetch relational data

When a method retrieves additional related entities, make this explicit in the method name using keywords like include, with, or andRelations.

// Good - Clear indication of included relations
class EventTypeRepository {
  findById(id: string) {
    return prisma.eventType.findUnique({
      where: { id },
    });
  }

  findByIdIncludeHosts(id: string) {
    return prisma.eventType.findUnique({
      where: { id },
      include: { hosts: true },
    });
  }

  findByIdIncludeHostsAndSchedule(id: string) {
    return prisma.eventType.findUnique({
      where: { id },
      include: { hosts: true, schedule: true },
    });
  }
}

// Bad - Unclear what data is included
class EventTypeRepository {
  findById(id: string) {
    return prisma.eventType.findUnique({
      where: { id },
      include: { hosts: true, schedule: true },
    });
  }

  findByIdForReporting(id: string) {
    return prisma.eventType.findUnique({
      where: { id },
      include: { hosts: true },
    });
  }
}

Rule 3: Keep methods generic and reusable - avoid use-case-specific names

Repository methods should be general-purpose and describe what data they return, not how or where it's used. This promotes code reuse across different features.

// Good - Generic, reusable methods
class BookingRepository {
  findByUserIdIncludeAttendees(userId: string) {
    return prisma.booking.findMany({
      where: { userId },
      include: { attendees: true },
    });
  }

  findByDateRangeIncludeEventType(startDate: Date, endDate: Date) {
    return prisma.booking.findMany({
      where: {
        startTime: { gte: startDate },
        endTime: { lte: endDate },
      },
      include: { eventType: true },
    });
  }
}

// Bad - Use-case-specific method names
class BookingRepository {
  findBookingsForReporting(userId: string) {
    return prisma.booking.findMany({
      where: { userId },
      include: { attendees: true },
    });
  }

  findBookingsForDashboard(startDate: Date, endDate: Date) {
    return prisma.booking.findMany({
      where: {
        startTime: { gte: startDate },
        endTime: { lte: endDate },
      },
      include: { eventType: true },
    });
  }
}

Rule 4: No business logic in repositories

Repositories should only handle data access. Business logic, validations, and complex transformations belong in the Service layer.

// Good - Repository only handles data access
class BookingRepository {
  findByIdIncludeAttendees(id: string) {
    return prisma.booking.findUnique({
      where: { id },
      include: { attendees: true },
    });
  }

  updateStatus(id: string, status: BookingStatus) {
    return prisma.booking.update({
      where: { id },
      data: { status },
    });
  }
}

class BookingService {
  async confirmBooking(bookingId: string) {
    const booking = await this.bookingRepository.findByIdIncludeAttendees(bookingId);
    
    if (!booking) {
      throw new Error("Booking not found");
    }

    if (booking.status !== "PENDING") {
      throw new Error("Only pending bookings can be confirmed");
    }

    await this.emailService.sendConfirmationToAttendees(booking.attendees);
    return this.bookingRepository.updateStatus(bookingId, "CONFIRMED");
  }
}

// Bad - Business logic in repository
class BookingRepository {
  async confirmBooking(bookingId: string) {
    const booking = await prisma.booking.findUnique({
      where: { id: bookingId },
      include: { attendees: true },
    });

    if (!booking) {
      throw new Error("Booking not found");
    }

    if (booking.status !== "PENDING") {
      throw new Error("Only pending bookings can be confirmed");
    }

    await sendEmailToAttendees(booking.attendees);

    return prisma.booking.update({
      where: { id: bookingId },
      data: { status: "CONFIRMED" },
    });
  }
}

Summary

  • Method names should be concise: findById not findBookingById
  • Use include/with keywords when fetching relations: findByIdIncludeHosts
  • Keep methods generic and reusable: findByUserIdIncludeAttendees not findBookingsForReporting
  • No business logic in repositories - that belongs in Services

Reference: Cal.diy Engineering Blog