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.

Domain Model

StatusUpdatedCovered Directories
🟢 Stable2026-03-19src/types, src/schemas, src/core/firestoreCollections.ts

Overview

GrantMaster’s domain is centred on the Organization (tenant). Every entity except global taxonomies and platform configurations belongs to exactly one organization via the TenantScoped base interface. The domain is organised into eleven aggregate groups, each with its own Firestore collection(s), owning feature/shared contract modules, and Zod validation schemas in src/schemas/.
TenantScoped
  └─ organizationId: string   (required on every write)
  └─ createdAt: Timestamp
  └─ updatedAt: Timestamp

Aggregate Groups

  1. Identity
  2. Grant Lifecycle
  3. Project Engine
  4. Finance
  5. Time Tracking
  6. Compliance
  7. Relations / CRM
  8. Documents
  9. People & HR
  10. Platform & Extensions
  11. Partnerships & Credits

1. Identity

Governs who can access the platform, under which tenant, and with what credentials. Firestore collections: organizations, employees, invitations, sessions, apiKeys, securityEvents
Naming gotcha: User documents are stored in the employees collection, not a users collection.

Organization

The root tenant. All multi-org relationships are handled at the platform layer — users belong to exactly one organization.
FieldTypeNotes
idstringFirestore document ID
namestringDisplay name
slugstringURL-safe identifier
subscriptionTierSubscriptionTierfree | starter | growth | enterprise
settingsOrganizationSettingsApp preferences, locale, branding
classificationTenantClassificationngo | charity | social_enterprise | ...
missionPillarsstring[]Tags used for mission-alignment scoring

User

Stored in the employees Firestore collection.
FieldTypeNotes
idstringFirebase Auth UID
emailstring
roleUserRoleadmin | manager | member | auditor | viewer
statusUserStatusactive | invited | suspended | deactivated
departmentstring
jobTitlestring
mfaEnabledboolean
referralCodestring | nullSet when user joins via referral

Invitation

Pending email invitations. Expire after 7 days.
FieldTypeNotes
emailstringInvitee
roleUserRoleIntended role
tokenstringSigned JWT, verified on accept
expiresAtTimestamp
status'pending' | 'accepted' | 'expired'

Session

Managed by SessionService. Concurrent session limits enforced per subscription tier.
FieldTypeNotes
userIdstring
deviceInfoDeviceInfoBrowser/OS fingerprint
lastActiveAtTimestampUsed for idle timeout
expiresAtTimestamp

2. Grant Lifecycle

A grant moves through five entity types as it progresses from discovery to close-out. Each type has its own Firestore collection. Firestore collections: grantOpportunities, grantPipeline, grantApplications, activeGrants, grantReports

GrantOpportunity

A potential funding source, either discovered via the GrantMaster discovery engine or entered manually.
FieldTypeNotes
titlestring
grantorstringFunder name
fundingRange{ min: number, max: number }
deadlineTimestamp
eligibilityCriteriastring[]
source'platform' | 'manual'
matchScorenumberAI-computed relevance 0–100

GrantPipelineEntry

An opportunity being actively pursued. Stored in grantPipeline.
FieldTypeNotes
opportunityIdstringFK → grantOpportunities
stagePipelineStageprospect | preparing | submitted | under_review | won | lost
probabilitynumber0–100
requestedAmountnumber
assignedTostring[]User IDs
notesstring

GrantApplication

Formal application document. Stored in grantApplications.
FieldTypeNotes
pipelineIdstringFK → grantPipeline
submittedAtTimestamp
narrativestringAI-assisted application text
attachmentsstring[]Storage URLs
status'draft' | 'submitted' | 'under_review' | 'awarded' | 'rejected'

ActiveGrant

A won grant. Tracks disbursements and reporting obligations.
FieldTypeNotes
applicationIdstringFK → grantApplications
awardedAmountnumber
currencystringISO 4217
disbursementScheduleDisbursement[]Tranche dates and amounts
reportingRequirementsReportingRequirement[]Deadlines and report types
projectIdsstring[]FK → projects — multiple allowed
status'active' | 'completed' | 'suspended'

GrantReport

Funder-facing report generated at a reporting milestone.
FieldTypeNotes
grantIdstringFK → activeGrants
period{ from: Timestamp, to: Timestamp }
contentstringReport body
status'draft' | 'submitted' | 'approved'
submittedAtTimestamp | null

3. Project Engine

Projects are the operational unit through which grant funds are spent and outcomes are tracked. Firestore collections: projects, budgetItems, milestones, tasks, deadlines

Project

FieldTypeNotes
namestring
statusProjectStatusplanning | active | on_hold | completed | archived
budgetnumberTotal project budget
currencystring
startDateTimestamp
endDateTimestamp
grantIdsstring[]FK → activeGrants
phaseProjectPhaseinitiation | planning | execution | monitoring | closure
missionPillarsstring[]Tags aligned to org mission
teamMemberIdsstring[]FK → employees
managerIdstringFK → employees
sectorTagsstring[]
templateIdstring | nullIf created from a template

BudgetItem (BudgetLine)

Line items within a project budget. Stored in budgetItems.
FieldTypeNotes
projectIdstringFK → projects
categoryBudgetCategoryOne of 6 standard categories (see Finance)
descriptionstring
allocatedAmountnumber
spentAmountnumberComputed / denormalized
grantIdstring | nullFunding source

Milestone

FieldTypeNotes
projectIdstringFK → projects
titlestring
dueDateTimestamp
status'pending' | 'in_progress' | 'completed'
completionPercentagenumber

Task

FieldTypeNotes
milestoneIdstringFK → milestones
projectIdstringDenormalized for query efficiency
titlestring
assigneeIdstringFK → employees
statusTaskStatustodo | in_progress | blocked | done
dueDateTimestamp
priority'low' | 'medium' | 'high' | 'urgent'

Deadline

Project-level external deadlines (reporting, funder meetings).
FieldTypeNotes
projectIdstringFK → projects
titlestring
dueDateTimestamp
type'reporting' | 'submission' | 'payment' | 'milestone'
completedboolean

4. Finance

Tracks all financial flows: expenses, allocations, invoices, and receipts. Firestore collections: expenses, invoices, receipts
Expense allocations are stored as a sub-array on the Expense document, not a separate collection.

Expense

FieldTypeNotes
amountnumber
currencystring
categoryExpenseCategory
descriptionstring
projectIdstringFK → projects
grantIdstring | nullFK → activeGrants
submittedBystringFK → employees
statusExpenseStatusdraft | pending | approved | rejected | paid
approvedBystring | nullFK → employees
allocationsExpenseAllocation[]Split across multiple grants
receiptUrlstring | nullFirebase Storage URL
xeroTransactionIdstring | nullSet after Xero push

ExpenseAllocation

Embedded in the Expense document. Allows a single expense to be split across multiple grants.
FieldTypeNotes
grantIdstringFK → activeGrants
amountnumberPortion allocated
percentagenumber0–100, must sum to 100 across all allocations

Invoice

FieldTypeNotes
projectIdstringFK → projects
vendorNamestring
amountnumber
currencystring
dueDateTimestamp
status'unpaid' | 'paid' | 'overdue'
attachmentUrlstring

BudgetCategory (enum)

Six standard categories used for both BudgetItem.category and Expense.category:
ValueDescription
PersonnelSalaries, benefits, HR costs
OperationsOffice, supplies, utilities
TravelTransport, accommodation, per diems
EquipmentHardware, software licences
ConsultancyExternal contractor fees
OverheadIndirect/admin cost allocation

5. Time Tracking

Staff time is tracked via JournalEntry records, grouped into monthly submissions for manager approval. Firestore collections: timesheets (JournalEntry), retrospectives (JournalSubmission)
Naming gotcha: The timesheets collection stores JournalEntry documents (not “timesheet” objects), and retrospectives stores JournalSubmission documents. These names reflect legacy collection naming; the UI calls them “journals.”

JournalEntry

Stored in the timesheets collection.
FieldTypeNotes
userIdstringFK → employees
projectIdstringFK → projects
datestringISO date YYYY-MM-DD
hoursnumber
descriptionstringActivity description
submissionIdstring | nullFK → retrospectives — set when submitted
grantIdstring | nullOptional: time directly attributed to a grant

JournalSubmission

Monthly summary submitted by a staff member for manager approval. Stored in the retrospectives collection.
FieldTypeNotes
userIdstringFK → employees — submitter
monthstringYYYY-MM
statusSubmissionStatusdraft | submitted | approved | rejected
totalHoursnumberDenormalized sum
approvedBystring | nullFK → employees
approvedAtTimestamp | null
rejectionReasonstring | nullSet on rejection
entryIdsstring[]FKs → timesheets

6. Compliance

Rule-based compliance monitoring across the organization, with audit logging of every significant action. Firestore collections: compliance, auditLogs

ComplianceRule

FieldTypeNotes
namestring
descriptionstring
domainComplianceDomainfinancial | operational | legal | ...
checkType'threshold' | 'deadline' | 'document' | 'approval'
thresholdnumber | nullFor numeric checks
severity'low' | 'medium' | 'high' | 'critical'
enabledboolean

ComplianceAlert

Generated when a rule’s check condition is met.
FieldTypeNotes
ruleIdstringFK → compliance rules
entityTypestringThe domain entity that triggered
entityIdstringFK into that entity’s collection
status'open' | 'acknowledged' | 'resolved'
assignedTostring | nullFK → employees
resolvedAtTimestamp | null

AuditLog

Append-only log of every significant action. Written by shared/audit/auditLogDataAccess.
FieldTypeNotes
actionAuditActionEnum of 80+ action constants
userIdstringActor
resourceTypestringEntity type
resourceIdstringEntity ID
organizationIdstring
metadataRecord<string, unknown>Before/after diffs, extensionId
ipAddressstring | null
timestampTimestamp

7. Relations / CRM

Tracks relationships with funders, donors, and external partners. Firestore collections: foundations, contacts, grantorRelationships, reportingCalendar

Foundation

Shared library of grant-making organizations. Shared across the platform (not strictly tenant-scoped — orgs can reference the same Foundation).
FieldTypeNotes
namestring
websitestring
type'foundation' | 'government' | 'corporate' | 'bilateral'
focusAreasstring[]
geographicFocusstring[]
totalGrantsValuenumberAggregated across all orgs

Contact

Individual stakeholder at a Foundation or external partner.
FieldTypeNotes
foundationIdstring | nullFK → foundations
firstNamestring
lastNamestring
emailstring
rolestringJob title at their org
segmentsstring[]Segment IDs
hubspotContactIdstring | nullSet after HubSpot sync

Interaction

Log entry for a meeting, call, or email with a contact.
FieldTypeNotes
contactIdstringFK → contacts
type'meeting' | 'call' | 'email' | 'event'
dateTimestamp
summarystring
followUpDateTimestamp | null
userIdstringFK → employees — who logged it

ContactSegment

Dynamic grouping of contacts by criteria. Evaluations run on a schedule via segmentService.
FieldTypeNotes
namestring
criteriaSegmentCriteria[]Filter rules
memberCountnumberDenormalized
lastEvaluatedAtTimestamp

GrantorRelationship

Per-org engagement tracking for a specific Foundation.
FieldTypeNotes
foundationIdstringFK → foundations
engagementScorenumber0–100, computed by calculateEngagementScore()
engagementLevel'low' | 'medium' | 'high' | 'champion'Derived from score
notesstring
deadlinesGrantorDeadline[]Embedded reporting/meeting deadlines

8. Documents

Document storage with AI-powered search via a RAG (Retrieval-Augmented Generation) pipeline. Firestore collections: documents, documentFolders
Document chunks for RAG are stored in a separate vector index, not directly in Firestore.

DocumentFolder

FieldTypeNotes
namestring
parentIdstring | nullSelf-reference for nesting
pathstring[]Ancestor folder IDs (for breadcrumbs)

Document

FieldTypeNotes
folderIdstring | nullFK → documentFolders
namestringDisplay name
storageUrlstringFirebase Storage path
mimeTypestring
sizeBytesnumber
uploadedBystringFK → employees
status'processing' | 'indexed' | 'failed'RAG indexing state
tagsstring[]
projectIdstring | nullFK → projects if scoped
grantIdstring | nullFK → activeGrants if scoped

DocumentChunk

Produced by the RAG pipeline. Stored in the vector store, not Firestore.
FieldTypeNotes
documentIdstringFK → documents
chunkIndexnumberPosition in document
contentstringText segment
embeddingnumber[]Vector embedding
citationSourceCitationSourcePage number, section heading

AIQueryLog

Logs all Document Brain AI queries for audit and quality improvement.
FieldTypeNotes
userIdstringFK → employees
querystringUser’s natural-language question
retrievedChunkIdsstring[]
responsestringGenerated answer
feedback'positive' | 'negative' | nullThumbs feedback

9. People & HR

Extends the User entity with HR-specific data: time-off requests and security events. Firestore collections: employees (extended User), timeOffRequests, securityEvents

TimeOffRequest

FieldTypeNotes
userIdstringFK → employees
typeLeaveTypeannual | sick | parental | unpaid | ...
startDatestringISO date
endDatestringISO date
totalDaysnumber
status'pending' | 'approved' | 'rejected'
approvedBystring | nullFK → employees
notesstring

SecurityEvent

Immutable log of authentication and key events. Written by securityMonitoringService.
FieldTypeNotes
userIdstringFK → employees
typeSecurityEventTypelogin | logout | failed_login | mfa_enrolled | password_changed | ...
ipAddressstring
userAgentstring
successboolean
metadataRecord<string, unknown>Additional context

ApiKey

Scoped API keys for external integrations. Secrets stored as SHA-256 hashes.
FieldTypeNotes
userIdstringOwner
namestringLabel
keyHashstringSHA-256 of the raw secret
prefixstringFirst 8 chars, shown in UI
scopesApiKeyScope[]Permissions granted
expiresAtTimestamp | null
lastUsedAtTimestamp | null
revokedAtTimestamp | null

10. Platform & Extensions

The extension/module system that allows feature packs to be installed per-organization. Firestore collections: organizations/{id}/moduleInstallations, widgetDefinitions, widgetAssignments

ModuleInstallation

Runtime state of an installed extension module.
FieldTypeNotes
moduleIdstringMatches manifest id
versionstringInstalled semver
status'installing' | 'active' | 'error' | 'deactivated'
installedBystringFK → employees
installedAtTimestamp
configRecord<string, unknown>Module-specific settings

WidgetDefinition

Registered dashboard widget contributed by an extension.
FieldTypeNotes
extensionIdstringSource extension
widgetIdstringNamespaced: {extensionId}_{id}
namestringDisplay name
componentstringLazy-load identifier
defaultSize'sm' | 'md' | 'lg' | 'xl'
allowedRolesstring[]

WidgetAssignment

A specific widget placed on a specific user’s dashboard.
FieldTypeNotes
userIdstringFK → employees
widgetIdstringFK → widgetDefinitions
position{ row: number, col: number }
size'sm' | 'md' | 'lg' | 'xl'May differ from default

11. Partnerships & Credits

The partner/reseller programme and the mission-credit wallet system. Firestore collections: partnerOrganizations, partnerInvitations, referrals, missionCredits, creditTransactions, subscriptions

PartnerOrganization

A reseller or implementation partner.
FieldTypeNotes
namestring
contactEmailstring
revenueShareRatenumber0.10–0.20 (10–20%)
status'active' | 'suspended' | 'pending'
referralCodestringFormat: PARTNER_{PREFIX}_{RANDOM}

Referral

Created when a referred user converts to a paying customer.
FieldTypeNotes
referredOrganizationIdstringFK → organizations
referringPartnerIdstringFK → partnerOrganizations
referralCodestringCode used at signup
convertedAtTimestamp
creditAwardednumberDefault: €100

MissionCredit

Wallet balance for an organization. One document per org.
FieldTypeNotes
balancenumberCurrent balance in credits
lifetimeEarnednumber
lifetimeSpentnumber
lastUpdatedAtTimestamp

CreditTransaction

Ledger entries for the credit wallet.
FieldTypeNotes
amountnumberPositive = credit, negative = debit
type'referral_award' | 'subscription_discount' | 'manual_adjustment'
descriptionstring
referenceIdstring | nullFK to the triggering entity

Subscription

Stripe subscription linked to an org.
FieldTypeNotes
stripeSubscriptionIdstring
tierSubscriptionTier
status'active' | 'past_due' | 'canceled' | 'trialing'
currentPeriodEndTimestamp
seatsnumberLicensed user count

Cross-Aggregate Relationship Map


Firestore Collection → Entity Reference

CollectionEntityNotes
organizationsOrganization
employeesUserNot users — legacy naming
invitationsInvitation
sessionsSession
grantOpportunitiesGrantOpportunity
grantPipelineGrantPipelineEntry
grantApplicationsGrantApplication
activeGrantsActiveGrant
grantReportsGrantReport
projectsProject
budgetItemsBudgetItem
milestonesMilestone
tasksTask
timesheetsJournalEntryNot journals or journalEntries
retrospectivesJournalSubmissionNot journalSubmissions
expensesExpenseAllocations embedded as array
invoicesInvoice
complianceComplianceRule + ComplianceAlertSingle collection, discriminated by type
auditLogsAuditLogAppend-only
foundationsFoundation
contactsContact
documentsDocument
documentFoldersDocumentFolder
partnerOrganizationsPartnerOrganization
referralsReferral
missionCreditsMissionCreditOne per org
creditTransactionsCreditTransaction
subscriptionsSubscription
organizations/{id}/moduleInstallations/{moduleId}ModuleInstallationSubcollection

Multi-Tenancy Rules

  1. Strict Isolation — No entity can belong to more than one Organization.
  2. Scoping — All Firestore queries must include an organizationId filter.
  3. Exceptionsfoundations is a shared library readable by all orgs; write access is platform-admin only.
  4. Cross-Tenant References — Prohibited at both the Service and Firestore Security Rules layers.
  5. BaseService enforcementorganizationId is validated in BaseService.create() and BaseService.update() via the Zod schema layer before any Firestore write.

Maintenance

Update this model when:
  • Introducing a new high-level module (e.g., Inventory, Payroll).
  • Changing the ownership structure (e.g., multi-organization users).
  • Adding or renaming a Firestore collection (update the reference table above).
  • A new “naming gotcha” is discovered — document it in the collection reference table.
For collection-level query patterns and denormalization decisions, see docs/engineering/data/collection-relationships.md. For state machine diagrams covering entity lifecycles, see state-machines.md.