Skip to main content

Documentation Index

Fetch the complete documentation index at: https://grantmaster.dev/llms.txt

Use this file to discover all available pages before exploring further.

Engineering reference: For service contracts, EventBus events, and data-layer details see src/features/grantors/grantors.md.

Grantors Feature

Comprehensive Funder Relationship Management (FRM) system for managing grantor (donor/funding agency) relationships, interactions, deadlines, compliance, and analytics.

Overview

The Grantors feature provides tools for nonprofits to:
  • Manage Funder Relationships: Track and organize all grantor/donor information in a CRM-style system
  • Log Interactions: Record touchpoints (emails, calls, meetings, site visits, proposals, reports) with funders
  • Track Reporting Deadlines: Auto-generate deadlines from grantor requirements and monitor compliance
  • Portfolio Analytics: View performance metrics across all funders (win rate, funding, diversification)
  • Compliance Matrix: Identify conflicting requirements across multiple funders on shared projects
  • Stakeholder Portal: Token-authenticated external portal for funders to view project progress
Core Data Source: Grantors are stored as TaxonomyItem records in the foundations Firestore collection, with bidirectional links to contacts and projects.

Page Organization

Route: /grantors/:tab — 5 tabs:
TabValueDescription
OverviewoverviewPortfolio-level KPIs, relationship health summary, and operational insights
DirectorydirectorySearchable grantor list with CRUD, detail sheets, and editor modals
AnalyticsanalyticsPerformance charts, concentration risk, funding diversification
ReportingreportingReporting obligations calendar and compliance tracking
CompliancecomplianceCompliance matrix for cross-funder requirement comparison
The page uses modular data computation via buildGrantorModuleData() which assembles relationships, compliance tracking, and reporting obligations from multiple data sources. Relationship health is classified as Strong, Stable, At Risk, or Dormant.
Note: The legacy tabs Relationships and Stakeholders were retired and consolidated into the remaining 5 tabs.

Key Features

1. Interaction Tracking (CRM)

  • Log all funder interactions: emails, calls, meetings, site visits, events, proposals, reports
  • Track sentiment (positive/neutral/negative), participants, duration, follow-ups
  • Filter by interaction type, date range, sentiment, or funder
  • Pending follow-up reminders and completion tracking
  • Auto-update grantor’s lastInteractionDate

2. Reporting Deadlines & Calendar

  • Manually create deadlines with due dates, assignees, and notes
  • Auto-generate deadlines from TaxonomyItem.reportingSchedule (frequency + offset days)
  • Recurring deadline support (monthly, quarterly, semi-annual, annual)
  • Deadline status tracking: upcoming → due-soon → overdue → completed
  • Calendar view grouped by month with statistics
  • Reminder tracking (30, 14, 7, 1 day reminders)

3. Engagement Scoring

  • Automated engagement score (0–100) based on:
    • Interaction recency (30% weight)
    • Communication frequency in last 90 days (30%)
    • Project success rate (20%)
    • Renewal rate (20%)
  • Engagement levels: hot (75+), active (50–74), at-risk (25–49), cold (<25)
  • Stored on grantor record as engagementScore: { score, level, lastCalculated, factors }

4. Portfolio Analytics

Portfolio-level metrics (GrantorPortfolioAnalytics):
  • Total grantors, active grantors, active funding value
  • Year-over-year growth, diversification score
  • Funding breakdown by grantor type
  • Win rate, average grant size, grant duration, overhead recovery rate
  • Engagement distribution (hot/active/at-risk/cold)
  • Concentration risk (Herfindahl-Hirschman Index + top grantor analysis)
  • Funding pipeline value and performance
Grantor-level metrics (GrantorAnalytics):
  • Funding awarded (total, active, completed), average & largest grant
  • Project metrics (total, active, completed, success rate)
  • Application metrics (total applications, win rate, time-to-decision)
  • Relationship duration and renewal rate
  • Interaction frequency and recency
  • Reporting compliance rate and overdue reports

5. Grantor-Contact Linking

  • Link contacts (staff, board) to grantors with roles: 'program-officer' | 'executive-director' | 'board-member' | 'grant-administrator' | 'other'
  • Mark primary contact for each grantor
  • Bidirectional navigation: grantor → contacts, contact → grantors
  • Stored as contacts[] array on TaxonomyItem

6. Compliance Matrix

  • Track compliance rules by category: time-tracking, cost-eligibility, reporting, procurement, documentation, audit
  • Compare requirements across grantors on shared projects
  • Detect conflicts (e.g., Funder A allows X, Funder B disallows X)
  • View compliance status per grantor-rule pair: applicable/not-applicable/conflict
  • Export compliance matrix for audit trails

7. Grantor Portal

  • External token-authenticated portal for stakeholders (funders, auditors, partners) to view project progress
  • Separate Vite app at portal/ served on impact.grantmaster.ai
  • Portal access managed via GrantorPortalTab in main app
  • Token-based auth with expiration and revocation
  • 12 visibility flags control what stakeholders see (budget, timeline, team, compliance, impact metrics)
  • Stakeholders can submit documents, acknowledge reports, send messages

Data Model

Core Collections

CollectionPrimary KeyPurpose
foundationsidGrantors/donors (TaxonomyItem with extensions)
grantorInteractionsidCRM-style touchpoints with funders
reportingDeadlinesidFunder reporting requirements & deadlines
contactsidFunder contacts (shared with other features)
portalTokensidAccess tokens for external stakeholder portal

Grantor (TaxonomyItem) Extensions

// On foundations/{id}
{
  // Existing fields (label, grantorType, logoUrl, etc.)

  // Grantors feature adds:
  contacts?: GrantorContactLink[];           // Links to contact records
  engagementScore?: EngagementScore;         // { score, level, factors, lastCalculated }
  lastInteractionDate?: string;              // ISO date of most recent interaction
  reportingSchedule?: {                      // Auto-deadline config
    frequency: 'Monthly' | 'Quarterly' | 'Semi-Annually' | 'Annually';
    deadlineOffsetDays: number;              // Days after period start
  };
  complianceRules?: ComplianceRule[];        // Rules specific to this grantor
}

Key Types

GrantorInteraction
{
  id: string;
  organizationId: string;
  grantorId: string;
  grantorName: string;
  type: InteractionType;              // 'email', 'call', 'meeting', etc.
  direction: 'inbound' | 'outbound';
  subject: string;
  summary: string;
  sentiment?: 'positive' | 'neutral' | 'negative';
  participants: { type, id, name, role }[];
  date: string;                       // ISO date
  duration?: number;                  // Minutes (calls/meetings)
  followUpDate?: string;
  followUpCompleted?: boolean;
  linkedProjectId?: string;
  createdBy: string;
  createdAt: string;
}
ReportingDeadline
{
  id: string;
  organizationId: string;
  grantorId: string;
  grantorName: string;
  title: string;
  type: ReportingDeadlineType;        // 'progress-report', 'financial-report', etc.
  dueDate: string;                    // ISO date
  status: ReportingDeadlineStatus;    // 'upcoming', 'due-soon', 'overdue', 'completed'
  assigneeId?: string;
  assigneeName?: string;
  isRecurring: boolean;
  recurrenceRule?: {
    frequency: 'monthly' | 'quarterly' | 'semi-annually' | 'annually';
    basedOnProjectStart?: boolean;
    basedOnProjectEnd?: boolean;
  };
  completedAt?: string;
  completedBy?: string;
  remindersSent: { thirtyDays?, fourteenDays?, sevenDays?, oneDay? };
  source: 'manual' | 'auto-generated' | 'imported';
  createdBy: string;
  createdAt: string;
}

Service Contract

GrantorRelationshipService

Interaction Management
  • fetchInteractions(organizationId: string) — All interactions
  • fetchInteractionsByGrantor(organizationId, grantorId) — Filter to grantor
  • createInteraction(input) — Log new interaction, auto-update grantor’s lastInteractionDate
  • updateInteraction(id, updates) — Update interaction details
  • deleteInteraction(id) — Remove interaction
  • fetchPendingFollowUps(organizationId) — Interactions with uncompleted follow-ups
  • completeFollowUp(id, notes?) — Mark follow-up as done
Contact Linking
  • linkContact(grantorId, contactId, role, isPrimary) — Create grantor-contact link
  • unlinkContact(grantorId, contactId) — Remove link
  • updateContactRole(grantorId, contactId, role, isPrimary?) — Change role/primary status
Engagement Scoring
  • calculateEngagementScore(organizationId, grantorId) — Compute score (0–100) and level (hot/active/at-risk/cold), store on grantor

ReportingCalendarService

Deadline Management
  • fetchDeadlines(organizationId) — All deadlines with status recalculation
  • fetchUpcomingDeadlines(organizationId) — Not completed
  • fetchOverdueDeadlines(organizationId) — Past due date
  • createDeadline(input) — Manually create deadline
  • updateDeadline(id, updates) — Modify deadline
  • completeDeadline(id, completedBy) — Mark completed
  • deleteDeadline(id) — Remove deadline
Auto-Generation
  • generateDeadlinesFromSchedule(organizationId, grantor, project?, createdBy) — Auto-create recurring deadlines from grantor.reportingSchedule for a project date range
Calendar Views
  • getCalendarView(organizationId, startMonth, endMonth) — Group deadlines by month with stats (upcoming, due-soon, overdue, completed)

GrantorAnalyticsService

Portfolio Analytics
  • calculatePortfolioAnalytics(organizationId) — Aggregate metrics across all grantors and projects
Grantor Analytics
  • calculateGrantorAnalytics(organizationId, grantorId) — Relationship metrics for single grantor
Note: Analytics are calculated on-demand from current data (projects, interactions, deadlines, pipeline). They are not real-time subscriptions.

Events (Emitted/Consumed)

EventBus Rule Compliance

The grantors feature does not currently emit EventBus events for the following operations:
  • createInteraction — Should emit event when interaction is logged
  • completeFollowUp — Should emit event when follow-up is completed
  • createDeadline — Should emit event when deadline is created
  • completeDeadline — Should emit event when deadline is completed (especially for overdue tracking)
  • calculateEngagementScore — Should emit event when engagement level changes (risk escalation)
Recommended Events (to implement per EventBus rule):
  • GRANTOR_INTERACTION_LOGGED — New CRM touchpoint recorded
  • GRANTOR_FOLLOW_UP_COMPLETED — Follow-up task completed
  • REPORTING_DEADLINE_CREATED — New deadline set
  • REPORTING_DEADLINE_OVERDUE — Deadline passed due date (compliance alert)
  • GRANTOR_ENGAGEMENT_LEVEL_CHANGED — Engagement level changed (e.g., active → at-risk)

Events Consumed

The grantors feature does not subscribe to any EventBus events. It is read-only from projects/contacts/foundations data.

Dependencies

Internal Features

  • projectsProject data, funding source links, project phase tracking
  • relationsContact records for grantor-contact linking
  • organizationsTaxonomyItem type, grantor taxonomy

External Libraries

  • Firebase — Firestore collections, queries, batch operations
  • React Query — Server state caching (via hooks using services)
  • React Context — Organization/tenant context (useCurrentTenant)
  • Toast notifications — User feedback on CRUD operations
  • Recharts (in components) — Data visualization for analytics

Core Services

  • BaseService — Inheritance for service pattern, validation, logging
  • EventBus — Available but not currently emitting events
  • Logger — Operation tracking and error logging

File Structure

src/features/grantors/
├── services/                           # Core business logic
│   ├── GrantorAnalyticsService.ts      # Portfolio & grantor analytics
│   ├── GrantorRelationshipService.ts   # Interactions, contacts, engagement
│   └── ReportingCalendarService.ts     # Deadlines & calendar

├── hooks/                              # React state management
│   ├── useGrantorInteractions.ts       # Interaction CRUD + filters
│   ├── useReportingDeadlines.ts        # Deadline CRUD + calendar views
│   ├── useGrantorAnalytics.ts          # Portfolio/grantor analytics fetching
│   ├── useOrgPortal.ts                 # Portal token management
│   └── useGrantorInteractions.ts       # Pending follow-ups, etc.

├── components/
│   ├── pages/                          # Page-level components
│   │   ├── Grantors.tsx                # Main grantors page entry
│   │   ├── GrantorsPageContent.tsx     # Page layout
│   │   └── grantors-page/
│   │       ├── GrantorDirectoryTab.tsx # Grantor list & CRUD
│   │       ├── GrantorOverviewTab.tsx  # Portfolio overview
│   │       ├── GrantorAnalyticsTab.tsx # Performance charts
│   │       ├── GrantorGovernanceTabs.tsx # Compliance matrix
│   │       ├── GrantorOperationsTabs.tsx # Interactions, deadlines
│   │       └── PortfolioOverviewTabs.tsx # Summary dashboard
│   │
│   ├── GrantorAnalyticsTab.tsx         # Analytics component
│   ├── RelationshipsTab.tsx            # Interactions & contacts
│   ├── ReportingCalendarTab.tsx        # Deadlines & calendar
│   ├── ComplianceMatrixTab.tsx         # Compliance rules & conflicts
│   │
│   ├── portal/                         # Stakeholder portal UI
│   │   ├── GrantorPortalTab.tsx        # Portal management (create token, etc.)
│   │   ├── CreateTokenModal.tsx
│   │   ├── RevokeTokenModal.tsx
│   │   ├── SubmissionsSection.tsx
│   │   ├── MessagesSection.tsx
│   │   ├── AnalyticsSection.tsx
│   │   └── AccessLinksSection.tsx
│   │
│   ├── compliance-matrix/              # Compliance-specific components
│   │   ├── ComplianceMatrixTable.tsx
│   │   ├── ComplianceFiltersBar.tsx
│   │   ├── ComplianceMatrixLegend.tsx
│   │   ├── RuleDetailModal.tsx
│   │   ├── GrantorComplianceCards.tsx
│   │   └── ComplianceStatsGrid.tsx
│   │
│   ├── GrantorStatsWidget.tsx          # Small KPI display
│   └── pages/grantors-page/
│       └── ui.tsx                      # Shared UI utilities

├── types/
│   └── complianceMatrix.types.ts       # Compliance-specific types

├── lib/
│   └── complianceMatrix.ts             # Compliance matrix logic (filtering, conflict detection)

├── constants/
│   └── complianceMatrixDefaults.ts     # Compliance categories, colors

├── hooks/
│   ├── useComplianceMatrixDerivedData.ts # Derived state for matrix
│   └── useComplianceMatrixExport.ts     # Export to CSV/Excel

├── tests/
│   ├── complianceMatrix.logic.test.ts
│   ├── GrantorComplianceCards.test.tsx
│   └── factories/complianceMatrixFactory.ts

├── index.ts                            # Public API barrel export
├── public.ts                           # Alternative public API
└── README.md                           # This file

Usage Examples

Logging an Interaction

import { useGrantorInteractions } from '@/features/grantors';

export function InteractionForm({ grantorId, grantorName }) {
  const { createInteraction } = useGrantorInteractions();

  const handleSubmit = async (data) => {
    const interactionId = await createInteraction({
      grantorId,
      grantorName,
      type: 'call',
      direction: 'inbound',
      subject: 'Q2 Funding Discussion',
      summary: 'Discussed upcoming grant cycle...',
      sentiment: 'positive',
      participants: [{ type: 'contact', id: 'jane-123', name: 'Jane Doe', role: 'Program Officer' }],
      date: new Date().toISOString(),
      duration: 30,
      createdBy: currentUserId,
      createdByName: currentUserName,
    });
  };
}

Creating a Deadline

import { useReportingDeadlines } from '@/features/grantors';

export function DeadlineForm({ grantorId, grantorName }) {
  const { createDeadline } = useReportingDeadlines();

  const handleSubmit = async (data) => {
    await createDeadline({
      grantorId,
      grantorName,
      title: 'Q2 Progress Report',
      type: 'progress-report',
      dueDate: '2026-06-30',
      assigneeId: 'user-456',
      assigneeName: 'Alice Smith',
      createdBy: currentUserId,
    });
  };
}

Calculating Engagement Score

import { grantorRelationshipService } from '@/features/grantors';

const score = await grantorRelationshipService.calculateEngagementScore(
  organizationId,
  grantorId
);
console.log(`Engagement: ${score.level} (${score.score}/100)`);

Fetching Portfolio Analytics

import { useGrantorAnalytics } from '@/features/grantors';

export function PortfolioOverview() {
  const { portfolioAnalytics, loading } = useGrantorAnalytics();

  return (
    <div>
      <p>Total Funding: ${portfolioAnalytics?.totalFundingReceived}</p>
      <p>Win Rate: {portfolioAnalytics?.overallWinRate.toFixed(1)}%</p>
      <p>Diversification: {portfolioAnalytics?.diversificationScore}/100</p>
    </div>
  );
}

Testing

  • Unit Tests (tests/*.test.ts) — Compliance matrix logic, compliance detection
  • Component Tests (tests/*.test.tsx) — Grantor cards, matrix table rendering
  • Factories (tests/factories/) — Test data generation
Run tests:
npm run test -- grantors

Key Behaviors

  1. Interaction RecencylastInteractionDate on grantor is auto-updated when any interaction is created
  2. Status Recalculation — Deadline status (upcoming/due-soon/overdue) is computed on each fetch based on current date
  3. Engagement Decay — Engagement score decreases with interaction recency (−2 points per day without contact)
  4. Conflict Detection — Compliance conflicts are identified when multiple grantors on a project have conflicting rules (e.g., Funder A allows cost, Funder B disallows)
  5. Auto-Generation — Deadlines are generated from reportingSchedule for the full project date range on deadline creation
  6. Portal Token Validation — Tokens are checked for isActive === true and expiresAt > now before granting portal access

Known Limitations

  • Analytics are calculated on-demand (not real-time subscribed)
  • No EventBus events currently emitted for compliance/deadline changes (should be added per EventBus rule)
  • Compliance matrix requires manual rule definition; no auto-extraction from grant agreements
  • Portal is a separate Vite app requiring separate deployment