On November 10, 2020, after over 16 months of work by a team of only 10 engineers, Rippling launched its first Professional Employer Organization (PEO). Building our PEO forced us to question all notions of typical SaaS product architectures—to say it was a challenge is an understatement!
Unlike other B2B SaaS products, which are built at a per client level, the Rippling PEO is a product suite that spans all of the PEO clients. This structure creates unusual security and data modeling problems not seen before in B2B products.
In this post, we’ll explain the issues we faced and how we modified the existing Rippling SaaS suite to support a PEO.
What is a PEO?
A PEO, or Professional Employer Organization, operates through a co-employment model, which means your employees are on the PEO's books, but they are still under your management.
Clients prefer to join a PEO for two reasons:
- They don’t have to worry about keeping track of the myriad local, city, state, and federal compliance rules when hiring and managing employees in a remote-first world.
- The PEO can provide high-quality, affordable health coverage on behalf of our worksite employees.
PEOs can also solve an extremely messy problem for the government. To ensure compliance and accurate tax collection for small businesses, the government holds one PEO responsible, instead of thousands of smaller companies. Such consolidation saves the government time and money.
PEOs, by nature, create an unusual and complex multi-tenancy problem. How do we ensure that the data of one company is not accessed by another company? How do we ensure that our existing SaaS product suite, which is built for one company, can still be used for PEO clients where employees belong to multiple companies?
The solution starts with Rippling’s SaaS suite architecture.
Rippling’s hub and spoke backend architecture
The Rippling backend is set up as a “hub and spokes” model. The hub corresponds to core Rippling features like Rippling accounts, company and user information, and onboarding/offboarding flows. The spokes are individual services like payroll, benefits, or user provisioning in third-party apps.
Since a PEO requires us to file for taxes across all PEO clients under a single PEO company, we needed to modify the multi-tenant nature of the above hub and spoke architecture to support combined tax filings for PEO. However, this became more complex as the PEO filings requirement is not uniform across all states.
PEOs, by nature, create an unusual and complex multi-tenancy problem. How do we ensure that the data of one company is not accessed by another company? How do we ensure that our existing SaaS product suite, which is built for one company, can still be used for PEO clients where employees belong to multiple companies? The solution starts with Rippling’s SaaS suite architecture.
While at a federal level, a PEO is expected to pay taxes for all of its clients, at a state level, some states want a PEO to make a combined tax filing while in other states the expectation is for the PEO to file taxes on behalf of clients under the client's own account.
For clarity we’ll call states which require tax payments under the PEO account as PEO reporting states and states that require tax payment under client account as client reporting states.
PEO reporting and client reporting states
The above image shows the tax reporting requirement across all US states as of 2019. Without getting into technicalities, you can imagine all grey and white-striped states as PEO reporting states and every other as a client reporting state.
We were tasked with building a platform with the following requirements:
- An employee can belong to 2 companies (client and PEO company)
- A PEO company should act like a parent company of the client companies but employees should not be directly tied to the PEO company
- For PEO reporting states, taxes will be paid to PEO company’s state account after the switch
- For client reporting states, taxes will be paid to the same client’s state account even after switching to PEO
- Maintain data consistency of company and employees before and after the client joins the PEO
To create a robust and scalable multi-tenant architecture to support the following needs, we had to first understand Rippling’s existing tax filings architecture.
Rippling’s tax filings: under the hood
Payroll and filings are the most important and complex functionalities for a company. A PEO can make them even more complicated. Here’s how payroll and filings are handled in Rippling.
Every company has at least one legal entity (
CompanyTaxInfo model), which is an identification number registered with the Internal Revenue Service (IRS) for an employer known as FEIN (Federal Employment Identification Number). Further, this FEIN is used to get the company registered with state agencies based on the office locations of the company. Each state agency has its tax account number, tax rate, and payment schedule which help determine the taxes being paid by the employee and employer.
In order to continue using the existing tax filings infrastructure, we decided to mimic a PEO company as any other company paying and filing taxes for different states and at a federal level.
We then had two different tax models, one for client and another for the PEO as detailed below.
To support the tax reporting of a client in both PEO reporting and client reporting states, we needed a way to tie the client’s company model to both the client’s company tax model and PEO’s company tax model. We now needed to pay taxes for two FEINs for one single client company payroll account.
PEO tax filings: under the hood
To achieve multi-reporting architecture while still maintaining multi-tenancy, we had to first create a way to map client company to PEO company, connect both tax filing models, and enable fetching any of them on demand.
As you can see in the above image, we introduced a new field
peo_company in the company model which points to the parent PEO company of a client company. For the client company, we duplicated the federal tax model to actually have two duplicate tax models. The first is the original tax model and the second would be used after the client joined the PEO.
We duplicated the state-level tax models as well. We only duplicated the client reporting states as the PEO reporting states are used in Rippling PEO’s state tax models.
Technically, we now have three legal entities which can be used by the client company. Now we just wanted an intelligent and robust system to pick correct agency attributes from correct objects according to various reporting types.
Creating combined PEO-client objects during runtime while keeping data otherwise segregated in the database
Although we defined the high-level database models, we had not solved how we wanted to report a company under two different FEIN entities without mixing data in the system.
We were tasked with creating such reports as an overlay on top of existing Rippling payroll and tax filings architecture which was not intended to have so many different tax objects for a single company. To do the above, we had to generate another additional tax model during runtime which was a merger of data from different PEO and client tax models. Doing so allowed the runtime object to work with the rest of our existing tax filing architecture. We called these runtime objects hybrid taxation models.
The hybrid class creates runtime objects which mimic the
CompanyStateTaxInfo objects but with logic changed for attribute getters. The
__getattr__ function has the logic to correctly return field values related to state from the company and PEO’s legal entity’s state details.
For example: New York (NY) is a PEO reporting state while Arkansas (AK) is a client reporting one. So the hybrid object for NY state SUI of company A will return
account_id of Rippling PEO’s NY state SUI and the hybrid object of AK state SUI of company A will return
account_id of company’s AK state SUI. There are also some states that are mixed reporting where the
account_id is of client’s state tax info but the rate is of PEO’s state tax info.
Implementation of basic hybrid class
Similar hybrid classes were created for other models as well to correctly compute taxes, tax filings, create W2s, etc. The hybrid models made sure we didn’t refactor the major components of the payroll architecture, support complex PEO agency use cases, and saved us significant time in the development of the PEO product.
The PEO recently celebrated 1 year anniversary and the team is growing across the locations and we need engineers to built the product to impact more businesses. By the way, did we mention we’re hiring? Come, join us.