Overview
This section covers the relationship type system in CongregationKit, including the RelationshipType enum, RelationshipCategory, MemberRelationship struct, and related types for managing connections between church members.
RelationshipType
Represents the type of relationship between two members.
public enum RelationshipType: String, Codable, CaseIterable, Sendable
Cases
spouse - “Spouse”
parent - “Parent”
child - “Child”
sibling - “Sibling”
Extended Family
grandparent - “Grandparent”
grandchild - “Grandchild”
uncle - “Uncle”
aunt - “Aunt”
nephew - “Nephew”
niece - “Niece”
cousin - “Cousin”
In-Laws
fatherInLaw - “Father-in-Law”
motherInLaw - “Mother-in-Law”
sonInLaw - “Son-in-Law”
daughterInLaw - “Daughter-in-Law”
brotherInLaw - “Brother-in-Law”
sisterInLaw - “Sister-in-Law”
Guardianship
guardian - “Guardian”
ward - “Ward”
Spiritual Relationships
mentor - “Mentor”
mentee - “Mentee”
discipler - “Discipler”
disciple - “Disciple”
prayerPartner - “Prayer Partner”
accountabilityPartner - “Accountability Partner”
Ministry Relationships
lifeGroupLeader - “Life Group Leader”
lifeGroupMember - “Life Group Member”
ministryLeader - “Ministry Leader”
ministryTeamMember - “Ministry Team Member”
Other
Properties
displayName
A user-friendly display name for the relationship type.
public var displayName: String
inverse
Returns the inverse relationship type.
public var inverse: RelationshipType
For example, if someone is a “Parent” to another person, that other person is a “Child” to them.
category
Returns the category of this relationship type.
public var category: RelationshipCategory
isSymmetrical
Whether this relationship type is symmetrical (same inverse as itself).
public var isSymmetrical: Bool
Example Usage
let type = RelationshipType.parent
print(type.displayName) // "Parent"
print(type.inverse) // .child
print(type.category) // .family
print(type.isSymmetrical) // false
// Symmetrical relationships
let spouse = RelationshipType.spouse
print(spouse.inverse == spouse) // true
print(spouse.isSymmetrical) // true
// Use for ministry planning
switch type {
case .spouse:
print("Couple ministry opportunity")
case .parent, .child:
print("Family ministry opportunity")
case .mentor, .mentee:
print("Discipleship ministry opportunity")
default:
break
}
RelationshipCategory
Categories for grouping relationship types.
public enum RelationshipCategory: String, Codable, CaseIterable, Sendable
Cases
family - “Family”
marriage - “Marriage”
spiritual - “Spiritual”
ministry - “Ministry”
other - “Other”
Properties
public var displayName: String
Example
let category = RelationshipCategory.spiritual
print(category.displayName) // "Spiritual"
// Filter relationships by category
let spiritualTypes = RelationshipType.allCases.filter {
$0.category == .spiritual
}
// [.mentor, .mentee, .discipler, .disciple, .prayerPartner, .accountabilityPartner]
MemberRelationship
Represents a relationship between two church members.
public struct MemberRelationship: Codable, Equatable, Sendable
Properties
Unique identifier for this relationship.
The member ID of the source (from) member.
The member ID of the target (to) member.
The type of relationship from source to target.
When this relationship started.
When this relationship ended (e.g., divorce, death).
Whether this is the primary relationship of its type. For example, if a child has multiple guardians, one might be designated as primary.
Additional notes about this relationship.
Computed Properties
isActive
Whether this relationship is currently active (no end date).
public var isActive: Bool
durationInYears
Duration of the relationship in years, if start date is available.
public var durationInYears: Int?
Initializer
public init(
id: RelationshipID,
sourceMemberId: MemberID,
targetMemberId: MemberID,
relationshipType: RelationshipType,
startDate: Date? = nil,
endDate: Date? = nil,
isPrimary: Bool = false,
notes: String? = nil
)
Methods
inverse(withId:)
Returns the inverse relationship (swapping source and target with inverse type).
public func inverse(withId newId: RelationshipID) -> MemberRelationship
This is useful for creating bidirectional relationships automatically.
Example Usage
// Create a parent-child relationship
let relationship = MemberRelationship(
id: RelationshipID(rawValue: "REL001")!,
sourceMemberId: MemberID(rawValue: "TKT1234")!,
targetMemberId: MemberID(rawValue: "TKT5678")!,
relationshipType: .parent,
startDate: Date(),
isPrimary: true,
notes: "Biological parent"
)
print("Type: \(relationship.relationshipType.displayName)")
print("Inverse: \(relationship.relationshipType.inverse.displayName)")
print("Active: \(relationship.isActive)")
// Create inverse relationship
let inverseRelationship = relationship.inverse(
withId: RelationshipID(rawValue: "REL002")!
)
print("Inverse type: \(inverseRelationship.relationshipType)") // .child
Relationship Direction
The relationship is directional from source to target. For example:
- Source: Parent (TKT1234)
- Target: Child (TKT5678)
- Type: .parent means TKT1234 is the parent OF TKT5678
To get the inverse relationship (TKT5678 is child OF TKT1234), use the inverse method.
SuggestedRelationship
A suggested relationship between two members based on heuristic analysis.
public struct SuggestedRelationship: Codable, Equatable, Sendable
Properties
The suggested relationship type.
Confidence score from 0.0 (low) to 1.0 (high).
The reason for this suggestion.
Additional context or evidence for the suggestion.
Computed Properties
public var isHighConfidence: Bool // >= 0.8
public var isMediumConfidence: Bool // 0.5 to 0.8
public var isLowConfidence: Bool // < 0.5
public var confidenceLevel: String // "High", "Medium", or "Low"
Example
let suggestion = SuggestedRelationship(
sourceMemberId: MemberID(rawValue: "TKT1234")!,
targetMemberId: MemberID(rawValue: "TKT5678")!,
suggestedType: .spouse,
confidence: 0.95,
reason: .spouseNameMatch,
additionalContext: "Spouse name matches member record"
)
if suggestion.isHighConfidence {
print("High confidence: \(suggestion.suggestedType.displayName)")
print("Reason: \(suggestion.reason.description)")
print("Context: \(suggestion.additionalContext ?? "")")
}
SuggestionReason
Reasons why a relationship was suggested.
public enum SuggestionReason: String, Codable, CaseIterable, Sendable
Cases
sameAddress - “Same Address”
sameLastName - “Same Last Name”
spouseNameMatch - “Spouse Name Match”
ageGapParentChild - “Age Gap Suggests Parent-Child”
ageGapSibling - “Similar Age Suggests Siblings”
maritalInfoMatch - “Marital Information Match”
lifeGroupConnection - “Same Life Group”
phoneNumberMatch - “Same Phone Number”
emergencyContactMatch - “Emergency Contact Match”
Properties
description
A human-readable description of the reason.
public var description: String
detailedExplanation
Detailed explanation of this reason.
public var detailedExplanation: String
Example
let reason = SuggestionReason.ageGapParentChild
print(reason.description)
// "Age Gap Suggests Parent-Child"
print(reason.detailedExplanation)
// "Age difference of 18-45 years suggests parent-child relationship."
Supporting ID Types
RelationshipID
A type-safe identifier for member relationships.
public struct RelationshipID: RawRepresentable, Codable, Hashable, Sendable
Example
if let relationshipId = RelationshipID(rawValue: "REL001") {
print("Valid relationship ID: \(relationshipId.rawValue)")
}
let invalidId = RelationshipID(rawValue: "") // Returns nil
FamilyID
A type-safe identifier for family units.
public struct FamilyID: RawRepresentable, Codable, Hashable, Sendable
Example
if let familyId = FamilyID(rawValue: "FAM001") {
print("Valid family ID: \(familyId.rawValue)")
}
let invalidId = FamilyID(rawValue: "") // Returns nil
FamilyRole
Represents the role a member plays within a family unit.
public enum FamilyRole: String, Codable, CaseIterable, Sendable
Cases
head - “Head” (Head of Household)
spouse - “Spouse”
child - “Child”
dependent - “Dependent”
other - “Other”
Properties
displayName
public var displayName: String
isAdultRole
Whether this role typically represents an adult in the family.
public var isAdultRole: Bool
Example
let role = FamilyRole.head
print(role.displayName) // "Head of Household"
print(role.isAdultRole) // true
switch role {
case .head:
print("Primary contact for family")
case .spouse:
print("Co-head of household")
case .child:
print("Children's ministry participant")
case .dependent:
print("Extended family member")
case .other:
print("Other family member")
}
FamilyMembership
Represents a member’s membership within a family unit.
public struct FamilyMembership: Codable, Equatable, Sendable
Properties
The family this membership belongs to.
The member who belongs to this family.
The member’s role within the family.
When the member joined this family.
When the member left this family (if applicable).
Whether this membership is currently active.
Additional notes about this membership.
Computed Properties
membershipDurationInYears
Duration of membership in years.
public var membershipDurationInYears: Int?
Example
let membership = FamilyMembership(
familyId: FamilyID(rawValue: "FAM001")!,
memberId: MemberID(rawValue: "TKT1234")!,
role: .head,
joinDate: Date(),
isActive: true
)
print("Role: \(membership.role.displayName)")
print("Active: \(membership.isActive)")
See Also