Skip to content

Tags & Activities

Tags provide freeform labeling for contacts, while activities create an automatic timeline of every significant interaction. Both systems are foundation-scoped and integrate with segmentation.

Tags are foundation-scoped labels applied to contacts via a many-to-many pivot table (contact_tag).

FieldTypeDescription
idUUIDPrimary key
foundation_idUUIDOwning foundation
namestringTag label (e.g., “major-donor”, “board-member”, “2026-gala”)
colorstring?Optional hex color for UI display

Tags are attached to contacts through the contact_tag pivot table, which also stores foundation_id for scoping. The relationship supports syncWithoutDetaching for idempotent tag application:

// Apply tags to a contact
$contact->tags()->syncWithoutDetaching([
$tag->id => ['foundation_id' => $foundationId],
]);

The import workflow supports tags in two ways:

  1. CSV column — A tags column with comma-separated values (e.g., "donor,2026-gala")
  2. Global tags — Applied to all imported contacts via the options.tags array

Tags are auto-created if they don’t already exist in the foundation.

Tags are a first-class segmentation criterion. The tags criteria key filters contacts who have any of the specified tag names:

{
"tags": ["major-donor", "annual-gala"]
}
MethodPathDescription
GET/api/tagsList all tags for the foundation
POST/api/tagsCreate a new tag
DELETE/api/tags/{tag}Delete a tag

Activities are timeline events recorded against contacts for audit and segmentation. They are created automatically by Miranda’s services — you do not create them manually.

FieldTypeDescription
idUUIDPrimary key
foundation_idUUIDOwning foundation
contact_idUUIDThe contact this event belongs to
typeActivityTypeEvent category (see table below)
descriptionstring?Human-readable description
metadataJSON?Arbitrary context (IDs, amounts, etc.)
ValueDescriptionTriggered by
donatedContact made a donationDonationService::recordDonation()
email_sentEmail was sent to contactEmailService::send()
email_openedContact opened an emailWebhook tracking
sms_sentSMS was sent to contactSmsService::send()
application_submittedScholarship application submittedScholarshipService::createApplication()
scholarship_awardedScholarship award grantedScholarshipService::awardScholarship()
tag_addedTag was applied to contactTag management
note_addedNote was added to contactNote creation
importedContact was importedImportService::importBatch()

The ActivityService provides a single method for recording activities:

class ActivityService
{
public function log(
Contact $contact,
ActivityType $type,
?string $description = null,
?array $metadata = null,
): Activity;
}
// Donation activity
{
"donation_id": "uuid-here",
"amount": 5000,
"donation_page": "Annual Fund"
}
// Import activity
{
"source": "csv"
}
// Campaign email activity
{
"campaign_id": "uuid-here",
"sequence_step_id": null
}

Every contact’s activities() relationship provides a chronological timeline of all interactions. This powers the contact detail view in the admin dashboard, giving foundation staff a complete picture of each person’s engagement history.