Overview
Understanding how the four core domains connect is essential for working effectively in the platform.
The Four Domains
| Domain | Purpose | Key Entities |
|---|---|---|
| Accounts | Multi-tenancy, users, auth | Account, User, Session |
| Organisations | Suppliers, transactions | Organisation, Transaction, Product |
| Footprints | ESG impact calculations | Impact, Intensity, Risk |
| Engagements | Compliance assessments | Engagement, 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:
| Domain | Owns | Uses (Read-Only) |
|---|---|---|
| Accounts | Account, User, Session | - |
| Organisations | Organisation, Transaction, Product | Account |
| Footprints | (Calculates, doesn't own) | Transaction, Organisation |
| Engagements | Engagement, Framework, Test | Organisation, 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
- Accounts - Multi-tenancy and authentication
- Organisations - Suppliers and transactions
- Footprints - Impact calculations
- Engagements - Compliance assessments