Engagements Domain
The Engagements domain handles ESG assessment workflows, where organisations are evaluated against compliance frameworks.
Entity Hierarchy
Key Concepts
| Entity | Description |
|---|---|
| Engagement | Assessment request sent to an organisation. Has respondents who answer. |
| Framework | ESG framework structure (e.g., Modern Slavery Act). Contains pillars. |
| Pillar | Category within framework (e.g., Governance, Due Diligence). Contains controls. |
| Control | Specific requirement to verify. Tested by one or more tests. |
| Test | Question with multiple-choice options. May require evidence. |
| TestResponse | User's answer to a test, linking selected options. |
Scoring System
Scores roll up hierarchically from individual test responses to the overall engagement score:
| Level | Calculation |
|---|---|
| Test Score | Based on selected option values |
| Control Score | Average of its test scores |
| Pillar Score | Average of its control scores |
| Framework Score | Average of its pillar scores |
| Engagement Score | Average of all framework scores |
Domain services for scoring live in packages/core/src/domain/services/scoring/.
Business Rules
- Only invited respondents can answer tests
- At least one framework required per engagement
- Submitted responses cannot be modified (finality)
- Scores are only calculated after submission
- Engagements can have optional due dates
- Test options have associated score values
Common Operations
Creating an Engagement
The CreateEngagement use case demonstrates the platform's transaction support pattern. All database operations are wrapped in a single transaction to ensure atomicity.
import { CreateEngagement } from '@repo/core';
const useCase = new CreateEngagement();
const engagement = await useCase.execute({
organisationId: 'org-123',
frameworkIds: ['framework-1', 'framework-2'],
respondentIds: ['user-1', 'user-2'],
dueDate: new Date('2025-03-01'),
});Transaction Flow:
- Validation phase (outside transaction - reads only)
- Transactional operations (all database writes within
withTransaction) - Side effects (emails sent after transaction commits)
Submitting a Test Response
import { SubmitTestResponse } from '@repo/core';
const useCase = new SubmitTestResponse();
await useCase.execute({
testId: 'test-123',
selectedOptionIds: ['option-1'],
evidenceUrls: ['https://example.com/evidence.pdf'],
});Transaction Support
The Engagements domain uses the platform's transaction support for atomic multi-step operations. This ensures data consistency when creating engagements with multiple respondents.
Using Transactions
import { withTransaction } from '@repo/core';
import { EngagementRepository, UserRepository } from '@repo/core';
const result = await withTransaction(async (tx) => {
// All operations share the same transaction
const engagement = await EngagementRepository.create({
status: EngagementStatus.NotStarted,
accountId,
organisationId,
}, { tx });
await EngagementRepository.addRespondent({
engagementId: engagement.id,
userId: respondent.id,
status: RespondentStatus.Pending,
}, { tx });
return engagement;
});Transaction Guidelines
| Guideline | Description |
|---|---|
| Validation first | Perform read operations outside the transaction |
| Side effects last | Send emails/notifications after transaction commits |
| External APIs | Auth0 calls cannot be rolled back - handle orphaned records if needed |
| DataLoaders | DataLoaders participate in transactions when executionContext is provided |
Error Handling
await withTransaction(async (tx) => {
// If any operation throws, all changes roll back
const engagement = await EngagementRepository.create(data, { tx });
if (!engagement) {
throw new Error('Failed to create engagement');
// Transaction automatically rolls back
}
return engagement;
});Related Files
| Type | Location |
|---|---|
| GraphQL Schema | packages/core/src/infrastructure/neo4j/schemas/engagement.graphql |
| Repository | packages/core/src/infrastructure/repositories/engagement-repository.ts |
| Use Cases | packages/core/src/application/use-cases/engagement/ |
| Scoring Services | packages/core/src/domain/services/scoring/ |
| Transaction Types | packages/core/src/infrastructure/graphql/transaction.ts |
| Transaction Utility | packages/core/src/infrastructure/graphql/with-transaction.ts |