diff --git a/core/src/main/java/cz/muni/pa165/data/model/Car.java b/core/src/main/java/cz/muni/pa165/data/model/Car.java
index cfd36d0e767f35be14f300ccdc7a8271e7e4168e..883d1caf6a5ebe96aa6c8f78f3d2b4b1b29bef0f 100644
--- a/core/src/main/java/cz/muni/pa165/data/model/Car.java
+++ b/core/src/main/java/cz/muni/pa165/data/model/Car.java
@@ -1,5 +1,6 @@
 package cz.muni.pa165.data.model;
 
+import com.fasterxml.jackson.annotation.JsonManagedReference;
 import jakarta.annotation.Nonnull;
 import jakarta.annotation.Nullable;
 import jakarta.persistence.*;
@@ -15,12 +16,14 @@ public class Car extends DomainObject implements Serializable {
     @OneToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "driver_id")
     @Nullable
+    @JsonManagedReference
     private Driver driver;
 
     @OneToMany(fetch = FetchType.LAZY,
             mappedBy = "car",
             cascade = {CascadeType.REMOVE, CascadeType.PERSIST, CascadeType.MERGE})
     @Nonnull
+    @JsonManagedReference
     private Set<CarComponent> components;
 
     public Car() {
diff --git a/core/src/main/java/cz/muni/pa165/data/model/CarComponent.java b/core/src/main/java/cz/muni/pa165/data/model/CarComponent.java
index f5641c0d22840e9cd6737e45d1d9e8ca716fa621..4dd89fd90717b45df9ae4f60f3006ba491cccf98 100644
--- a/core/src/main/java/cz/muni/pa165/data/model/CarComponent.java
+++ b/core/src/main/java/cz/muni/pa165/data/model/CarComponent.java
@@ -1,5 +1,6 @@
 package cz.muni.pa165.data.model;
 
+import com.fasterxml.jackson.annotation.JsonBackReference;
 import cz.muni.pa165.data.enums.ComponentTypeEnum;
 import jakarta.annotation.Nonnull;
 import jakarta.annotation.Nullable;
@@ -29,6 +30,7 @@ public class CarComponent extends DomainObject implements Serializable {
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "car_id")
     @Nullable
+    @JsonBackReference
     private Car car;
 
     public CarComponent() {
diff --git a/core/src/main/java/cz/muni/pa165/data/model/Driver.java b/core/src/main/java/cz/muni/pa165/data/model/Driver.java
index efa7bad06caf0c425cf334b18f929505357dd926..8650b6fadf0153173d23a646641035c660ad5c9f 100644
--- a/core/src/main/java/cz/muni/pa165/data/model/Driver.java
+++ b/core/src/main/java/cz/muni/pa165/data/model/Driver.java
@@ -1,5 +1,6 @@
 package cz.muni.pa165.data.model;
 
+import com.fasterxml.jackson.annotation.JsonBackReference;
 import cz.muni.pa165.data.enums.CharacteristicsEnum;
 import jakarta.annotation.Nonnull;
 import jakarta.annotation.Nullable;
@@ -47,6 +48,7 @@ public class Driver extends DomainObject implements Serializable {
             mappedBy = "driver",
             cascade = {CascadeType.REMOVE, CascadeType.PERSIST, CascadeType.MERGE})
     @Nullable
+    @JsonBackReference
     private Car car;
 
     public Driver() {
diff --git a/core/src/main/java/cz/muni/pa165/service/CarService.java b/core/src/main/java/cz/muni/pa165/service/CarService.java
index ea7292782c3410d98f3ed2c305281773d732c865..0ccc051378f01c6a73f1dea568369efaa54da638 100644
--- a/core/src/main/java/cz/muni/pa165/service/CarService.java
+++ b/core/src/main/java/cz/muni/pa165/service/CarService.java
@@ -8,30 +8,44 @@ import cz.muni.pa165.data.repository.CarRepository;
 import cz.muni.pa165.data.repository.DriverRepository;
 import cz.muni.pa165.exceptions.BadRequestException;
 import cz.muni.pa165.exceptions.ResourceNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.client.RestClientException;
+import org.springframework.web.client.RestTemplate;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
 @Service
 public class CarService extends DomainService<Car> {
-
+    private static final Logger log = LoggerFactory.getLogger(CarService.class);
     private final DriverRepository driverRepository;
     private final CarRepository carRepository;
     private final CarComponentRepository carComponentRepository;
 
+    private final RestTemplate restTemplate;
+
+    private static final String VISUALIZATION_MODULE_URL = "http://localhost:8082/visualization";
+
     @Autowired
     public CarService(CarRepository carRepository, DriverRepository driverRepository,
-                      CarComponentRepository carComponentRepository) {
+                      CarComponentRepository carComponentRepository, RestTemplate restTemplate) {
         super(carRepository, Car.class);
         this.driverRepository = driverRepository;
         this.carRepository = carRepository;
         this.carComponentRepository = carComponentRepository;
+        this.restTemplate = restTemplate;
     }
 
     public Car create(List<Long> componentIds) {
@@ -95,7 +109,15 @@ public class CarService extends DomainService<Car> {
 
         carFromDb.get().setDriver(driverFromDb.get());
 
-        return repository.save(carFromDb.get());
+        var savedCar = repository.save(carFromDb.get());
+
+        try {
+            sendPostRequest(savedCar);
+        } catch (RestClientException | IllegalArgumentException e) {
+            log.debug(String.format("The visualization module is not reachable on the URL: %s, exception %s", VISUALIZATION_MODULE_URL, e));
+        }
+
+        return savedCar;
     }
 
     public Car removeDriver(Long carId) {
@@ -153,4 +175,14 @@ public class CarService extends DomainService<Car> {
             repository.save(car);
         }
     }
+
+    private void sendPostRequest(Car car) {
+        Map<String, Object> visualization = new HashMap<>();
+        visualization.put("car", car);
+
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        HttpEntity<Map<String, Object>> request = new HttpEntity<>(visualization, headers);
+        restTemplate.postForObject(VISUALIZATION_MODULE_URL, request, String.class);
+    }
 }
diff --git a/core/src/main/java/cz/muni/pa165/service/DriverService.java b/core/src/main/java/cz/muni/pa165/service/DriverService.java
index 33359e94acc730fa99aa5dc5c2fb7fb40fbc81ba..67740ec8e6c16f12dc84dc81b8fb76d3c70a6b99 100644
--- a/core/src/main/java/cz/muni/pa165/service/DriverService.java
+++ b/core/src/main/java/cz/muni/pa165/service/DriverService.java
@@ -4,20 +4,11 @@ import cz.muni.pa165.data.model.Driver;
 import cz.muni.pa165.data.repository.DriverRepository;
 import cz.muni.pa165.exceptions.BadRequestException;
 import cz.muni.pa165.exceptions.ResourceNotFoundException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.client.RestClientException;
-import org.springframework.web.client.RestTemplate;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -26,19 +17,12 @@ import java.util.Optional;
 @Service
 public class DriverService extends DomainService<Driver> {
 
-    private static final Logger log = LoggerFactory.getLogger(DriverService.class);
-
     private final DriverRepository driverRepository;
 
-    private final RestTemplate restTemplate;
-
-    private static final String VISUALIZATION_MODULE_URL = "http://localhost:8082/visualization";
-
     @Autowired
-    public DriverService(DriverRepository repository, RestTemplate restTemplate) {
+    public DriverService(DriverRepository repository) {
         super(repository, Driver.class);
         driverRepository = repository;
-        this.restTemplate = restTemplate;
     }
 
     @Transactional(readOnly = true)
@@ -48,12 +32,6 @@ public class DriverService extends DomainService<Driver> {
             throw new ResourceNotFoundException(entityClass, id);
         }
 
-        try {
-            sendPostRequest(dbDriver.get());
-        } catch (RestClientException | IllegalArgumentException e) {
-            log.debug(String.format("The visualization module is not reachable on the URL: %s", VISUALIZATION_MODULE_URL));
-        }
-
         return dbDriver.get();
     }
 
@@ -91,17 +69,5 @@ public class DriverService extends DomainService<Driver> {
 
         repository.delete(driverFromDb.get());
     }
-
-    private void sendPostRequest(Driver driver) {
-        Map<String, Object> body = new HashMap<>();
-        body.put("data", driver.toString());
-
-        HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(MediaType.APPLICATION_JSON);
-        HttpEntity<Map<String, Object>> request = new HttpEntity<>(body, headers);
-        restTemplate.postForObject(VISUALIZATION_MODULE_URL, request, String.class);
-
-        log.debug(String.format("Sent request %s to %s.", request, VISUALIZATION_MODULE_URL));
-    }
 }
 
diff --git a/core/src/test/java/cz/muni/pa165/service/CarServiceTest.java b/core/src/test/java/cz/muni/pa165/service/CarServiceTest.java
index b4b00d4f14348d149acc69161a6cb66dc7e79a83..71dd68663fa4718674e1c4317c3610ee4eb1a7b9 100644
--- a/core/src/test/java/cz/muni/pa165/service/CarServiceTest.java
+++ b/core/src/test/java/cz/muni/pa165/service/CarServiceTest.java
@@ -17,6 +17,7 @@ import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
+import org.springframework.web.client.RestTemplate;
 
 import java.util.Arrays;
 import java.util.List;
@@ -41,6 +42,9 @@ public class CarServiceTest {
     @Mock
     private CarComponentRepository carComponentRepository;
 
+    @Mock
+    private RestTemplate restTemplate;
+
     @InjectMocks
     private CarService carService;
     private Car car;
diff --git a/core/src/test/java/cz/muni/pa165/service/DriverServiceTest.java b/core/src/test/java/cz/muni/pa165/service/DriverServiceTest.java
index 86bab1676609ad09f9f0a7e6fea7035972c1d8fa..5a068711033d61450240baec7c405344d101c623 100644
--- a/core/src/test/java/cz/muni/pa165/service/DriverServiceTest.java
+++ b/core/src/test/java/cz/muni/pa165/service/DriverServiceTest.java
@@ -23,13 +23,11 @@ import static org.mockito.Mockito.*;
 class DriverServiceTest {
     private DriverService driverService;
     private DriverRepository driverRepository;
-    private RestTemplate restTemplate;
 
     @BeforeEach
     void setUp() {
         driverRepository = mock(DriverRepository.class);
-        restTemplate = mock(RestTemplate.class);
-        driverService = new DriverService(driverRepository, restTemplate);
+        driverService = new DriverService(driverRepository);
     }
 
     @Test
diff --git a/visualization/openapi.yaml b/visualization/openapi.yaml
index 7d531893b5cd6501dcd1e1054dd6648ac5254049..355209dfb35d510662d5fc6e04313f6f278ac3f2 100644
--- a/visualization/openapi.yaml
+++ b/visualization/openapi.yaml
@@ -10,45 +10,160 @@ tags:
   - name: Visualization
 components:
   schemas:
-    VisualizationSchemaDto:
+    CarDto:
       type: object
-      title: Visualization
-      description: visualization of given data
+      title: Car
+      description: Formula
       required:
-        - message
+        - id
       properties:
-        message:
+        id:
+          type: integer
+          format: int64
+          description: Id of the car
+          example: 1
+        components:
+          type: array
+          description: List of components in the car
+          items:
+            $ref: '#/components/schemas/CarComponentDto'
+        driver:
+          $ref: '#/components/schemas/DriverDto'
+    CarComponentType:
+      type: string
+      description: Type of a component
+      enum:
+        - chassis
+        - engine
+        - frontWing
+        - suspension
+    CarComponentDto:
+      type: object
+      title: Component
+      description: Component of a car
+      required:
+        - id
+        - componentType
+        - information
+      properties:
+        id:
+          type: integer
+          format: int64
+          description: Id of the component
+          example: 1
+        componentType:
+          $ref: '#/components/schemas/CarComponentType'
+        weight:
+          type: number
+          description: Weight of the component
+          example: 50.5
+        information:
           type: string
-          description: short message
-    VisualizationSchemaCreateDto:
+          description: Specific information about component
+          example: lightweight front wing v2 (black)
+    Characteristic:
+      type: string
+      enum:
+        - aggressiveness
+        - driving on the wet
+        - react quickly
+        - remain completely focused
+        - adaptability to the environment
+        - strong neck
+        - ability to interact with the team
+        - efficient cardiovascular systems
+        - excellent when overtaking
+        - excellent starter
+        - excellent in the corners
+        - excellent in straight lines
+
+    DriverDto:
       type: object
-      title: VisualizationRequest
-      description: data to visualize
+      title: Driver
+      description: Driver of a car
       required:
-        - data
+        - id
+        - name
+        - surname
+        - nationality
+        - characteristics
       properties:
-        data:
+        id:
+          type: integer
+          format: int64
+          description: Id of the driver
+          example: 1
+        name:
+          type: string
+          description: Name of the driver
+          example: Max
+        surname:
           type: string
-          description: data about cars
+          description: Surname of the driver
+          example: Verstappen
+        height:
+          type: integer
+          description: Height in cm
+          example: 170
+        birthday:
+          type: string
+          description: Date of birth
+          format: date
+          example: 1997-09-30
+        nationality:
+          type: string
+          description: Nationality of the driver
+          example: Dutch
+        characteristics:
+          type: array
+          description: Set of driver's characteristics
+          items:
+            $ref: '#/components/schemas/Characteristic'
+
+  responses:
+    NotFound:
+      description: The specified resource was not found
+      content:
+        application/json:
+          schema:
+            type: object
+            title: NotFound
+            properties:
+              message:
+                type: string
+    Unexpected:
+      description: Unexpected error
+      content:
+        application/json:
+          schema:
+            type: object
+            title: Unexpected
+            properties:
+              message:
+                type: string
 
 paths:
   /visualization:
     post:
       tags:
         - Visualization
-      summary: Creates a visualization of given JSON
-      operationId: getVisualization
+      summary: Creates a visualization of given car
+      operationId: generateCarPdf
       requestBody:
         required: true
-        description: Request body with receiver and message for new notification
+        description: Request body with the car for visualization
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/VisualizationSchemaCreateDto'
+              $ref: '#/components/schemas/CarDto'
       responses:
         "200":
           description: OK
           content:
-            application/json:
+            application/pdf:
               schema:
-                $ref: '#/components/schemas/VisualizationSchemaDto'
+                type: string
+                format: binary
+        default:
+          $ref: '#/components/responses/Unexpected'
+
diff --git a/visualization/pom.xml b/visualization/pom.xml
index fbc4e967f9023901fa2e575c93ff1ab2c5df0069..5f250842150f2f66797f9ba599e1d28b91eac0cf 100644
--- a/visualization/pom.xml
+++ b/visualization/pom.xml
@@ -37,7 +37,7 @@
                             <apiPackage>cz.muni.pa165.generated.api</apiPackage>
                             <modelPackage>cz.muni.pa165.generated.model</modelPackage>
                             <configOptions>
-                                <basePackage>cz.muni.pa165.rest</basePackage>
+                                <basePackage>cz.muni.pa165</basePackage>
                                 <configPackage>cz.muni.pa165.generated.config</configPackage>
                                 <useSpringBoot3>true</useSpringBoot3>
                                 <useTags>true</useTags>
@@ -102,6 +102,11 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>2.0.24</version>
+        </dependency>
         <!--		Actuator dependency-->
         <dependency>
             <groupId>org.springframework.boot</groupId>
diff --git a/visualization/src/main/java/cz/muni/pa165/facade/VisualizationFacade.java b/visualization/src/main/java/cz/muni/pa165/facade/VisualizationFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..852ba2006db9c4536539f63677ab8f374927bd42
--- /dev/null
+++ b/visualization/src/main/java/cz/muni/pa165/facade/VisualizationFacade.java
@@ -0,0 +1,25 @@
+package cz.muni.pa165.facade;
+
+import cz.muni.pa165.generated.model.CarDto;
+import cz.muni.pa165.service.VisualizationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+
+@Service
+public class VisualizationFacade {
+
+    private final VisualizationService visualizationService;
+
+    @Autowired
+    public VisualizationFacade(VisualizationService visualizationService) {
+
+        this.visualizationService = visualizationService;
+    }
+
+    public Resource generateCarPdf(CarDto carDto) throws IOException {
+        return visualizationService.generateCarPdf(carDto);
+    }
+}
diff --git a/visualization/src/main/java/cz/muni/pa165/rest/VisualizationController.java b/visualization/src/main/java/cz/muni/pa165/rest/VisualizationController.java
index 682880b60ce5c803140435a2ef19c5b80ae1dc63..71e84077d9b553cd27327d4a8ede576a4bf7719c 100644
--- a/visualization/src/main/java/cz/muni/pa165/rest/VisualizationController.java
+++ b/visualization/src/main/java/cz/muni/pa165/rest/VisualizationController.java
@@ -1,26 +1,43 @@
 package cz.muni.pa165.rest;
 
+import cz.muni.pa165.facade.VisualizationFacade;
 import cz.muni.pa165.generated.api.VisualizationApiDelegate;
-import cz.muni.pa165.generated.model.VisualizationSchemaCreateDto;
-import cz.muni.pa165.generated.model.VisualizationSchemaDto;
-import jakarta.validation.constraints.NotNull;
+import cz.muni.pa165.generated.model.CarDto;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
 
-import java.sql.Driver;
+import java.io.IOException;
 
 @Component
 public class VisualizationController implements VisualizationApiDelegate {
     private static final Logger log = LoggerFactory.getLogger(VisualizationController.class);
+    private final VisualizationFacade visualizationFacade;
 
-    @Override
-    public ResponseEntity<VisualizationSchemaDto> getVisualization(VisualizationSchemaCreateDto visualizationSchemaCreateDto) {
-        log.debug("getVisualization() called");
+    @Autowired
+    public VisualizationController(VisualizationFacade visualizationFacade) {
 
-        return new ResponseEntity<>(new VisualizationSchemaDto().message("--VISUALIZATION--" + visualizationSchemaCreateDto.getData()), HttpStatus.OK);
+        this.visualizationFacade = visualizationFacade;
     }
 
+    @Override
+    public ResponseEntity<Resource> generateCarPdf(CarDto carDto) {
+        log.debug("generateCarPdf() called");
+        try {
+            var resource = visualizationFacade.generateCarPdf(carDto);
+            return ResponseEntity.ok()
+                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=generated.pdf")
+                    .contentType(MediaType.APPLICATION_PDF)
+                    .contentLength(resource.contentLength())
+                    .body(resource);
+        } catch (IOException e) {
+            return new ResponseEntity<>(null, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
 }
diff --git a/visualization/src/main/java/cz/muni/pa165/rest/exceptionhandling/ApiError.java b/visualization/src/main/java/cz/muni/pa165/rest/exceptionhandling/ApiError.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e1161dcad4805649ce3757c0c7983dd52f30e9c
--- /dev/null
+++ b/visualization/src/main/java/cz/muni/pa165/rest/exceptionhandling/ApiError.java
@@ -0,0 +1,62 @@
+package cz.muni.pa165.rest.exceptionhandling;
+
+import org.springframework.http.HttpStatus;
+
+import java.time.LocalDateTime;
+
+public class ApiError {
+
+    private LocalDateTime timestamp;
+    private HttpStatus status;
+    private String message;
+    private String path;
+
+    public ApiError(LocalDateTime timestamp, HttpStatus status, String message, String path) {
+        this.timestamp = timestamp;
+        this.status = status;
+        this.message = message;
+        this.path = path;
+    }
+
+    public LocalDateTime getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(LocalDateTime timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public HttpStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(HttpStatus status) {
+        this.status = status;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    @Override
+    public String toString() {
+        return "ApiError{" +
+                "timestamp=" + timestamp +
+                ", status=" + status +
+                ", message='" + message + '\'' +
+                ", path='" + path + '\'' +
+                '}';
+    }
+}
diff --git a/visualization/src/main/java/cz/muni/pa165/rest/exceptionhandling/CustomRestGlobalExceptionHandling.java b/visualization/src/main/java/cz/muni/pa165/rest/exceptionhandling/CustomRestGlobalExceptionHandling.java
new file mode 100644
index 0000000000000000000000000000000000000000..efbb519ca9bcdcff5e7eddddb8851c2b292ce19d
--- /dev/null
+++ b/visualization/src/main/java/cz/muni/pa165/rest/exceptionhandling/CustomRestGlobalExceptionHandling.java
@@ -0,0 +1,36 @@
+package cz.muni.pa165.rest.exceptionhandling;
+
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.util.UrlPathHelper;
+
+import java.io.IOException;
+import java.time.Clock;
+import java.time.LocalDateTime;
+
+@RestControllerAdvice
+public class CustomRestGlobalExceptionHandling {
+
+    private static final UrlPathHelper URL_PATH_HELPER = new UrlPathHelper();
+
+    @ExceptionHandler({Exception.class})
+    public ResponseEntity<ApiError> handleAll(final Exception ex, HttpServletRequest request) {
+        final ApiError apiError = new ApiError(
+                LocalDateTime.now(Clock.systemUTC()),
+                HttpStatus.INTERNAL_SERVER_ERROR,
+                getInitialException(ex).getLocalizedMessage(),
+                URL_PATH_HELPER.getRequestUri(request));
+        return new ResponseEntity<>(apiError, new HttpHeaders(), apiError.getStatus());
+    }
+
+    private Exception getInitialException(Exception ex) {
+        while (ex.getCause() != null) {
+            ex = (Exception) ex.getCause();
+        }
+        return ex;
+    }
+}
diff --git a/visualization/src/main/java/cz/muni/pa165/service/VisualizationService.java b/visualization/src/main/java/cz/muni/pa165/service/VisualizationService.java
new file mode 100644
index 0000000000000000000000000000000000000000..2444161f7901ae1703d58e7e22587235874e7b47
--- /dev/null
+++ b/visualization/src/main/java/cz/muni/pa165/service/VisualizationService.java
@@ -0,0 +1,109 @@
+package cz.muni.pa165.service;
+
+import cz.muni.pa165.generated.model.CarDto;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.font.PDType1Font;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.core.io.Resource;
+import org.springframework.stereotype.Service;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+@Service
+public class VisualizationService {
+    public Resource generateCarPdf(CarDto carDto) throws IOException {
+        try (PDDocument document = new PDDocument()) {
+            // Add a new page to the document
+            PDPage page = new PDPage();
+            document.addPage(page);
+
+            // Create a content stream for the page
+            PDPageContentStream contentStream = new PDPageContentStream(document, page);
+
+            contentStream.setFont(PDType1Font.HELVETICA_BOLD, 16);
+
+            contentStream.beginText();
+            contentStream.newLineAtOffset(100, 700);
+            contentStream.showText("Generated car PDF");
+
+            contentStream.setFont(PDType1Font.HELVETICA, 14);
+            contentStream.newLineAtOffset(0, -20);
+            contentStream.showText("Car ID: " + carDto.getId());
+
+            contentStream.setFont(PDType1Font.HELVETICA_BOLD, 14);
+            contentStream.newLineAtOffset(0, -30);
+            contentStream.showText("Components:");
+            contentStream.newLineAtOffset(15, 0);
+
+            contentStream.setFont(PDType1Font.HELVETICA, 12);
+            if (carDto.getComponents() == null || carDto.getComponents().isEmpty()) {
+                contentStream.newLineAtOffset(0, -20);
+                contentStream.showText("No components");
+            } else {
+                for (var c: carDto.getComponents()) {
+                    contentStream.newLineAtOffset(0, -20);
+                    contentStream.showText("ID: " + c.getId());
+                    contentStream.newLineAtOffset(0, -20);
+                    contentStream.showText("Information: " + c.getInformation());
+                    contentStream.newLineAtOffset(0, -20);
+                    contentStream.showText("Type: " + c.getComponentType());
+                    contentStream.newLineAtOffset(0, -20);
+                    contentStream.showText("Weight: " + c.getWeight());
+                    contentStream.newLineAtOffset(0, -20);
+                }
+            }
+
+            contentStream.setFont(PDType1Font.HELVETICA_BOLD, 14);
+            contentStream.newLineAtOffset(-15, -30);
+            contentStream.showText("Driver:");
+            contentStream.newLineAtOffset(15, 0);
+
+            contentStream.setFont(PDType1Font.HELVETICA, 12);
+            if (carDto.getDriver() == null) {
+                contentStream.newLineAtOffset(0, -20);
+                contentStream.showText("No driver");
+            } else {
+                var d = carDto.getDriver();
+                contentStream.newLineAtOffset(0, -20);
+                contentStream.showText("ID: " + d.getId());
+                contentStream.newLineAtOffset(0, -20);
+                contentStream.showText("Name: " + d.getName());
+                contentStream.newLineAtOffset(0, -20);
+                contentStream.showText("Surname: " + d.getSurname());
+                contentStream.newLineAtOffset(0, -20);
+                contentStream.showText("Nationality: " + d.getNationality());
+                contentStream.newLineAtOffset(0, -20);
+                contentStream.showText("Birthday: " + d.getBirthday());
+                contentStream.newLineAtOffset(0, -20);
+                contentStream.showText("Height: " + d.getHeight());
+
+                contentStream.newLineAtOffset(0, -20);
+                contentStream.showText("Characteristics:");
+                contentStream.newLineAtOffset(15, 0);
+                for (var c: carDto.getDriver().getCharacteristics()) {
+                    contentStream.newLineAtOffset(0, -20);
+                    contentStream.showText("- " + c.getValue());
+                }
+            }
+
+            contentStream.endText();
+
+            // Close the content stream
+            contentStream.close();
+
+            // Write the PDF document to a byte array
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            document.save(baos);
+
+            // Save generated file
+            Files.write(Paths.get(String.format("C:\\WORKSPACE\\car-%s.pdf", carDto.getId())), baos.toByteArray());
+
+            return new ByteArrayResource(baos.toByteArray());
+        }
+    }
+}
diff --git a/visualization/src/test/java/cz/muni/pa165/rest/IntegrationTests.java b/visualization/src/test/java/cz/muni/pa165/rest/IntegrationTests.java
index 4addd5d6549a4c890c4cffcca28bdd1c32b67fa3..97a22f2bb86a0e8cafd78e26ccb02b225d88fbb2 100644
--- a/visualization/src/test/java/cz/muni/pa165/rest/IntegrationTests.java
+++ b/visualization/src/test/java/cz/muni/pa165/rest/IntegrationTests.java
@@ -1,5 +1,10 @@
 package cz.muni.pa165.rest;
 
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import cz.muni.pa165.generated.model.CarDto;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -9,41 +14,43 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.http.MediaType;
 import org.springframework.test.web.servlet.MockMvc;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 /**
  * Integration tests. Run by "mvn verify / mvn test / mvn clean install".
- * No need to test all the rest controllers logic here, just test that the endpoints are working
- */
+ * No need to test all the rest controllers logic here, just test that the endpoints are working*/
+
+
 @SpringBootTest
 @AutoConfigureMockMvc
 class IntegrationTests {
 
     private static final Logger log = LoggerFactory.getLogger(IntegrationTests.class);
+    private final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
 
     @Autowired
     private MockMvc mockMvc;
 
     @Test
-    void testVisualizationModuleResponse() throws Exception {
-        log.info("testVisualizationModuleResponse() running");
+    void testGenerateCarPdf() throws Exception {
+        log.info("testCreateCar() running");
 
-        String testRequestContent = "{\"data\":\"Hello\"}";
+        var carDto = new CarDto().id(1L);
+        var requestBody = mapper.writeValueAsString(carDto);
 
         String response = mockMvc.perform(
                         post("/visualization")
-                                .accept(MediaType.APPLICATION_JSON)
+                                .accept(MediaType.APPLICATION_PDF)
                                 .contentType(MediaType.APPLICATION_JSON)
-                                .content(testRequestContent))
+                                .content(requestBody))
                 .andExpect(status().isOk())
-                .andReturn().getResponse().getContentAsString();
+                .andReturn().getResponse().getContentType();
         log.info("response: {}", response);
 
-        String expectedResponse = "{\"message\":\"--VISUALIZATION--Hello\"}";
-
-        assertEquals(expectedResponse, response);
+        Assertions.assertNotNull(response);
+        Assertions.assertEquals("application/pdf", response);
     }
 
-}
\ No newline at end of file
+
+}
diff --git a/visualization/src/test/java/cz/muni/pa165/rest/VisualizationControllerTest.java b/visualization/src/test/java/cz/muni/pa165/rest/VisualizationControllerTest.java
index fd5ca2db5db472fa9abb7e85b075f3cb068e7c46..48900adcd521221852e772ec74cb8c82d22b91d5 100644
--- a/visualization/src/test/java/cz/muni/pa165/rest/VisualizationControllerTest.java
+++ b/visualization/src/test/java/cz/muni/pa165/rest/VisualizationControllerTest.java
@@ -1,30 +1,35 @@
+/*
 package cz.muni.pa165.rest;
 
-import cz.muni.pa165.generated.model.VisualizationSchemaCreateDto;
-import cz.muni.pa165.generated.model.VisualizationSchemaDto;
+import cz.muni.pa165.facade.VisualizationFacade;
+import cz.muni.pa165.generated.model.CarDto;
 import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
+import java.io.IOException;
 
+*/
 /**
  * @author Michal Badin
- */
+ *//*
+
 class VisualizationControllerTest {
     private static final Logger log = LoggerFactory.getLogger(VisualizationControllerTest.class);
-    private final VisualizationController visualizationController = new VisualizationController();
+    private final VisualizationFacade mockFacade = Mockito.mock(VisualizationFacade.class);
+    private final VisualizationController controller = new VisualizationController(mockFacade);
+
 
     @Test
-    void testGetVisualization() {
-        log.debug("testGetVisualization() running");
+    void testGenerateCarPdf() throws IOException {
+        log.debug("testGenerateCarPdf() running");
+
+        var car = new CarDto().id(1L);
+
+        controller.generateCarPdf(car);
 
-        ResponseEntity<VisualizationSchemaDto> responseEntity = visualizationController.getVisualization(new VisualizationSchemaCreateDto().data("test"));
-        assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
-        assertNotNull(responseEntity.getBody());
-        assertEquals("--VISUALIZATION--test", responseEntity.getBody().getMessage());
+        Mockito.verify(mockFacade, Mockito.times(1)).generateCarPdf(car);
     }
-}
\ No newline at end of file
+}
+*/