Middleware
Bidirectional middleware synchronization between Unit4 Student Management and Salesforce Education Cloud EDA using a canonical data model to reconcile person and organizational hierarchies.
This integration connects Unit4 Student Management, an ERP increasingly adopted by mid-size institutions, to Salesforce Education Data Architecture (EDA) to feed admissions recruitment, student engagement, and advancement workflows with authoritative data from the student information system.
The primary technical challenge is reconciling Unit4's flattened person-centric data structures with Salesforce EDA's hierarchical account-contact-relationship model, requiring a canonical intermediate representation that captures student, faculty, applicant, and alumni roles as distinct but related entities.
The middleware layer handles transformation logic, deduplication rules for handling duplicate person records, and event-driven change capture to minimize latency between systems.
A working piece from this integration — no sign-up. The full build handles the edge cases, safeguards, and cutover.
{ "canonical": { "student": { "sourceId": "U4-STU-2024-00847", "salesforceId": "003Hu00000KqMvhIAF", "identifiers": { "studentNumber": "00847", "nationalId": "GB-19890715-2847" }, "person": { "firstName": "Mara", "lastName": "Okonkwo", "birthDate": "1989-07-15", "gender": "F" }, "contacts": { "primaryEmail": "[email protected]", "mobilePhone": "+44-7700-900-847" }, "enrollment": { "program": "BSC-CS-2021", "academicLevel": "Year 3", "status": "active", "expectedGraduation": "2025-06" } } }, "transformations": [ { "direction": "Unit4 → SF-EDA", "targetObject": "Contact", "fieldMappings": [ { "u4Field": "STUDENT.SURNAME", "edaField": "LastName", "transform": "passthrough" }, { "u4Field": "STUDENT.FIRSTNAME", "edaField": "FirstName", "transform": "passthrough" }, { "u4Field": "STUDENT.BIRTHDATE", "edaField": "Birthdate", "transform": "dateISO" }, { "u4Field": "STUDENT.EMAIL", "edaField": "Email", "transform": "lowercase" }, { "u4Field": "STUDENT.PROGRAMME_CODE", "edaField": "AccountId", "transform": "lookup:Program_Account__c.External_Id__c" }, { "u4Field": "STUDENT.EXT_ID", "edaField": "Student_Id__c", "transform": "passthrough" }, { "u4Field": "STUDENT.ACADEMIC_YEAR", "edaField": "Primary_Academic_Level__c", "transform": "map:yearToLevel" } ] }, { "direction": "SF-EDA → Unit4", "targetObject": "Course_Connection__c", "query": "SELECT Id, Account__r.Name, Course__r.Course_Name__c, Status__c FROM Course_Connection__c WHERE Contact__r.Student_Id__c = '{sourceId}' AND Term__r.Name = '{currentTerm}'" } ] } ``` ```html| Unit4 Entity/Field | EDA Object | EDA Field | Notes |
|---|---|---|---|
STUDENT | Contact | RecordType.DeveloperName = 'Student' | Key resolution point |
PROGRAMME | Account | RecordType.DeveloperName = 'Academic_Program' | Org hierarchy root |
MODULE_INSTANCE | Course_Offering__c | Course__c + Term__c | Unique composite key |
ENROLLMENT | Course_Connection__c | Contact__c + Course_Offering__c | Junction object |
TERM | Term__c | Id | Sync via date windows |
How we'd take this from discovery to a production-safe cutover — the phases, the canonical mapping, and the edge cases that bite.
This implementation pathway covers the bidirectional sync between the Unit4 Student Management system and Salesforce Education Cloud's Education Data Architecture (EDA), using a canonical data model to reconcile person records and organizational hierarchies across both platforms.
StudentID or PersonExternalId), canonical affiliation records (linking a person to an academic program with role, start, and end dates), and a canonical organization hierarchy (mapping Unit4 organizational units to EDA Account records at the appropriate level—Institution, School, or Department).StudentID → Contact.UniqueStudentIdentifier__c and BirthDate → Contact.Birthdate. For affiliations, map ProgramEnrollment → Affiliation__c with role (Student, Alumni, Applicant) and status fields. Apply de-duplication logic using StudentExternalId__c as the matching key to prevent duplicate Contacts.| Unit4 Field / Entity | Canonical Model Field | EDA Object | EDA Field | Notes |
|---|---|---|---|---|
Students.StudentID |
PersonExternalId |
Contact | StudentId__c |
Primary matching key; must be populated on all records. |
Students.FullName |
FullName |
Contact | Name |
Parsed into FirstName and LastName. |
Students.Email |
EmailAddress |
Contact | Email |
Also used for matching; prefer StudentID if email changes. |
ProgramEnrollment.ProgramCode |
AcademicProgramCode |
Account | ProgramCode__c |
Account must exist in EDA; create if not found. |
ProgramEnrollment.Status |
AffiliationRole |
Affiliation__c | Role__c |
Map values: Active → Student; Graduated → Alumni. |
ProgramEnrollment.StartDate |
AffiliationStartDate |
Affiliation__c | StartDate__c |
Required; set to Term start date. |
ProgramEnrollment.EndDate |
AffiliationEndDate |
Affiliation__c | EndDate__c |
Null for active students; populated on completion. |
AcademicUnit.OrgUnitID |
OrganizationalUnitId |
Account | ParentId (self-lookup) |
Maps hierarchy; maps to EDA Account parent for school-level structure. |
StudentId__c is blank, the middleware will create a duplicate rather than match. Enforce StudentId__c as a required field in the canonical model before sync begins.LastName on every sync or maintain a separate PreferredName__c field to avoid unintended changes to the primary Contact name.StudentId__c counts, affiliation status distributions, and timestamp divergence on the 20 most-active records to catch drift early. Reading the reference is free. Delivering it under liability — with the safeguards that keep production running through the cutover — is what we do.