Work
Case Study HR & Workforce Management

Multi-Tenant Time Tracking & HR Platform

Delivered locale-aware schema changes and internationalisation for a Norway-based multi-tenant SaaS timesheet platform serving public and private sector clients.

Overview

A Norway-based software company had built a SaaS timesheet platform used by clients in both the private and public sectors. The platform was expanding to support new locales - different regional date formats, work hour regulations and payroll rules that varied by jurisdiction.

The engagement focused on a specific phase of that expansion: implementing locale-based schema changes in the PostgreSQL multi-tenant database and building out the internationalisation layer in the React frontend to support the new regions without breaking existing tenants.

What We Built

Locale-based schema migration (PostgreSQL)

The database used a shared schema with tenant isolation via tenant_id foreign keys - a common multi-tenant pattern that minimises operational overhead compared to per-tenant schemas. Adding locale support required new fields and lookup tables to capture per-tenant regional configuration: work week definition, public holiday sets by region, overtime rules and payroll period boundaries.

We designed the migration carefully to preserve existing tenant behaviour. New columns were added as nullable with defaults matching current behaviour, allowing existing tenants to continue without configuration changes while new tenants specify their locale settings during onboarding.

Payroll calculation queries were refactored to resolve locale-specific rules at query time using the tenant's configuration rather than hardcoded constants. This added complexity to the query layer but eliminated the maintenance burden of per-locale code paths.

Internationalisation (React / i18n)

The frontend used a custom translation setup that wasn't structured for scale. We migrated it to react-i18next with a namespace-organised translation file structure - each feature area has its own namespace, making it practical for translators to work on sections independently without the conflicts that arise from a single global translation file.

Date and number formatting was centralised through a formatting utility that reads the current tenant's locale from session context. This replaced scattered toLocaleDateString() calls throughout the codebase that were inconsistently parameterised.

Deployment and branch management

The engagement also covered release coordination - managing feature branches for the locale work alongside ongoing product development, ensuring locale changes merged cleanly with other work in progress and staging the deployment across tenant groups to catch any migration issues before full rollout.

Technical Decisions Worth Noting

The shared schema approach limited options for locale data isolation but it was the existing architecture and the right call to work within it. Adding locale as a tenant configuration dimension rather than a schema dimension was consistent with how other tenant-specific settings were handled and avoided the operational complexity of per-tenant schema management.

The phased rollout approach for the migration was important given that payroll data is high-stakes. Any migration issue that corrupts timesheet records has real consequences for affected tenants. Deploying to a small pilot group first, monitoring for errors, then expanding incrementally was the only responsible path.

Outcome

The locale expansion launched on schedule. Existing tenants were unaffected by the migration - their configuration defaulted to existing behaviour. New region onboarding was validated through a pilot group before full release, with no payroll calculation errors reported. The i18n refactor reduced translation maintenance overhead for the client's product team, who could now work with structured namespace files rather than a single growing translation object.