Skip to content

Implement location service with API and Docker setup#1

Merged
vikasutf8 merged 6 commits into
dev-masterfrom
dev-work
Apr 10, 2026
Merged

Implement location service with API and Docker setup#1
vikasutf8 merged 6 commits into
dev-masterfrom
dev-work

Conversation

@vikasutf8
Copy link
Copy Markdown
Owner

@vikasutf8 vikasutf8 commented Apr 10, 2026

[Copilot is generating a summary..
This pull request primarily introduces and configures the City and Airport domain models, along with their associated controller, service, and repository layers for the location service. It also adds supporting request/response DTOs, embeddable value objects, and project configuration files for IDE and build tooling. Additionally, it updates the project documentation with lessons learned about using MapStruct and Lombok together.

Domain Model and DTO Additions:

  • Added AirportRequest, CityRequest, and AirportResponse DTOs to the common-lib module for handling API requests and responses related to airports and cities. These classes include validation annotations and use Lombok for boilerplate reduction. [1] [2] [3]
  • Introduced embeddable value objects Address and GeoCode in the common-lib module to encapsulate address and geolocation data, with appropriate validation and Lombok annotations. [1] [2]

IDE and Build Configuration:

  • Added and updated various .idea configuration files to set up project encoding, annotation processor profiles (notably for Lombok and MapStruct), Maven modules, and workspace settings. This helps ensure consistent development environment setup for all contributors. [1] [2] [3] [4] [5] [6]
  • Removed the .idea/.gitignore file, which previously excluded default IDE-generated files from version control.

Project Structure and Documentation:

  • Added a minimal CommonLibApplication entry point class in the common-lib module.
  • Updated the README.md to document lessons learned about using MapStruct with Lombok, including the importance of annotation processor ordering and a sample mapper interface for cities.
  • Commented out sub-modules in cloud/pom.xml for service-registry, config-server, and api-gateway, possibly to temporarily disable their build..]

Summary by Sourcery

Introduce a new Spring Boot-based location-service for managing cities and airports, wired into the multi-module build and backed by MySQL via Docker Compose.

New Features:

  • Add location-service Spring Boot application with REST endpoints for managing cities and airports, including pagination and search for cities and city-scoped queries for airports.
  • Define City and Airport JPA entities with embeddable address and geocode value objects and corresponding request/response DTOs shared via the common-lib module.
  • Provide a standardized ApiResponse wrapper for API responses across the location-service.

Enhancements:

  • Wire the new location-service module into the services Maven aggregator and configure its dependencies, annotation processors, and application properties.
  • Document the design and responsibilities of the location-service, including planned caching, bulk operations, and API endpoints.
  • Add Docker Compose configuration for a MySQL database suitable for local development of the booking system and location-service.
  • Introduce IDE and Maven wrapper configuration for the location-service and common-lib modules, including a minimal CommonLibApplication entry point.

Build:

  • Enable the location-service Maven module with Spring Boot, Lombok, JPA, validation, and common-lib dependencies, and configure compiler annotation processors for Lombok.

Deployment:

  • Provide a Docker Compose setup for running a MySQL instance used by the booking/location services in local environments.

Documentation:

  • Extend the top-level README with notes and a sample mapper about using MapStruct with Lombok and add a dedicated README describing the location-service responsibilities and API design.

Tests:

  • Add a basic Spring Boot context load test for the new location-service module.

Chores:

  • Comment out unused cloud modules (service-registry, config-server, api-gateway) from the cloud Maven aggregator to simplify the current build.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 10, 2026

Reviewer's Guide

Implements a new Spring Boot-based location-service module (with City and Airport domain models, REST controllers, services, repositories, mappers, DTOs, and MySQL configuration), wires it into the multi-module build, and adds Docker/MySQL setup plus documentation about MapStruct/Lombok usage and development tooling.

Sequence diagram for creating a city via CityController

sequenceDiagram
    actor Client
    participant CityController
    participant CityServiceImpl
    participant CityRepository
    participant CityMapper
    participant Database

    Client->>CityController: POST /api/v1/cities (CityRequest)
    CityController->>CityServiceImpl: createCity(cityRequest)

    CityServiceImpl->>CityRepository: existsByCityCodeIgnoreCase(cityRequest.cityCode)
    CityRepository-->>CityServiceImpl: boolean exists
    alt cityCode already exists
        CityServiceImpl-->>CityController: throw IllegalArgumentException
        CityController-->>Client: 400 error
    else cityCode unique
        CityServiceImpl->>CityMapper: toEntity(cityRequest)
        CityMapper-->>CityServiceImpl: City

        CityServiceImpl->>CityRepository: save(city)
        CityRepository->>Database: insert City
        Database-->>CityRepository: persisted City
        CityRepository-->>CityServiceImpl: City

        CityServiceImpl->>CityMapper: toDto(city)
        CityMapper-->>CityServiceImpl: CityResponse

        CityServiceImpl-->>CityController: CityResponse
        CityController-->>Client: 201 ApiResponse\<CityResponse\>
    end
Loading

Sequence diagram for creating an airport via AirportController

sequenceDiagram
    actor Client
    participant AirportController
    participant AirportServiceimpl
    participant CityRepository
    participant AirportRepository
    participant AirportMapper
    participant Database

    Client->>AirportController: POST /api/v1/airports (AirportRequest)
    AirportController->>AirportServiceimpl: createAirport(request)

    AirportServiceimpl->>CityRepository: findById(request.cityId)
    CityRepository-->>AirportServiceimpl: Optional<City>
    alt city not found
        AirportServiceimpl-->>AirportController: throw IllegalArgumentException
        AirportController-->>Client: 400 error
    else city found
        AirportServiceimpl->>AirportMapper: toEntity(request)
        AirportMapper-->>AirportServiceimpl: Airport
        AirportServiceimpl->>AirportServiceimpl: setCity(city)

        AirportServiceimpl->>AirportRepository: save(airport)
        AirportRepository->>Database: insert Airport
        Database-->>AirportRepository: persisted Airport
        AirportRepository-->>AirportServiceimpl: Airport

        AirportServiceimpl->>AirportMapper: toDto(airport)
        AirportMapper-->>AirportServiceimpl: AirportResponse

        AirportServiceimpl-->>AirportController: AirportResponse
        AirportController-->>Client: 201 ApiResponse<AirportResponse>
    end
Loading

ER diagram for City and Airport tables in location-service

erDiagram
    CITY {
        bigint id PK
        varchar name
        varchar country_code
        varchar country
        varchar city_code
        varchar region_code
        varchar time_zone_id
    }

    AIRPORT {
        bigint id PK
        char iata
        varchar name
        varchar time_zone_id
        varchar street
        varchar postal_code
        double latitude
        double longitude
        bigint city_id FK
    }

    CITY ||--o{ AIRPORT : has
Loading

Class diagram for location-service domain, DTOs, services, and mappers

classDiagram

%% ===== Common-lib DTOs and value objects =====
class CityRequest {
  +String name
  +String countryCode
  +String country
  +String cityCode
  +String regionCode
  +String timeZoneOffset
}

class AirportRequest {
  +String iata
  +String name
  +String timeZoneId
  +Address address
  +GeoCode geoCode
  +Long cityId
}

class CityResponse {
  +Long id
  +String name
  +String countryCode
  +String country
  +String cityCode
  +String regionCode
  +String timeZoneOffest
}

class AirportResponse {
  +Long id
  +String iata
  +String name
  +String timeZoneId
  +Address address
  +GeoCode geoCode
  +CityResponse city
}

class ApiResponse~T~ {
  +boolean success
  +String message
  +T data
  +LocalDateTime timestamp
  +success(data) ApiResponse~T~
  +success(message, data) ApiResponse~T~
}

class Address {
  +String street
  +String postalCode
}

class GeoCode {
  +Double latitude
  +Double longitude
}

class CommonLibApplication


%% ===== JPA entities =====
class City {
  +Long id
  +String name
  +String countryCode
  +String country
  +String cityCode
  +String regionCode
  +String timeZoneId
  +List~Airport~ airports
}

class Airport {
  +Long id
  +String iata
  +String name
  +String timeZoneId
  +Address address
  +GeoCode geoCode
  +City city
}


%% ===== Repositories =====
class CityRepository {
  +Page~City~ findByCountryCodeIgnoreCase(countryCode, pageable)
  +boolean existsByCityCodeIgnoreCase(cityCode)
  +Page~City~ searchByKeyword(keyword, pageable)
}

class AirportRepository {
  +boolean existsByIataIgnoreCase(iata)
  +boolean existsByIataIgnoreCaseAndIdNot(iata, id)
  +List~Airport~ findByCityId(cityId)
  +boolean existsByCityId(cityId)
}


%% ===== Services =====
class CityService {
  +CityResponse createCity(cityRequest)
  +CityResponse updateCity(id, cityRequest)
  +CityResponse getCityById(id)
  +void deleteCity(id)
  +Page~CityResponse~ getAllCities(pageable)
  +Page~CityResponse~ searchCities(keyword, pageable)
  +Page~CityResponse~ getCitiesByCountryCode(countryCode, pageable)
  +boolean cityExists(cityCode)
}

class CityServiceImpl {
  -CityRepository cityRepository
  +CityResponse createCity(cityRequest)
  +CityResponse updateCity(id, cityRequest)
  +CityResponse getCityById(id)
  +void deleteCity(id)
  +Page~CityResponse~ getAllCities(pageable)
  +Page~CityResponse~ searchCities(keyword, pageable)
  +Page~CityResponse~ getCitiesByCountryCode(countryCode, pageable)
  +boolean cityExists(cityCode)
}

class AirportService {
  +AirportResponse createAirport(request)
  +AirportResponse updateAirport(id, request)
  +List~AirportResponse~ getAllAirports()
  +AirportResponse getAirportById(id)
  +void deleteAirport(id)
  +List~AirportResponse~ getAirportsByCityId(cityId)
}

class AirportServiceimpl {
  -AirportRepository airportRepository
  -CityRepository cityRepository
  -CityService cityService
  +AirportResponse createAirport(request)
  +AirportResponse updateAirport(id, request)
  +List~AirportResponse~ getAllAirports()
  +AirportResponse getAirportById(id)
  +void deleteAirport(id)
  +List~AirportResponse~ getAirportsByCityId(cityId)
}


%% ===== Mappers =====
class CityMapper {
  +City toEntity(request)
  +CityResponse toDto(city)
  +void updateEntityFromRequest(request, city)
}

class AirportMapper {
  -CityMapper cityMapper
  +Airport toEntity(request)
  +AirportResponse toDto(airport)
  +void updateEntityFromRequest(request, airport)
}


%% ===== Controllers and application =====
class CityController {
  -CityService cityService
  +ResponseEntity createCity(cityRequest)
  +ResponseEntity updateCity(id, cityRequest)
  +ResponseEntity getCityById(id)
  +ResponseEntity deleteCity(id)
  +ResponseEntity getAllCities(pageable)
  +ResponseEntity searchCities(keyword, pageable)
  +ResponseEntity getCitiesByCountryCode(countryCode, pageable)
  +ResponseEntity cityExists(cityCode)
}

class AirportController {
  -AirportService airportService
  +ResponseEntity createAirport(request)
  +ResponseEntity updateAirport(id, request)
  +ResponseEntity getAirportById(id)
  +ResponseEntity getAllAirports()
  +ResponseEntity deleteAirport(id)
  +ResponseEntity getAirportsByCityId(cityId)
}

class HomeController {
  +String HomeController()
}

class LocationServiceApplication {
  +main(args)
}


%% ===== Relationships =====
City "1" --> "*" Airport : airports
Airport --> City : city

Airport --> Address : embedded
Airport --> GeoCode : embedded
AirportRequest --> Address : uses
AirportRequest --> GeoCode : uses
AirportResponse --> Address : uses
AirportResponse --> GeoCode : uses
AirportResponse --> CityResponse : uses

CityController --> CityService
AirportController --> AirportService
HomeController --> ApiResponse

CityServiceImpl ..|> CityService
AirportServiceimpl ..|> AirportService

CityServiceImpl --> CityRepository
AirportServiceimpl --> AirportRepository
AirportServiceimpl --> CityRepository
AirportServiceimpl --> CityService

CityRepository --> City
AirportRepository --> Airport

CityMapper --> City
CityMapper --> CityRequest
CityMapper --> CityResponse

AirportMapper --> Airport
AirportMapper --> AirportRequest
AirportMapper --> AirportResponse
AirportMapper --> CityMapper

LocationServiceApplication --> CityController
LocationServiceApplication --> AirportController
LocationServiceApplication --> HomeController

ApiResponse --> "T" CityResponse
ApiResponse --> "T" AirportResponse
Loading

File-Level Changes

Change Details Files
Introduce location-service Spring Boot module with REST APIs for managing cities and airports backed by JPA entities and repositories.
  • Create location-service Maven module with dependencies on common-lib, Spring Boot web/JPA, MySQL driver, Lombok, validation API, and compiler plugin setup for Lombok
  • Add LocationServiceApplication bootstrap class and basic HomeController health endpoint
  • Define City and Airport JPA entities including relationships, embedded Address/GeoCode, and indexes
  • Implement CityService and AirportService interfaces plus their service implementations with validation, CRUD operations, and transactional behavior
  • Expose REST controllers for City and Airport with validation, pagination, search, and standardized ApiResponse envelopes
  • Add Spring Boot configuration for location-service (application name, port, and MySQL datasource)
  • Add skeletal service README documenting responsibilities, entities, caching plans, bulk operations, and endpoints
services/location-service/pom.xml
services/location-service/src/main/java/com/flynest/location_service/LocationServiceApplication.java
services/location-service/src/main/java/com/flynest/location_service/controller/HomeController.java
services/location-service/src/main/java/com/flynest/location_service/controller/CityController.java
services/location-service/src/main/java/com/flynest/location_service/controller/AirportController.java
services/location-service/src/main/java/com/flynest/location_service/model/City.java
services/location-service/src/main/java/com/flynest/location_service/model/Airport.java
services/location-service/src/main/java/com/flynest/location_service/Repository/CityRepository.java
services/location-service/src/main/java/com/flynest/location_service/Repository/AirportRepository.java
services/location-service/src/main/java/com/flynest/location_service/service/CityService.java
services/location-service/src/main/java/com/flynest/location_service/service/AirportService.java
services/location-service/src/main/java/com/flynest/location_service/service/impl/CityServiceImpl.java
services/location-service/src/main/java/com/flynest/location_service/service/impl/AirportServiceimpl.java
services/location-service/src/main/java/com/flynest/location_service/mapper/CityMapper.java
services/location-service/src/main/java/com/flynest/location_service/mapper/AirportMapper.java
services/location-service/src/main/resources/application.yaml
services/location-service/src/test/java/com/flynest/location_service/LocationServiceApplicationTests.java
services/location-service/readme.md
Add shared DTOs, value objects, and API response wrapper in common-lib for location-related operations.
  • Introduce CityRequest and AirportRequest DTOs with validation constraints for incoming API payloads
  • Add CityResponse and AirportResponse DTOs for outbound responses, including nested CityResponse within AirportResponse
  • Create embeddable Address and GeoCode value objects with validation for use in entities and DTOs
  • Provide a generic ApiResponse wrapper with success flag, message, data, and timestamp
  • Add a minimal CommonLibApplication entry point class
common-lib/src/main/java/com/flynest/payload/request/CityRequest.java
common-lib/src/main/java/com/flynest/payload/request/AirportRequest.java
common-lib/src/main/java/com/flynest/payload/response/CityResponse.java
common-lib/src/main/java/com/flynest/payload/response/AirportResponse.java
common-lib/src/main/java/com/flynest/payload/response/ApiResponse.java
common-lib/src/main/java/com/flynest/emabbedable/Address.java
common-lib/src/main/java/com/flynest/emabbedable/GeoCode.java
common-lib/src/main/java/com.flynest/CommonLibApplication.java
Adjust multi-module Maven configuration and add Maven wrapper for the new service.
  • Switch services aggregator module from user-services to location-service
  • Comment out cloud modules (service-registry, config-server, api-gateway) in the cloud POM to exclude them from the build
  • Add Maven wrapper scripts and properties for the location-service module
services/pom.xml
cloud/pom.xml
services/location-service/mvnw
services/location-service/mvnw.cmd
services/location-service/.mvn/wrapper/maven-wrapper.properties
Introduce Docker Compose configuration for a MySQL database to support the booking/location services.
  • Add docker-compose configuration defining a MySQL 8.0 service with credentials, exposed port, volume, and healthcheck
  • Align datasource settings in location-service application.yaml with the MySQL setup (database and credentials)
docker-compose.yaml
services/location-service/src/main/resources/application.yaml
Update documentation and IDE configuration, and check in build metadata.
  • Extend root README with notes and example code on using MapStruct with Lombok and annotation processor ordering
  • Add IDE configuration files for encoding, compiler, materials theme, modules, and workspace
  • Remove .idea/.gitignore so IDE files are now tracked
  • Add generated maven-status metadata files under common-lib/target
README.md
.idea/compiler.xml
.idea/copilotDiffState.xml
.idea/encodings.xml
.idea/material_theme_project_new.xml
.idea/misc.xml
.idea/workspace.xml
.idea/.gitignore
common-lib/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
common-lib/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@vikasutf8 vikasutf8 merged commit 928ce5b into dev-master Apr 10, 2026
1 check passed
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 17 issues, and left some high level feedback:

  • AirportMapper is annotated as a Spring @component but only exposes static methods and never uses the injected CityMapper, which is both redundant and misleading; either remove @component and the field/constructor or refactor the methods to be instance-based and leverage the injected mapper.
  • HomeController currently constructs ApiResponse via new ApiResponse() even though ApiResponse is a Lombok @builder with final fields and no explicit constructor, which is unlikely to compile and also bypasses the provided factory methods; consider returning ApiResponse.success("Welcome to Location Service API") (or similar) directly from the endpoint.
  • Service and repository naming is inconsistent with common conventions (e.g., AirportServiceimpl instead of AirportServiceImpl, package Repository capitalized, and service methods throwing bare IllegalArgumentException for not-found cases); aligning class/package names and using domain-specific exceptions mapped to proper HTTP status codes (e.g., 404) would make the API clearer and easier to maintain.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- AirportMapper is annotated as a Spring @Component but only exposes static methods and never uses the injected CityMapper, which is both redundant and misleading; either remove @Component and the field/constructor or refactor the methods to be instance-based and leverage the injected mapper.
- HomeController currently constructs ApiResponse via `new ApiResponse()` even though ApiResponse is a Lombok @Builder with final fields and no explicit constructor, which is unlikely to compile and also bypasses the provided factory methods; consider returning `ApiResponse.success("Welcome to Location Service API")` (or similar) directly from the endpoint.
- Service and repository naming is inconsistent with common conventions (e.g., `AirportServiceimpl` instead of `AirportServiceImpl`, package `Repository` capitalized, and service methods throwing bare IllegalArgumentException for not-found cases); aligning class/package names and using domain-specific exceptions mapped to proper HTTP status codes (e.g., 404) would make the API clearer and easier to maintain.

## Individual Comments

### Comment 1
<location path="services/location-service/pom.xml" line_range="18-27" />
<code_context>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-jpa</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-webmvc</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-devtools</artifactId>
+			<scope>runtime</scope>
+			<optional>true</optional>
+		</dependency>
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+			<optional>true</optional>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-jpa-test</artifactId>
+			<scope>test</scope>
+		</dependency>
</code_context>
<issue_to_address>
**issue (bug_risk):** The `spring-boot-starter-data-jpa-test` artifact does not exist and will cause build failures.

Spring Boot only provides `spring-boot-starter-test` for test support (including JPA-related tests), not `spring-boot-starter-data-jpa-test`. You should replace this dependency with `spring-boot-starter-test` (and add any extra test-scope dependencies you need), otherwise Maven will fail to resolve it.
</issue_to_address>

### Comment 2
<location path="services/location-service/src/main/java/com/flynest/location_service/service/impl/AirportServiceimpl.java" line_range="23" />
<code_context>
+@Service
+@RequiredArgsConstructor
+@Slf4j
+@Transactional(readOnly = true)
+public class AirportServiceimpl implements AirportService {
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Class-level `@Transactional(readOnly = true)` conflicts with write operations in this service.

Because of the class-level `@Transactional(readOnly = true)`, write methods like `createAirport`, `updateAirport`, and `deleteAirport` will execute in a read-only transaction, which may prevent changes from being persisted or cause vendor-specific issues. Consider removing the class-level `readOnly = true` and annotating only read methods, or explicitly overriding write methods with `@Transactional(readOnly = false)`.
</issue_to_address>

### Comment 3
<location path="services/location-service/src/main/java/com/flynest/location_service/service/impl/AirportServiceimpl.java" line_range="24" />
<code_context>
+@RequiredArgsConstructor
+@Slf4j
+@Transactional(readOnly = true)
+public class AirportServiceimpl implements AirportService {
+
+
</code_context>
<issue_to_address>
**nitpick (typo):** Class name `AirportServiceimpl` is likely a typo and inconsistent with Java naming conventions.

This mismatch may make it harder to find the implementation when searching the codebase. Please rename the class and file to `AirportServiceImpl` for consistency.

Suggested implementation:

```java
public class AirportServiceImpl implements AirportService {

```

1. Rename the file from:
   `services/location-service/src/main/java/com/flynest/location_service/service/impl/AirportServiceimpl.java`
   to:
   `services/location-service/src/main/java/com/flynest/location_service/service/impl/AirportServiceImpl.java`
   (e.g., using `git mv`).

2. Search the codebase for `AirportServiceimpl` (including configuration files, tests, and Spring component scans) and replace with `AirportServiceImpl` wherever it refers to this class/file.
</issue_to_address>

### Comment 4
<location path="services/location-service/src/main/java/com/flynest/location_service/controller/HomeController.java" line_range="14" />
<code_context>
+
+    @GetMapping("")
+    public String HomeController(){
+        ApiResponse response = new ApiResponse();
+        response.setMessage("Welcome to Location Service API");
+        return response.getMessage();
</code_context>
<issue_to_address>
**issue (bug_risk):** `ApiResponse` cannot be instantiated with `new` and the controller currently returns a plain String instead of the response wrapper.

Because `ApiResponse` uses `@Builder` and `final` fields, it has no no-args constructor, so `new ApiResponse()` will not compile. In addition, the method returns `String` while constructing an `ApiResponse`. Update the method to return something like `ResponseEntity<ApiResponse<String>>` and build the response via `ApiResponse.success("Welcome to Location Service API")`.
</issue_to_address>

### Comment 5
<location path="services/location-service/src/main/java/com/flynest/location_service/mapper/AirportMapper.java" line_range="9-12" />
<code_context>
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AirportMapper {
+
+    private final CityMapper cityMapper;
+
+    public AirportMapper(CityMapper cityMapper) {
</code_context>
<issue_to_address>
**suggestion:** `AirportMapper` is a Spring component but exposes only static methods and the injected `CityMapper` is unused.

The class is declared as a Spring `@Component` with a `CityMapper` dependency, but all exposed methods are static and never use the injected instance. This inconsistency can confuse maintainers. Please either remove the `@Component` and the unused dependency, or convert the methods to instance methods that use the injected `CityMapper` where relevant.

Suggested implementation:

```java
import com.flynest.payload.response.AirportResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class AirportMapper {

    private final CityMapper cityMapper;

    // AirportRequest ──► Airport entity
    public Airport toEntity(AirportRequest request) {

```

There are likely other static methods in `AirportMapper` (for mapping `Airport` to `AirportResponse`, etc.). To fully align with the suggestion:
1. Convert all remaining `public static` methods in this class to instance methods (`public ...`).
2. Where a `City` or city-related field is mapped, delegate to `cityMapper` (for example, `cityMapper.toResponse(airport.getCity())`) instead of manual mapping.
3. Update all usages of `AirportMapper` to obtain it via Spring injection (`@Autowired`/constructor injection) rather than calling static methods.
</issue_to_address>

### Comment 6
<location path="services/location-service/src/main/java/com/flynest/location_service/service/impl/CityServiceImpl.java" line_range="35-38" />
<code_context>
+    public CityResponse updateCity(Long id, CityRequest cityRequest) {
+        City city = cityRepository.findById(id)
+                .orElseThrow(() -> new IllegalArgumentException("City not found with id: " + id));
+//        if (cityRequest.getCityCode() != null &&
+//                !cityRequest.getCityCode().equalsIgnoreCase(city.getCityCode()) &&
+//                cityRepository.existsByCityCodeIgnoreCase(cityRequest.getCityCode())) {
+//            throw new IllegalArgumentException("City code already exists: " + cityRequest.getCityCode());
+//        }
+        CityMapper.updateEntityFromRequest(cityRequest, city);
</code_context>
<issue_to_address>
**question (bug_risk):** Commented-out uniqueness check in `updateCity` may allow duplicate city codes.

Because `createCity` enforces `existsByCityCodeIgnoreCase` and `cityCode` is unique at the entity/DB level, updating a city without this check can lead to duplicate codes or DB constraint violations when the code changes. If uniqueness on update is still required, please restore this guard (or equivalent logic) rather than relying solely on the DB constraint.
</issue_to_address>

### Comment 7
<location path="services/location-service/src/main/java/com/flynest/location_service/mapper/CityMapper.java" line_range="32" />
<code_context>
+                .country(city.getCountry())
+                .cityCode(city.getCityCode())
+                .regionCode(city.getRegionCode())
+                .timeZoneOffest(city.getTimeZoneId())
+                .build();
+    }
</code_context>
<issue_to_address>
**suggestion (typo):** Typo in `timeZoneOffest` field name will propagate into the API contract.

`CityResponse` and the mapper both use the misspelled `timeZoneOffest`. If the API isn’t yet public, please rename this consistently to `timeZoneOffset` in all DTOs and mappers. If it’s already public, consider adding a correctly named field while still accepting the old one for backward compatibility.

Suggested implementation:

```java
                .regionCode(city.getRegionCode())
                .timeZoneOffset(city.getTimeZoneId())

```

To fully implement the suggestion you made in the review, you will also need to:
1. Update `CityResponse` in `services/location-service/src/main/java/com/flynest/location_service/dto/CityResponse.java` (or the equivalent package) to rename the field, getters/setters, and builder method from `timeZoneOffest` to `timeZoneOffset`.
2. If the API is already public and you need backward compatibility:
   - Keep the old `timeZoneOffest` field annotated with `@JsonProperty("timeZoneOffest")`, mark it as `@Deprecated`, and/or ignore it for output.
   - Add the new `timeZoneOffset` field with `@JsonProperty("timeZoneOffset")`.
   - In the mapper, populate only `timeZoneOffset` for outgoing responses.
   - For incoming requests, optionally accept both `timeZoneOffset` and `timeZoneOffest` if this DTO is also used as a request body model.
3. Update any tests, builders, or code constructing `CityResponse` directly to use `timeZoneOffset` instead of `timeZoneOffest`.
</issue_to_address>

### Comment 8
<location path="services/location-service/src/test/java/com/flynest/location_service/LocationServiceApplicationTests.java" line_range="6-7" />
<code_context>
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class LocationServiceApplicationTests {
+
+	@Test
</code_context>
<issue_to_address>
**issue (testing):** Add unit tests for CityServiceImpl and AirportServiceimpl to cover core domain logic and edge cases

Currently only a context-load smoke test exists, so none of the new service logic is exercised. Please add unit tests for `CityServiceImpl` and `AirportServiceimpl` with mocked repositories to validate both success and failure paths, for example:

- `CityServiceImpl.createCity`: unique city code succeeds; duplicate code (via `existsByCityCodeIgnoreCase`) throws.
- `CityServiceImpl.updateCity`: throws when `findById` is empty; correctly applies `CityMapper.updateEntityFromRequest` before saving.
- `AirportServiceimpl.createAirport`: throws when `cityRepository.findById` is empty; sets `city` on `Airport` before saving.
- `AirportServiceimpl.updateAirport`: throws when `airportRepository.findById` is empty; updates only non-null fields, including `city` when `cityId` is provided.
- `getAirportsByCityId` / `deleteAirport`: throw when `existsById` / `existsByCityId` preconditions fail.

This will ensure the service layer behavior is verified and guard against regressions if repository or mapper behavior changes.
</issue_to_address>

### Comment 9
<location path="services/location-service/src/test/java/com/flynest/location_service/LocationServiceApplicationTests.java" line_range="7-11" />
<code_context>
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class LocationServiceApplicationTests {
+
+	@Test
+	void contextLoads() {
+	}
+
+}
</code_context>
<issue_to_address>
**suggestion (testing):** Consider adding simple mapper tests for CityMapper and AirportMapper to guard against mapping regressions

Because a lot of logic depends on `CityMapper` and `AirportMapper`, it would be good to add focused unit tests for them, for example:

- `CityMapper.toEntity` / `toDto`: verify all fields, including `timeZoneOffset` ↔ `timeZoneId`.
- `CityMapper.updateEntityFromRequest`: confirm only non-null request fields overwrite the entity.
- `AirportMapper.toEntity`: check `city` remains unset and other fields map correctly.
- `AirportMapper.toDto`: ensure nested `City` is mapped to `CityResponse` via `CityMapper.toDto`.
- `AirportMapper.updateEntityFromRequest`: validate only non-null fields update the entity and `city` is unchanged.

This will help catch subtle mapping regressions as DTOs/entities change.

Suggested implementation:

```java
package com.flynest.location_service;

import com.flynest.location_service.city.City;
import com.flynest.location_service.city.CityMapper;
import com.flynest.location_service.city.dto.CityRequest;
import com.flynest.location_service.city.dto.CityResponse;
import com.flynest.location_service.airport.Airport;
import com.flynest.location_service.airport.AirportMapper;
import com.flynest.location_service.airport.dto.AirportRequest;
import com.flynest.location_service.airport.dto.AirportResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest
class LocationServiceApplicationTests {

	@Autowired
	private CityMapper cityMapper;

	@Autowired
	private AirportMapper airportMapper;

	@Test
	void contextLoads() {
	}

	@Test
	void cityMapper_toEntity_and_toDto_shouldMapAllFields() {
		// given
		CityRequest request = new CityRequest();
		request.setName("Berlin");
		request.setCountryCode("DE");
		// Adjust these field names/types to match your DTO
		// e.g. request.setTimeZoneId("Europe/Berlin");
		// request.setIataCode("BER");

		// when
		City entity = cityMapper.toEntity(request);
		CityResponse response = cityMapper.toDto(entity);

		// then
		assertThat(response.getName()).isEqualTo(request.getName());
		assertThat(response.getCountryCode()).isEqualTo(request.getCountryCode());
		// For time zone mapping, assert the expected conversion between timeZoneId and timeZoneOffset here.
		// Example (adjust to your actual model):
		// assertThat(entity.getTimeZoneOffset()).isEqualTo(120);
		// assertThat(response.getTimeZoneId()).isEqualTo("Europe/Berlin");
	}

	@Test
	void cityMapper_updateEntityFromRequest_shouldUpdateOnlyNonNullFields() {
		// given
		City existing = new City();
		existing.setName("Old Name");
		existing.setCountryCode("DE");
		// existing.setTimeZoneOffset(60);

		CityRequest update = new CityRequest();
		update.setName("New Name");
		// leave countryCode and time zone null so they should not be overwritten

		// when
		cityMapper.updateEntityFromRequest(update, existing);

		// then
		assertThat(existing.getName()).isEqualTo("New Name");
		assertThat(existing.getCountryCode()).isEqualTo("DE");
		// assertThat(existing.getTimeZoneOffset()).isEqualTo(60);
	}

	@Test
	void airportMapper_toEntity_shouldMapAllFields_andLeaveCityUnset() {
		// given
		AirportRequest request = new AirportRequest();
		request.setCode("TXL");
		request.setName("Tegel Airport");
		request.setCountryCode("DE");
		// request.setCityId(1L); // if such a field exists, entity.city should still remain null

		// when
		Airport entity = airportMapper.toEntity(request);

		// then
		assertThat(entity.getCode()).isEqualTo(request.getCode());
		assertThat(entity.getName()).isEqualTo(request.getName());
		assertThat(entity.getCountryCode()).isEqualTo(request.getCountryCode());
		assertThat(entity.getCity()).isNull();
	}

	@Test
	void airportMapper_toDto_shouldMapNestedCityUsingCityMapper() {
		// given
		City city = new City();
		city.setName("Berlin");
		city.setCountryCode("DE");
		// city.setTimeZoneOffset(120);

		Airport airport = new Airport();
		airport.setCode("BER");
		airport.setName("Berlin Brandenburg");
		airport.setCountryCode("DE");
		airport.setCity(city);

		// when
		AirportResponse response = airportMapper.toDto(airport);

		// then
		assertThat(response.getCode()).isEqualTo(airport.getCode());
		assertThat(response.getName()).isEqualTo(airport.getName());
		assertThat(response.getCountryCode()).isEqualTo(airport.getCountryCode());
		assertThat(response.getCity()).isNotNull();
		assertThat(response.getCity().getName()).isEqualTo(city.getName());
		assertThat(response.getCity().getCountryCode()).isEqualTo(city.getCountryCode());
		// Assert time zone mapping between City and CityResponse if applicable
	}

	@Test
	void airportMapper_updateEntityFromRequest_shouldUpdateOnlyNonNullFields_andKeepCityUnchanged() {
		// given
		City city = new City();
		city.setName("Berlin");

		Airport existing = new Airport();
		existing.setCode("OLD");
		existing.setName("Old Airport");
		existing.setCountryCode("DE");
		existing.setCity(city);

		AirportRequest update = new AirportRequest();
		update.setCode("NEW");
		// leave name and countryCode null so they should not be overwritten

		// when
		airportMapper.updateEntityFromRequest(update, existing);

		// then
		assertThat(existing.getCode()).isEqualTo("NEW");
		assertThat(existing.getName()).isEqualTo("Old Airport");
		assertThat(existing.getCountryCode()).isEqualTo("DE");
		assertThat(existing.getCity()).isSameAs(city);
	}
}

```

The above implementation assumes:
- Package names for `City`, `CityMapper`, `CityRequest`, `CityResponse`, `Airport`, `AirportMapper`, `AirportRequest`, and `AirportResponse`.
- Field names like `name`, `countryCode`, `code`, and time zone–related accessors.

You may need to:
1. Adjust the import statements to match the actual package structure of your entities, DTOs, and mappers.
2. Update field names and method calls in the tests (e.g. `getCode`, `getCountryCode`, time zone accessors) to match your real model.
3. Replace the commented time zone assertions with concrete expectations that align with your `timeZoneOffset` ↔ `timeZoneId` mapping logic.
</issue_to_address>

### Comment 10
<location path="services/location-service/readme.md" line_range="8" />
<code_context>
+- Airport
+  - IATA with country code and infos
+
+### Entities type
+1. Cities
+- id: string
</code_context>
<issue_to_address>
**suggestion (typo):** Consider changing "Entities type" to "Entity types" for correct grammar.

```suggestion
### Entity types
```
</issue_to_address>

### Comment 11
<location path="services/location-service/readme.md" line_range="26" />
<code_context>
+- geoCode --Embedded object
+  - latitude
+  - longitude
+- city  [refreence of cities] 
+  - one city have many airports @manytoone 
+  - bidirection or unidirectional [each city airport hold reference of city but city hold reference of airport]  ----Bidirectional
</code_context>
<issue_to_address>
**issue (typo):** Fix the spelling of "refreence" to "reference".

Change the bracket text to "[reference of cities]".

```suggestion
- city  [reference of cities] 
```
</issue_to_address>

### Comment 12
<location path="services/location-service/readme.md" line_range="31-33" />
<code_context>
+  - bidirection or unidirectional [each city airport hold reference of city but city hold reference of airport]  ----Bidirectional
+
+
+### Redis Caching 
+Cities and Airport data rarely change and its read very frequenctly 
+- Cache annotion 
+  - @Cacheable: to cache the result of a method call (airportByiata)
</code_context>
<issue_to_address>
**issue (typo):** Fix "its" and "frequenctly" in the Redis caching description.

Suggest: "Cities and airport data rarely change and it's read very frequently."

```suggestion
### Redis Caching 
Cities and airport data rarely change and it's read very frequently 
- Cache annotion 
```
</issue_to_address>

### Comment 13
<location path="services/location-service/readme.md" line_range="33" />
<code_context>
+
+### Redis Caching 
+Cities and Airport data rarely change and its read very frequenctly 
+- Cache annotion 
+  - @Cacheable: to cache the result of a method call (airportByiata)
+  - @CachePut: to update the cache without interfering with the method execution
</code_context>
<issue_to_address>
**issue (typo):** Correct the spelling of "annotion" to "annotation".

Change this bullet to “Cache annotation”.

```suggestion
- Cache annotation 
```
</issue_to_address>

### Comment 14
<location path="services/location-service/readme.md" line_range="49" />
<code_context>
+  - POST: api/cities/bulk
+- Validation failure
+
+### Dto & Mappeer Pattern
+
+### Api EndPoints
</code_context>
<issue_to_address>
**issue (typo):** Fix the typo "Mappeer" to "Mapper".

Also consider renaming this heading to “DTO & Mapper Pattern” to correct the spelling and capitalization.

```suggestion
### DTO & Mapper Pattern
```
</issue_to_address>

### Comment 15
<location path="services/location-service/readme.md" line_range="56" />
<code_context>
+base : api/cities
+1. Post : create 
+2. Post : bulk create /bulk
+3. Get : get  all citiest
+4. get : get by id {id}
+5. Put : update cities by id {id}
</code_context>
<issue_to_address>
**issue (typo):** Correct the typo "citiest" to "cities".

Change this phrase to “get all cities” to correct the spelling.

```suggestion
3. Get : get all cities
```
</issue_to_address>

### Comment 16
<location path="services/location-service/readme.md" line_range="61" />
<code_context>
+5. Put : update cities by id {id}
+6. delete : hard delete city  by id {id}
+
+7. get : search by cititest /search 
+#### Airports
+base :api/airport
</code_context>
<issue_to_address>
**question (typo):** Fix the typo "cititest" in this endpoint description.

Use "city" or "cities" instead of "cititest", e.g., "search by city/cities".

```suggestion
7. get : search by city /search 
```
</issue_to_address>

### Comment 17
<location path="services/location-service/readme.md" line_range="64" />
<code_context>
+7. get : search by cititest /search 
+#### Airports
+base :api/airport
+CURD operation  [1 -6 ]
+7. get : get by iata code /iata/{iata}
+8. get : search by city id-code /city/{city}
</code_context>
<issue_to_address>
**suggestion (typo):** Correct "CURD operation" to the usual term "CRUD operation".

Use the standard CRUD acronym (Create, Read, Update, Delete) instead of CURD.

```suggestion
CRUD (Create, Read, Update, Delete) operations [1-6]
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +18 to +27
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>

<dependency>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): The spring-boot-starter-data-jpa-test artifact does not exist and will cause build failures.

Spring Boot only provides spring-boot-starter-test for test support (including JPA-related tests), not spring-boot-starter-data-jpa-test. You should replace this dependency with spring-boot-starter-test (and add any extra test-scope dependencies you need), otherwise Maven will fail to resolve it.

@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Class-level @Transactional(readOnly = true) conflicts with write operations in this service.

Because of the class-level @Transactional(readOnly = true), write methods like createAirport, updateAirport, and deleteAirport will execute in a read-only transaction, which may prevent changes from being persisted or cause vendor-specific issues. Consider removing the class-level readOnly = true and annotating only read methods, or explicitly overriding write methods with @Transactional(readOnly = false).

@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true)
public class AirportServiceimpl implements AirportService {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nitpick (typo): Class name AirportServiceimpl is likely a typo and inconsistent with Java naming conventions.

This mismatch may make it harder to find the implementation when searching the codebase. Please rename the class and file to AirportServiceImpl for consistency.

Suggested implementation:

public class AirportServiceImpl implements AirportService {
  1. Rename the file from:
    services/location-service/src/main/java/com/flynest/location_service/service/impl/AirportServiceimpl.java
    to:
    services/location-service/src/main/java/com/flynest/location_service/service/impl/AirportServiceImpl.java
    (e.g., using git mv).

  2. Search the codebase for AirportServiceimpl (including configuration files, tests, and Spring component scans) and replace with AirportServiceImpl wherever it refers to this class/file.


@GetMapping("")
public String HomeController(){
ApiResponse response = new ApiResponse();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): ApiResponse cannot be instantiated with new and the controller currently returns a plain String instead of the response wrapper.

Because ApiResponse uses @Builder and final fields, it has no no-args constructor, so new ApiResponse() will not compile. In addition, the method returns String while constructing an ApiResponse. Update the method to return something like ResponseEntity<ApiResponse<String>> and build the response via ApiResponse.success("Welcome to Location Service API").

Comment on lines +9 to +12
@Component
public class AirportMapper {

private final CityMapper cityMapper;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion: AirportMapper is a Spring component but exposes only static methods and the injected CityMapper is unused.

The class is declared as a Spring @Component with a CityMapper dependency, but all exposed methods are static and never use the injected instance. This inconsistency can confuse maintainers. Please either remove the @Component and the unused dependency, or convert the methods to instance methods that use the injected CityMapper where relevant.

Suggested implementation:

import com.flynest.payload.response.AirportResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class AirportMapper {

    private final CityMapper cityMapper;

    // AirportRequest ──► Airport entity
    public Airport toEntity(AirportRequest request) {

There are likely other static methods in AirportMapper (for mapping Airport to AirportResponse, etc.). To fully align with the suggestion:

  1. Convert all remaining public static methods in this class to instance methods (public ...).
  2. Where a City or city-related field is mapped, delegate to cityMapper (for example, cityMapper.toResponse(airport.getCity())) instead of manual mapping.
  3. Update all usages of AirportMapper to obtain it via Spring injection (@Autowired/constructor injection) rather than calling static methods.


### Redis Caching
Cities and Airport data rarely change and its read very frequenctly
- Cache annotion
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (typo): Correct the spelling of "annotion" to "annotation".

Change this bullet to “Cache annotation”.

Suggested change
- Cache annotion
- Cache annotation

- POST: api/cities/bulk
- Validation failure

### Dto & Mappeer Pattern
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (typo): Fix the typo "Mappeer" to "Mapper".

Also consider renaming this heading to “DTO & Mapper Pattern” to correct the spelling and capitalization.

Suggested change
### Dto & Mappeer Pattern
### DTO & Mapper Pattern

base : api/cities
1. Post : create
2. Post : bulk create /bulk
3. Get : get all citiest
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (typo): Correct the typo "citiest" to "cities".

Change this phrase to “get all cities” to correct the spelling.

Suggested change
3. Get : get all citiest
3. Get : get all cities

5. Put : update cities by id {id}
6. delete : hard delete city by id {id}

7. get : search by cititest /search
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

question (typo): Fix the typo "cititest" in this endpoint description.

Use "city" or "cities" instead of "cititest", e.g., "search by city/cities".

Suggested change
7. get : search by cititest /search
7. get : search by city /search

7. get : search by cititest /search
#### Airports
base :api/airport
CURD operation [1 -6 ]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (typo): Correct "CURD operation" to the usual term "CRUD operation".

Use the standard CRUD acronym (Create, Read, Update, Delete) instead of CURD.

Suggested change
CURD operation [1 -6 ]
CRUD (Create, Read, Update, Delete) operations [1-6]

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.

Feat : Implment @Mapper MapSturck functionality in Mapper Packages accros the service

1 participant