michael-orenda / party
A Laravel 13 package providing reusable Party, Person, Organization, Role, and Relationship domain models, inspired by the universal data modeling concepts presented by Len Silverston in The Data Model Resource Book, Volume 1.
Requires
- php: ^8.3
- laravel/framework: ^13.0
Requires (Dev)
- orchestra/testbench: ^11.0
- phpunit/phpunit: ^12.0
README
A reusable Laravel 13 Party Model package for representing people, organizations, roles, and relationships across enterprise applications.
The package provides a foundational enterprise identity model inspired by the Universal Data Model concepts described by Len Silverston in The Data Model Resource Book, Volume 1.
Instead of creating separate identities for customers, employees, suppliers, directors, members, borrowers, guarantors, and other participants, the package represents each real-world person or organization once as a Party and models the different capacities in which that Party participates using Party Roles and Party Relationships.
PARTY
│
┌──────────┴──────────┐
│ │
PERSON ORGANIZATION
│ │
└──────────┬──────────┘
│
PARTY ROLE
│
▼
PARTY RELATIONSHIP
Why a Party Model?
Traditional applications commonly create domain-specific entities such as:
customers
employees
suppliers
directors
members
borrowers
guarantors
This works initially, but can cause the same real-world person or organization to be represented multiple times.
For example, Michael may simultaneously be:
Employee
Customer
Director
Member
Borrower
These are not five different people.
They are five capacities in which the same person participates.
The Party model represents this as:
Michael
│
PARTY
│
┌───────────────┼───────────────┐
│ │ │
EMPLOYEE CUSTOMER DIRECTOR
│
├──────────── MEMBER
│
└──────────── BORROWER
The identity exists once.
Its roles and relationships can change over time.
Core Principle
The package is built around a simple principle:
Model what an entity is separately from the roles it plays and the relationships in which it participates.
A Party answers:
Who or what is this?
A Party Role answers:
In what capacity is this Party participating?
A Party Relationship answers:
Why does this role exist, and with whom is it exercised?
Conceptually:
PARTY
│
│ Who or what is this?
▼
PERSON / ORGANIZATION
│
│ In what capacity is the Party participating?
▼
PARTY ROLE
│
│ Why does that role exist and
│ with whom is it exercised?
▼
PARTY RELATIONSHIP
For the complete explanation of the model and its design philosophy, see:
Party Model Concepts and Design Philosophy
Example
Consider the statement:
Michael is employed by Software Technologies.
The model does not simply connect Michael directly to Software Technologies.
Instead, it captures the capacities in which both Parties participate:
Michael
│
▼
PARTY
│
▼
EMPLOYEE
│
│ EMPLOYMENT
▼
EMPLOYER
│
▼
PARTY
│
▼
Software Technologies
This provides considerably more business meaning than a simple foreign-key association.
It also allows the relationship to contain information such as:
from_date
thru_date
comment
and allows the historical relationship to remain intact after it ends.
Features
The package currently provides:
- Party identities using UUIDv7 identifiers
- Person specialization
- Organization specialization
- hierarchical Organizations
- Party Role Types
- Party Roles
- Party Relationship Types
- permitted relationship role combinations
- directional Party Relationships
- effective relationship dates
- historical relationship preservation
- relationship comments
- organization hierarchy validation
- cycle prevention in Organization hierarchies
- transactional Party creation
- transactional relationship creation
- data-driven Role and Relationship vocabularies
- Laravel Eloquent models and relationships
- service-layer domain operations
- Form Request validation
- Laravel API Resources
- REST API endpoints
- reference-data API endpoints
- seeders for standard Party vocabulary
- PHPUnit/Testbench test suite
- Laravel package auto-discovery
Requirements
The package requires:
PHP >= 8.3
Laravel 13
The package is developed and tested as a Laravel package using Orchestra Testbench and PHPUnit.
Installation
Install the package through Composer:
composer require michael-orenda/party
Laravel package discovery automatically registers:
MichaelOrenda\Party\PartyServiceProvider::class
Run the migrations:
php artisan migrate
The package migrations create the core Party schema.
For complete installation instructions, local package development, configuration publishing, migrations, and verification, see:
Database Model
The package uses eight core tables:
parties
people
organizations
party_role_types
party_roles
party_relationship_types
party_relationship_role_types
party_relationships
At a high level:
parties
/ \
/ \
people organizations
parties
│
▼
party_roles
│
▼
party_role_types
party_role_types
│
▼
party_relationship_role_types
│
▼
party_relationship_types
│
▼
party_relationships
/ \
/ \
from_party_role to_party_role
For the complete schema, constraints, keys, indexes, and table-by-table explanation, see:
Core Models
The package provides the following Eloquent models:
Party
Person
Organization
PartyRoleType
PartyRole
PartyRelationshipType
PartyRelationshipRoleType
PartyRelationship
The central identity model is:
Party
├── Person
└── Organization
A Party may then hold multiple roles:
Party
│
└── PartyRole
│
└── PartyRoleType
Relationships connect Party Roles:
PartyRole
│
▼
PartyRelationship
│
▼
PartyRole
For the complete model and Eloquent relationship reference, see:
Models and Eloquent Relationships
Creating a Person
Using the package service layer:
use MichaelOrenda\Party\Data\CreatePersonData; use MichaelOrenda\Party\Services\PartyService; $person = app(PartyService::class)->createPerson( new CreatePersonData( firstName: 'Michael', lastName: 'Orenda', middleName: 'Philip', ) );
This creates both:
Party
│
▼
Person
inside a database transaction.
The common Party identity is available through:
$person->party;
or:
$person->party_id;
Creating an Organization
use MichaelOrenda\Party\Data\CreateOrganizationData; use MichaelOrenda\Party\Services\PartyService; $organization = app(PartyService::class)->createOrganization( new CreateOrganizationData( name: 'Software Technologies' ) );
This creates:
Party
│
▼
Organization
Organization Hierarchies
Organizations may contain other Organizations.
For example:
Software Technologies
│
├── Development
├── Finance
└── Human Resources
The hierarchy is represented using:
organizations.parent_id
The package prevents invalid structures such as:
A
└── B
└── C
└── A
and prevents an Organization from becoming its own parent.
Organization hierarchy is intentionally separate from general Party Relationships.
Assigning Party Roles
A Party can participate in multiple capacities.
For example:
$employeeRole = app(PartyService::class)->assignRole( $person->party, 'EMPLOYEE' );
The same Party could later also receive:
CUSTOMER
DIRECTOR
MEMBER
BORROWER
without creating another Person.
Party Relationships
Relationships connect Party Roles rather than merely connecting Parties.
For example:
Michael [EMPLOYEE]
│
│ EMPLOYMENT
▼
Software Technologies [EMPLOYER]
A relationship contains:
relationship type
FROM Party Role
TO Party Role
from date
thru date
comment
Relationship direction is controlled by the configured relationship-role rules.
Applications should therefore not assume that a particular role is always the FROM or TO side.
For the complete service-layer documentation, see:
Services and Domain Operations
REST API
The package exposes its API under:
/api/party
The current API includes:
/api/party/people
/api/party/organizations
/api/party/roles
/api/party/relationships
/api/party/reference/role-types
/api/party/reference/relationship-types
/api/party/reference/relationship-role-types
For example:
POST /api/party/people
{
"first_name": "Michael",
"middle_name": "Philip",
"last_name": "Orenda"
}
Create an Organization:
POST /api/party/organizations
{
"name": "Software Technologies"
}
Assign a role:
POST /api/party/roles
{
"party_id": "019f...",
"role_type_code": "EMPLOYEE"
}
The API also exposes reference-data endpoints so clients can discover the configured Party vocabulary and valid relationship-role combinations.
For the complete endpoint reference, validation rules, request bodies, responses, and status codes, see:
Postman Collection
A complete Postman collection is included with the package for exploring and testing the Party REST API.
The collection is located at:
postman/Michael-Orenda-Party.postman_collection.json
The collection covers all Party API endpoints, including:
- People
- Organizations
- Party Roles
- Party Relationships
- Party Role Types
- Party Relationship Types
- Party Relationship Role Types
- validation and domain-rule examples
The collection uses the following base URL variable:
{{base_url}}
Set this to the URL of the Laravel application in which the package is installed.
For example:
http://datamodels.test
The collection automatically captures identifiers returned by create operations and stores them as collection variables.
For example:
Create Person
│
├── person_id
└── person_party_id
Create Organization
│
├── organization_id
└── organization_party_id
Assign Party Roles
│
├── from_party_role_id
└── to_party_role_id
Create Relationship
│
└── party_relationship_id
This allows related requests to be executed sequentially without manually copying UUIDs between requests.
Importing the Collection
In Postman:
-
Select Import.
-
Select the file:
postman/Michael-Orenda-Party.postman_collection.json -
Open the imported Michael Orenda - Party API collection.
-
Set the
base_urlcollection variable to the URL of your Laravel application. -
Start with the Reference Data requests to inspect the configured Party vocabulary.
A typical workflow is:
Reference Data
│
▼
Create Person
│
▼
Create Organization
│
▼
Assign Party Roles
│
▼
Create Party Relationship
│
▼
Retrieve / Update Relationship
For detailed explanations of every endpoint, see:
For complete business examples demonstrating how these endpoints work together, see:
Practical Examples and Usage Patterns
Practical Examples
The documentation includes examples covering:
People
Organizations
Organization hierarchies
Employees and Employers
Employment history
Directors
Customers
Suppliers
Borrowers
Lenders
Guarantors
Members
Board Management
Human Resources
Procurement
CRM
Lending
cross-domain enterprise identity
See:
Practical Examples and Usage Patterns
Universal Identity Across Applications
The package is designed to act as foundational infrastructure for multiple business domains.
For example:
PARTY
│
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
HR Lending CRM
│ │ │
▼ ▼ ▼
Employee Borrower Customer
│
┌─────────────┴─────────────┐
│ │
▼ ▼
Board Management Membership
│ │
▼ ▼
Director Member
Instead of each application redefining the same Person or Organization, domain packages can reference the common:
party_id
This makes Party suitable as a foundational model for modular enterprise systems.
What This Package Does Not Do
The package deliberately does not attempt to implement every business domain.
For example, a Lending package may reference:
BORROWER
LENDER
GUARANTOR
but loan-specific concepts such as:
principal
interest
repayment schedules
collateral
credit assessment
loan balances
belong in the Lending domain.
Likewise, HR-specific concepts such as:
payroll
leave
performance management
positions
compensation
belong in an HR domain.
The Party package provides identity and relationship infrastructure upon which these domains can be built.
Documentation
The package documentation is organized as a progressive guide:
| Chapter | Documentation | Description |
|---|---|---|
| 01 | Concepts and Design Philosophy | Why the Party model exists and the principles behind it |
| 02 | Architecture | Package structure and architectural design |
| 03 | Installation | Installation, configuration, migrations, and setup |
| 04 | Database Schema | Tables, keys, constraints, indexes, and relationships |
| 05 | Models | Eloquent models and model relationships |
| 06 | Services | Domain operations and PartyService |
| 07 | HTTP API | Complete REST API reference |
| 08 | Examples | Practical enterprise modeling examples |
Developers unfamiliar with Party modeling should begin with:
01 — Concepts and Design Philosophy
and then read:
08 — Practical Examples and Usage Patterns
before designing application-specific Party extensions.
Testing
The package includes a PHPUnit test suite built using Orchestra Testbench.
Run:
composer test
The package can therefore be tested independently from the consuming Laravel application.
Additional Composer validation can be performed using:
composer validate
and:
composer check-platform-reqs
Package Development
When developing the package locally using a Composer path repository, the host application's composer.json can reference the package:
{
"repositories": [
{
"type": "path",
"url": "packages/michael-orenda/party",
"options": {
"symlink": true
}
}
]
}
Then require it from the host application:
composer require michael-orenda/party:@dev
This allows changes in the package source directory to be immediately available to the host Laravel application.
See the Installation Guide for the complete development setup.
Design Philosophy
The package deliberately separates:
Identity
│
▼
Party
Participation
│
▼
Party Role
Business Context
│
▼
Party Relationship
This avoids coupling enterprise identity to any single business application.
For the complete discussion—including identity versus roles, relationship context, historical relationships, universal concepts versus application concepts, and extensibility—see:
Party Model Concepts and Design Philosophy
Acknowledgements
The domain modeling concepts used in this package are inspired by the work of Len Silverston, particularly the universal data modeling patterns presented in:
Len Silverston, The Data Model Resource Book, Volume 1: A Library of Universal Data Models for All Enterprises, John Wiley & Sons.
Silverston's work demonstrates how common enterprise concepts—including parties, people, organizations, roles, relationships, products, orders, agreements, work efforts, and other business entities—can be represented using reusable and extensible data models.
The michael-orenda/party package applies these ideas to a modern Laravel architecture, with particular emphasis on the Party, Person, Organization, Party Role, and Party Relationship concepts.
This package is an independent implementation.
It is not affiliated with, endorsed by, or an official implementation of Len Silverston's work or the publisher.
The software design and source code in this package are independently developed for use within Laravel applications.
License
The michael-orenda/party package is open-source software licensed under the MIT License.
See:
Author
Michael Philip Orenda
Michael Orenda
Package:
michael-orenda/party
Website:
[https://michael-orenda.com](https://michael-orenda.com)
Project Goal
The long-term objective of michael-orenda/party is to provide a stable, reusable enterprise identity foundation for Laravel applications.
Instead of repeatedly asking:
Should this application have a customer table, employee table, supplier table, borrower table, or member table?
the Party model encourages a more fundamental question:
Who or what is this Party, in what capacity is it participating, and what relationship gives that participation meaning?
That distinction allows multiple enterprise applications to share a consistent representation of people and organizations while remaining free to implement their own domain-specific behavior.