Skip to content

Feature/extend lifecycle for staff - #62

Merged
codebyNorthsteep merged 8 commits into
mainfrom
feature/extendLifecycleForStaff
Apr 14, 2026
Merged

Feature/extend lifecycle for staff#62
codebyNorthsteep merged 8 commits into
mainfrom
feature/extendLifecycleForStaff

Conversation

@codebyNorthsteep

@codebyNorthsteep codebyNorthsteep commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

This pull request introduces a complete implementation of the staff management feature, including controller, service, repository, DTOs, mapping logic, and comprehensive unit tests. It enables secure CRUD operations for staff entities, supports filtering by role or department, and enforces validation and authorization. The changes also improve code structure and maintainability by separating update and view models and adding repository annotations.

Staff Management Feature Implementation

Controller and Service Layer:

  • Added StaffController with REST endpoints for retrieving, updating, deleting, and filtering staff members, secured with appropriate role-based access controls. (StaffController.java)
  • Implemented StaffService to handle business logic for staff operations, including validation, exception handling, and logging. (StaffService.java)

DTOs and Mapping:

  • Introduced UpdateStaffDTO for validated staff updates and updated StaffDTO to remove validation annotations, separating concerns between input validation and data transfer. (UpdateStaffDTO.java, StaffDTO.java) [1] [2]
  • Enhanced StaffMapper with update and list mapping methods to support new service logic. (StaffMapper.java)

Repository Layer:

  • Added query methods for filtering staff by role or department and annotated the repository with @Repository. (StaffRepository.java)

Testing:

  • Added comprehensive unit tests for all main service methods, covering success and failure cases. (StaffServiceTest.java)

General Improvements

  • Annotated repositories with @Repository for proper Spring management. (EmploymentFormRepository.java, StaffRepository.java) [1] [2]
  • Minor import and organization cleanups in configuration and model files. (SecurityConfig.java, StaffDTO.java, StaffMapper.java) [1] [2] [3]

Summary by CodeRabbit

  • New Features

    • REST API for staff management: retrieval, update, deletion; list filtering by role or department
    • Structured input validation added for staff update requests
  • Security

    • Expanded role-based access rules for staff and forms endpoints; tickets now require authentication
    • Method-level access checks applied to staff operations
  • Tests

    • Added comprehensive unit tests for staff service behaviors
  • Bug Fixes

    • Improved error messages for invalid type/mismatch inputs

…th update and list conversion methods, introduce `getStaffById` in `StaffService`, and add `@Repository` annotations for repositories.
…, and expand `StaffService` with staff update and retrieval logic
… enhance `StaffService` with delete and filter methods, and update `StaffRepository` with role and department-based queries.
…te, delete, and filtered retrieval; enhance `StaffService` with additional validations and logic; introduce `StaffServiceTest` for comprehensive unit testing.
@coderabbitai

coderabbitai Bot commented Apr 13, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@codebyNorthsteep has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 48 minutes and 13 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 48 minutes and 13 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 99290ce2-32c9-4f1a-88c5-0ce03d936895

📥 Commits

Reviewing files that changed from the base of the PR and between eb031d7 and d9bd9f9.

📒 Files selected for processing (1)
  • src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java
📝 Walkthrough

Walkthrough

Converts staff endpoints to a REST API, implements StaffService with role-based method security and repository queries, introduces UpdateStaffDTO and mapper updates, annotates repositories with @Repository, adjusts SecurityConfig authorization rules, and refactors GlobalExceptionHandler enum handling; includes unit tests for StaffService.

Changes

Cohort / File(s) Summary
Security & Repository Annotations
src/main/java/org/example/cyberwatch/config/SecurityConfig.java, src/main/java/org/example/cyberwatch/features/form/repository/EmploymentFormRepository.java
Reordered imports and expanded HTTP authorization rules in SecurityConfig; added @Repository to EmploymentFormRepository.
Staff REST Controller
src/main/java/org/example/cyberwatch/features/staff/controller/StaffController.java
Converted @Controller@RestController, added @RequestMapping("/api/staff"), constructor injection, and REST endpoints (GET by id, PUT update, DELETE, GET list with optional filters) returning ResponseEntity.
DTOs & Validation
src/main/java/org/example/cyberwatch/features/staff/model/StaffDTO.java, src/main/java/org/example/cyberwatch/features/staff/model/UpdateStaffDTO.java
Removed bean-validation from StaffDTO; added new UpdateStaffDTO with validation annotations for update operations.
Mapper & Repository Queries
src/main/java/org/example/cyberwatch/features/staff/model/StaffMapper.java, src/main/java/org/example/cyberwatch/features/staff/repository/StaffRepository.java
Replaced toEntity(StaffDTO) with updateEntity(UpdateStaffDTO, Staff) and added toDTOList(List<Staff>); added @Repository and query methods findByRole(Role) and findByDepartment(Department).
Service Implementation & Tests
src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java, src/test/java/org/example/cyberwatch/features/staff/service/StaffServiceTest.java
Added StaffService (@Service) with CRUD methods, role-based @PreAuthorize annotations, logging, and repository interactions; comprehensive JUnit5 + Mockito tests covering success and failure paths.
Exception Handling
src/main/java/org/example/cyberwatch/exception/GlobalExceptionHandler.java
Updated type-mismatch handler to dynamically list valid enum values by inspecting ex.getRequiredType() instead of hardcoded enum usage.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Controller as "StaffController\n(/api/staff)"
  participant Security as "SecurityFilter\n(SecurityConfig)"
  participant Service as "StaffService"
  participant Repo as "StaffRepository"
  participant DB as "Database"

  Client->>Security: HTTP request /api/staff...
  Note right of Security: Authorization rules checked\n(e.g., /api/staff/** roles)
  Security->>Controller: forward if authorized
  Controller->>Service: call service method (get/update/delete/list)
  Service->>Repo: query or save entity (findById/findByRole/save/delete)
  Repo->>DB: execute SQL
  DB-->>Repo: result
  Repo-->>Service: entity/list
  Service-->>Controller: DTO / status
  Controller-->>Client: HTTP response (ResponseEntity)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • Ericthilen
  • alicewersen-rgb
  • gitnes94

Poem

🐰 Hopping through code with a joyful cheer,
Controllers turned RESTful, DTOs now clear,
Services that log and repos that find,
Tests keep the bugs neatly confined,
A little rabbit celebrates progress here!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feature/extend lifecycle for staff' broadly describes the PR's purpose but is vague and uses the prefix pattern. It does not specifically convey the main changes: REST API endpoints, service layer implementation, DTOs, repository updates, and testing. Consider a more specific title like 'Add staff REST API with service layer and role-based access control' to clearly communicate the primary changes in the changeset.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/extendLifecycleForStaff

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/main/java/org/example/cyberwatch/features/form/repository/EmploymentFormRepository.java (1)

6-10: @Repository is redundant here; consider removing for consistency.

For JpaRepository interfaces, Spring Data already registers the bean, so this annotation/import can be omitted. It would also align with existing repository style in src/main/java/org/example/cyberwatch/features/activitylog/repository/ActivityLogRepository.java (Line 1-10) and src/main/java/org/example/cyberwatch/features/comment/repository/CommentRepository.java (Line 1-10).

Optional cleanup diff
 import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
@@
-@Repository
 public interface EmploymentFormRepository extends JpaRepository<EmploymentForm, Long> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/cyberwatch/features/form/repository/EmploymentFormRepository.java`
around lines 6 - 10, Remove the redundant Spring `@Repository` annotation and its
import from the EmploymentFormRepository interface: delete the import line for
org.springframework.stereotype.Repository and remove the `@Repository` annotation
above the interface declaration so the JpaRepository-based repository relies on
Spring Data auto-registration (addressing EmploymentFormRepository).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/org/example/cyberwatch/features/staff/controller/StaffController.java`:
- Around line 50-51: The TypeMismatch handler is hardcoded to enumerate
Status.values(), causing invalid-value errors from endpoints like
StaffController.getStaffByRoleOrDepartment to show ticket statuses; update
GlobalExceptionHandler.handleTypeMismatch to inspect the exception's required
type (e.g., ex.getRequiredType()) and, if it is an enum, enumerate its constants
(using getEnumConstants() and their names) to produce the correct "valid values"
list for Role or Department; ensure you null-check requiredType and fall back to
a generic message if it's not an enum.
- Line 27: The method-level `@PreAuthorize` annotations in StaffController (e.g.,
the `@PreAuthorize`("hasAnyRole('HR', 'CEO', 'CTO')") and the other role checks at
the other endpoints) conflict with the global /api/staff/** ADMIN requirement in
SecurityConfig; update the security configuration so the endpoint-level roles
are honored by either (A) relaxing the SecurityConfig rule that currently
requires hasRole("ADMIN") for /api/staff/** to include the roles used in
StaffController, or (B) removing the global /api/staff/** ADMIN gate and relying
on the controller's `@PreAuthorize` annotations; modify SecurityConfig and verify
the changes affect StaffController methods (the `@PreAuthorize` annotations) so
HR/CEO/CTO users can access the intended endpoints.

In
`@src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java`:
- Around line 51-56: When updating in StaffService (around
staffRepository.findById(...) and staffMapper.updateEntity(...)), guard against
duplicate emails by checking staffRepository.findByEmail(dto.getEmail()) before
calling staffRepository.save(existingStaff); if dto.getEmail() is non-null and
differs from existingStaff.getEmail() and findByEmail(...) returns a different
Staff (id != staffId) then throw the same IllegalStateException path you use
elsewhere (e.g., "Email already in use") so updates produce a controlled 409
instead of a DB constraint error; ensure null-safe comparisons of emails and
compare entity IDs when deciding conflict.

In
`@src/test/java/org/example/cyberwatch/features/staff/service/StaffServiceTest.java`:
- Around line 85-86: The test UpdateStaffWhenValid currently constructs
UpdateStaffDTO with phoneNumber set to null which violates the `@NotBlank`
constraint and doesn't mirror valid controller input; update the test to supply
a non-blank phone number (e.g., "070-1234567") when creating UpdateStaffDTO in
StaffServiceTest (the instance used by the updateStaffWhenValid test) so the DTO
passes validation and the "valid input" path exercised by
StaffController.updateStaff(...) is realistic.

---

Nitpick comments:
In
`@src/main/java/org/example/cyberwatch/features/form/repository/EmploymentFormRepository.java`:
- Around line 6-10: Remove the redundant Spring `@Repository` annotation and its
import from the EmploymentFormRepository interface: delete the import line for
org.springframework.stereotype.Repository and remove the `@Repository` annotation
above the interface declaration so the JpaRepository-based repository relies on
Spring Data auto-registration (addressing EmploymentFormRepository).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6395eadc-e2b6-4d8d-ac0c-8183d63686dc

📥 Commits

Reviewing files that changed from the base of the PR and between bea96fb and 981c5e9.

📒 Files selected for processing (9)
  • src/main/java/org/example/cyberwatch/config/SecurityConfig.java
  • src/main/java/org/example/cyberwatch/features/form/repository/EmploymentFormRepository.java
  • src/main/java/org/example/cyberwatch/features/staff/controller/StaffController.java
  • src/main/java/org/example/cyberwatch/features/staff/model/StaffDTO.java
  • src/main/java/org/example/cyberwatch/features/staff/model/StaffMapper.java
  • src/main/java/org/example/cyberwatch/features/staff/model/UpdateStaffDTO.java
  • src/main/java/org/example/cyberwatch/features/staff/repository/StaffRepository.java
  • src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java
  • src/test/java/org/example/cyberwatch/features/staff/service/StaffServiceTest.java
💤 Files with no reviewable changes (1)
  • src/main/java/org/example/cyberwatch/features/staff/model/StaffDTO.java

Comment thread src/test/java/org/example/cyberwatch/features/staff/service/StaffServiceTest.java Outdated
… update related tests in `StaffServiceTest`.
…rvice`, update role-based access in `SecurityConfig`, and refine exception handling for enum validation in `GlobalExceptionHandler`.
# Conflicts:
#	src/main/java/org/example/cyberwatch/config/SecurityConfig.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java (2)

44-66: Consider adding @Transactional for atomicity.

updateStaff performs read → email check → update → save operations. Without @Transactional, these are separate transactions, creating a small window for race conditions (e.g., another request claims the email between check and save).

Similarly, deleteStaff does find → delete which should be atomic.

Suggested addition

Add import:

import org.springframework.transaction.annotation.Transactional;

Then annotate the methods:

     `@PreAuthorize`("hasAnyRole('HR', 'ADMIN')")
+    `@Transactional`
     public StaffDTO updateStaff(Long staffId, UpdateStaffDTO dto) {
     `@PreAuthorize`("hasAnyRole('HR', 'ADMIN')")
+    `@Transactional`
     public void deleteStaff(Long staffId) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java`
around lines 44 - 66, The updateStaff and deleteStaff flows in StaffService must
be made atomic to prevent race conditions; add the import for
org.springframework.transaction.annotation.Transactional and annotate the
methods updateStaff(...) and deleteStaff(...) in StaffService with
`@Transactional` (use default read-write for updateStaff and deleteStaff;
optionally use `@Transactional`(readOnly = true) only for pure reads elsewhere),
ensuring the methods execute within a single transaction so the read→check→save
and find→delete sequences are atomic.

82-88: Consider using toDTOList for consistency.

Lines 84 and 87 use .stream().map(staffMapper::toDto).toList(), while getAllStaff() on line 41 uses staffMapper.toDTOList(). Using the mapper method consistently improves readability.

Optional refactor
         if (role != null) {
-            return staffRepository.findByRole(role)
-                    .stream().map(staffMapper::toDto).toList();
+            return staffMapper.toDTOList(staffRepository.findByRole(role));
         } else if (department != null) {
-            return staffRepository.findByDepartment(department)
-                    .stream().map(staffMapper::toDto).toList();
+            return staffMapper.toDTOList(staffRepository.findByDepartment(department));
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java`
around lines 82 - 88, Replace the inline stream mapping in the role and
department branches with the mapper's bulk method for consistency: instead of
using staffRepository.findByRole(role).stream().map(staffMapper::toDto).toList()
and
staffRepository.findByDepartment(department).stream().map(staffMapper::toDto).toList(),
call staffMapper.toDTOList(...) on the returned lists (from
staffRepository.findByRole and staffRepository.findByDepartment) to match the
existing use of staffMapper.toDTOList() in getAllStaff().
src/main/java/org/example/cyberwatch/exception/GlobalExceptionHandler.java (1)

30-47: Clean refactor for dynamic enum value enumeration.

The approach correctly extracts enum constants at runtime using reflection, making the handler work for any enum type (not just Status). This is a good improvement for maintainability.

One minor consideration: ex.getValue() could potentially be null if the binding failed before parsing (though rare). Consider null-safe handling:

Optional defensive improvement
         return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(
-                Map.of("error", "Ogiltigt värde '" + ex.getValue()
+                Map.of("error", "Ogiltigt värde '" + (ex.getValue() != null ? ex.getValue() : "null")
                         + "'. Giltiga värden: " + validValues)
         );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/cyberwatch/exception/GlobalExceptionHandler.java`
around lines 30 - 47, The handler handleTypeMismatch for
MethodArgumentTypeMismatchException should guard against a null ex.getValue();
update both places that build the error message (inside the enum branch and the
fallback) to use a null-safe string conversion (e.g.,
String.valueOf(ex.getValue()) or a conditional that substitutes "null" or an
empty string) so the message never throws NPE or prints "null" unexpectedly;
ensure you also fix the fallback Map.of construction to include the closing
quotes/concatenation around the value when replacing ex.getValue() with the
null-safe expression.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java`:
- Around line 56-60: The null-safe equality check should be used to avoid a
NullPointerException when existingStaff.getEmail() is null: replace the
conditional that uses existingStaff.getEmail().equals(dto.getEmail()) with a
null-safe comparison (e.g., Objects.equals(existingStaff.getEmail(),
dto.getEmail())) inside the StaffService update flow so the subsequent
staffRepository.findByEmail(dto.getEmail()).ifPresent(...) still runs only when
emails differ; ensure you import java.util.Objects and keep the existing
staffRepository.findByEmail(...) block unchanged.

---

Nitpick comments:
In `@src/main/java/org/example/cyberwatch/exception/GlobalExceptionHandler.java`:
- Around line 30-47: The handler handleTypeMismatch for
MethodArgumentTypeMismatchException should guard against a null ex.getValue();
update both places that build the error message (inside the enum branch and the
fallback) to use a null-safe string conversion (e.g.,
String.valueOf(ex.getValue()) or a conditional that substitutes "null" or an
empty string) so the message never throws NPE or prints "null" unexpectedly;
ensure you also fix the fallback Map.of construction to include the closing
quotes/concatenation around the value when replacing ex.getValue() with the
null-safe expression.

In
`@src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java`:
- Around line 44-66: The updateStaff and deleteStaff flows in StaffService must
be made atomic to prevent race conditions; add the import for
org.springframework.transaction.annotation.Transactional and annotate the
methods updateStaff(...) and deleteStaff(...) in StaffService with
`@Transactional` (use default read-write for updateStaff and deleteStaff;
optionally use `@Transactional`(readOnly = true) only for pure reads elsewhere),
ensuring the methods execute within a single transaction so the read→check→save
and find→delete sequences are atomic.
- Around line 82-88: Replace the inline stream mapping in the role and
department branches with the mapper's bulk method for consistency: instead of
using staffRepository.findByRole(role).stream().map(staffMapper::toDto).toList()
and
staffRepository.findByDepartment(department).stream().map(staffMapper::toDto).toList(),
call staffMapper.toDTOList(...) on the returned lists (from
staffRepository.findByRole and staffRepository.findByDepartment) to match the
existing use of staffMapper.toDTOList() in getAllStaff().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 11295338-2382-4f34-9f0e-ec182f1a5911

📥 Commits

Reviewing files that changed from the base of the PR and between 981c5e9 and eb031d7.

📒 Files selected for processing (5)
  • src/main/java/org/example/cyberwatch/config/SecurityConfig.java
  • src/main/java/org/example/cyberwatch/exception/GlobalExceptionHandler.java
  • src/main/java/org/example/cyberwatch/features/staff/controller/StaffController.java
  • src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java
  • src/test/java/org/example/cyberwatch/features/staff/service/StaffServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/test/java/org/example/cyberwatch/features/staff/service/StaffServiceTest.java
  • src/main/java/org/example/cyberwatch/features/staff/controller/StaffController.java

Comment thread src/main/java/org/example/cyberwatch/features/staff/service/StaffService.java Outdated
@codebyNorthsteep codebyNorthsteep linked an issue Apr 14, 2026 that may be closed by this pull request
@codebyNorthsteep
codebyNorthsteep merged commit eaf8793 into main Apr 14, 2026
1 check passed
This was referenced Apr 14, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Finnish lifecycle For Staff

1 participant