Regulation Deployment
Regulations are distributed as NuGet packages — self-contained archives combining
JSON definitions, C# scripts, and an install manifest. The
Payroll Console
InstallRegulationPackage command reads the package and imports all files into the
backend in the correct order.
Layer Model
The number of regulation layers is freely configurable — payrolls can consist of one layer or many, depending on the use case. The diagram above shows a typical three-layer example with Country, Business, and Tenant regulations. Other common configurations are:
| Configuration | Layers |
|---|---|
| Single-country, single-tenant | Country only |
| Single-country, multi-tenant | Country + Tenant |
| Multi-country provider | Country + Business + Tenant |
| With multi-country consolidation | COM.Base + Country + Consolidation + Business + Tenant |
Each layer may reference lower layers via baseRegulations. The dependency chain is
enforced at install time — installing a package before its dependencies are present in
the target tenant will fail with a clear error listing what is missing.
Package Structure
A regulation package is a standard .nupkg file (ZIP format) containing two parallel
sets of the same files:
Embedded resources — compiled into the DLL for use by PayrollEngine.Client.Scripting
and the Roslyn-based script compiler at runtime.
regulation/ folder — plain files inside the ZIP, read directly by
InstallRegulationPackage without loading the DLL.
MyRegulation.nupkg
├── lib/net10.0/MyRegulation.dll ← embedded resources (JSON + scripts)
└── regulation/
├── regulation-package.json ← install manifest
├── Regulation/
│ ├── MyRegulation.2026.json
│ ├── MyRegulation.Cases.2026.json
│ └── MyRegulation.WageTypes.2026.json
└── Scripts/
└── WageTypeValueFunction.Action.cs
Install Manifest
Every package contains a regulation-package.json that defines the install metadata
and the ordered list of files to import:
{
"packageId": "Acme.Regulation.Country.2026.1",
"regulationName": "Acme.Country",
"version": "2026.1",
"baseRegulations": [],
"installFiles": [
"Regulation/Country.2026.json",
"Regulation/Country.Cases.2026.json",
"Regulation/Country.Collectors.2026.json",
"Regulation/Country.WageTypes.2026.json",
"Regulation/Country.Data.Tax.2026.json",
"Regulation/Country.Data.SocialInsurance.2026.json"
]
}
The first file creates the regulation structure; all subsequent files extend it. Data regulations (annual tax rates, statutory parameters) are always last — they can be updated independently without touching the calculation logic.
InstallRegulationPackage Command
InstallRegulationPackage <packageFile|url> <tenant> [/new|/overwrite] [/execute|/dryrun]
| Step | Description |
|---|---|
| 1. Resolve source | Downloads package if URL; resolves wildcard to single file if local path |
| 2. Open package | Reads .nupkg as a ZIP archive |
| 3. Read manifest | Loads regulation/regulation-package.json |
| 4. Resolve tenant | Fails if tenant not found in backend |
| 5. Version check | /new: fails if regulation exists; /overwrite: logs overwrite active |
| 6. Dependency check | Queries backend for each baseRegulations entry — lists all missing |
| 7. DryRun exit | /dryrun: reports what would be imported, no changes made |
| 8. Import in order | Imports each file via the REST API in manifest order |
Examples:
# Fresh install
InstallRegulationPackage Acme.Regulation.Country.2026.1.nupkg MyTenant
# Validate only — no changes
InstallRegulationPackage Acme.Regulation.Country.2026.1.nupkg MyTenant /dryrun
# Mid-year data update
InstallRegulationPackage Acme.Regulation.Country.2026.2.nupkg MyTenant /overwrite
# Wildcard — single match
InstallRegulationPackage Acme.Regulation.Country.*.nupkg MyTenant /dryrun
# Install directly from a URL (e.g. GitHub Release asset)
InstallRegulationPackage https://github.com/Acme/Regulation/releases/download/v2026.1/Acme.Regulation.Country.2026.1.nupkg MyTenant
InstallRegulationPackage https://github.com/Acme/Regulation/releases/download/v2026.1/Acme.Regulation.Country.2026.1.nupkg MyTenant /dryrun
Example install order for a multi-country setup:
# 1. Shared COM schema — no dependencies
InstallRegulationPackage Acme.Regulation.COM.Base.2026.1.nupkg ComTenant
# 2. Country regulation — no dependencies
InstallRegulationPackage Acme.Regulation.Country.2026.1.nupkg CountryTenant
# 3. Consolidation — depends on COM schema + Country
InstallRegulationPackage Acme.Regulation.Country.Consolidation.2026.1.nupkg CountryTenant
# 4. Business regulation — depends on Country
InstallRegulationPackage Acme.Regulation.Business.2026.1.nupkg BusinessTenant
Shared Regulations
Country and consolidation regulations are marked sharedRegulation: true in their
JSON definition. This allows a single regulation instance to be
shared across multiple tenants via the Regulation
Sharing API — one import serves all tenants, with no per-tenant reimport needed on
annual updates.
{
"name": "Acme.Country",
"namespace": "Country",
"sharedRegulation": true,
"validFrom": "2026-01-01T00:00:00Z"
}
NuGet Reference Chain
Packages reference each other as NuGet dependencies, following the same layer order:
PayrollEngine.Client.Scripting
↑
Acme.Regulation.COM.Base
↑
Acme.Regulation.Country
↑
Acme.Regulation.Country.Consolidation
↑
Acme.Regulation.Business
↑
Acme.Regulation.Tenant
This ensures that when a package is built, all its upstream dependencies are already available as versioned NuGet packages — locally from a packages folder during development, or from GitHub Packages in CI/CD.
Versioning
Regulation packages use calendar-semantic versioning: {Year}.{Revision}.
| Version | Meaning |
|---|---|
2026.1 |
First release for tax year 2026 |
2026.2 |
Mid-year update (e.g. minimum wage adjustment) |
2026.3 |
Correction after legislative change |
2027.1 |
Tax year 2027 |
Pre-release suffixes are supported: 2026.1-beta.1. Annual data regulations
(tax tables, statutory rates) are updated by importing a new data regulation with
a matching validFrom date — the calculation logic regulation remains unchanged.
See Also
- Regulations
- Regulation Design
- Payroll Console
- Country Regulation Template — GitHub template for new country regulation repos