Skip to main content

Event Volunteers and Volunteer Groups

This guide explains how individual volunteers, volunteer groups, and memberships work for events in Talawa, including recurring series behavior.

Overview

Key Concepts

  • Two attachment scopes for recurring events:
    • Entire series (template): volunteer/group applies to every instance unless explicitly excluded for specific dates.
    • This instance only: volunteer/group exists only for one occurrence.
  • Per-instance removal uses "exceptions" rows rather than deleting the series record.

Data Model

Tables Overview

Tables in talawa-api (Drizzle ORM):

Event Volunteers Table

  • event_volunteers
    • One row per user volunteering for an event context.
    • Template volunteer (series-wide): eventId = base template event id, isTemplate = true, recurringEventInstanceId = null.
    • Instance-only volunteer: eventId = base template event id, isTemplate = false, recurringEventInstanceId = instance id.
    • Other fields: hasAccepted, isPublic, hoursVolunteered, creatorId, updaterId.
    • Unique(userId, eventId, recurringEventInstanceId) prevents duplicates across series vs one instance.

Event Volunteer Groups Table

  • event_volunteer_groups
    • Volunteer group definition for an event context.
    • Template group (series-wide): eventId = base template event id, isTemplate = true, recurringEventInstanceId = null.
    • Instance-only group: eventId = base template event id, isTemplate = false, recurringEventInstanceId = instance id.
    • Other fields: leaderId, name, description, volunteersRequired, creatorId, updaterId.
    • Unique(eventId, name, recurringEventInstanceId) prevents name collisions per instance.

Event Volunteer Memberships Table

  • event_volunteer_memberships
    • Connects an EventVolunteer to an optional EventVolunteerGroup for an event.
    • Fields: volunteerId, groupId (nullable for individual volunteers), eventId, status (invited/requested/accepted/rejected), audit fields.
    • Unique(volunteerId, groupId, eventId).
    • Note: in create requests, eventId is stored as provided (instance or template) to support admin requests UI; the volunteer row itself is linked to the base event id.

Exceptions Tables

  • event_volunteer_exceptions: unique(volunteerId, recurringEventInstanceId). Marks a template volunteer as "excluded" on a specific instance.
  • event_volunteer_group_exceptions: unique(volunteerGroupId, recurringEventInstanceId). Marks a template group as "excluded" on a specific instance.

Recurring Event Instances Table

  • recurring_event_instances
    • Materialized occurrences for recurring events; anchor for instance-only volunteers/groups and per-instance exceptions.

Concepts

Core Concepts

  • Event Volunteer: a user attached to an event series or a single occurrence.
  • Volunteer Group: a named group with a leader, optionally with a target number of volunteers required.
  • Volunteer Membership: the relationship (with status) between a volunteer and a group and/or event; supports invitations and requests.
  • Template (series-wide): applies automatically to every past/present/future instance unless excluded by an exception for a specific date.
  • Instance-only: exists only for a single occurrence.
  • Exception: per-instance exclusion record that hides a template volunteer/group from one occurrence.

Data Access

Instance Resolution

  • Determine baseEventId = instance.baseRecurringEventId (for recurring) or event.id (for standalone).
  • Volunteers for a recurring instance:
    • Query event_volunteers where eventId = baseEventId (template volunteers) OR recurringEventInstanceId = instance.id (instance-only volunteers).
    • Query event_volunteer_exceptions where recurringEventInstanceId = instance.id and exclude those volunteer IDs from the template set.
  • Volunteer groups for a recurring instance:
    • Query event_volunteer_groups where eventId = baseEventId (template groups) OR recurringEventInstanceId = instance.id (instance-only groups).
    • Query event_volunteer_group_exceptions where recurringEventInstanceId = instance.id and exclude those group IDs from the template set.
  • For standalone events, simply query by eventId = event.id and ignore exceptions/instances.

Operations

Creating and Updating

Volunteers

  • Create
    • createEventVolunteer supports a scope:
      • ENTIRE_SERIES → create or reuse a template volunteer (isTemplate=true, recurringEventInstanceId=null), converts/removes prior instance-only duplicates for the same user/event.
      • THIS_INSTANCE_ONLY → create an instance-only volunteer for recurringEventInstanceId.
  • Update
    • updateEventVolunteer updates fields such as hasAccepted, isPublic for the specific volunteer row (template or instance-only).
  • Delete
    • Entire row: deleteEventVolunteer removes the volunteer and cascades memberships.
    • For one instance of a template volunteer: deleteEventVolunteerForInstance upserts an exception row to exclude only that date; the template volunteer remains for all other dates.

Volunteer Groups

  • Create
    • createEventVolunteerGroup supports a scope:
      • ENTIRE_SERIES → create or reuse a template group (isTemplate=true), converts/removes prior instance-only duplicates with same name.
      • THIS_INSTANCE_ONLY → create an instance-only group for recurringEventInstanceId.
    • Optional volunteerUserIds allows inviting/creating volunteers and adding memberships to the new group, matching old API behavior.
  • Update
    • updateEventVolunteerGroup updates name/description/volunteersRequired; checks for name conflicts within the same event context.
  • Delete
    • Entire row: deleteEventVolunteerGroup removes the group and cascades its memberships.
    • For one instance of a template group: deleteEventVolunteerGroupForInstance upserts an exception row to exclude only that date; the template group remains for other dates.

Volunteer Memberships

  • Create
    • createVolunteerMembership creates a membership with status (invited/requested/accepted/rejected).
    • If no EventVolunteer exists yet for the user + base event, it creates one (template vs instance-only determined by scope and recurringEventInstanceId).
    • Stores eventId as provided (instance or template) to support admin review screens.
  • Update
    • updateVolunteerMembership updates the status. If accepted, the linked EventVolunteer.hasAccepted is synced appropriately.

Code References

  • Tables

    • eventVolunteers: src/drizzle/tables/eventVolunteers.ts
    • eventVolunteerGroups: src/drizzle/tables/eventVolunteerGroups.ts
    • eventVolunteerMemberships: src/drizzle/tables/eventVolunteerMemberships.ts
    • eventVolunteerExceptions: src/drizzle/tables/eventVolunteerExceptions.ts
    • eventVolunteerGroupExceptions: src/drizzle/tables/eventVolunteerGroupExceptions.ts
    • recurringEventInstances: src/drizzle/tables/recurringEventInstances.ts
  • Resolvers (read path)

    • Event.volunteers: src/graphql/types/Event/volunteers.ts
    • Event.volunteerGroups: src/graphql/types/Event/volunteerGroups.ts
  • Mutations (volunteers)

    • createEventVolunteer: src/graphql/types/Mutation/createEventVolunteer.ts
    • updateEventVolunteer: src/graphql/types/Mutation/updateEventVolunteer.ts
    • deleteEventVolunteer: src/graphql/types/Mutation/deleteEventVolunteer.ts
    • deleteEventVolunteerForInstance: src/graphql/types/Mutation/deleteEventVolunteerForInstance.ts
  • Mutations (volunteer groups)

    • createEventVolunteerGroup: src/graphql/types/Mutation/createEventVolunteerGroup.ts
    • updateEventVolunteerGroup: src/graphql/types/Mutation/updateEventVolunteerGroup.ts
    • deleteEventVolunteerGroup: src/graphql/types/Mutation/deleteEventVolunteerGroup.ts
    • deleteEventVolunteerGroupForInstance: src/graphql/types/Mutation/deleteEventVolunteerGroupForInstance.ts
  • Mutations (memberships)

    • createVolunteerMembership: src/graphql/types/Mutation/createVolunteerMembership.ts
    • updateVolunteerMembership: src/graphql/types/Mutation/updateVolunteerMembership.ts