Scenario · Internal web app · Human resources

Human resources
out of the spreadsheets.

A growing company that manages attendance, leave and reviews across Excel files, emails and messages. An internal web app that puts everything in one place, with clear approvals and reports ready when needed.

Project typeInternal web app
SectorHuman resources
Typical timing10–14 weeks
●Scenario
web app · HR platform
HR Dashboard
Overview · July 2025
LIVE
PRESENT
187
out of 214 total
ON LEAVE TODAY
12
approved
REVIEWS
34
due soon
ADMIN HOURS
↓
vs previous year
ATTENDANCE · LAST 6 MONTHS
Feb
Mar
Apr
May
Jun
Jul
LEAVE REQUESTS
L
Employee A
✓ ok
M
Employee B
⏳ pend.
A
Employee C
✓ ok

Web app scenario — custom HR system

150 people managed
with three tools that don't talk to each other.

The scenario: a fast-growing company that passes 150 employees, when the HR team raises its hand: the system can't cope any more. Attendance goes into a shared Google Sheet, leave requests arrive by email, reviews live in one Excel file per department, and the monthly reports for management take a couple of days of manual work to piece together from different sources.

With the next hires, the chaos would become unmanageable. HR spends most of its time on repetitive admin instead of recruiting, wellbeing and people development.

What's needed isn't a generic HR package to configure a thousand ways: it's a tool built around the company's real processes, connected to existing systems and simple enough for everyone to use without training.

«Every Monday morning I spend two hours checking who's on holiday, who's working from home and who has overtime to make up. Two hours on data that should be visible in a second.»

— What I often hear from HR managers
Scenario Internal HR web app — attendance, leave, reviews, reports (example)
Stack React + TypeScript · Laravel · MySQL · Redis
Access HR Admin · Manager · Employee (RBAC)
Integrations Slack · Google Calendar · Export PDF/CSV
Typical duration 10–12 weeks
Tags
React TypeScript Laravel RBAC data viz PDF export Slack API

Company HR platform requirements

A single source of truth.
Three access levels.

Real-time attendance and clock-in management

Every employee must be able to record clock-in, clock-out and work mode (office / remote / business trip) from any device. HR sees the status of the whole team updated to the minute, with automatic alerts for unjustified absences.

Leave and permission workflow with multi-level approval

The employee requests leave from their own area. The request goes to their direct manager (first level) and then to HR (second level). Automatic Slack notification at every status change. A shared calendar to see the team's absences before approving.

Structured performance reviews with configurable cycles

HR configures the review cycles (half-yearly / yearly), goals per role and evaluation templates. Manager and employee fill in their sections asynchronously. The aggregated results feed the management dashboard.

Automatic reporting with PDF and CSV export

Monthly reports (attendance, overtime, remaining leave, headcount per department) must be generated in one click — not in two days. Branded PDF export for management and CSV for payroll. Automatic scheduling with an email sent on the first of every month.

Granular RBAC: HR Admin, Manager, Employee

Three distinct roles with configurable permissions. The HR Admin sees everything and can edit any record. The Manager sees and approves only their own team. The Employee accesses only their own data. Permissions are checked on both the frontend and the API — no implicit trust in the client.

Technical challenges of an HR management system

Sensitive data, complex logic,
zero margin for error.

An HR platform handles personal data, payroll and confidential reviews. Every bug isn't an annoyance: it's a legal or trust problem. The challenges are architectural before they're about code.

01

RBAC: consistent permissions across API and UI

The classic risk is an interface that hides buttons while the API still answers unauthorised requests. The answer is Laravel policies (Gate + Policy) used by the backend and also exposed as a /me/permissions endpoint: the React front end builds the interface accordingly without duplicating permission logic.

02

Concurrency on leave requests

Two managers approve the same request at the same time, or an employee sends two overlapping requests for the same period. Solution: MySQL transactions with a SELECT ... FOR UPDATE lock on the leave balance table, plus API-side validation that checks the remaining available days within the same atomic transaction.

03

PDF reports with real-time aggregated data

Generating a PDF with hundreds of employees, monthly attendance and aggregated hours can take tens of seconds — too long for an immediate response. Fix: a queued job with Laravel Horizon (Redis), a Slack or email notification when the report is ready, a temporary file on S3-compatible storage with a signed link valid for 24 hours.

04

Two-way sync with Google Calendar

Approved leave has to appear on the company Google calendar with no duplicates or conflicts if it's edited on either side. A Google Calendar webhook updates the database and a reconciliation job every 15 minutes resolves conflicts, with the HR platform as the source of truth.

05

GDPR: separating sensitive performance data

Reviews are sensitive data that shouldn't be visible to the whole HR team — only to the direct manager, the employee concerned and the admin, with logged access. That means a separate table and field-level encryption (AES-256) for comments, with a key tied to the authorised user.

HR web app development process

10–12 weeks,
from spreadsheet to go-live.

Weeks 1–2
Discovery: mapping the real processes, not the theoretical ones

Separate interviews with HR staff, a few department heads and a sample of employees. The aim: understand how attendance and leave are really handled — not how they should be. There are always lots of small informal processes (WhatsApp messages, personal reminders, emails cc'ing everyone) that no written requirement would capture. They become the edge cases the system has to handle.

→ Delivered: current process map · documented edge cases · navigation wireframe
Weeks 3–5
Backend: Laravel API, RBAC and data model

A Laravel backend with Sanctum authentication, RBAC with detailed policies and the three core entities: attendance, leave requests and review cycles. Each endpoint returns the current user's permissions, so the React front end doesn't need separate calls to know what to show. A MySQL database with indexes designed for aggregated reports.

→ REST API · migrations · PHPUnit tests · Sanctum + RBAC
Weeks 6–8
React frontend: dashboard, workflows and data viz

A React interface with TypeScript, React Query for server state and Recharts for charts. Three layouts for the three roles — HR Admin, Manager, Employee — adapting to the permissions received from the API. The leave flow is the most complex module: several states (draft → submitted → manager approval → HR approval → approved/rejected) with a Slack notification at each step.

→ React 18 · TypeScript · React Query · Recharts · Slack Webhook API
Week 9
Reporting engine: asynchronous PDF and scheduling

A report generator using Laravel Horizon (Redis) for queues. Each monthly report is a background job: it aggregates the data, builds the PDF with DomPDF (template with company logo and colours), stores it on MinIO (self-hosted S3), creates a signed link valid for 24 hours and notifies by email and Slack. The job runs automatically on the first of each month at 7:00.

→ Laravel Horizon · Redis · DomPDF · MinIO · scheduled job
Weeks 10–11
UAT, historical data migration and gradual go-live

Two weeks of acceptance testing with a group of users for each role. Migration of historical data from the Excel files with a PHP clean-up script. Rollout by department: first one team, then the others, then everyone. Two weeks of running in parallel, with the old tools still available read-only.

→ tests with real users · historical data migrated · 3-phase rollout · no downtime

Technical solution: RBAC and React dashboard

Three modules, one platform.
Zero silos.

The platform is built around three independent but integrated modules, each designed from how people really work — not from an abstract model.

Module 01 / 03

Clock-ins and attendance — real-time dashboard

Every employee logs in from browser or mobile and selects the day's mode (office, remote, business trip, sick leave). The system records the time and updates the HR dashboard in real time through polling every 60 seconds with React Query. Managers see only their team; the HR Admin sees everything with filters by department, location and mode. Anomalies (unjustified absence by 10:00) trigger an automatic Slack alert to the responsible manager.

// React hook for real-time attendance with React Query function useTeamPresenze( teamId: string ) { return useQuery({ queryKey: ['presenze', teamId], queryFn: () => api.get(`/teams/${teamId}/presenze/oggi`), refetchInterval: 60_000, // polling every 60s staleTime: 30_000, // permissions already in the payload — no extra call select: (data) => data.filter( (p) => hasPermission(p, 'view') ), }); }
Module 02 / 03

Leave workflow — from 3 emails to 1 click

A leave request goes through 5 states with explicit steps and automatic notifications. Before submitting, the employee sees their team's calendar to avoid overlaps. The manager gets a Slack notification with a direct link to approve, without having to hunt for the request. If they don't reply within 48 hours, HR gets a reminder. Goal: nearly every request handled within 24 hours, instead of the days an email process takes.

Leave request status
Request submitted
Approved by manager
Awaiting HR ← now
Final approval
Module 03 / 03

Performance reviews — structured, asynchronous, confidential

HR sets up the review cycle: period, templates per role (Junior to Lead), company objectives and deadlines. Manager and employee fill in their sections independently — neither sees the other's review until both are closed. Comments are encrypted at field level (AES-256), so even direct database access doesn't expose them. Aggregated data — averages by department, rating distribution, trend versus the previous cycle — feeds the management dashboard with interactive charts.

GDPR note: review data requires enhanced security measures under Art. 25 GDPR (privacy by design). Field-level encryption is a technical measure to document in the company's record of processing activities.

React TypeScript Laravel tech stack

Deliberate choices,
not random ones.

React + TypeScript
Laravel
MySQL
Redis + Horizon
React Query
Recharts
Slack Webhook API
Google Calendar API
DomPDF
MinIO (S3)
PHPUnit + Pest
Vite + ESBuild

Why Laravel and not Node.js?

Laravel has a mature policy and gate system for RBAC, an ORM (Eloquent) that handles relationships between teams, roles and permissions well, and Laravel Horizon for queues — all already integrated and proven. On Node.js the same system would mean assembling separate libraries with fewer consistency guarantees. For an internal web app with sensitive data, ecosystem maturity matters.

Why React Query and not Redux?

The application state is almost entirely server state: data that lives in the backend and must be kept in sync. React Query handles caching, refetching, optimistic UI and invalidation declaratively — without Redux boilerplate. The result is an interface that feels real-time with the simplicity of an API call.

Example goals — HR web app

HR stops
doing admin.

Example figures, not a client's results: realistic goals for a scenario like this, to be measured a few months after full go-live against the same period before.

−50%
HR admin hours
goal for admin time saved
−80%
Attendance errors
goal for fewer manual corrections
90%+
Leave processed <24h
goal, versus days before
5 min
Monthly report generation
instead of days of manual work
95%+
Adoption rate
adoption goal after the first month
4.5/5
User satisfaction
goal in the internal survey

«The first monthly report arrives on its own, on the first of the month at 7:01, with a Slack notification.» That's the moment that makes the whole project worthwhile.

— The concrete goal of the reports module

HR web app development learnings

What I bring
to every project like this.

→

Interviewing users before writing code isn't overhead: it's a saving. The informal processes that come out of interviews are bugs avoided in production. Every hour of discovery saves several of development and testing.

→

RBAC must live in the backend, not in the UI. Hiding a button in the frontend isn't security — it's cosmetics. The Laravel Policy system that exposes permissions as data made it possible to have a UI that adapts dynamically without duplicating authorization logic in the React code.

→

A gradual rollout by department is always worth the extra complexity. Starting with a single team surfaces usability problems — not code problems — before they affect the whole company.

→

Background jobs change the experience out of all proportion. Moving from a PDF generated while the user waits tens of seconds to a notification when it's ready greatly improves satisfaction, for the same output.

→

Running in parallel is key to trust. Leaving the old spreadsheets read-only for a couple of weeks after launch breaks down resistance to change: people can "check" the data is right, and then they stop checking.

Do you have an internal process that deserves a tailor-made tool?

Excel and email are fine until you grow. Then you need tools that grow with you.

Have a similar project in mind?

Tell me about it: we start from goals and priorities, and the first call is free.