Fair Supply LogoFair Supply - Docs

Overview

Understanding how the four core domains connect is essential for working effectively in the platform.

The Four Domains

DomainPurposeKey Entities
AccountsMulti-tenancy, users, authAccount, User, Session
OrganisationsSuppliers, transactionsOrganisation, Transaction, Product
FootprintsESG impact calculationsImpact, Intensity, Risk
EngagementsCompliance assessmentsEngagement, Framework, Test

How Domains Connect

Data Flow: End-to-End

A typical user journey touches all four domains:

1. Account Setup (Accounts Domain)

  • Admin creates an Account (tenant)
  • Users are invited and assigned roles
  • Session tracks which account is active

2. Supply Chain Data (Organisations Domain)

  • Transactions uploaded (spend/revenue with suppliers)
  • Organisations created or matched from Diffbot
  • Products and industries (Aquila1) assigned

3. Impact Calculation (Footprints Domain)

  • ClickHouse calculates impacts from transaction data
  • Requires: country, industry (Aquila1), amount (USD)
  • Outputs: modern slavery risk, emissions, biodiversity metrics

4. Supplier Assessment (Engagements Domain)

  • Engagements created for high-risk suppliers
  • Respondents answer framework tests
  • Scores calculate compliance levels

Entity Relationships

Account as Root

All data is scoped to an Account. This is the multi-tenancy boundary:

Organisation as Hub

Organisations are the central entity that other domains connect through:


Technical Details

Cross-Domain Queries

When querying across domains, always start from the Account scope:

// Get transactions for an organisation within current account
const transactions = await TransactionRepository.findByOrganisation({
  organisationId: 'org-123',
  accountId: session.selectedAccountId, // Always scope to account
});

Domain Boundaries

Each domain has clear responsibilities:

DomainOwnsUses (Read-Only)
AccountsAccount, User, Session-
OrganisationsOrganisation, Transaction, ProductAccount
Footprints(Calculates, doesn't own)Transaction, Organisation
EngagementsEngagement, Framework, TestOrganisation, User

Key GraphQL Types

# Accounts
type Account {
  id: ID!
  name: String!
  users: [User!]!
  transactions: [Transaction!]!
}

# Organisations
type Organisation {
  id: ID!
  name: String!
  identifiers: [Identifier!]!
  aquila1: [Aquila1!]!
}

type Transaction {
  id: ID!
  amount: Float!
  currency: String!
  organisation: Organisation!
}

# Engagements
type Engagement {
  id: ID!
  organisation: Organisation!
  frameworks: [Framework!]!
  respondents: [User!]!
}

Common Patterns

Fetching related data across domains:

// In a use case, coordinate across repositories
export class GetOrganisationWithFootprint implements UseCase<Input, Output> {
  async execute({ organisationId }: Input): Promise<Output> {
    const [organisation, footprint, engagements] = await Promise.all([
      OrganisationRepository.findById(organisationId),
      new CalculateOrganisationFootprint().execute({ organisationId }),
      EngagementRepository.findByOrganisation(organisationId),
    ]);

    return { organisation, footprint, engagements };
  }
}

Scoping all queries to current account:

// Session provides account context
const session = await getSession();
const accountId = session.selectedAccountId;

// All repositories accept accountId for scoping
const transactions = await TransactionRepository.findAll({ accountId });

Next Steps