← Back to projects
Case study

Employee Management System

A full-stack app where admins, managers and employees manage users, departments and tasks. I designed and built it end to end, from the database schema and security layer to the React frontend, Docker image, CI pipeline and production deployment.

Live demo login: username demo · password demo123

API docs run on a free server and can take up to a minute to wake up on first load.

The problem

Who can do what, and what happened

Most CRUD demos let anyone do anything. I wanted something closer to a real internal tool, where permissions actually matter: an employee should only see their own tasks, a manager should only manage their own department, and there should be a record of every change that matters.

So the goal wasn't just "build an app with login." It was to get the access rules, the task workflow and the audit trail right, and then ship it somewhere people can actually use it.

Architecture

How it fits together

React + TypeScriptMUI frontend on Netlify. Axios sends the JWT on each request.
JWT filterCustom filter validates the token and loads the user before anything else runs.
ControllersEndpoint access by role, configured in SecurityConfig.
ServicesBusiness rules, data-level access checks, state machine, audit logging.
MySQLJPA / Hibernate repositories. Hosted on Aiven.

The backend runs in Docker on Render. GitHub Actions builds and tests every push, and secrets come from environment variables, never the repo.

Key decisions

The parts I'm most proud of

Access control in two layers

SecurityConfig answers "can this role call this endpoint?" The service layer answers "can this user touch this specific record?" A manager can call the update-task endpoint, but the service still checks that the task belongs to their department. Keeping these separate means one missed rule doesn't open everything up.

Tasks follow a state machine

Tasks move through fixed states, and the service rejects anything that skips a step or goes backwards incorrectly. An employee can't mark their own task as done; it has to go through review.

ASSIGNED→ STARTED→ UNDER_REVIEW→ DONE

Audit log with Spring AOP

Instead of adding logging calls inside every service method, an aspect records admin and manager actions (who, what, which record, when). The business code stays clean, and new actions get logged without remembering to add anything.

Guard rails on department transfers

You can't move an employee to another department while they still have active tasks. Otherwise their old manager loses visibility of work that's still in progress.

JWT auth from scratch

I wrote the filter, UserDetailsService and token utility myself instead of copying a starter, so I understand every step from login to authorized request. Passwords are hashed with BCrypt, and users can change their own password or have an admin reset it.

Tests where the rules live

JUnit 5 and Mockito tests cover the service-layer business rules and role-based endpoint access, including failure paths like invalid state changes and forbidden requests. CI runs them on every push.

Screens

What it looks like

Deployment

Getting it live

  • Backend packaged as a Docker image and deployed on Render.
  • MySQL hosted on Aiven, connected through environment-based config.
  • Frontend on Netlify with SPA routing so deep links don't 404.
  • CORS locked to the frontend's domain.
  • GitHub Actions builds and runs the test suite on every push.
  • Interactive API docs with Swagger / OpenAPI, so you can explore every endpoint without the frontend: open Swagger UI.
Next

What I'd add next

  • Move hosting to AWS (EC2 or ECS + RDS) as I finish the Developer Associate cert.
  • Refresh tokens so sessions can stay short without logging people out constantly.
← Back to all projects