Skip to content

feat: Add company to the codebase#24

Merged
StoynovAngel merged 19 commits into
mainfrom
feat/add-company
Apr 10, 2026
Merged

feat: Add company to the codebase#24
StoynovAngel merged 19 commits into
mainfrom
feat/add-company

Conversation

@StoynovAngel
Copy link
Copy Markdown
Owner

@StoynovAngel StoynovAngel commented Apr 10, 2026

Summary by CodeRabbit

  • New Features

    • Full company management (create/read/update/delete), company membership flow, and COMPANY_ADMIN role.
    • Drivers and vehicles can be associated with companies; new endpoints to list drivers/vehicles by company.
    • Company admins granted management rights alongside global admins.
  • Tests

    • Added integration and unit tests for company flows, fixtures, and a company-admin JWT test helper.
  • Chores

    • Seed data added for companies and related associations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 10, 2026

Warning

Rate limit exceeded

@StoynovAngel has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 2 minutes and 48 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 2 minutes and 48 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c36d8579-b0ba-4e45-a5fb-e9897c8ec2e5

📥 Commits

Reviewing files that changed from the base of the PR and between 0fca41d and c77f5d6.

📒 Files selected for processing (15)
  • backend/src/main/java/com/angel/autonow/company/CompanyController.java
  • backend/src/main/java/com/angel/autonow/company/CompanyRequestDTO.java
  • backend/src/main/java/com/angel/autonow/company/CompanyService.java
  • backend/src/main/java/com/angel/autonow/driver/DriverController.java
  • backend/src/main/java/com/angel/autonow/driver/DriverRepository.java
  • backend/src/main/java/com/angel/autonow/driver/DriverRequestDTO.java
  • backend/src/main/java/com/angel/autonow/driver/DriverService.java
  • backend/src/main/java/com/angel/autonow/user/UserRepository.java
  • backend/src/main/java/com/angel/autonow/vehicle/VehicleRepository.java
  • backend/src/main/java/com/angel/autonow/vehicle/VehicleRequestDTO.java
  • backend/src/main/resources/data.sql
  • backend/src/test/java/com/angel/autonow/company/CompanyServiceTest.java
  • backend/src/test/java/com/angel/autonow/data/TestData.java
  • backend/src/test/java/com/angel/autonow/driver/DriverControllerIT.java
  • backend/src/test/java/com/angel/autonow/driver/DriverServiceTest.java
📝 Walkthrough

Walkthrough

Adds a Company domain (entity, DTOs, mapper, repository, service, controller) with CRUD and join endpoints, connects Company to Driver/Vehicle/User entities, introduces COMPANY_ADMIN role and authorization changes, updates services/controllers to validate/set company associations, and adds related tests and data seeds.

Changes

Cohort / File(s) Summary
Company Core Domain
backend/src/main/java/com/angel/autonow/company/CompanyType.java, .../CompanyEntity.java, .../CompanyRequestDTO.java, .../CompanyResponseDTO.java, .../CompanyMapper.java, .../CompanyRepository.java, .../CompanyService.java, .../CompanyController.java
New Company entity, request/response DTOs, MapStruct mapper, JPA repository (with findByEmail), service exposing create/join/get/update/delete semantics, and REST controller mapped to /api/companies with role-based guards.
Driver-Company Integration
backend/src/main/java/com/angel/autonow/driver/DriverEntity.java, .../DriverRequestDTO.java, .../DriverResponseDTO.java, .../DriverMapper.java, .../DriverRepository.java, .../DriverService.java, .../DriverController.java
Adds @ManyToOne company relation to DriverEntity; DTOs include companyId; mapper maps company.id → DTO and ignores company on writes; repository adds findByCompanyId; service validates/assigns company on create/update; controller auth broadened and adds GET by company.
Vehicle-Company Integration
backend/src/main/java/com/angel/autonow/vehicle/VehicleEntity.java, .../VehicleRequestDTO.java, .../VehicleResponseDTO.java, .../VehicleMapper.java, .../VehicleRepository.java, .../VehicleService.java, .../VehicleController.java
Adds @ManyToOne company relation to VehicleEntity; DTOs include companyId; mapper maps company.id → DTO and ignores company on writes; repository adds findByCompanyId; service validates/assigns company and switches create/update to Optional returns; controller auth broadened and adds GET by company.
User & Role Updates
backend/src/main/java/com/angel/autonow/user/UserEntity.java, .../user/role/Role.java
Adds @ManyToOne company relation to UserEntity; Role enum gains COMPANY_ADMIN constant.
Tests & Test Data
backend/src/test/java/com/angel/autonow/data/TestData.java, .../driver/DriverServiceTest.java, .../vehicle/VehicleServiceTest.java, .../company/CompanyControllerIT.java, .../company/CompanyServiceTest.java
Adds company test factories and companyAdminJwt(), updates tests to mock/inject CompanyRepository, adapts assertions for Optional-returning services, and adds comprehensive Company controller/service integration/unit tests.
Database Seeding
backend/src/main/resources/data.sql
Adds seed companies, assigns users/drivers/vehicles to companies, and grants ROLE_COMPANY_ADMIN to an admin user.

Sequence Diagram

sequenceDiagram
    actor Client
    participant Controller as CompanyController
    participant Service as CompanyService
    participant CompRepo as CompanyRepository
    participant UserRepo as UserRepository
    participant DB as Database

    Client->>Controller: POST /api/companies/{id}/join
    activate Controller
    Controller->>Service: joinCompany(id, principalName)
    activate Service
    Service->>CompRepo: findById(id)
    activate CompRepo
    CompRepo->>DB: SELECT company WHERE id=?
    DB-->>CompRepo: CompanyEntity
    CompRepo-->>Service: Optional<CompanyEntity>
    deactivate CompRepo
    Service->>UserRepo: findByEmail(principalName)
    activate UserRepo
    UserRepo->>DB: SELECT user WHERE email=?
    DB-->>UserRepo: UserEntity
    UserRepo-->>Service: Optional<UserEntity>
    deactivate UserRepo
    alt Company or User missing
        Service-->>Controller: false
    else Both exist
        Service->>Service: user.setCompany(company)
        Service->>Service: user.authorities.add(COMPANY_ADMIN)
        Service->>UserRepo: save(user)
        activate UserRepo
        UserRepo->>DB: UPDATE user SET company_id=?, authorities=?
        DB-->>UserRepo: OK
        deactivate UserRepo
        Service-->>Controller: true
    end
    deactivate Service
    Controller-->>Client: 200 OK / 400 Bad Request
    deactivate Controller
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

Poem

🐰
I hopped in with a planner and pen,
Built burrows for fleets and admin den,
Drivers and vans now snugly aligned,
Seeds sown, tests passing — carrots all assigned,
Hooray — company burrows all set again! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: Add company to the codebase' clearly summarizes the main purpose of the changeset, which is to introduce a comprehensive company feature with controllers, services, entities, mappers, and related modifications across the application.

✏️ 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 feat/add-company

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/src/main/java/com/angel/autonow/company/CompanyController.java`:
- Around line 43-47: The getCompanyById method in CompanyController currently
returns null when companyService.getCompanyById(id) is empty; change it to
return a 400 Bad Request instead by checking the Optional from
companyService.getCompanyById(id) and, if empty, throw a
ResponseStatusException(HttpStatus.BAD_REQUEST) (or change the method to return
ResponseEntity<CompanyResponseDTO> and return
ResponseEntity.badRequest().build()); update the getCompanyById signature and
imports accordingly so a missing company results in HTTP 400 rather than a 200
with null body.
- Around line 55-60: The update endpoint currently allows any user with role
COMPANY_ADMIN to update any company; modify CompanyService.updateCompany(...) to
enforce ownership: retrieve the authenticated principal/authorities (e.g. via
SecurityContextHolder) inside CompanyService.updateCompany(Long id,
CompanyRequestDTO request) and if the caller has role ADMIN allow the operation,
but if the caller has role COMPANY_ADMIN verify the principal's company id
equals the target id before proceeding (throw AccessDeniedException or return
Optional.empty() on mismatch); keep CompanyController.updateCompany(...) as-is
but ensure CompanyService.performing the check uses unique identifiers from the
authenticated user (e.g., getCompanyId or userId on the Principal/UserDetails)
so COMPANY_ADMIN can only update their own company.

In `@backend/src/main/java/com/angel/autonow/company/CompanyRequestDTO.java`:
- Line 27: CompanyRequestDTO is missing URL validation for the logoUrl field, so
invalid URLs are only rejected at persistence; add the same validation used on
CompanyEntity by annotating the logoUrl field in CompanyRequestDTO with the
appropriate `@URL` annotation (importing org.hibernate.validator.constraints.URL)
and any necessary `@Nullable/`@NotBlank per existing DTO semantics to match
CompanyEntity's behavior, ensuring validation occurs during request
binding/validation in methods that accept CompanyRequestDTO.

In `@backend/src/main/java/com/angel/autonow/company/CompanyService.java`:
- Around line 63-70: The deleteCompany method currently calls
companyRepository.deleteById(id) without handling dependent User, Vehicle, or
Driver records and will hit FK constraints or leave dangling refs; update
deleteCompany to first check for dependents (e.g., use
UserRepository.countByCompanyId(id), VehicleRepository.countByCompanyId(id),
DriverRepository.countByCompanyId(id)) and either block deletion (return false
or throw a clear exception) if any counts > 0, or perform safe cleanup (reassign
or nullify company_id via repository update methods) before calling
companyRepository.deleteById(id); ensure you reference deleteCompany,
companyRepository and the User/Vehicle/Driver repository methods when
implementing the chosen strategy.
- Around line 28-42: The joinCompany method updates UserEntity and persists the
new Role.COMPANY_ADMIN but does not update the caller's current JWT so the
session still lacks the new authority; modify the flow in joinCompany to either
(a) generate and return a fresh JWT containing the updated authorities after
userRepository.save(user) (reuse your existing JWT creation code/path used by
SecurityConfig), or (b) return a flag prompting the client to re-authenticate so
the client obtains a new token; ensure the returned response includes the new
token or explicit instruction, and reference joinCompany, UserEntity,
Role.COMPANY_ADMIN, userRepository, and SecurityConfig when wiring the token
re-issuance or re-auth path.

In `@backend/src/main/java/com/angel/autonow/driver/DriverController.java`:
- Line 27: The controller currently authorizes ROLE_COMPANY_ADMIN but does not
enforce that the caller's company owns the target resources; update
DriverController (and corresponding checks in DriverService) to fetch the
caller's company id from the security context (e.g., current principal / JWT)
and, for all endpoints that accept or resolve a companyId or driver id
(createDriver, listDrivers, getDriver/updateDriver/deleteDriver), compare that
caller company id to the target companyId or the driver's persisted companyId
and throw AccessDeniedException (or return 403) if they differ; add the same
guard inside DriverService methods that perform the actual persistence/lookup to
prevent bypass via direct service calls. Ensure you reference and validate
companyId from request body/path or loaded Driver entity before proceeding for
COMPANY_ADMIN callers only, while leaving ADMIN unchanged.

In `@backend/src/main/java/com/angel/autonow/vehicle/VehicleController.java`:
- Line 27: Controller methods in VehicleController (e.g., createVehicle,
listVehicles, updateVehicle, deleteVehicle) currently permit any COMPANY_ADMIN
to operate on arbitrary companyId/vehicle; add enforcement so non-ADMIN callers
can only act on their own company: retrieve the caller's companyId from the
security context (e.g., Authentication/Principal or a UserDetails service), and
before proceeding in each controller method validate that the request's
companyId (or the target vehicle's company owner fetched via VehicleService)
equals the caller's companyId; if not, throw AccessDeniedException (or return
403). Factor the check into a reusable method (e.g., verifyCompanyOwnership or
ensureCallerOwnsCompany) and call it from the controller endpoints and/or in
VehicleService methods that accept companyId or vehicleId so updates/deletes
also validate ownership. Ensure lookups for vehicleId resolve the vehicle's
companyId to validate ownership for update/delete operations.

In `@backend/src/main/java/com/angel/autonow/vehicle/VehicleRequestDTO.java`:
- Line 30: The VehicleRequestDTO currently allows null or non-positive
companyId; annotate the companyId field in class VehicleRequestDTO with
validation constraints (e.g., `@NotNull` and `@Positive` or `@Min`(1)) and add the
corresponding imports from javax.validation.constraints so invalid payloads fail
fast with 400s; also ensure the controller accepts the DTO with `@Valid` (if not
already) so the validation is enforced at the API boundary.

In `@backend/src/main/java/com/angel/autonow/vehicle/VehicleService.java`:
- Around line 20-32: The unit test still treats createVehicle(...) as returning
a VehicleResponseDTO instead of Optional<VehicleResponseDTO>; update the test in
VehicleServiceTest to unwrap the Optional before asserting fields (e.g., call
createVehicle(...), assert that the Optional is present, then use the contained
VehicleResponseDTO for result.id() and result.brand() assertions) or adjust
assertions to match Optional semantics; ensure you're referencing the
createVehicle method and checking Optional.isPresent() (or using
get()/orElseThrow()) before accessing DTO fields.

In `@backend/src/main/resources/data.sql`:
- Around line 39-43: The UPDATE statements currently target vehicle rows by
brand only (UPDATE vehicle ... WHERE brand IN (...) and WHERE brand =
'Mercedes'), which can misassign vehicles; modify these to use a deterministic
key such as brand plus model (e.g., WHERE brand = 'Toyota' AND model =
'Corolla') or the stable vehicle identifier (e.g., vehicle.vin or id) when
setting company_id for the company rows selected by email ('fleet@autonow.com'
and 'info@medtransport.bg'); update both occurrences (the UPDATE vehicle
statements) to use the deterministic predicate (brand+model or id/VIN) so
seeding is integrity-safe.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c96ced95-ee3e-4282-bc59-7049ae7664a9

📥 Commits

Reviewing files that changed from the base of the PR and between d0cf4bb and e9a9a9a.

📒 Files selected for processing (25)
  • backend/src/main/java/com/angel/autonow/company/CompanyController.java
  • backend/src/main/java/com/angel/autonow/company/CompanyEntity.java
  • backend/src/main/java/com/angel/autonow/company/CompanyMapper.java
  • backend/src/main/java/com/angel/autonow/company/CompanyRepository.java
  • backend/src/main/java/com/angel/autonow/company/CompanyRequestDTO.java
  • backend/src/main/java/com/angel/autonow/company/CompanyResponseDTO.java
  • backend/src/main/java/com/angel/autonow/company/CompanyService.java
  • backend/src/main/java/com/angel/autonow/company/CompanyType.java
  • backend/src/main/java/com/angel/autonow/driver/DriverController.java
  • backend/src/main/java/com/angel/autonow/driver/DriverEntity.java
  • backend/src/main/java/com/angel/autonow/driver/DriverMapper.java
  • backend/src/main/java/com/angel/autonow/driver/DriverRepository.java
  • backend/src/main/java/com/angel/autonow/driver/DriverRequestDTO.java
  • backend/src/main/java/com/angel/autonow/driver/DriverResponseDTO.java
  • backend/src/main/java/com/angel/autonow/driver/DriverService.java
  • backend/src/main/java/com/angel/autonow/user/UserEntity.java
  • backend/src/main/java/com/angel/autonow/user/role/Role.java
  • backend/src/main/java/com/angel/autonow/vehicle/VehicleController.java
  • backend/src/main/java/com/angel/autonow/vehicle/VehicleEntity.java
  • backend/src/main/java/com/angel/autonow/vehicle/VehicleMapper.java
  • backend/src/main/java/com/angel/autonow/vehicle/VehicleRepository.java
  • backend/src/main/java/com/angel/autonow/vehicle/VehicleRequestDTO.java
  • backend/src/main/java/com/angel/autonow/vehicle/VehicleResponseDTO.java
  • backend/src/main/java/com/angel/autonow/vehicle/VehicleService.java
  • backend/src/main/resources/data.sql

Comment thread backend/src/main/java/com/angel/autonow/company/CompanyService.java Outdated
Comment thread backend/src/main/java/com/angel/autonow/company/CompanyService.java
Comment thread backend/src/main/java/com/angel/autonow/vehicle/VehicleService.java
Comment thread backend/src/main/resources/data.sql Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
backend/src/test/java/com/angel/autonow/vehicle/VehicleServiceTest.java (1)

27-29: Please add company-association tests for createVehicle/updateVehicle.

With CompanyRepository now part of the service dependency graph, this test class should also cover: (1) existing companyId attaches company and saves, and (2) missing companyId in DB returns Optional.empty() (and avoids save where applicable).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/test/java/com/angel/autonow/vehicle/VehicleServiceTest.java`
around lines 27 - 29, Add two unit tests in VehicleServiceTest covering company
association: mock CompanyRepository to return Optional.of(company) when
companyId exists and assert that VehicleService.createVehicle and updateVehicle
attach the returned Company to the Vehicle before saving and that
vehicleRepository.save is invoked; then mock CompanyRepository to return
Optional.empty() for a missing companyId and assert that
createVehicle/updateVehicle return Optional.empty() (or propagate empty result)
and that vehicleRepository.save is not called. Use the existing mocks for
CompanyRepository, VehicleRepository, and the VehicleService methods
(createVehicle/updateVehicle) and verify interactions with
companyRepository.findById(...) and vehicleRepository.save(...) accordingly.
backend/src/test/java/com/angel/autonow/driver/DriverServiceTest.java (1)

28-30: Add tests for the new companyId branch behavior in createDriver.

Now that CompanyRepository is injected, please cover both cases: valid companyId (driver is saved with company) and missing companyId in DB (Optional.empty() and no save). This is the new business path introduced in DriverService and currently unexercised here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/test/java/com/angel/autonow/driver/DriverServiceTest.java` around
lines 28 - 30, Add two unit tests in DriverServiceTest exercising the new
companyId branch in DriverService.createDriver: (1) when
companyRepository.findById(...) returns Optional.of(company) assert the
returned/created Driver has its company set and verify
driverRepository.save(...) was called with that Driver; (2) when
companyRepository.findById(...) returns Optional.empty() assert that
driverRepository.save(...) is not called (or appropriate behavior asserted) and
no company is set. Use the existing `@Mock` CompanyRepository and mock its
findById for both scenarios, invoke DriverService.createDriver(...), and use
Mockito.verify on driverRepository to assert save interactions.
backend/src/test/java/com/angel/autonow/data/TestData.java (1)

265-294: Consider extracting shared company fixture literals into constants.

name/address/phone/email/companyType are duplicated across three methods; centralizing them will reduce fixture drift.

♻️ Suggested refactor
+	private static final String TEST_COMPANY_NAME = "Test Fleet Co";
+	private static final String TEST_COMPANY_ADDRESS = "123 Test St";
+	private static final String TEST_COMPANY_PHONE = "+1234567890";
+	private static final String TEST_COMPANY_EMAIL = "test@fleet.com";
+	private static final CompanyType TEST_COMPANY_TYPE = CompanyType.TAXI;
+
 	public static CompanyEntity createCompanyEntity() {
 		return CompanyEntity.builder()
-				.name("Test Fleet Co")
-				.address("123 Test St")
-				.phone("+1234567890")
-				.email("test@fleet.com")
-				.companyType(CompanyType.TAXI)
+				.name(TEST_COMPANY_NAME)
+				.address(TEST_COMPANY_ADDRESS)
+				.phone(TEST_COMPANY_PHONE)
+				.email(TEST_COMPANY_EMAIL)
+				.companyType(TEST_COMPANY_TYPE)
 				.build();
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/test/java/com/angel/autonow/data/TestData.java` around lines 265
- 294, The three company fixture methods (createCompanyEntity,
createCompanyRequest, createCompanyResponse) duplicate the same literals;
extract them into shared private static final constants (e.g., COMPANY_NAME,
COMPANY_ADDRESS, COMPANY_PHONE, COMPANY_EMAIL, COMPANY_TYPE) declared at the top
of the TestData class and update those methods to reference the constants
instead of hard-coded strings/types so the fixture is centralized and prevents
drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/src/test/java/com/angel/autonow/data/TestData.java`:
- Around line 265-294: The three company fixture methods (createCompanyEntity,
createCompanyRequest, createCompanyResponse) duplicate the same literals;
extract them into shared private static final constants (e.g., COMPANY_NAME,
COMPANY_ADDRESS, COMPANY_PHONE, COMPANY_EMAIL, COMPANY_TYPE) declared at the top
of the TestData class and update those methods to reference the constants
instead of hard-coded strings/types so the fixture is centralized and prevents
drift.

In `@backend/src/test/java/com/angel/autonow/driver/DriverServiceTest.java`:
- Around line 28-30: Add two unit tests in DriverServiceTest exercising the new
companyId branch in DriverService.createDriver: (1) when
companyRepository.findById(...) returns Optional.of(company) assert the
returned/created Driver has its company set and verify
driverRepository.save(...) was called with that Driver; (2) when
companyRepository.findById(...) returns Optional.empty() assert that
driverRepository.save(...) is not called (or appropriate behavior asserted) and
no company is set. Use the existing `@Mock` CompanyRepository and mock its
findById for both scenarios, invoke DriverService.createDriver(...), and use
Mockito.verify on driverRepository to assert save interactions.

In `@backend/src/test/java/com/angel/autonow/vehicle/VehicleServiceTest.java`:
- Around line 27-29: Add two unit tests in VehicleServiceTest covering company
association: mock CompanyRepository to return Optional.of(company) when
companyId exists and assert that VehicleService.createVehicle and updateVehicle
attach the returned Company to the Vehicle before saving and that
vehicleRepository.save is invoked; then mock CompanyRepository to return
Optional.empty() for a missing companyId and assert that
createVehicle/updateVehicle return Optional.empty() (or propagate empty result)
and that vehicleRepository.save is not called. Use the existing mocks for
CompanyRepository, VehicleRepository, and the VehicleService methods
(createVehicle/updateVehicle) and verify interactions with
companyRepository.findById(...) and vehicleRepository.save(...) accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9c5ded64-d511-4c17-ad54-a366fb03890c

📥 Commits

Reviewing files that changed from the base of the PR and between e9a9a9a and 57e1a38.

📒 Files selected for processing (3)
  • backend/src/test/java/com/angel/autonow/data/TestData.java
  • backend/src/test/java/com/angel/autonow/driver/DriverServiceTest.java
  • backend/src/test/java/com/angel/autonow/vehicle/VehicleServiceTest.java

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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 (4)
backend/src/test/java/com/angel/autonow/company/CompanyControllerIT.java (2)

106-124: Missing success test for joinCompany endpoint.

The join company tests only cover failure scenarios (company not found, guest forbidden, unauthenticated). Consider adding a success test that creates both a company and a user in the database, then verifies the join succeeds and the user is properly associated.

🧪 Suggested success test
`@Test`
void joinCompany_success() throws Exception {
	var company = TestData.createCompanyEntity();
	companyRepository.save(company);

	var user = UserEntity.builder()
			.email("joiner@test.com")
			.password("encodedPassword")
			.authorities(new HashSet<>(Set.of(Role.CUSTOMER.getAuthority())))
			.build();
	userRepository.save(user);

	mockMvc.perform(post("/api/companies/{id}/join", company.getId())
					.with(jwt().jwt(j -> j.subject("joiner@test.com"))
							.authorities(new SimpleGrantedAuthority(Role.CUSTOMER.getAuthority()))))
			.andExpect(status().isOk());

	// Verify user is now associated with company
	var updatedUser = userRepository.findByEmail("joiner@test.com").orElseThrow();
	assertEquals(company.getId(), updatedUser.getCompany().getId());
	assertTrue(updatedUser.getAuthorities().contains(Role.COMPANY_ADMIN.getAuthority()));
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/test/java/com/angel/autonow/company/CompanyControllerIT.java`
around lines 106 - 124, Add a positive integration test for the joinCompany
flow: create and save a Company entity (using
TestData.createCompanyEntity()/companyRepository.save) and a UserEntity with
CUSTOMER authority (userRepository.save), perform
mockMvc.post("/api/companies/{id}/join", company.getId()) with a JWT for that
user's email and CUSTOMER authority, expect status().isOk(), then reload the
user via userRepository.findByEmail(...) and assert the user's company id equals
company.getId() and their authorities now include
Role.COMPANY_ADMIN.getAuthority(); name the test joinCompany_success in
CompanyControllerIT.

137-143: Returning 200 OK with empty body for not-found resource is unconventional.

Standard REST semantics typically return 404 Not Found when a resource doesn't exist. Returning 200 OK with an empty body can confuse API consumers. Consider updating the controller to return 404 for non-existent resources.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/test/java/com/angel/autonow/company/CompanyControllerIT.java`
around lines 137 - 143, The test reveals the controller currently returns 200
with an empty body for a missing company; change the controller logic
(CompanyController.getCompanyById) to return 404 Not Found when the
service/repository cannot find the entity (e.g., when CompanyService.findById or
repository.findById returns empty/Optional.empty), and update the integration
test (CompanyControllerIT#getCompanyById_notFound_returnsOkEmpty) to expect
status().isNotFound() instead of isOk(); ensure any exception mapping or
ResponseEntity usage returns ResponseEntity.notFound() or throws a
ResourceNotFoundException handled by a `@ControllerAdvice` to produce 404.
backend/src/test/java/com/angel/autonow/company/CompanyServiceTest.java (1)

56-96: Consider adding test for user already belonging to a company.

The tests cover company-not-found and user-not-found scenarios, but there's no test verifying behavior when a user who already belongs to a company attempts to join another. This edge case should be covered to document the expected behavior (whether it should succeed, fail, or require explicit handling).

🧪 Suggested additional test
`@Test`
void joinCompany_userAlreadyInCompany_behaviorDocumented() {
	CompanyEntity existingCompany = CompanyEntity.builder().id(1L).build();
	CompanyEntity newCompany = CompanyEntity.builder().id(2L).build();
	UserEntity user = UserEntity.builder()
			.id(1L)
			.email("test@example.com")
			.authorities(new HashSet<>(Set.of(Role.COMPANY_ADMIN.getAuthority())))
			.company(existingCompany)
			.build();

	when(companyRepository.findById(2L)).thenReturn(Optional.of(newCompany));
	when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(user));

	var result = companyService.joinCompany(2L, "test@example.com");

	// Document expected behavior - currently allows silent switch
	assertTrue(result);
	assertEquals(newCompany, user.getCompany());
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/test/java/com/angel/autonow/company/CompanyServiceTest.java`
around lines 56 - 96, Add a test covering the "user already belongs to a
company" edge case: create existingCompany and newCompany (CompanyEntity), build
a UserEntity with company(existingCompany) and authorities containing
Role.COMPANY_ADMIN.getAuthority(), mock companyRepository.findById(newCompanyId)
to return newCompany and userRepository.findByEmail(...) to return the user,
call companyService.joinCompany(newCompanyId, email) and assert the documented
behavior (e.g., if current behavior is to switch companies, assertTrue(result),
assertEquals(newCompany, user.getCompany()) and
verify(userRepository).save(user); if desired behavior is to refuse,
assertFalse(result) and verify(userRepository, never()).save(any())).
backend/src/main/java/com/angel/autonow/company/CompanyService.java (1)

21-26: createCompany always succeeds—Optional wrapper provides no value.

The method wraps the result in Optional.of() unconditionally, so it can never return Optional.empty(). Either remove the Optional wrapper and return CompanyResponseDTO directly, or add validation/failure conditions that would justify returning empty.

♻️ Suggested simplification
-	public Optional<CompanyResponseDTO> createCompany(CompanyRequestDTO request) {
+	public CompanyResponseDTO createCompany(CompanyRequestDTO request) {
 		CompanyEntity company = companyMapper.toEntity(request);
 		CompanyEntity saved = companyRepository.save(company);
-		return Optional.of(companyMapper.toDTO(saved));
+		return companyMapper.toDTO(saved);
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/main/java/com/angel/autonow/company/CompanyService.java` around
lines 21 - 26, The createCompany method always returns Optional.of(...) so
Optional.empty() is impossible; fix by either removing the Optional wrapper and
changing the signature to return CompanyResponseDTO (update callers) or
implement real failure/validation paths and return Optional.empty() when
appropriate—e.g., validate the CompanyRequestDTO before mapping, check for save
failures (use Optional.ofNullable(companyRepository.save(...)) or catch
exceptions and return Optional.empty()), and keep companyMapper.toDTO(saved) for
the success path; adjust the createCompany signature and any callers
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/src/test/java/com/angel/autonow/company/CompanyControllerIT.java`:
- Line 12: Replace the malformed import for AutoConfigureMockMvc: locate the
import statement currently referencing
org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc and
change it to the correct Spring Boot package
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc so
CompanyControllerIT compiles and uses the proper test annotation.

---

Nitpick comments:
In `@backend/src/main/java/com/angel/autonow/company/CompanyService.java`:
- Around line 21-26: The createCompany method always returns Optional.of(...) so
Optional.empty() is impossible; fix by either removing the Optional wrapper and
changing the signature to return CompanyResponseDTO (update callers) or
implement real failure/validation paths and return Optional.empty() when
appropriate—e.g., validate the CompanyRequestDTO before mapping, check for save
failures (use Optional.ofNullable(companyRepository.save(...)) or catch
exceptions and return Optional.empty()), and keep companyMapper.toDTO(saved) for
the success path; adjust the createCompany signature and any callers
accordingly.

In `@backend/src/test/java/com/angel/autonow/company/CompanyControllerIT.java`:
- Around line 106-124: Add a positive integration test for the joinCompany flow:
create and save a Company entity (using
TestData.createCompanyEntity()/companyRepository.save) and a UserEntity with
CUSTOMER authority (userRepository.save), perform
mockMvc.post("/api/companies/{id}/join", company.getId()) with a JWT for that
user's email and CUSTOMER authority, expect status().isOk(), then reload the
user via userRepository.findByEmail(...) and assert the user's company id equals
company.getId() and their authorities now include
Role.COMPANY_ADMIN.getAuthority(); name the test joinCompany_success in
CompanyControllerIT.
- Around line 137-143: The test reveals the controller currently returns 200
with an empty body for a missing company; change the controller logic
(CompanyController.getCompanyById) to return 404 Not Found when the
service/repository cannot find the entity (e.g., when CompanyService.findById or
repository.findById returns empty/Optional.empty), and update the integration
test (CompanyControllerIT#getCompanyById_notFound_returnsOkEmpty) to expect
status().isNotFound() instead of isOk(); ensure any exception mapping or
ResponseEntity usage returns ResponseEntity.notFound() or throws a
ResourceNotFoundException handled by a `@ControllerAdvice` to produce 404.

In `@backend/src/test/java/com/angel/autonow/company/CompanyServiceTest.java`:
- Around line 56-96: Add a test covering the "user already belongs to a company"
edge case: create existingCompany and newCompany (CompanyEntity), build a
UserEntity with company(existingCompany) and authorities containing
Role.COMPANY_ADMIN.getAuthority(), mock companyRepository.findById(newCompanyId)
to return newCompany and userRepository.findByEmail(...) to return the user,
call companyService.joinCompany(newCompanyId, email) and assert the documented
behavior (e.g., if current behavior is to switch companies, assertTrue(result),
assertEquals(newCompany, user.getCompany()) and
verify(userRepository).save(user); if desired behavior is to refuse,
assertFalse(result) and verify(userRepository, never()).save(any())).
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a94649f9-6299-44ca-9539-dd0195d4d7a8

📥 Commits

Reviewing files that changed from the base of the PR and between 57e1a38 and 0fca41d.

📒 Files selected for processing (4)
  • backend/src/main/java/com/angel/autonow/company/CompanyController.java
  • backend/src/main/java/com/angel/autonow/company/CompanyService.java
  • backend/src/test/java/com/angel/autonow/company/CompanyControllerIT.java
  • backend/src/test/java/com/angel/autonow/company/CompanyServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/src/main/java/com/angel/autonow/company/CompanyController.java

Stoynov added 3 commits April 10, 2026 20:07
Cannot delete a company if there are drivers/vehicles attached.
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@StoynovAngel StoynovAngel merged commit b299643 into main Apr 10, 2026
7 of 8 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 14, 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.

1 participant