ESG Backend Domain Models (v1)
Laravel-Oriented Architecture Specification
1. Design Principles
- Audit-first: all ESG data is immutable once submitted
- Evidence-driven: no metric exists without traceable evidence
- GRI-aligned but extensible: GRI standards are first-class, custom KPIs supported
- Offline-compatible ingestion: UUID-based, idempotent submissions
- Separation of concerns:
- Collection ≠ Review ≠ Approval ≠ Reporting
2. Entity Relationship Diagram
The following diagram shows the relationships between all domain entities:
erDiagram
Organisation ||--o{ BusinessUnit : "has many"
Organisation ||--o{ ReportingPeriod : "has many"
Organisation ||--o{ MaterialTopic : "has many"
Organisation ||--o{ MetricSubmission : "has many"
Organisation ||--o| Organisation : "parent of"
BusinessUnit ||--o{ Site : "has many"
BusinessUnit }o--|| Organisation : "belongs to"
BusinessUnit ||--o{ MetricSubmission : "has many"
Site }o--|| BusinessUnit : "belongs to"
Site ||--o{ MetricSubmission : "has many"
GriStandard ||--o{ GriDisclosure : "has many"
GriStandard ||--o{ MaterialTopic : "referenced by"
GriDisclosure }o--|| GriStandard : "belongs to"
GriDisclosure ||--o{ MetricDefinition : "has many"
MetricDefinition }o--o| GriDisclosure : "optionally mapped to"
MetricDefinition ||--o{ MetricSubmission : "has many"
MetricSubmission }o--|| MetricDefinition : "belongs to"
MetricSubmission }o--|| Organisation : "belongs to"
MetricSubmission }o--o| BusinessUnit : "optionally belongs to"
MetricSubmission }o--o| Site : "optionally belongs to"
MetricSubmission }o--|| ReportingPeriod : "belongs to"
MetricSubmission ||--o{ MetricEvidence : "has many"
MetricSubmission ||--o{ ReviewAction : "has many"
Evidence ||--o{ MetricEvidence : "has many"
MetricEvidence }o--|| MetricSubmission : "belongs to"
MetricEvidence }o--|| Evidence : "belongs to"
ReportingPeriod }o--|| Organisation : "belongs to"
MaterialTopic }o--|| Organisation : "belongs to"
MaterialTopic }o--o| GriStandard : "optionally references"
ReviewAction }o--|| MetricSubmission : "belongs to"
AuditLog }o--o| Organisation : "tracks"
AuditLog }o--o| MetricSubmission : "tracks"
AuditLog }o--o| Evidence : "tracks"
Organisation {
uuid id PK
string name
string registration_number
string reporting_currency
string country
uuid parent_organisation_id FK
timestamp created_at
timestamp updated_at
}
BusinessUnit {
uuid id PK
uuid organisation_id FK
string name
enum type
text description
timestamp created_at
timestamp updated_at
}
Site {
uuid id PK
uuid business_unit_id FK
string name
string location
decimal latitude
decimal longitude
string operational_status
timestamp created_at
timestamp updated_at
}
GriStandard {
uuid id PK
string code
string title
enum category
integer effective_year
}
GriDisclosure {
uuid id PK
uuid gri_standard_id FK
string disclosure_code
string title
text description
boolean quantitative
}
MetricDefinition {
uuid id PK
string code
string name
string unit
enum data_type
uuid gri_disclosure_id FK
boolean custom
text description
}
MetricSubmission {
uuid id PK
uuid metric_definition_id FK
uuid organisation_id FK
uuid business_unit_id FK
uuid site_id FK
uuid reporting_period_id FK
string value
uuid submitted_by
timestamp submitted_at
enum status
}
Evidence {
uuid id PK
string file_path
string file_type
string mime_type
string checksum
enum source_type
uuid uploaded_by
timestamp uploaded_at
}
MetricEvidence {
uuid metric_submission_id FK
uuid evidence_id FK
}
ReportingPeriod {
uuid id PK
uuid organisation_id FK
string label
date start_date
date end_date
boolean locked
}
MaterialTopic {
uuid id PK
uuid organisation_id FK
string name
text description
uuid gri_standard_id FK
text rationale
}
ReviewAction {
uuid id PK
uuid metric_submission_id FK
uuid reviewer_id
enum action
text comments
timestamp created_at
}
AuditLog {
uuid id PK
uuid actor_id
string action
string entity_type
uuid entity_id
json payload
timestamp created_at
}
3. Core Aggregate Roots
3.1 Organisation
Represents the reporting entity (group or subsidiary).
Organisation
- id (uuid)
- name
- registration_number
- reporting_currency
- country
- parent_organisation_id (nullable)
- created_at
- updated_at
Relationships:
• hasMany BusinessUnits
• hasMany ReportingPeriods
• hasMany MaterialTopics
3.2 BusinessUnit
Used to separate mining vs agribusiness operations.
BusinessUnit
- id (uuid)
- organisation_id
- name
- type (mining | agribusiness | corporate)
- description
- created_at
- updated_at
Relationships:
• belongsTo Organisation
• hasMany Sites
• hasMany Metrics
3.3 Site
Physical reporting locations (mine, farm, processing facility).
Site
- id (uuid)
- business_unit_id
- name
- location
- latitude
- longitude
- operational_status
- created_at
- updated_at
Relationships:
• belongsTo BusinessUnit
• hasMany MetricSubmissions
4. GRI Standards Model
4.1 GriStandard
GriStandard
- id (uuid)
- code (e.g. "GRI 302")
- title
- category (universal | topic)
- effective_year
4.2 GriDisclosure
Individual disclosures within a standard.
GriDisclosure
- id (uuid)
- gri_standard_id
- disclosure_code (e.g. "302-1")
- title
- description
- quantitative (boolean)
Relationships:
• belongsTo GriStandard
• hasMany Metrics
5. Metrics & KPIs
5.1 MetricDefinition
Defines what is being measured.
MetricDefinition
- id (uuid)
- code
- name
- unit
- data_type (number | percentage | text | boolean)
- gri_disclosure_id (nullable)
- custom (boolean)
- description
Examples: • Total energy consumed (GJ) • Lost Time Injury Frequency Rate • Total water withdrawn (m³)
5.2 MetricSubmission
Actual reported values (append-only).
MetricSubmission
- id (uuid)
- metric_definition_id
- organisation_id
- business_unit_id (nullable)
- site_id (nullable)
- reporting_period_id
- value
- submitted_by
- submitted_at
- status (submitted | reviewed | approved | rejected)
Rules: • Never updated after submission • Corrections are new submissions with references
6. Evidence Management
6.1 Evidence
Central to auditability.
Evidence
- id (uuid)
- file_path
- file_type
- mime_type
- checksum (sha256)
- source_type (invoice | photo | report | log | policy)
- uploaded_by
- uploaded_at
6.2 MetricEvidence (Pivot)
Rules: • At least one Evidence record per MetricSubmission • Evidence is immutable
7. Reporting Periods
ReportingPeriod
- id (uuid)
- organisation_id
- label (e.g. "FY2024")
- start_date
- end_date
- locked (boolean)
Rules: • Locked periods are read-only • Locking happens after final approval
8. Material Topics
8.1 MaterialTopic
Scope v1: • Materiality assumed (no scoring) • Rationale stored as narrative text
9. Workflow & Review
9.1 ReviewAction
ReviewAction
- id (uuid)
- metric_submission_id
- reviewer_id
- action (reviewed | approved | rejected)
- comments
- created_at
Rules: • Supports multi-step review • Immutable history
10. Audit Log (Mandatory)
Tracked events: • Submission • Evidence upload • Review decision • Period lock
11. Access Control (RBAC)
See: Tenancy & Role Model for comprehensive RBAC specification including permission matrices, workflow states, and API-level access control patterns.
Implementation Resources: - RBAC Matrix (YAML) - Machine-readable policy-as-code specification - Laravel RBAC Implementation Guide - Complete Laravel implementation with policies, middleware, and code examples
11.1 Role Summary
Recommended roles: • Collector (mobile / field) • Reviewer • Approver • Admin (ESG system owner) • Auditor (read-only)
11.2 Enforcement Points
Access control enforced at: • MetricSubmission (CRUD operations) • Evidence access (upload, read, delete) • Period locking (state transitions) • ReviewAction (workflow state changes)
11.3 Implementation Notes
User-Role Assignment
// Tenant-scoped role assignment
UserRole
- id (uuid)
- user_id
- tenant_id (organisation_id)
- role (collector | reviewer | approver | admin | auditor)
- scope_type (nullable: site | project | business_unit)
- scope_id (nullable: uuid)
- expires_at (nullable)
- created_at
- updated_at
Permission Checks
- All MetricSubmission operations must verify tenant boundary
- Collectors can only CRUD their own submissions (until submitted)
- Reviewers can transition submissions: submitted → reviewed
- Approvers can transition submissions: reviewed → approved
- No self-approval: submitted_by ≠ approver_id
Reporting Period State Gates
- locked = false: Collectors can create/update submissions
- locked = true: All write operations blocked except Admin with justification
See Section 5: RBAC Permission Matrix for detailed permission mappings.
12. API Boundary Notes
Collector API
• Create MetricSubmission • Upload Evidence • Offline-safe UUIDs
Admin API
• Define Metrics • Manage GRI mappings • Review & approve submissions • Generate reports
13. Explicit Non-Goals (v1)
• No deletions • No inline edits • No computed carbon factors • No real-time sensors
14. Forward-Compatible Extensions
Planned additions: • Targets & baselines • Materiality scoring • Assurance workflows • ISSB / IFRS S2 mapping • Sector standards
Status: Ready for Laravel implementation Alignment: GRI / ESG Scope v1 & Client Annual Report