How We Built a Multi-Tenant Employee Engagement SaaS Platform

Multi-tenant SaaS platform built with Frappe, React and Flutter

Client: Simme B.V., Netherlands

Industry: Employee Engagement / HR Tech

Tech Stack: Frappe, React, Flutter, GetStream, Firebase

Timeline: 10 months

Team: 5 people (3 developers, 1 QA, 1 project manager)

Delivered by: CitrusLeaf (citrusleaf.in)

The Brief

We received a cold email from Simme B.V., a startup based in Drachten, Netherlands. Attached was a 20-page product requirements document describing an ambitious vision – an all-in-one employee engagement platform that would replace the mess of scattered tools most organizations rely on today.

The problem Simme wanted to solve was real and widespread. Employees waste time jumping between WhatsApp groups for team communication, email threads for company news, shared drives for documents, and disconnected systems for HR tasks. Managers have no single place to track onboarding, performance reviews, or team engagement. The result is disengaged employees, poor onboarding experiences, and high turnover – especially costly for small and mid-sized organizations.

Simme’s answer was a single branded app – available on mobile and web – where everything lives in one place. Communication, onboarding, development goals, e-learning, feedback surveys, document management, resource booking, and even a team password manager. Each client organization would get their own isolated environment with custom branding, and managers could toggle modules on or off based on what they actually need.

The scope was significant: 12 distinct modules, multiple user roles with granular permissions, a mobile app, an employee web portal, a separate admin panel, multi-tenant architecture, and multi-lingual support in Dutch and English. The client had a clear product vision but no technical team to execute it.

That’s where CitrusLeaf came in.

Why Frappe as the Backend

The client came to us with a product vision, not a technology preference. They had no prior experience with Frappe or any specific backend framework. During our initial consultation, CitrusLeaf proposed Frappe as the backbone of the platform. The reasoning was simple – for a startup working with limited runway, every month of development time is money. Frappe would let us deliver more in less time and at a lower cost than a conventional build-from-scratch approach.

For those unfamiliar – Frappe is a rapid application development framework built on Python. It gives you an ORM, automatic REST API generation, role-based access control, file handling, email infrastructure, and a built-in admin interface out of the box. For a small team building a feature-rich product on a startup budget, this mattered enormously. Instead of spending months wiring up boilerplate backend infrastructure, we could focus engineering effort on the actual product logic that makes Simme unique.

This is also where CitrusLeaf’s deep expertise in the Frappe ecosystem made a real difference. We have been building on Frappe for years – implementing ERPNext for manufacturing and trading businesses, developing custom Frappe applications, and working intimately with the framework’s internals across dozens of client engagements. We didn’t just pick Frappe from a list of options. We knew exactly what it could handle, where its boundaries were, and how to push past them when needed. That experience translated directly into faster architecture decisions, fewer dead ends, and a backend that was production-ready without the usual trial-and-error overhead.

One of the biggest accelerators was Frappe HR. Simme needed a full-fledged HRMS – leave management, attendance tracking, employee lifecycle, and shift management. Building all of this from scratch would have added months to the timeline and significantly inflated the budget. Instead, we extended Frappe HR, an existing module in the Frappe ecosystem, and customized it to fit Simme’s requirements. Payroll was deliberately excluded since Simme’s target market (Dutch and EU organizations) typically handles payroll through specialized local providers.

The result: Frappe saved not just time but real money – without compromising on quality. What would have been roughly three months of backend infrastructure work was available on day one. Our team could stay small and still deliver a platform that looks and feels like a premium SaaS product – polished user interfaces, robust multi-tenant architecture, secure data handling, and enterprise-grade HR functionality. For a startup, this is the sweet spot: a product that can compete with well-funded players in the employee engagement space, built at a fraction of the cost and timeline.

Architecture – The Multi-Tenancy Challenge

Simme is not a single-company tool. It is a SaaS platform where each client organization gets its own isolated environment – their own data, their own branding, their own set of modules. This meant multi-tenancy was not a nice-to-have. It was the core architectural problem we had to solve before anything else could work.

There are multiple ways to approach multi-tenancy. You can use a shared database with tenant IDs to separate data. You can use separate schemas within a single database. Or you can go with fully isolated instances. We chose full isolation – each tenant runs as a separate Frappe site on a single Frappe Cloud server. This gave us complete data separation with zero risk of cross-tenant data leakage, which was especially important given that Simme handles sensitive information like HR records, performance reviews, and encrypted passwords.

The challenge then became discovery. If every tenant lives on its own site, how does a user find their way to the right one? For this, we built a custom Frappe application called Simme Registry. The Registry is a lightweight central service that holds a mapping of every employee email address to their organization’s tenant URL.

The login flow works like this: the user opens the Simme app or web portal and enters their email address. The app calls the Registry, which looks up the email and returns the correct tenant URL. From this point, the frontend silently switches its API target to the correct tenant site – the user stays on the same page throughout. They then complete authentication via an email-based OTP. No passwords to remember, no tenant URLs to bookmark, no redirects – just an email address and a one-time code.

On the infrastructure side, the Frappe Cloud server hosts all tenant sites plus the Registry. The React applications – both the employee portal and the admin panel – run on a separate VPS and dynamically connect to the appropriate tenant’s API based on what the Registry returns. This separation keeps the frontend deployment independent from the backend, making updates and scaling simpler on both sides.

The Frontend Story – React and Flutter

Simme needed three user-facing interfaces: an employee portal where staff access news, chat, development goals, and HR functions; an admin panel where managers and HR teams configure modules, manage employees, and run the organization’s Simme environment; and a mobile app for employees on the go.

The employee portal and admin panel are both built in React, running as separate applications on a dedicated VPS. The mobile app is built in Flutter.

The admin panel has an interesting backstory. Our original plan was to use Frappe’s built-in Desk interface as the admin panel. Desk already provides a functional backend UI – forms, list views, role-based access, workflow management. For a multi-tenant SaaS product, it seemed like a sensible shortcut. We began customizing Desk to fit Simme’s needs and were roughly 25% into that work when the client requested a fully separate, custom-built admin panel. They wanted a cleaner, more branded experience for their customers – tenant admins and HR managers should never feel like they are using a developer tool.

This was a significant pivot. We set aside the Desk customizations and built the admin panel from scratch in React. The client funded this as a paid change request, so there was no friction – just a clear product decision that added to the timeline. In hindsight, it was the right call. The result is a polished admin interface that feels native to the Simme brand rather than a reskinned framework backend.

Both React apps pull theme configuration from a dedicated doctype in Simme’s Frappe backend. On login, the app fetches the tenant’s branding – colors, logos, styling – and persists it locally on the device or browser. This means every organization sees their own branded environment without any manual frontend deployment per tenant. A new customer signs up, their admin configures the theme once, and every employee in that organization immediately sees a Simme that looks like it was built just for them.

Frappe HR was also delivered entirely through these React interfaces. Tenant admins and HR managers interact with leave management, attendance, employee lifecycle, and shift management through the custom admin panel – not through Frappe Desk. Employees access their own HR functions through the employee portal. We customized Frappe HR under the hood to fit Simme’s requirements, but the user never touches or sees the Frappe backend directly.

The Flutter mobile app takes a pragmatic approach. It wraps the employee React portal while using native device capabilities for push notifications via Firebase. This let us ship a mobile app without maintaining a completely separate codebase, while still delivering the native notification experience that employees expect from a mobile app. One codebase for the employee experience across web and mobile, with native functionality where it actually matters.

Smart Build-vs-Buy Decisions

One of the most important roles CitrusLeaf played on this project was not just building things, but deciding what not to build. Simme was a startup. Every engineering hour spent on something that already exists as a reliable service is an hour taken away from the features that actually differentiate the product. We were deliberate about this from day one.

The clearest example is real-time chat. Simme’s spec included a full chat module – direct messaging between employees, photo and video sharing, file attachments, team-scoped conversations. Building a real-time chat system from scratch is notoriously complex. It involves websocket infrastructure, message persistence, delivery guarantees, read receipts, presence indicators, and the kind of edge cases that can consume an entire engineering team for months. We were upfront with the client early in the project – we will not build a real-time chat service. It would be a waste of time and money, and as a startup, Simme could not afford to sink budget into solving a problem that has already been solved well by dedicated services.

We recommended a handful of established real-time chat providers, and the client chose GetStream. On the Flutter mobile app, we integrated GetStream natively using its SDK. On the React employee portal, we used GetStream’s API with custom-built chat components that match Simme’s look and feel. Chat data is segregated by Tenant ID, maintaining the same data isolation principle that runs through the entire platform.

Push notifications followed a similar philosophy. We used Firebase Cloud Messaging, integrated into the Frappe backend for app-level notifications – things like news updates, onboarding reminders, and HR alerts. GetStream also uses the same Firebase account for chat-specific notifications. One Firebase setup, two notification sources, clean and maintainable.

And then there was the HRMS decision, which we have already covered earlier. Rather than building HR functionality from scratch, we extended Frappe HR and delivered it through Simme’s custom interfaces. Same principle – don’t rebuild what already exists.

These decisions – GetStream for chat, Firebase for notifications, Frappe HR for HRMS – collectively saved months of development time and kept the budget realistic for a startup. More importantly, they let our small team focus engineering effort on the things that make Simme genuinely unique: the multi-tenant registry, the onboarding engine, the development goal workflows, the encrypted password manager, and the branded white-label experience.

The Modules – What We Delivered

Simme’s feature set spans four pillars: onboarding, communication, development, and accessibility. Across these pillars, we built and delivered the following modules:

  • Onboarding – configurable day-by-day induction programs with linked content
  • E-Learnings – a course creation engine with images, videos, and questions
  • My Development – full performance review and development goal tracking
  • My Team – team-scoped messaging, activity registration, and checklists
  • My Opinion – anonymous feedback, targeted questionnaires, and satisfaction surveys
  • News – organizational news feed with rich content and push notifications
  • Chat – real-time messaging powered by GetStream
  • Agenda – shared calendar for events, appointments, and team outings
  • Box – resource reservation for workspaces, company cars, and equipment
  • Key – encrypted team password manager with OTP-protected viewing
  • HR – leave management, attendance, employee lifecycle, and shift management
  • Theme – seasonal engagement features like prize wheels and lottery draws
  • Push Notifications – targeted alerts from managers to employees or teams
  • Forms – custom form builder for organizational use
  • Documents – centralized document management
  • Quicklinks – shortcuts to external systems

Managers can toggle any of these modules on or off per organization. If a tenant does not use Box, it simply does not appear for their employees. No empty screens, no clutter – just the features each organization actually needs.

A few modules deserve a closer look.

My Development

This is the most workflow-heavy module in the platform. It covers the entire performance management cycle. Before a review meeting, the manager distributes a preparatory questionnaire to the employee through the app. The conversation happens, and the form is completed digitally by both parties. The manager then sets development goals with linked actions – these can include e-learnings, external training, or document uploads as proof of completion like a photo of a certificate. The employee can agree with the goals or leave comments. Progress is tracked visually through a progress bar, and everything is archived so development history builds up over years. Getting this workflow right – with its back-and-forth between manager and employee, linked e-learnings, and long-term archival – was one of the more complex pieces of the project.

Key

This is the module we are most proud of from a security standpoint. It is a team password manager where credentials are fully encrypted at rest. But encryption alone is not enough – the real differentiator is access control. Every time a user wants to view a stored password, they must verify their identity through a fresh email-based OTP. It is not a simple notes field with a password in it. Managers control which teams and roles can access which credentials. This makes shared passwords genuinely secure rather than just conveniently stored in a spreadsheet somewhere.

Chat

Chat was a deliberate build-vs-buy decision that we covered in the previous section, but it is worth noting the implementation detail here. On the Flutter mobile app, GetStream is integrated natively via its SDK. On the React employee portal, we used GetStream’s API with custom-built chat components styled to match Simme’s branding. All chat data is segregated by Tenant ID, maintaining the same data isolation that runs through the rest of the platform.

What We Learned

The original timeline for Simme was six months. We delivered in ten. That gap deserves an honest explanation.

The stretch was not caused by technical failure or missed deadlines. It was driven by the natural evolution of a product being built for the first time. The admin panel pivot from Frappe Desk to a custom React application added to the timeline. Additional modules that were not in the original spec were requested and built along the way. And there were a fair number of ad-hoc requirements that came in between planned sprints – features that felt small in conversation but added up over the course of the project.

This is not a criticism of the client. Simme’s founders had a strong product vision but had not built enterprise software before. When you are seeing your product take shape for the first time, new ideas and refinements are inevitable. Requirements that seem clear on paper often shift once you see them running on a screen. That is the reality of working with first-time SaaS founders, and it is something we have come to expect and plan for.

Looking back, the one thing we would do differently is invest even more time upfront in requirements crystallization. Spending an extra week or two at the start – walking through each module with detailed wireframes, mapping out every user flow, and explicitly documenting edge cases – would have reduced the ad-hoc changes later. It would not have eliminated them entirely, but it would have made the middle months smoother.

That said, CitrusLeaf’s role on this project went beyond writing code. We were a consulting partner as much as a development team. We proposed Frappe when the client had no technology preference. We pushed back on building chat from scratch. We recommended the multi-tenant architecture. We guided the client toward Frappe HR instead of custom-building an HRMS. These were not just technical decisions – they were business decisions that kept the project viable for a startup budget. And that consulting mindset is something we carry into every engagement.

Where Simme Is Today

Simme is live. The platform is running on Frappe Cloud with a fully operational multi-tenant infrastructure – the Registry, the tenant sites, the React apps, and the Flutter mobile app all in production. The first tenant has been onboarded, and a dedicated demo tenant site is available for prospects to experience the platform firsthand.

Although Simme’s current marketing focus is on Dutch healthcare organizations, the platform itself is industry-agnostic. Nothing in the architecture or the module set is specific to healthcare. Any organization with a team – whether in manufacturing, professional services, retail, or education – can use Simme to centralize employee engagement, onboarding, and HR operations.

CitrusLeaf continues to support the Simme team as they onboard new customers and evolve the product.

To put the project in perspective: 16 modules, multiple user roles with granular permissions, three user-facing interfaces, a multi-tenant SaaS architecture with full data isolation, third-party integrations with GetStream and Firebase, a complete HRMS built on Frappe HR, multi-lingual support in Dutch and English, white-label branding per tenant – all delivered by a five-person team in ten months.

Building a SaaS product?

CitrusLeaf specializes in turning product visions into production-ready platforms. We combine deep expertise in Frappe’s rapid application development ecosystem with modern frontend technologies like React and Flutter to deliver full-stack SaaS products – on time and on budget. Whether you are a startup with a spec document or an established business looking to launch a new product line, we can help you get from idea to live product.

Get in touch at citrusleaf.in

case studies

See More Case Studies

Contact us

You are one step away from digitizing your entire business

Just fill the form to schedule a free consultation with us and know how ERPNext can be beneficial for your business.

Your benefits:
What happens next?
1

We reach out to you to setup a discovery call

2

We understand your challenges in the discovery call

3

Our consultants will prepare a detailed solution for you

Schedule a Free Consultation