Tenure
Multi-tenant enterprise HRMS & recruitment platform
One platform covering the entire employee lifecycle — requisition to offboarding — for many client organisations at once. Twenty independently owned domain modules over a shared datastore, with tenant scoping enforced at the data-access layer, enterprise SSO, and automated user provisioning from day one.
The problem
Mid-size and enterprise HR teams run the employee lifecycle across a dozen disconnected tools: one for hiring, another for attendance, spreadsheets for payroll inputs, email for approvals. Nothing reconciles, and every new client organisation means another isolated deployment to maintain. Service length — the thing every entitlement, gratuity and vesting calculation depends on — ends up recomputed by hand, differently, in each tool.
Our approach
Tenure is a single multi-tenant NestJS application composed of twenty independently owned domain modules over a shared MongoDB, with tenant scoping enforced at the data-access layer rather than trusted to callers. Long-running work — imports, document generation, webhook delivery — is pushed onto a BullMQ queue so request latency stays flat. A single Flutter codebase serves web, iOS, Android and desktop clients, which keeps the surface area of the UI work proportional to one product rather than four.
The outcome
A platform that onboards a new client organisation as a configuration change instead of a deployment, and integrates into an existing enterprise identity estate on day one via SAML, Entra ID and SCIM.
What is inside
20 domain modules: recruitment, onboarding, employees, attendance & leave, payroll, performance, LMS, engagement, service desk, offboarding, documents, billing and more
Strict multi-tenant isolation with per-tenant configuration, org structure and billing
Enterprise identity: SAML 2.0, Azure AD / Entra ID through MSAL, and SCIM 2.0 user provisioning
Background pipeline on BullMQ + Redis for bulk imports, exports and document generation
Outbound webhooks with retry/backoff plus a scoped client API secured by rotatable integration keys
Real-time notifications and presence over Socket.IO
Immutable audit log across privileged actions, with a super-admin control plane
One Flutter codebase targeting web (embeddable), iOS, Android and desktop
Engineering notes · 5 min read
Twenty modules, one deployment
20
Domain modules
independently owned4
Client platforms
one Flutter codebaseConfig
New tenant
not a deploymentThe usual way to serve many client organisations is to deploy the application many times. It works until the eleventh customer, at which point every patch is eleven releases and every incident is a question about which version someone is on.
Tenure is one deployment. That decision moves the entire risk profile onto one thing: tenant isolation. If scoping is a convention that callers are trusted to follow, one forgotten filter is a cross-tenant data leak in a system holding salary and disciplinary records.
Isolation belongs below the callers
- Tenant scoping enforced at the data-access layer, not in each service that remembers to ask
- Per-tenant configuration, organisation structure and billing, so tenants can genuinely differ
- Immutable audit log over privileged actions, with a separate super-admin control plane
- Integration keys are per-tenant and rotatable, so revoking one customer’s access is not a deploy
Service length is the number everything else depends on
Gratuity, leave accrual, notice periods and vesting all resolve from one quantity: how long someone has actually worked here. In a fragmented HR estate that number is recomputed in four tools, four different ways, and they disagree by a few days each.
Modelling it once — with joining date, confirmed probation, unpaid leave and any break in service as explicit events — is why the tenure timeline is the demo’s signature screen. It is the one place where you can see the calculation rather than being told its result.
| Operation | Naive | Tenure |
|---|---|---|
| Import 4,000 employees | Request times out | Queued job, progress polled |
| Generate 300 contracts | Blocks a worker for minutes | Queued, retried on failure |
| Deliver a webhook to a slow endpoint | Ties up the request | Queued with backoff |
Enterprise identity was treated as a launch requirement rather than a later integration: SAML 2.0, Entra ID through MSAL, and SCIM 2.0 provisioning. An HR platform that cannot join an existing identity estate on day one does not get evaluated twice.
Back end
Data
Client
Integrations
Platforms
Web · iOS · Android · Desktop
Need a platform like Tenure?
We can walk you through how this was built, what it cost to run, and what the equivalent looks like for your business.
Or email us directly at [email protected]