/claim #18947
This PR implements the backend foundation for issue #18947, which adds the ability to invite team members as optional guests to events. Optional guests receive calendar invitations marked as PARTSTAT=OPTIONAL and their calendars are not checked for conflicts.
optionalTeamMemberGuests Int[] field to EventType Prisma schemagenerateIcsString to support PARTSTAT=OPTIONAL for specified guestsFixes #18947 (GitHub issue)
Fixes CAL-5091 (Linear issue - bounty)
Not applicable - This PR is backend-only (schema + ICS generation). No visual changes yet.
Future PR will add UI in Event Type Advanced settings to:
<UpgradeTeamsBadge /> for non-team usersFile: packages/prisma/schema.prisma
model EventType {
// ... existing fields ...
/// Optional team member guests - invited without calendar conflict checking
/// @zod.array(z.number())
optionalTeamMemberGuests Int[] @default([])
}
Migration SQL:
ALTER TABLE "EventType"
ADD COLUMN "optionalTeamMemberGuests" INTEGER[] DEFAULT ARRAY[]::INTEGER[];
File: packages/emails/lib/generateIcsString.ts
Changes:
optionalGuestEmails?: string[] parameter to function signaturePARTSTAT:
optionalGuestEmails → PARTSTAT=OPTIONALPARTSTAT=ACCEPTED (default behavior)Code:
partstat: optionalGuestEmails.includes(attendee.email) ? "OPTIONAL" : partstat,
File: packages/emails/lib/generateIcsString.test.ts
Added 2 test cases:
should mark team members as OPTIONAL when their email is in optionalGuestEmailsshould mark all attendees as OPTIONAL when all are in optionalGuestEmailsCoverage:
PARTSTAT=OPTIONALPARTSTAT=ACCEPTEDStandard Cal.com .env configuration required (DATABASE_URL, etc.)
npx prisma migrate dev --name add_optional_team_member_guests
This creates the optionalTeamMemberGuests column in the EventType table.
yarn test packages/emails/lib/generateIcsString.test.ts
Expected Output:
✓ should mark team members as OPTIONAL when their email is in optionalGuestEmails
✓ should mark all attendees as OPTIONAL when all are in optionalGuestEmails
npx prisma studio
EventType modeloptionalTeamMemberGuests field exists (type: Int[])const icsString = generateIcsString({
event: mockEvent,
status: "CONFIRMED",
optionalGuestEmails: ["optional@example.com"],
});
// Verify output contains:
// PARTSTAT=OPTIONAL for optional@example.com
// PARTSTAT=ACCEPTED for other attendees
Input:
optionalGuestEmails = ["guest1@example.com"]
attendees = [
{ email: "guest1@example.com", name: "Guest 1" },
{ email: "guest2@example.com", name: "Guest 2" }
]
Output (ICS file):
ATTENDEE;PARTSTAT=OPTIONAL;...;EMAIL=guest1@example.com:...
ATTENDEE;PARTSTAT=ACCEPTED;...;EMAIL=guest2@example.com:...
This PR contains only backend changes to keep the PR small and focused per contributing guidelines. The frontend implementation will come in a follow-up PR with:
EventAdvancedTab.tsxComplete implementation guide is available in the branch at:
frontend_guide.md - Step-by-step frontend implementationwalkthrough.md - Full technical walkthroughbackend_changes_summary.md - Backend changes documentation✅ Fully backward compatible:
@default([]) so existing event types are unaffectedoptionalGuestEmails parameter is optional (defaults to [])Jessy LANGE
@jessy2027
Cal.com, Inc.
@cal