Releases: Payroll-Engine/PayrollEngine
PayrollEngine v1.0.0
Payroll Engine — Release Notes
v1.0.0 - Apr 2026
Highlights
- Wage type caches —
WageTypeCycleCacheandWageTypeConsolidatedCycleCachebulk-load cycle and consolidated wage-type results once per employee when wage types are tagged via the corresponding payroll cluster sets, reducing database round-trips during payrun scripts PasswordAvailable— user API and client models expose whether a password is set without transferring the hash- Exchange import — payrun jobs that end with
Abort/CancelandCompletedJobStatus=Abortare treated as an expected test outcome during import, not as a hard import failure
Backend
Database Update required — run the Update-Model scripts (SQL Server and MySQL) from schema 0.9.7 → 1.0.0 before starting the backend. The nine Payroll columns ClusterSetCase, ClusterSetCaseField, ClusterSetCollector, ClusterSetCollectorRetro, ClusterSetWageType, ClusterSetWageTypeRetro, ClusterSetCaseValue, ClusterSetWageTypePeriod, and ClusterSetWageTypeLookup are replaced by a single ClusterSet JSON column; existing data is migrated in the scripts. The persistence layer enforces minimum schema version 1.0.0 — the backend will not start against a pre-1.0.0 database.
New Features
WageTypeCycleCache— for wage types tagged viaPayroll.ClusterSet.ClusterSetWageTypeCycle,GetWageTypeResultsdata for the cycle/YTD path is loaded in bulk once per employee at payrun employee start; the cache is reset and reloaded before retro re-evaluationWageTypeConsolidatedCycleCache— for wage types tagged for the consolidated cache,GetConsolidatedWageTypeResultsis bulk-loaded once per employee; calls withnoRetro=truebypass the cache by designPasswordAvailablein the user API response — derived from the stored hash in memory; the password hash remains[JsonIgnore]on the model
Bug Fixes
- ClusterSet persistence — pre-serialize
ClusterSetas PascalCase JSON before write to avoidsql_variantconversion issues; registerJsonObjectTypeHandler<PayrollClusterSets>for correct Dapper deserialization on read - Payrun jobs —
CompletedJobStatus=Abortis no longer applied to successfully completed jobs; abort remains reserved for processor failures and expected-abort test scenarios PayrunProcessorSettings— XML documentation forMaxParallelPersistdefault corrected (validated by load tests)
Breaking Change
- Database schema 1.0.0 —
Payrollcluster-set columns consolidated into oneClusterSetJSON column; breaking change (see Database Update above)
Libraries
- Client.Core —
IPayroll/Payroll: individualClusterSet*string properties replaced by a singleClusterSetproperty of typePayrollClusterSetsbreaking change;PasswordAvailableonIUser/User; ExchangeImport honors intentional abort status for test expectations; project references use$(Version)for PE dependencies; release workflow no longer patches versions withsed - Client.Scripting — fixed double-encoding of strings in
PayrunFunction; GitHub Actionspages.ymlpatches PE dependency versions before build
Breaking Change
- JSON schema (
PayrollEngine.Exchange.schema.json) — the former top-levelPayrollpropertiesclusterSetCase,clusterSetCaseField,clusterSetCollector,clusterSetCollectorRetro,clusterSetWageType,clusterSetWageTypeRetro,clusterSetCaseValue, andclusterSetWageTypePeriodare removed; the same references must appear underclusterSet(PayrollClusterSets). Existing payroll JSON files used for import/export must be migrated — breaking change
📦 NuGet Packages (v1.0.0)
| Package | GitHub Packages | NuGet.org |
|---|---|---|
| PayrollEngine.Core | 1.0.0 | 1.0.0 |
| PayrollEngine.Serilog | 1.0.0 | 1.0.0 |
| PayrollEngine.Document | 1.0.0 | 1.0.0 |
| PayrollEngine.Client.Core | 1.0.0 | 1.0.0 |
| PayrollEngine.Client.Scripting | 1.0.0 | 1.0.0 |
| PayrollEngine.Client.Test | 1.0.0 | 1.0.0 |
| PayrollEngine.Client.Services | 1.0.0 | 1.0.0 |
| PayrollEngine.Mcp.Core | 1.0.0 | 1.0.0 |
| PayrollEngine.Mcp.Tools | 1.0.0 | 1.0.0 |
🐳 Docker Images (Linux)
| App | Version | Pull Command |
|---|---|---|
| PayrollEngine.Backend | 1.0.0 | docker pull ghcr.io/payroll-engine/payrollengine.backend:1.0.0 |
| PayrollEngine.PayrollConsole | 1.0.0 | docker pull ghcr.io/payroll-engine/payrollengine.payrollconsole:1.0.0 |
| PayrollEngine.WebApp | 1.0.0 | docker pull ghcr.io/payroll-engine/payrollengine.webapp:1.0.0 |
| PayrollEngine.Mcp.Server | 1.0.0 | docker pull ghcr.io/payroll-engine/payrollengine.mcp.server:1.0.0 |
PayrollEngine v0.10.0-beta.4
Bug Fixes
Features
-
Payrun.RetroTimeType(enum) replaced byPayrun.RetroBackCycles(int):-1= unlimited (default),0= current cycle only,n= n previous cycles breaking changePayrollResultdenormalized with business-key string fields:PayrunName,PayrunJobName,EmployeeIdentifier,PayrollName,DivisionName— enables archive restore idempotency and self-describing results (consistent with existingCycleName/PeriodNamepattern)- New
POST /payruns/jobs/importendpoint — importsPayrunJobSet[](payrun job + result sets) into a tenant; Phase 1a resolves all references (Payrun, Division, User, Employee) by business-key names (422on failure); Phase 1b checks for duplicate payrun job names (409on conflict); Phase 2 inserts in aTransactionScope— payrun job first, then result sets with new job ID; full rollback on failure (use cases: archive restore, tenant migration, system migration, staging seeding) - OData
any()lambda operator — filters on JSON collection columns (List<string>,List<int>, etc.) using correlatedEXISTSsub-queries; supports scalar arrays and key/value object arrays - OData
inoperator — value-set filter (field in (v1, v2, ...)) mapped to SQLWHERE col IN (...) - Both operators are backend-aware: SQL Server uses
OPENJSON, MySQL usesJSON_TABLE - MySQL support:
IDbContext.BuildCollectionFromRawabstracts theOPENJSON/JSON_TABLEdifference TenantIsolationLevelserver-wide policy — newTenantIsolationFilterenforces cross-tenant HTTP access control on every request:None(transparent),Consolidation(report scripts only),Read(GET + ReadSemantic POST cross-tenant),Write(full cross-tenant,Auth-Tenantheader forbidden). Configured inappsettings.json. See SecurityRegulationShare.IsolationLevel— new field controlling access granted to the consumer tenant:Consolidation(cross-tenant result access for report scripts, regulation not added as payroll layer) orWrite(full payroll layer, default)Report.ReportIsolation— new field onReport; exposed viaGetDerivedReportsto allow per-report access control aligned withTenantIsolationLevel- Database Update required — run
ModelUpdate.sql(SQL Server, schema0.9.6 → 0.9.7) or apply the equivalent changes manually (MySQL) before starting the backend.
-
- Division isolation:
list_employeesnow pushes the division filter to the backend viadivisions/any(d: d eq 'DivisionName')— eliminates client-side post-filtering
- Division isolation:
-
Mcp.Core (new)
- Core infrastructure for building Payroll Engine MCP servers: isolation model (
MultiTenant,Tenant,Division,Employee), role-based permission system (HR,Payroll,Report,System),ToolBaseabstract base class with typed service factories, isolation-aware query helpers and resolver methods,ToolRegistrarfor startup-time tool filtering by role and isolation level compatibility
- Core infrastructure for building Payroll Engine MCP servers: isolation model (
-
Mcp.Tools (new)
- Complete set of read-only MCP tools built on
Mcp.Core: 27 tools across HR, Payroll, Report and System roles; all tools are read-only by design (get_employee_pay_previewandexecute_payroll_reportexecute calculations without persisting results)
- Complete set of read-only MCP tools built on
-
RetroTimeTypeenum removed — replaced byPayrun.RetroBackCycles(int) breaking change
-
- WageType and Collector temporal selectors in action syntax — new scope properties on
^$WageTypeand^$Collectortokens:.PrevPeriod,.NextPeriod,.Cycle,.PrevCycle,.NextCycle; additionally.RetroSumfor WageTypes (sum of retro corrections within the current cycle) - New
Calculationaction group — 15 standard payroll calculation actions onPayrunFunction:AnnualProjection,CycleToPeriod,PeriodToCycle,RoundToFraction,CappedContribution,RateContribution,LookupRateContribution,PhaseOut,LinearPhaseOut,PhaseIn,ProRateByDays,InsuranceWage,D2Delta,MinMaxContribution,ContributionIfObligated - New
GetConsolidatedWageTypeValueandGetConsolidatedCollectorValueactions — period-offset based consolidation (e.g.-11for a 12-period rolling window)
- WageType and Collector temporal selectors in action syntax — new scope properties on
-
- New
PayrunEmployeePreviewTestcommand — executes an employee payrun preview (no persistence) and tests the results - New
InstallRegulationPackagecommand — installs a regulation NuGet package (.nupkg) directly into a PE backend tenant. Supports local file paths, wildcards, and HTTP(S) URLs (e.g. GitHub Release assets). Features: version check, cross-tenant dependency check, ordered manifest-driven import, dry-run mode, and automatic temp cleanup. HttpGet: optional second parameter writes response body to a fileHttpPost/HttpPut:Content-Typeset toapplication/json(wastext/plain→ HTTP 415)- URL placeholder resolution in HTTP commands:
{tenant:X},{user:X},{division:X},{employee:X},{regulation:X},{payroll:X},{payrun:X},{payrunJob:X}resolved to numeric IDs at runtime
- New
-
- New
PayrunJobImport.Test— full export → delete → import → verify cycle forPOST /payruns/jobs/import
- New
📦 NuGet Packages (v0.10.0-beta.4)
| Package | GitHub Packages | NuGet.org |
|---|---|---|
| PayrollEngine.Core | 0.10.0-beta.4 | pending sync |
| PayrollEngine.Serilog | 0.10.0-beta.4 | pending sync |
| PayrollEngine.Document | 0.10.0-beta.4 | pending sync |
| PayrollEngine.Client.Core | 0.10.0-beta.4 | pending sync |
| PayrollEngine.Client.Scripting | 0.10.0-beta.4 | pending sync |
| PayrollEngine.Client.Test | 0.10.0-beta.4 | pending sync |
| PayrollEngine.Client.Services | 0.10.0-beta.4 | pending sync |
| PayrollEngine.Mcp.Core | 0.10.0-beta.4 | pending sync |
| PayrollEngine.Mcp.Tools | 0.10.0-beta.4 | pending sync |
🐳 Docker Images (Linux)
| App | Version | Pull Command |
|---|---|---|
| PayrollEngine.Backend | 0.10.0-beta.4 (pre-release) | docker pull ghcr.io/payroll-engine/payrollengine.backend:0.10.0-beta.4 |
| PayrollEngine.PayrollConsole | 0.10.0-beta.4 (pre-release) | docker pull ghcr.io/payroll-engine/payrollengine.payrollconsole:0.10.0-beta.4 |
| PayrollEngine.WebApp | 0.10.0-beta.4 (pre-release) | docker pull ghcr.io/payroll-engine/payrollengine.webapp:0.10.0-beta.4 |
| PayrollEngine.Mcp.Server | 0.10.0-beta.4 (pre-release) | docker pull ghcr.io/payroll-engine/payrollengine.mcp.server:0.10.0-beta.4 |
PayrollEngine v0.10.0-beta.3
Bug Fixes
-
CasePayrollValue: fixedFindMatchingPeriodValue— added left-contains-right containment branch for retro payruns where aPeriodfield (open-ended,End=MaxValue) appears on the left side of a binary operator and aCalendarPeriodfield (trimmed end) on the right; previously the match returnednullsilently, causing all operators (+,-,*,/,%) to returnEmptyand the payrun to fail withMissing results
-
- Fixed concurrent assembly load collision in
AssemblyCache— replaced lock-free double-entry with a proper lock to prevent race conditions during parallel payrun execution - Fixed
CaseValueRepositoryBase.GetPeriodCaseValuesAsyncperiod filter: changed<to<=forStartboundary, ensuring period-edge case values are included correctly
- Fixed concurrent assembly load collision in
-
- Fixed report template encoding: changed ASCII to UTF-8 for XSL, XSD and FRX streams
- Fixed payrun job workflow: Draft panel now displayed correctly after job start and on page reload
-
WeekPayrollCycle: migrated from removedIPayrollCalendartoCultureInfo/Calendar— aligns withWeekPayrollPeriod,MonthPayrollPeriod, andYearPayrollCycle
-
CumulativeJournal: fixed monthly result columns typed as decimal
Features
-
- MySQL 8.4 LTS support via new
Persistence.MySqlprovider (preview) — activate withPayrollServerConfiguration__DbProvider=MySql MaxParallelEmployeesdefault changed from sequential to auto (ProcessorCount) breaking change — useoffor-1to restore sequential behavior- values:
0/empty = auto,off/-1= sequential,half= ProcessorCount/2,max= ProcessorCount,1–N= explicit
- values:
GET /api/admin/information— new endpoint returning backend server diagnostics- Assembly: version, build date
- API: version, name
- Authentication: mode (
None/ApiKey/OAuth); OAuth authority and audience (no secrets exposed) - Database: type, catalog name, server version, edition
- Runtime:
MaxParallelEmployees(resolved integer),MaxRetroPayrunPeriods, command/transaction/cache/webhook timeouts,ScriptSafetyAnalysis, audit trail flags, CORS origins, rate limiting policies
IDbContextextended withGetDatabaseInformationAsync()returningDatabaseInformation(type, name, catalog, version, edition)ReportIsolation— new domain model and audit: report execution can be scoped toNone,Global,Company,Division, orEmployee
- MySQL 8.4 LTS support via new
-
MCP Server (new, preview)
- AI agent interface for payroll data queries — read-only by design, no mutation operations
- stdio transport via Model Context Protocol; compatible with Claude Desktop, GitHub Copilot, Cursor, and other MCP clients
- 29 tools in 4 roles:
System— tenant and user queries (list_tenants,get_tenant,get_tenant_attribute,list_users,get_user,get_user_attribute)HR— employee master data, case values, and audit trail (list_divisions,get_division,get_division_attribute,list_employees,get_employee,get_employee_attribute,list_employee_case_values,list_company_case_values,list_employee_case_changes,list_company_case_changes)Regulation— regulation definitions (list_regulations,get_regulation,list_wage_types,list_lookups,list_lookup_values)Payroll— payroll execution and results (list_payrolls,get_payroll,list_payruns,list_payrun_jobs,list_payroll_wage_types,list_payroll_result_values,get_consolidated_payroll_result,get_case_time_values)
- Enrichment: employee context (
identifier,firstName,lastName) injected into all employee-scoped results; division name lookup inlist_payrun_jobs;list_payroll_result_valuesfully denormalized get_case_time_valuessupports three temporal perspectives: Historical, Current knowledge, Forecast- Access control: role-based permissions (
McpRole/McpPermission) and isolation levels (MultiTenant,Tenant) configurable per deployment viaappsettings.jsonor environment variables - Docker image available;
claude_desktop_config.jsonexample included
-
- New
PayrunPreviewRetroException, replaced SHA1 with SHA256, regex timeout for ReDoS prevention, stream and DataTable fixes IDocumentServicewithGenerateAsync,MergeAsyncandExcelMergeAsyncApplyproperty added toQuery;ApplyOperationadded toQuerySpecification- New
ReportIsolationenum (None,Global,Company,Division,Employee)
- New
-
AdminService— new service (IAdminService) withGetBackendInformationAsync()callingGET /api/admin/informationBackendInformationmodel hierarchy:BackendAuthInformation,BackendDatabaseInformation(incl.Edition),BackendRuntimeInformation,BackendAuditTrailInformation,BackendCorsInformation,BackendRateLimitingInformationApiEndpoints.AdminInformationUrl()— new endpoint constantIAttributeServiceadded toIDivisionService,ITaskService,IRegulationService,IReportService— consistent attribute URL endpoints and service implementations across all object typesReportIsolationadded toIReportinterface andReportmodel — synchronized with API model
-
IDocumentService.GenerateAsync— generates a schema document (.frxskeleton) from a DataSet or rebuilds the Dictionary section of an existing template (CI mode), preserving all design elements
-
- New
PayrunEmployeePreviewTestRunnerfor preview-based payrun testing without persisting results PayrunTestRunnerrefactored:ImportAsyncandTestAsyncare now separate phases, enabling independent re-test without re-import
- New
-
ReportBuild— executes a report and generates a schema document for template design; format-agnostic, output extension derived fromTemplateFile- without
TemplateFile: generates new skeleton from DataSet - with
TemplateFile(CI mode): updates schema section, preserving layout
- without
PayrunLoadTest: optional Excel report alongside CSV/ExcelReport— write.xlsxwith derived filename/ExcelFile=<path>— explicit Excel output path/ParallelSetting=<v>— documents backendMaxParallelEmployeesin the Excel setup sheet- Excel contains three sheets: Setup (machine, OS, ProcessorCount, MaxParallelEmployees), Results (formatted CSV), Avg ms/Employee (pivot with outlier highlighting)
PayrunLoadTest: optional Markdown report alongside CSV/MarkdownReport— write.mdwith derived filename/MarkdownFile=<path>— explicit Markdown output path- Report sections: Test Summary (median timing, per-run breakdown table, ms/Employee and Employees/h columns) and Test Infrastructure
- Computer: machine name, OS, framework, CPU model (Windows Registry), CPU cores, RAM total + available (Windows:
GlobalMemoryStatusEx), disk total + free - Console: version, build date
- Backend: version, build date, API version, auth mode, max parallel employees, timeouts, script safety analysis, database (type/name/version/edition), audit trail flags, CORS origins, rate limiting policies — sourced from
GET /api/admin/information
- Computer: machine name, OS, framework, CPU model (Windows Registry), CPU cores, RAM total + available (Windows:
-
ConsolidatedEdge.Test(new) —NoRetroflag isolation inGetConsolidatedWageTypeResults:NoRetro=falsereturns the retro-corrected prior value;NoRetro=truereturns the original main-run valuePayrunTag.Test(new) —GetWageTypeResultstag-filter isolation: Alpha-tagged retro sub-run result queryable by tag; non-existent tag returns zeroMultiDivision.Test(new) — division-scoped case value isolation (valueScope: Division): same employee across two divisions, each payroll resolves its own salary independently
-
TemporalPayroll— new example demonstrating the two independent time axes of case value resolutionperiodStart(valueDate): which value was active on a given dateevaluationDate: which entries were known on a given date- 7 payrun jobs cover a 2×2 retro matrix (past/today × past/today) and 3 forecast scenarios including a forecast entry with validity window expiry
- minimal regulation (one case field, one wage type, one No-Code action) — all complexity lives in the payrun invocations
ReportPayroll— newPayslipreport: single-employee payslip with current-month value, retro column, and YTD accumulation- parameters:
PayslipYear,PayslipMonth(zero-padded, e.g.03),EmployeeIdentifier(optional employee filter) ReportEndFunctionaccumulates months 1..N viaGetConsolidatedWageTypeResults; buildsValue,YtdValue,RetroValuecolumns- columns:
Name(WageTypeName - WageTypeNumber) ·Amount·Retro·YTD - A4 portrait template with full-width employee card header; negative values in red, retro ad...
- parameters:
PayrollEngine v0.10.0-beta.1
Features
-
General
- Internal tooling and infrastructure improvements
- Updated exchange schema (
PayrollEngine.Exchange.schema.json)
-
Website
- New documentation website at payrollengine.org, replacing the GitHub Wiki
- Role-based structure: Provider (REST API), Regulator (No-Code/Low-Code), Automator (Client Services)
- White Paper content integrated into the documentation; standalone PDF removed
-
Examples
- New self-contained payroll examples — each includes regulation, case data, payrun jobs, and a test file
- Tutorial:
StartPayroll— incremental three-layer regulation build (JSON + YAML variants) - Business Scenarios
GlobalPayroll— age supplement, one-time bonus, progressive taxMultiCountryPayroll— DE/FR/NL with shared base regulation and split employeeMinWagePayroll— automatic top-up via year-versioned lookup, fully No-CodePartTimePayroll— overtime guard and retroactive level correction, fully No-CodeForecastPayroll— parallel what-if scenarios without regulation change, fully No-CodeMarchClausePayroll— German Märzklausel Q1 bonus routing via Low-Code extension methods
- Retro Corrections:
RetroPayroll— positive deltas, late Moment entry, cascading correction - Data Import:
TaxTablePayroll— ~7 100 records bulk import with range-based withholding tax
-
Tests
- New
PayrunEmployeePreview.Test— payrun job preview without persisting results - New
WageTracingPayroll.Test— wage calculation traceability viaclusterSetWageTypePeriod - New
RetroPayMode.Test—retroPayModeNone vs. ValueChange: verifies thatNonesuppresses retro sub-runs even when prior-period mutations are detected, whileValueChangetriggers them - New
Collector.Test— collector features: multi-source accumulation,maxResultcap (3 jobs),minResultfloor,negatedsign inversion - New
PayrunEdge.Test— payrun date boundary and temporal edge cases: period boundaries, retro trigger viacreated/evaluationDatealignment, Period touching, CalendarPeriod overlap, mid-period split,evalDate==PeriodStart/PeriodEnd/CycleEnd, forecast
- New
-
CI/CD Pipeline
- New orchestrated release pipeline with wave-based build ordering
- Single-click release for all libraries and applications via GitHub Actions
- Version guard prevents accidental overwrites of existing releases, packages, and tags
Directory.Build.propsis auto-updated, committed, and tagged by the workflow- Dry-run mode for pipeline testing without side effects
RELEASE_NOTES.mdas single source for release text (umbrella release + wiki)- New
ci.ymlworkflow for build and test on pull requests and pushes tomain - New
devops/scriptswith release preparation tooling:Update-BreakingChanges.ps1— automated breaking change detection across REST API, Backend, Scripting, and Client Services surfacesRelease-Changelog.ps1— cross-repo changelog collection with conventional commit parsingUpdate-CommitMessage.ps1— pre-fills Git commit message fromRELEASE_NOTES.mdfor Visual Studio
- New
devops/scriptswith database schema tooling:Export-DbScript.ps1— exports the live SQL Server schema to a.sqlfile (Create or Delete mode) viaPayrollDatabaseConnectionFormat-DbScript.ps1— normalises GO delimiters and topologically sorts DDL objects to eliminate forward-reference warningsCompare-DbScript.ps1— diffs two formatted.sqlfiles and generates an incremental update script (Added / Removed / Modified)Generate-DbUpdate.ps1— orchestrates Format + Compare in one step to generate an update script from any two SQL filesCompose-DbScript.ps1— injects version-check and version-set blocks into Create and Update scripts from a JSON config
-
NuGet Packages
- GitHub Packages as primary NuGet source for all
PayrollEngine.*packages - New
nuget.configwith package source mapping (PayrollEngine.*→ GitHub Packages,*→ NuGet.org) - Dedicated sync workflow for selective NuGet.org publishing
- GitHub Packages as primary NuGet source for all
-
Docker
- Automated Linux container builds for Backend, PayrollConsole, and WebApp
- Images published to
ghcr.io/payroll-engine/* - Pre-release images skip the
:latesttag
-
- Payrun job preview endpoint (
POST .../payruns/jobs/preview)- synchronous single-employee payrun calculation without persisting results
- returns
PayrollResultSetwith wage type, collector, and payrun results - preview accepts any
RetroPayModeto match production behavior; returns HTTP 422 if retro is triggered - new
PayrunPreviewRetroExceptionwith employee identifier and retro date context - runs in-memory only — no payrun job or result records written to the database
- Refactored
PayrunJobInvocationfrom id-based to name/identifier-based references breaking change- removed
PayrunIdandUserIdproperties from API and domain models PayrunNameandUserIdentifierare now the required fields- payrun and user resolution by name/identifier in
PayrunProcessorand controller - retro job invocations use
Payrun.NameandUser.Identifierinstead of ids
- removed
- Asynchronous payrun job processing with background queue
PayrunJobQueuewith bounded channel for backpressure (capacity: 100)PayrunJobWorkerServiceasBackgroundServicefor job dequeuing and processing- job pre-created and persisted before enqueue, returns HTTP 202 with location header
- infrastructure abort on unhandled exceptions or service shutdown
- webhook notification on job completion or abort
- Configurable parallel employee processing (
MaxParallelEmployees)- values:
0/off(sequential, default),half,max,-1(automatic),1–N(explicit) - per-employee
PayrunEmployeeScopefor mutable state isolation in parallel mode - thread-safe progress reporting with batched DB persistence (every 10 employees)
- payroll calculator cache with
Lazy<T>and composite key (calendar+culture) for thread-safe reuse
- values:
- Employee processing timing logs (
LogEmployeeTiming)- per-employee duration and summary (mode, total, average) logged at Information level
- Bulk employee creation endpoint (
POST .../employees/bulk)- accepts
Employee[], usesSqlBulkCopyfor high-throughput insert (5'000 item chunks) - generic
CreateBulkAsyncinRepositoryChildObjectControllerfor reuse across entity types - returns created item count (no individual IDs); duplicate identifiers caught by DB unique constraint
- accepts
- Retro payrun period limit (
MaxRetroPayrunPeriods, default: 0/unlimited)- safety guard to prevent runaway retro calculations with
RetroTimeType.Anytime
- safety guard to prevent runaway retro calculations with
- CORS configuration (
Cors)- configurable AllowedOrigins, AllowedMethods, AllowedHeaders, AllowCredentials, PreflightMaxAgeSeconds
- inactive by default (no cross-origin requests allowed)
- Rate limiting (
RateLimiting)- global policy for all endpoints and dedicated policy for payrun job start endpoint
- configurable PermitLimit and WindowSeconds per policy
- Configurable authentication (
Authentication)- supports three modes:
None,ApiKey,OAuth - OAuth with Authority, Audience, RequireHttpsMetadata, ClientSecret
- startup validation for OAuth authority and audience to prevent token confusion
- environment variable fallback for API key
- supports three modes:
- Explicit Swagger toggle (
EnableSwagger, default: false) - Per-category audit trail configuration (
AuditTrail)- replaced single
AuditTrailDisabledbool with granular flags: Script, Lookup, Input, Payrun, Report
- replaced single
- Script safety analysis (
ScriptSafetyAnalysis, default: false)- static analysis of user scripts for banned API usage (System.IO, System.Net, System.Diagnostics, System.Reflection)
- opt-in via appsettings due to compilation overhead
- Configurable database collation check (
DbCollation, default: SQL_Latin1_General_CP1_CS_AS)- verified on startup in
TestVersionAsyncbefore the schema version check - prevents silent data integrity issues from mismatched collation
- verified on startup in
- Added
ConsolidatedPayrunResultQueryfor consolidated payrun result queries - Updated database scripts (ModelCreate, ModelDrop, ModelUpdate) for schema version 0.9.6
- Added database script history — previous schema versions archived under
Database/History/v{version} - Added production
UseExceptionHandlermiddleware for structured JSON error responses
- Payrun job preview endpoint (
-
- New
PayrunEmployeePreviewTestcommand for testing payrun job preview results - New
PayrollMergecommand — merges multiple payroll files (JSON or YAML) into a single file- supports file masks (e.g.
*.yaml,*.json) - toggle
/top(default) or/recursivefor directory scope
- supports file masks (e.g.
- Built-in load test commands for payrun performance testing
LoadTestGenerategenerates scaled exchange files from any regulation templateLoadTestSetupbulk-imports employees viaCreateEmployeesBulkAsyncLoadTestSetupCasesbulk-imports case changes viaAddCasesBulkAsync(replaces slowPayrollImportfor load test setup)PayrunLoadTestexecutes payrun with warmup, measured repetitions, and CSV report (client + server timing)
- New
.pecmdfile type registration scripts included in the release packageRegister-PecmdExtension.ps1— Windows (user-level, no admin required)register-pecmd.sh— Linux (MIME + desktop integration) and macOS (shell wrapper)
- New
-
- Updated MudBlazor to v9.1.0
- Fixed SSL certificate validation bypass with config-controlled
AllowInsecureSslsetting - Fixed
HttpClientsingl...
v0.9.0-beta.17
-
- Added OAuth support, configurable in
appsettings.json. - Assembly cache: added tenant isolation
- Added OAuth support, configurable in
-
- All import, export, and test commands now support for
YAML. - New command
PayrollConvert.- Converts payroll files between
JSONandYAML. - Support for file masks and recursive conversions.
- Converts payroll files between
- Wiki: updated examples to
YAML.
- All import, export, and test commands now support for
-
Client Services
- New
YamlReaderandYamlWriterto read and writeYAMLfiles. - Support for JSON schema embedding in YAML files.
- New
v0.9.0-beta.16
-
Lookup Range Brackets
- New objects lookup range result containing a list of lookup range brackets.
- Each bracket is defined by a numeric range from
RangeStarttoRangeEndincluding the lookup key and value. - The
RangeValuefield in each bracket contains the distributed value for progressive lookups, as well as the amount used from the matching bracket. - For an example check the Lookup test.
-
Scripting API
- Payroll function: added acces to the lookup range bracktes.
- Payroll function: added access the threshold lookup bracket using a range value.
- Payroll function: added access to progressive lookup bracktes using a range value.
-
- Payroll controller: new endpoint to get the payroll lookup ranges.
- Action parser: alternative text added for the logical operators
&&(AND) and operator||(OR). - Regulation audit trail Breaking Change
- The regulation audit trail is now disabled by default.
- Enable the audit trail configuration in
appsettings.json:Script: enable or disbable auditing of scripts.Lookup: enable or disbable auditing of lookups and lookup values.Input: enable or disbable auditing of cases, case fields and case relations.Payrun: enable or disbable auditing of collectors and wage types.Report: enable or disbable auditing of reports, report templates and report parameters.
v0.9.0-beta.15
-
No-Code Actions
- Actions
Min,Max,Range,Contains: support for time range. - New action
Within: test if a value is within a range. - New action
GetTimeSpan: duration between two dates. - New action
YearDiff: calculate years between two dates. - New action
Age: calculate age. - New actions
SameYear,SameMonth,SameDay: test for equal dates. - Action value: added timespan/year/month/day properties.
- Action value: added methods to add and subtract year/month/day/timespan.
- Actions
-
Scripting API
- Payroll function: added properties year/month/day for cycle/period start and end date.
-
- Improved bulk data import performance for lookups.
-
- Regulation page action grid: use italic font style for comments.
v0.9.0-beta.14
- New feature Async payrun job processing Payroll-Engine/PayrollEngine.Backend#6
- Implement asynchronous payrun job processing using Channel and BackgroundService.
- Return HTTP 202 Accepted immediately with Location header for status polling.
- Prevent HTTP 524 timeout errors when processing large payrolls (500+ employees).
- Backend Breaking Changes:
- POST/api/tenants/{id}/payruns/jobsnow returns HTTP202 Acceptedinstead of HTTP201 Created.
- Response includes Location header for status polling.
- Clients must poll status endpoint to determine job completion. - Test library: added support for async payrun jobs.
- Web App payrun jobs page: added support for async payrun jobs.
v0.9.0-beta.13
-
General
- Updated to .NET 10 and C-Sharp 14
- Updated third-party NuGets
-
No-Code Actions
- Actions for collector start, apply and end function
- Actions for wage type value and result function
- Read more
-
Scripting API
- Function: new method to get calendar day count
- Payroll function: added support for the regulation namespace
- Payrun function
- Added get/set payrun result
- Added get wage type name/number by number/name
-
- Updated to OpenApi version 3.1
- Collector and wage type: added actions
- Case field: removed actions
- Regulation: added namespace
- Tenant controller: added an endpoint to retrieve system action properties
- New application setting for HTTPS redirection
- New db stored procedure to delete a lookup
- Updated database to version 0.9.5
- New installation script
Database\ModelCreate.sql - Update from version 0.9.4 script
Database\ModelUpdate.sql
- New installation script
-
- New command lookup text import
- Payroll import command: refactored file mask handling
- Payrun employee test: added result count to the statistics
-
- Regulation item editor: added undo support and save confirmation
- Regulation page: added action support for collector and wage type
- Payrun job page: added virtualization for list selections
- Regulation obejct: added namespace
- Refactored action editor
v0.9.0-beta.12
- Common
Lookup: calculation of wage data (e.g. tax rates) using various methods.Threshold- scaling a value based on a threshold lookup range value.Progressive- value distribution based on lookup value ranges.
- Scripting API
PayrollFunction: new methodApplyRangeValueto calculate lookup range values.
- Backend
- C# compiler: enhanced error message with source file info (first comment).
- Updated database version to 0.9.4.
- Console
- Payroll import: added support for source file mask.