From 8db0e0424a0fc7000e6c6ce891b3a98c0eb7ed6b Mon Sep 17 00:00:00 2001
From: bglamadrid <bg.lamadrid@gmail.com>
Date: Sat, 28 Sep 2024 23:27:39 -0300
Subject: [PATCH 1/3] feat(docs): add `springdoc` library

---
 CHANGELOG.md                              | 10 +++++++++-
 pom.xml                                   |  5 +++++
 src/main/resources/application.properties |  8 ++++++++
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 34d6fd8a..8774c251 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## Unreleased
 
-### Conforming to API v3
+### Added
+
+- [Springdoc](https://springdoc.org) library, to enrich the project with two new features:
+  - Generation of an OpenAPI 3.0 spec file, akin to [the Trebol API](https://github.com/trebol-ecommerce/api)'s
+  - Generation of a [Swagger UI](https://swagger.io/tools/swagger-ui/) page and endpoint.
+
+### Changed
+
+#### Conforming to API v3
 
   - Follow new specification for error messages
     - Introduce new model class `AppError`
diff --git a/pom.xml b/pom.xml
index bd557b5c..8d703bce 100644
--- a/pom.xml
+++ b/pom.xml
@@ -157,6 +157,11 @@
       <artifactId>unirest-java</artifactId>
       <version>${unirest.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.springdoc</groupId>
+      <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+      <version>2.6.0</version>
+    </dependency>
 
     <!-- Testing -->
     <dependency>
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index b0cc8e43..d81ba2d1 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -56,6 +56,14 @@ trebol.api.able-to-edit-orders-after-being-processed=false
 trebol.validation.id-number-regexp=^\d{7,9}[\dk]$
 trebol.validation.phonenumber-regexp=^\\+(?:[0-9] ?){6,14}[0-9]$
 ##############################
+# SPRINGDOC OPENAPI
+## Disallow generation of OpenAPI specification
+#springdoc.api-docs.enabled=false
+#springdoc.api-docs.path=/v3/api-docs
+## Disallow Swagger UI interface (for API navigation and testing)
+#springdoc.swagger-ui.enabled=false
+#springdoc.swagger-ui.path=/swagger-ui/index.html
+##############################
 # SECURITY
 ## The private key to encrypt and decrypt JWTs with
 trebol.security.jwt-secret-key=YOU.SHOULD.PROVIDE.YOUR.OWN.SECRET.KEY.THIS.IS.JUST.A.PLACEHOLDDER

From f257e7485880a2288996ec78f40436d62063efc6 Mon Sep 17 00:00:00 2001
From: bglamadrid <bg.lamadrid@gmail.com>
Date: Sat, 28 Sep 2024 23:34:51 -0300
Subject: [PATCH 2/3] chore(api): remove path mappings with leading slash

most REST APIs tend to stick to this convention
plus, it looks bad in the documentation
and Trebol API specification does not include paths with leading slashes either
---
 CHANGELOG.md                                     |  2 ++
 .../trebol/api/controllers/AccessController.java |  4 ++--
 .../controllers/AccountProfileController.java    |  4 ++--
 .../controllers/DataBillingTypesController.java  |  2 +-
 .../api/controllers/DataCustomersController.java |  8 ++++----
 .../api/controllers/DataImagesController.java    | 10 +++++-----
 .../controllers/DataOrderStatusesController.java |  2 +-
 .../api/controllers/DataOrdersController.java    | 16 ++++++++--------
 .../api/controllers/DataPeopleController.java    |  2 +-
 .../DataProductCategoriesController.java         | 10 +++++-----
 .../DataProductListContentsController.java       |  8 ++++----
 .../controllers/DataProductListsController.java  | 10 +++++-----
 .../api/controllers/DataProductsController.java  | 10 +++++-----
 .../controllers/DataSalespeopleController.java   |  8 ++++----
 .../api/controllers/DataShippersController.java  | 10 +++++-----
 .../api/controllers/DataUserRolesController.java |  8 ++++----
 .../api/controllers/DataUsersController.java     |  8 ++++----
 .../api/controllers/PublicAboutController.java   |  2 +-
 .../controllers/PublicCheckoutController.java    |  8 ++++----
 .../api/controllers/PublicReceiptController.java |  2 +-
 .../controllers/PublicRegisterController.java    |  2 +-
 .../trebol/api/controllers/RootController.java   |  2 +-
 22 files changed, 70 insertions(+), 68 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8774c251..f680465f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -74,6 +74,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
       - `/data/orders/rejection`
       - `/data/orders/completion`
     - All PUT,PATCH,DELETE,OPTIONS requests return 204
+  - Remove support for paths with leading slash
+    - For example, `/public/checkout/` is no longer accepted, only `/public/checkout`
 
 ## [v0.2.4] - 2024-28-08
 
diff --git a/src/main/java/org/trebol/api/controllers/AccessController.java b/src/main/java/org/trebol/api/controllers/AccessController.java
index f13f54e8..2905079f 100644
--- a/src/main/java/org/trebol/api/controllers/AccessController.java
+++ b/src/main/java/org/trebol/api/controllers/AccessController.java
@@ -66,7 +66,7 @@ public AccessController(
         this.regexMatcherService = regexMatcherService;
     }
 
-    @GetMapping({"", "/"})
+    @GetMapping
     public AuthorizedAccessPojo getApiRoutesAccess(@RequestHeader HttpHeaders requestHeaders)
         throws UsernameNotFoundException, IllegalStateException {
         UserDetails userDetails = this.getUserDetails(requestHeaders);
@@ -79,7 +79,7 @@ public AuthorizedAccessPojo getApiRoutesAccess(@RequestHeader HttpHeaders reques
             .build();
     }
 
-    @GetMapping({"/{apiRoute}", "/{apiRoute}/"})
+    @GetMapping("/{apiRoute}")
     public AuthorizedAccessPojo getApiResourceAccess(
         @RequestHeader HttpHeaders requestHeaders,
         @PathVariable String apiRoute)
diff --git a/src/main/java/org/trebol/api/controllers/AccountProfileController.java b/src/main/java/org/trebol/api/controllers/AccountProfileController.java
index fe83bcf0..485b2eff 100644
--- a/src/main/java/org/trebol/api/controllers/AccountProfileController.java
+++ b/src/main/java/org/trebol/api/controllers/AccountProfileController.java
@@ -47,14 +47,14 @@ public AccountProfileController(
         this.userProfileService = userProfileService;
     }
 
-    @GetMapping({"", "/"})
+    @GetMapping
     public PersonPojo getProfile(Principal principal)
         throws EntityNotFoundException {
         String username = principal.getName();
         return userProfileService.getProfileFromUserName(username);
     }
 
-    @PutMapping({"", "/"})
+    @PutMapping
     public void updateProfile(Principal principal, @RequestBody PersonPojo newProfile)
         throws EntityNotFoundException, BadInputException {
         String username = principal.getName();
diff --git a/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java b/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java
index 5ca68511..45450a67 100644
--- a/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java
@@ -54,7 +54,7 @@ public DataBillingTypesController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     public DataPagePojo<BillingTypePojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
diff --git a/src/main/java/org/trebol/api/controllers/DataCustomersController.java b/src/main/java/org/trebol/api/controllers/DataCustomersController.java
index 7a0ce1b6..289f1930 100644
--- a/src/main/java/org/trebol/api/controllers/DataCustomersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataCustomersController.java
@@ -60,14 +60,14 @@ public DataCustomersController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     @PreAuthorize("hasAuthority('customers:read')")
     public DataPagePojo<PersonPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @PreAuthorize("hasAuthority('customers:create')")
     @ResponseStatus(CREATED)
     public void create(@Valid @RequestBody PersonPojo input)
@@ -76,7 +76,7 @@ public void create(@Valid @RequestBody PersonPojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('customers:update')")
     public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map<String, String> requestParams)
@@ -85,7 +85,7 @@ public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map<Strin
     }
 
     @Override
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('customers:delete')")
     public void delete(Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataImagesController.java b/src/main/java/org/trebol/api/controllers/DataImagesController.java
index b55ad28a..a5e5d8b1 100644
--- a/src/main/java/org/trebol/api/controllers/DataImagesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataImagesController.java
@@ -69,14 +69,14 @@ public DataImagesController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     @PreAuthorize("hasAuthority('images:read')")
     public DataPagePojo<ImagePojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('images:create')")
     public void create(@Valid @RequestBody ImagePojo input)
@@ -85,7 +85,7 @@ public void create(@Valid @RequestBody ImagePojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('images:update')")
     public void update(@Valid @RequestBody ImagePojo input, @RequestParam Map<String, String> requestParams)
@@ -94,7 +94,7 @@ public void update(@Valid @RequestBody ImagePojo input, @RequestParam Map<String
     }
 
     @Override
-    @PatchMapping({"", "/"})
+    @PatchMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('images:update')")
     public void partialUpdate(
@@ -105,7 +105,7 @@ public void partialUpdate(
     }
 
     @Override
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('images:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java b/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java
index 81f835d0..bb9076b8 100644
--- a/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java
@@ -56,7 +56,7 @@ public DataOrderStatusesController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     @PreAuthorize("hasAuthority('order_statuses:read')")
     public DataPagePojo<OrderStatusPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
diff --git a/src/main/java/org/trebol/api/controllers/DataOrdersController.java b/src/main/java/org/trebol/api/controllers/DataOrdersController.java
index e1daf6e8..d669605b 100644
--- a/src/main/java/org/trebol/api/controllers/DataOrdersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataOrdersController.java
@@ -83,7 +83,7 @@ public DataOrdersController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     @PreAuthorize("hasAuthority('orders:read')")
     public DataPagePojo<OrderPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         if (allRequestParams!=null) {
@@ -106,7 +106,7 @@ public DataPagePojo<OrderPojo> readMany(@RequestParam Map<String, String> allReq
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('orders:create')")
     public void create(@Valid @RequestBody OrderPojo input)
@@ -115,7 +115,7 @@ public void create(@Valid @RequestBody OrderPojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('orders:update')")
     public void update(@Valid @RequestBody OrderPojo input, @RequestParam Map<String, String> requestParams)
@@ -124,7 +124,7 @@ public void update(@Valid @RequestBody OrderPojo input, @RequestParam Map<String
     }
 
     @Override
-    @PatchMapping({"", "/"})
+    @PatchMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('orders:update')")
     public void partialUpdate(
@@ -135,7 +135,7 @@ public void partialUpdate(
     }
 
     @Override
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('orders:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
@@ -143,7 +143,7 @@ public void delete(@RequestParam Map<String, String> requestParams)
         super.delete(requestParams);
     }
 
-    @PostMapping({"/confirmation", "/confirmation/"})
+    @PostMapping("/confirmation")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('orders:update')")
     public void confirmSell(@RequestBody OrderPojo sell)
@@ -155,7 +155,7 @@ public void confirmSell(@RequestBody OrderPojo sell)
         }
     }
 
-    @PostMapping({"/rejection", "/rejection/"})
+    @PostMapping("/rejection")
     @PreAuthorize("hasAuthority('orders:update')")
     public void rejectSell(@RequestBody OrderPojo sell)
         throws BadInputException, MailingServiceException {
@@ -165,7 +165,7 @@ public void rejectSell(@RequestBody OrderPojo sell)
         }
     }
 
-    @PostMapping({"/completion", "/completion/"})
+    @PostMapping("/completion")
     @PreAuthorize("hasAuthority('orders:update')")
     public void completeSell(@RequestBody OrderPojo sell)
         throws BadInputException, MailingServiceException {
diff --git a/src/main/java/org/trebol/api/controllers/DataPeopleController.java b/src/main/java/org/trebol/api/controllers/DataPeopleController.java
index f2cfb03c..6ae4ebb5 100644
--- a/src/main/java/org/trebol/api/controllers/DataPeopleController.java
+++ b/src/main/java/org/trebol/api/controllers/DataPeopleController.java
@@ -56,7 +56,7 @@ public DataPeopleController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     @PreAuthorize("hasAuthority('people:read')")
     public DataPagePojo<PersonPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
diff --git a/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java b/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java
index c3fc359e..f888ca72 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java
@@ -68,7 +68,7 @@ public DataProductCategoriesController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     public DataPagePojo<ProductCategoryPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         if (allRequestParams==null || allRequestParams.isEmpty()) {
             allRequestParams = Map.of("parentId", "");
@@ -77,7 +77,7 @@ public DataPagePojo<ProductCategoryPojo> readMany(@RequestParam Map<String, Stri
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('product_categories:create')")
     public void create(@Valid @RequestBody ProductCategoryPojo input)
@@ -86,7 +86,7 @@ public void create(@Valid @RequestBody ProductCategoryPojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_categories:update')")
     public void update(@Valid @RequestBody ProductCategoryPojo input, @RequestParam Map<String, String> requestParams)
@@ -95,7 +95,7 @@ public void update(@Valid @RequestBody ProductCategoryPojo input, @RequestParam
     }
 
     @Override
-    @PatchMapping({"", "/"})
+    @PatchMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_categories:update')")
     public void partialUpdate(
@@ -106,7 +106,7 @@ public void partialUpdate(
     }
 
     @Override
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_categories:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java b/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java
index f2e6dba9..c406e4a4 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java
@@ -97,7 +97,7 @@ public DataProductListContentsController(
         this.itemConverterService = itemConverterService;
     }
 
-    @GetMapping({"", "/"})
+    @GetMapping
     public DataPagePojo<ProductPojo> readContents(@RequestParam Map<String, String> requestParams)
         throws BadInputException, EntityNotFoundException {
         Optional<ProductList> match = this.fetchProductListByCode(requestParams);
@@ -128,7 +128,7 @@ public DataPagePojo<ProductPojo> readContents(@RequestParam Map<String, String>
         return new DataPagePojo<>(products, pageIndex, totalCount, pageSize);
     }
 
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('product_lists:contents')")
     public void addToContents(@Valid @RequestBody ProductPojo input,
@@ -151,7 +151,7 @@ public void addToContents(@Valid @RequestBody ProductPojo input,
         }
     }
 
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:contents')")
     public void updateContents(@RequestBody Collection<ProductPojo> input,
@@ -177,7 +177,7 @@ public void updateContents(@RequestBody Collection<ProductPojo> input,
         }
     }
 
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:contents')")
     public void deleteFromContents(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataProductListsController.java b/src/main/java/org/trebol/api/controllers/DataProductListsController.java
index 2c63068b..875ae18c 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductListsController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductListsController.java
@@ -68,13 +68,13 @@ public DataProductListsController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     public DataPagePojo<ProductListPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('product_lists:create')")
     public void create(@Valid @RequestBody ProductListPojo input)
@@ -83,7 +83,7 @@ public void create(@Valid @RequestBody ProductListPojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:update')")
     public void update(@Valid @RequestBody ProductListPojo input, @RequestParam Map<String, String> requestParams)
@@ -92,7 +92,7 @@ public void update(@Valid @RequestBody ProductListPojo input, @RequestParam Map<
     }
 
     @Override
-    @PatchMapping({"", "/"})
+    @PatchMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:update')")
     public void partialUpdate(
@@ -103,7 +103,7 @@ public void partialUpdate(
     }
 
     @Override
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataProductsController.java b/src/main/java/org/trebol/api/controllers/DataProductsController.java
index b4837c0a..76859f38 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductsController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductsController.java
@@ -68,13 +68,13 @@ public DataProductsController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     public DataPagePojo<ProductPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('products:create')")
     public void create(@Valid @RequestBody ProductPojo input)
@@ -83,7 +83,7 @@ public void create(@Valid @RequestBody ProductPojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('products:update')")
     public void update(@Valid @RequestBody ProductPojo input, @RequestParam Map<String, String> requestParams)
@@ -92,7 +92,7 @@ public void update(@Valid @RequestBody ProductPojo input, @RequestParam Map<Stri
     }
 
     @Override
-    @PatchMapping({"", "/"})
+    @PatchMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('products:update')")
     public void partialUpdate(
@@ -103,7 +103,7 @@ public void partialUpdate(
     }
 
     @Override
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('products:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java b/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java
index 38b99e9b..dbb58956 100644
--- a/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java
+++ b/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java
@@ -68,14 +68,14 @@ public DataSalespeopleController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     @PreAuthorize("hasAuthority('salespeople:read')")
     public DataPagePojo<PersonPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('salespeople:create')")
     public void create(@Valid @RequestBody PersonPojo input)
@@ -84,7 +84,7 @@ public void create(@Valid @RequestBody PersonPojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('salespeople:update')")
     public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map<String, String> requestParams)
@@ -93,7 +93,7 @@ public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map<Strin
     }
 
     @Override
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('salespeople:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataShippersController.java b/src/main/java/org/trebol/api/controllers/DataShippersController.java
index 07a4ad49..2774b959 100644
--- a/src/main/java/org/trebol/api/controllers/DataShippersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataShippersController.java
@@ -68,13 +68,13 @@ public DataShippersController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     public DataPagePojo<ShipperPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('shippers:create')")
     public void create(@Valid @RequestBody ShipperPojo input)
@@ -83,7 +83,7 @@ public void create(@Valid @RequestBody ShipperPojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('shippers:update')")
     public void update(@Valid @RequestBody ShipperPojo input, @RequestParam Map<String, String> requestParams)
@@ -92,7 +92,7 @@ public void update(@Valid @RequestBody ShipperPojo input, @RequestParam Map<Stri
     }
 
     @Override
-    @PatchMapping({"", "/"})
+    @PatchMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('shippers:update')")
     public void partialUpdate(
@@ -103,7 +103,7 @@ public void partialUpdate(
     }
 
     @Override
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('shippers:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataUserRolesController.java b/src/main/java/org/trebol/api/controllers/DataUserRolesController.java
index 433849c0..658b2989 100644
--- a/src/main/java/org/trebol/api/controllers/DataUserRolesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataUserRolesController.java
@@ -68,14 +68,14 @@ public DataUserRolesController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     @PreAuthorize("hasAuthority('user_roles:read')")
     public DataPagePojo<UserRolePojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('user_roles:create')")
     public void create(@Valid @RequestBody UserRolePojo input)
@@ -84,7 +84,7 @@ public void create(@Valid @RequestBody UserRolePojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('user_roles:update')")
     public void update(@Valid @RequestBody UserRolePojo input, @RequestParam Map<String, String> requestParams)
@@ -93,7 +93,7 @@ public void update(@Valid @RequestBody UserRolePojo input, @RequestParam Map<Str
     }
 
     @Override
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('user_roles:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataUsersController.java b/src/main/java/org/trebol/api/controllers/DataUsersController.java
index 13661c98..88439d70 100644
--- a/src/main/java/org/trebol/api/controllers/DataUsersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataUsersController.java
@@ -69,14 +69,14 @@ public DataUsersController(
     }
 
     @Override
-    @GetMapping({"", "/"})
+    @GetMapping
     @PreAuthorize("hasAuthority('users:read')")
     public DataPagePojo<UserPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
-    @PostMapping({"", "/"})
+    @PostMapping
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('users:create')")
     public void create(@Valid @RequestBody UserPojo input)
@@ -85,7 +85,7 @@ public void create(@Valid @RequestBody UserPojo input)
     }
 
     @Override
-    @PutMapping({"", "/"})
+    @PutMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('users:update')")
     public void update(@Valid @RequestBody UserPojo input, @RequestParam Map<String, String> requestParams)
@@ -93,7 +93,7 @@ public void update(@Valid @RequestBody UserPojo input, @RequestParam Map<String,
         super.update(input, requestParams);
     }
 
-    @DeleteMapping({"", "/"})
+    @DeleteMapping
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('users:delete')")
     public void delete(Principal principal, @RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/PublicAboutController.java b/src/main/java/org/trebol/api/controllers/PublicAboutController.java
index eee7af27..1672c1e6 100644
--- a/src/main/java/org/trebol/api/controllers/PublicAboutController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicAboutController.java
@@ -38,7 +38,7 @@ public PublicAboutController(CompanyService companyService) {
         this.companyService = companyService;
     }
 
-    @GetMapping({"", "/"})
+    @GetMapping
     public CompanyDetailsPojo readCompanyDetails() {
         return companyService.readDetails();
     }
diff --git a/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java b/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java
index 9cf31289..35126653 100644
--- a/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java
@@ -89,7 +89,7 @@ public PublicCheckoutController(
      * @throws PaymentServiceException If an error happens during the payment
      *                                 payment process
      */
-    @PostMapping({"", "/"})
+    @PostMapping
     @PreAuthorize("hasAuthority('" + AUTHORITY_CHECKOUT + "')")
     public PaymentRedirectionDetailsPojo submitCart(@Valid @RequestBody OrderPojo transactionRequest)
         throws BadInputException, PaymentServiceException, EntityExistsException {
@@ -106,7 +106,7 @@ public PaymentRedirectionDetailsPojo submitCart(@Valid @RequestBody OrderPojo tr
      * @throws EntityNotFoundException If the token does not match that of any "pending" transaction
      * @throws PaymentServiceException If an error happens during internal API calls
      */
-    @GetMapping({"/validate", "/validate/"})
+    @GetMapping("/validate")
     public ResponseEntity<Void> validateSuccesfulTransaction(@RequestParam Map<String, String> transactionData)
         throws BadInputException, EntityNotFoundException, PaymentServiceException, MailingServiceException {
         if (!transactionData.containsKey(WEBPAY_SUCCESS_TOKEN_HEADER_NAME)) { // success
@@ -133,7 +133,7 @@ public ResponseEntity<Void> validateSuccesfulTransaction(@RequestParam Map<Strin
      * @throws EntityNotFoundException If the token does not match that of any "pending" transaction
      * @throws PaymentServiceException If an error happens during internal API calls
      */
-    @PostMapping({"/validate", "/validate/"})
+    @PostMapping("/validate")
     public ResponseEntity<Void> validateAbortedTransaction(@RequestParam Map<String, String> transactionData)
         throws BadInputException, EntityNotFoundException, PaymentServiceException {
 
@@ -156,7 +156,7 @@ public ResponseEntity<Void> validateAbortedTransaction(@RequestParam Map<String,
      * @return An object with all available data about the transaction
      * @throws EntityNotFoundException when no transaction matched the provided token
      */
-    @GetMapping({"/result/{token}", "/result/{token}/"})
+    @GetMapping("/result/{token}")
     public OrderPojo getTransactionResultFor(@NotBlank @PathVariable String token)
         throws EntityNotFoundException {
         Map<String, String> tokenMatcher = Maps.of("token", token).build();
diff --git a/src/main/java/org/trebol/api/controllers/PublicReceiptController.java b/src/main/java/org/trebol/api/controllers/PublicReceiptController.java
index 5a9c634e..4fc0e506 100644
--- a/src/main/java/org/trebol/api/controllers/PublicReceiptController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicReceiptController.java
@@ -44,7 +44,7 @@ public PublicReceiptController(
         this.receiptService = receiptService;
     }
 
-    @GetMapping({"/{token}", "/{token}/"})
+    @GetMapping("/{token}")
     public ReceiptPojo fetchReceiptById(@PathVariable("token") String token)
         throws BadInputException, EntityNotFoundException {
         if (StringUtils.isBlank(token)) {
diff --git a/src/main/java/org/trebol/api/controllers/PublicRegisterController.java b/src/main/java/org/trebol/api/controllers/PublicRegisterController.java
index f7edc5d2..6167f062 100644
--- a/src/main/java/org/trebol/api/controllers/PublicRegisterController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicRegisterController.java
@@ -44,7 +44,7 @@ public PublicRegisterController(
         this.registrationService = registrationService;
     }
 
-    @PostMapping({"", "/"})
+    @PostMapping
     public void register(@Valid @RequestBody RegistrationPojo userProfile)
         throws BadInputException, EntityExistsException {
         this.registrationService.register(userProfile);
diff --git a/src/main/java/org/trebol/api/controllers/RootController.java b/src/main/java/org/trebol/api/controllers/RootController.java
index f4615c3d..6771d491 100644
--- a/src/main/java/org/trebol/api/controllers/RootController.java
+++ b/src/main/java/org/trebol/api/controllers/RootController.java
@@ -27,7 +27,7 @@
 @RestController
 public class RootController {
 
-    @GetMapping({"", "/"})
+    @GetMapping
     public ResponseEntity<Void> defaultMapping() {
         return ResponseEntity.ok().build();
     }

From 9b3cfbcc96c343efc2915678ba16d88b4f016b17 Mon Sep 17 00:00:00 2001
From: bglamadrid <bg.lamadrid@gmail.com>
Date: Fri, 4 Oct 2024 23:13:44 -0300
Subject: [PATCH 3/3] docs(swagger): tag and summarize all rest endpoints

---
 .../org/trebol/api/controllers/AccessController.java |  5 +++++
 .../api/controllers/AccountProfileController.java    |  5 +++++
 .../api/controllers/DataBillingTypesController.java  |  4 ++++
 .../api/controllers/DataCustomersController.java     |  7 +++++++
 .../trebol/api/controllers/DataImagesController.java |  8 ++++++++
 .../api/controllers/DataOrderStatusesController.java |  4 ++++
 .../trebol/api/controllers/DataOrdersController.java | 11 +++++++++++
 .../trebol/api/controllers/DataPeopleController.java |  4 ++++
 .../controllers/DataProductCategoriesController.java |  8 ++++++++
 .../DataProductListContentsController.java           |  7 +++++++
 .../api/controllers/DataProductListsController.java  |  8 ++++++++
 .../api/controllers/DataProductsController.java      |  8 ++++++++
 .../api/controllers/DataSalespeopleController.java   |  7 +++++++
 .../api/controllers/DataShippersController.java      |  8 ++++++++
 .../api/controllers/DataUserRolesController.java     |  7 +++++++
 .../trebol/api/controllers/DataUsersController.java  |  7 +++++++
 .../api/controllers/PublicAboutController.java       |  4 ++++
 .../api/controllers/PublicCheckoutController.java    |  7 +++++++
 .../api/controllers/PublicReceiptController.java     | 12 ++++++++++++
 .../api/controllers/PublicRegisterController.java    |  4 ++++
 .../org/trebol/api/controllers/RootController.java   |  4 ++++
 21 files changed, 139 insertions(+)

diff --git a/src/main/java/org/trebol/api/controllers/AccessController.java b/src/main/java/org/trebol/api/controllers/AccessController.java
index 2905079f..c3cd2096 100644
--- a/src/main/java/org/trebol/api/controllers/AccessController.java
+++ b/src/main/java/org/trebol/api/controllers/AccessController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import io.jsonwebtoken.Claims;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpHeaders;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -46,6 +48,7 @@
 
 @RestController
 @RequestMapping("/access")
+@Tag(name = "User Accounts")
 @PreAuthorize("isAuthenticated()")
 public class AccessController {
     private final AuthorizationHeaderParserService<Claims> jwtClaimsParserService;
@@ -67,6 +70,7 @@ public AccessController(
     }
 
     @GetMapping
+    @Operation(summary = "List authorized API routes")
     public AuthorizedAccessPojo getApiRoutesAccess(@RequestHeader HttpHeaders requestHeaders)
         throws UsernameNotFoundException, IllegalStateException {
         UserDetails userDetails = this.getUserDetails(requestHeaders);
@@ -80,6 +84,7 @@ public AuthorizedAccessPojo getApiRoutesAccess(@RequestHeader HttpHeaders reques
     }
 
     @GetMapping("/{apiRoute}")
+    @Operation(summary = "List authorized access to API route")
     public AuthorizedAccessPojo getApiResourceAccess(
         @RequestHeader HttpHeaders requestHeaders,
         @PathVariable String apiRoute)
diff --git a/src/main/java/org/trebol/api/controllers/AccountProfileController.java b/src/main/java/org/trebol/api/controllers/AccountProfileController.java
index 485b2eff..acd0a8af 100644
--- a/src/main/java/org/trebol/api/controllers/AccountProfileController.java
+++ b/src/main/java/org/trebol/api/controllers/AccountProfileController.java
@@ -20,6 +20,8 @@
 
 package org.trebol.api.controllers;
 
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -36,6 +38,7 @@
 
 @RestController
 @RequestMapping("/account/profile")
+@Tag(name = "User Accounts")
 @PreAuthorize("isAuthenticated()")
 public class AccountProfileController {
     private final ProfileService userProfileService;
@@ -48,6 +51,7 @@ public AccountProfileController(
     }
 
     @GetMapping
+    @Operation(summary = "View stored profile information")
     public PersonPojo getProfile(Principal principal)
         throws EntityNotFoundException {
         String username = principal.getName();
@@ -55,6 +59,7 @@ public PersonPojo getProfile(Principal principal)
     }
 
     @PutMapping
+    @Operation(summary = "Replace stored profile information")
     public void updateProfile(Principal principal, @RequestBody PersonPojo newProfile)
         throws EntityNotFoundException, BadInputException {
         String username = principal.getName();
diff --git a/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java b/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java
index 45450a67..b826c3c8 100644
--- a/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -40,6 +42,7 @@
 
 @RestController
 @RequestMapping("/data/billing_types")
+@Tag(name = "Params management")
 public class DataBillingTypesController
     extends DataGenericController<BillingTypePojo, BillingType> {
 
@@ -55,6 +58,7 @@ public DataBillingTypesController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List billing types.")
     public DataPagePojo<BillingTypePojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
diff --git a/src/main/java/org/trebol/api/controllers/DataCustomersController.java b/src/main/java/org/trebol/api/controllers/DataCustomersController.java
index 289f1930..0b3a7019 100644
--- a/src/main/java/org/trebol/api/controllers/DataCustomersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataCustomersController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -45,6 +47,7 @@
 
 @RestController
 @RequestMapping("/data/customers")
+@Tag(name = "People management")
 @PreAuthorize("isAuthenticated()")
 public class DataCustomersController
     extends DataCrudGenericController<PersonPojo, Customer> {
@@ -61,6 +64,7 @@ public DataCustomersController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List customers.")
     @PreAuthorize("hasAuthority('customers:read')")
     public DataPagePojo<PersonPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
@@ -68,6 +72,7 @@ public DataPagePojo<PersonPojo> readMany(@RequestParam Map<String, String> allRe
 
     @Override
     @PostMapping
+    @Operation(summary = "Register new customer.")
     @PreAuthorize("hasAuthority('customers:create')")
     @ResponseStatus(CREATED)
     public void create(@Valid @RequestBody PersonPojo input)
@@ -77,6 +82,7 @@ public void create(@Valid @RequestBody PersonPojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace customers data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('customers:update')")
     public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map<String, String> requestParams)
@@ -86,6 +92,7 @@ public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map<Strin
 
     @Override
     @DeleteMapping
+    @Operation(summary = "Deregister customers.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('customers:delete')")
     public void delete(Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataImagesController.java b/src/main/java/org/trebol/api/controllers/DataImagesController.java
index a5e5d8b1..a0a22fb2 100644
--- a/src/main/java/org/trebol/api/controllers/DataImagesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataImagesController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
 
 @RestController
 @RequestMapping("/data/images")
+@Tag(name = "Images management")
 @PreAuthorize("isAuthenticated()")
 public class DataImagesController
     extends DataCrudGenericController<ImagePojo, Image> {
@@ -70,6 +73,7 @@ public DataImagesController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List image links data.")
     @PreAuthorize("hasAuthority('images:read')")
     public DataPagePojo<ImagePojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
@@ -77,6 +81,7 @@ public DataPagePojo<ImagePojo> readMany(@RequestParam Map<String, String> allReq
 
     @Override
     @PostMapping
+    @Operation(summary = "Define new image links.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('images:create')")
     public void create(@Valid @RequestBody ImagePojo input)
@@ -86,6 +91,7 @@ public void create(@Valid @RequestBody ImagePojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace image links data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('images:update')")
     public void update(@Valid @RequestBody ImagePojo input, @RequestParam Map<String, String> requestParams)
@@ -95,6 +101,7 @@ public void update(@Valid @RequestBody ImagePojo input, @RequestParam Map<String
 
     @Override
     @PatchMapping
+    @Operation(summary = "Update parts of image links data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('images:update')")
     public void partialUpdate(
@@ -106,6 +113,7 @@ public void partialUpdate(
 
     @Override
     @DeleteMapping
+    @Operation(summary = "Remove image links.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('images:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java b/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java
index bb9076b8..e2dee329 100644
--- a/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -41,6 +43,7 @@
 
 @RestController
 @RequestMapping("/data/order_statuses")
+@Tag(name = "Params management")
 @PreAuthorize("isAuthenticated()")
 public class DataOrderStatusesController
     extends DataGenericController<OrderStatusPojo, OrderStatus> {
@@ -57,6 +60,7 @@ public DataOrderStatusesController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List order statuses.")
     @PreAuthorize("hasAuthority('order_statuses:read')")
     public DataPagePojo<OrderStatusPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
diff --git a/src/main/java/org/trebol/api/controllers/DataOrdersController.java b/src/main/java/org/trebol/api/controllers/DataOrdersController.java
index d669605b..c2447624 100644
--- a/src/main/java/org/trebol/api/controllers/DataOrdersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataOrdersController.java
@@ -22,6 +22,8 @@
 
 import com.querydsl.core.types.OrderSpecifier;
 import com.querydsl.core.types.Predicate;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.lang.Nullable;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -61,6 +63,7 @@
 
 @RestController
 @RequestMapping("/data/orders")
+@Tag(name = "Orders management")
 @PreAuthorize("isAuthenticated()")
 public class DataOrdersController
     extends DataCrudGenericController<OrderPojo, Order> {
@@ -84,6 +87,7 @@ public DataOrdersController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List orders.")
     @PreAuthorize("hasAuthority('orders:read')")
     public DataPagePojo<OrderPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         if (allRequestParams!=null) {
@@ -107,6 +111,7 @@ public DataPagePojo<OrderPojo> readMany(@RequestParam Map<String, String> allReq
 
     @Override
     @PostMapping
+    @Operation(summary = "Create new orders.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('orders:create')")
     public void create(@Valid @RequestBody OrderPojo input)
@@ -116,6 +121,7 @@ public void create(@Valid @RequestBody OrderPojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace orders data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('orders:update')")
     public void update(@Valid @RequestBody OrderPojo input, @RequestParam Map<String, String> requestParams)
@@ -125,6 +131,7 @@ public void update(@Valid @RequestBody OrderPojo input, @RequestParam Map<String
 
     @Override
     @PatchMapping
+    @Operation(summary = "Update parts of orders data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('orders:update')")
     public void partialUpdate(
@@ -136,6 +143,7 @@ public void partialUpdate(
 
     @Override
     @DeleteMapping
+    @Operation(summary = "Remove orders.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('orders:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
@@ -144,6 +152,7 @@ public void delete(@RequestParam Map<String, String> requestParams)
     }
 
     @PostMapping("/confirmation")
+    @Operation(summary = "Confirm a pending order.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('orders:update')")
     public void confirmSell(@RequestBody OrderPojo sell)
@@ -156,6 +165,7 @@ public void confirmSell(@RequestBody OrderPojo sell)
     }
 
     @PostMapping("/rejection")
+    @Operation(summary = "Reject a pending order.")
     @PreAuthorize("hasAuthority('orders:update')")
     public void rejectSell(@RequestBody OrderPojo sell)
         throws BadInputException, MailingServiceException {
@@ -166,6 +176,7 @@ public void rejectSell(@RequestBody OrderPojo sell)
     }
 
     @PostMapping("/completion")
+    @Operation(summary = "Mark an order as completed.")
     @PreAuthorize("hasAuthority('orders:update')")
     public void completeSell(@RequestBody OrderPojo sell)
         throws BadInputException, MailingServiceException {
diff --git a/src/main/java/org/trebol/api/controllers/DataPeopleController.java b/src/main/java/org/trebol/api/controllers/DataPeopleController.java
index 6ae4ebb5..c7f99254 100644
--- a/src/main/java/org/trebol/api/controllers/DataPeopleController.java
+++ b/src/main/java/org/trebol/api/controllers/DataPeopleController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -41,6 +43,7 @@
 
 @RestController
 @RequestMapping("/data/people")
+@Tag(name = "People management")
 @PreAuthorize("isAuthenticated()")
 public class DataPeopleController
     extends DataGenericController<PersonPojo, Person> {
@@ -57,6 +60,7 @@ public DataPeopleController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List people.")
     @PreAuthorize("hasAuthority('people:read')")
     public DataPagePojo<PersonPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
diff --git a/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java b/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java
index f888ca72..512008e6 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
 
 @RestController
 @RequestMapping("/data/product_categories")
+@Tag(name = "Product Categories management")
 public class DataProductCategoriesController
     extends DataCrudGenericController<ProductCategoryPojo, ProductCategory> {
 
@@ -69,6 +72,7 @@ public DataProductCategoriesController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List product categories.")
     public DataPagePojo<ProductCategoryPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         if (allRequestParams==null || allRequestParams.isEmpty()) {
             allRequestParams = Map.of("parentId", "");
@@ -78,6 +82,7 @@ public DataPagePojo<ProductCategoryPojo> readMany(@RequestParam Map<String, Stri
 
     @Override
     @PostMapping
+    @Operation(summary = "Define new product categories.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('product_categories:create')")
     public void create(@Valid @RequestBody ProductCategoryPojo input)
@@ -87,6 +92,7 @@ public void create(@Valid @RequestBody ProductCategoryPojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace product categories data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_categories:update')")
     public void update(@Valid @RequestBody ProductCategoryPojo input, @RequestParam Map<String, String> requestParams)
@@ -96,6 +102,7 @@ public void update(@Valid @RequestBody ProductCategoryPojo input, @RequestParam
 
     @Override
     @PatchMapping
+    @Operation(summary = "Update parts of product categories data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_categories:update')")
     public void partialUpdate(
@@ -107,6 +114,7 @@ public void partialUpdate(
 
     @Override
     @DeleteMapping
+    @Operation(summary = "Remove product categories.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_categories:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java b/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java
index c406e4a4..d71cebbf 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.Predicate;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Example;
@@ -68,6 +70,7 @@
 
 @RestController
 @RequestMapping("/data/product_list_contents")
+@Tag(name = "Product Lists management")
 public class DataProductListContentsController {
     private static final String ITEM_NOT_FOUND = "Requested item(s) not found";
     private final PaginationService paginationService;
@@ -98,6 +101,7 @@ public DataProductListContentsController(
     }
 
     @GetMapping
+    @Operation(summary = "View contents of product lists.")
     public DataPagePojo<ProductPojo> readContents(@RequestParam Map<String, String> requestParams)
         throws BadInputException, EntityNotFoundException {
         Optional<ProductList> match = this.fetchProductListByCode(requestParams);
@@ -129,6 +133,7 @@ public DataPagePojo<ProductPojo> readContents(@RequestParam Map<String, String>
     }
 
     @PostMapping
+    @Operation(summary = "Add products to lists.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('product_lists:contents')")
     public void addToContents(@Valid @RequestBody ProductPojo input,
@@ -152,6 +157,7 @@ public void addToContents(@Valid @RequestBody ProductPojo input,
     }
 
     @PutMapping
+    @Operation(summary = "Fully replace contents of product lists.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:contents')")
     public void updateContents(@RequestBody Collection<ProductPojo> input,
@@ -178,6 +184,7 @@ public void updateContents(@RequestBody Collection<ProductPojo> input,
     }
 
     @DeleteMapping
+    @Operation(summary = "Remove products from lists.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:contents')")
     public void deleteFromContents(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataProductListsController.java b/src/main/java/org/trebol/api/controllers/DataProductListsController.java
index 875ae18c..74993d84 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductListsController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductListsController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
 
 @RestController
 @RequestMapping("/data/product_lists")
+@Tag(name = "Product Lists management")
 public class DataProductListsController
     extends DataCrudGenericController<ProductListPojo, ProductList> {
 
@@ -69,12 +72,14 @@ public DataProductListsController(
 
     @Override
     @GetMapping
+    @Operation(summary = "View product lists.")
     public DataPagePojo<ProductListPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
     @PostMapping
+    @Operation(summary = "Define new product lists.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('product_lists:create')")
     public void create(@Valid @RequestBody ProductListPojo input)
@@ -84,6 +89,7 @@ public void create(@Valid @RequestBody ProductListPojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace product lists data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:update')")
     public void update(@Valid @RequestBody ProductListPojo input, @RequestParam Map<String, String> requestParams)
@@ -93,6 +99,7 @@ public void update(@Valid @RequestBody ProductListPojo input, @RequestParam Map<
 
     @Override
     @PatchMapping
+    @Operation(summary = "Update parts of product lists data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:update')")
     public void partialUpdate(
@@ -104,6 +111,7 @@ public void partialUpdate(
 
     @Override
     @DeleteMapping
+    @Operation(summary = "Remove product lists.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('product_lists:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataProductsController.java b/src/main/java/org/trebol/api/controllers/DataProductsController.java
index 76859f38..35bdeb41 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductsController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductsController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
 
 @RestController
 @RequestMapping("/data/products")
+@Tag(name = "Products management")
 public class DataProductsController
     extends DataCrudGenericController<ProductPojo, Product> {
 
@@ -69,12 +72,14 @@ public DataProductsController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List products.")
     public DataPagePojo<ProductPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
     @PostMapping
+    @Operation(summary = "Define new products.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('products:create')")
     public void create(@Valid @RequestBody ProductPojo input)
@@ -84,6 +89,7 @@ public void create(@Valid @RequestBody ProductPojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace products data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('products:update')")
     public void update(@Valid @RequestBody ProductPojo input, @RequestParam Map<String, String> requestParams)
@@ -93,6 +99,7 @@ public void update(@Valid @RequestBody ProductPojo input, @RequestParam Map<Stri
 
     @Override
     @PatchMapping
+    @Operation(summary = "Update parts of products data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('products:update')")
     public void partialUpdate(
@@ -104,6 +111,7 @@ public void partialUpdate(
 
     @Override
     @DeleteMapping
+    @Operation(summary = "Remove products.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('products:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java b/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java
index dbb58956..c4c466a5 100644
--- a/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java
+++ b/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -53,6 +55,7 @@
 
 @RestController
 @RequestMapping("/data/salespeople")
+@Tag(name = "People management")
 @PreAuthorize("isAuthenticated()")
 public class DataSalespeopleController
     extends DataCrudGenericController<PersonPojo, Salesperson> {
@@ -69,6 +72,7 @@ public DataSalespeopleController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List salespeople.")
     @PreAuthorize("hasAuthority('salespeople:read')")
     public DataPagePojo<PersonPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
@@ -76,6 +80,7 @@ public DataPagePojo<PersonPojo> readMany(@RequestParam Map<String, String> allRe
 
     @Override
     @PostMapping
+    @Operation(summary = "Register new salespeople.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('salespeople:create')")
     public void create(@Valid @RequestBody PersonPojo input)
@@ -85,6 +90,7 @@ public void create(@Valid @RequestBody PersonPojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace salespeople data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('salespeople:update')")
     public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map<String, String> requestParams)
@@ -94,6 +100,7 @@ public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map<Strin
 
     @Override
     @DeleteMapping
+    @Operation(summary = "Deregister salespeople.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('salespeople:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataShippersController.java b/src/main/java/org/trebol/api/controllers/DataShippersController.java
index 2774b959..6a44e3f0 100644
--- a/src/main/java/org/trebol/api/controllers/DataShippersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataShippersController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
 
 @RestController
 @RequestMapping("/data/shippers")
+@Tag(name = "Shippers management")
 public class DataShippersController
     extends DataCrudGenericController<ShipperPojo, Shipper> {
 
@@ -69,12 +72,14 @@ public DataShippersController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List shippers.")
     public DataPagePojo<ShipperPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
     }
 
     @Override
     @PostMapping
+    @Operation(summary = "Define new shippers.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('shippers:create')")
     public void create(@Valid @RequestBody ShipperPojo input)
@@ -84,6 +89,7 @@ public void create(@Valid @RequestBody ShipperPojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace shippers data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('shippers:update')")
     public void update(@Valid @RequestBody ShipperPojo input, @RequestParam Map<String, String> requestParams)
@@ -93,6 +99,7 @@ public void update(@Valid @RequestBody ShipperPojo input, @RequestParam Map<Stri
 
     @Override
     @PatchMapping
+    @Operation(summary = "Update parts of shippers data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('shippers:update')")
     public void partialUpdate(
@@ -104,6 +111,7 @@ public void partialUpdate(
 
     @Override
     @DeleteMapping
+    @Operation(summary = "Remove shippers.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('shippers:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataUserRolesController.java b/src/main/java/org/trebol/api/controllers/DataUserRolesController.java
index 658b2989..3b16e800 100644
--- a/src/main/java/org/trebol/api/controllers/DataUserRolesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataUserRolesController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -53,6 +55,7 @@
 
 @RestController
 @RequestMapping("/data/user_roles")
+@Tag(name = "Params management")
 @PreAuthorize("isAuthenticated()")
 public class DataUserRolesController
     extends DataCrudGenericController<UserRolePojo, UserRole> {
@@ -69,6 +72,7 @@ public DataUserRolesController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List user roles.")
     @PreAuthorize("hasAuthority('user_roles:read')")
     public DataPagePojo<UserRolePojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
@@ -76,6 +80,7 @@ public DataPagePojo<UserRolePojo> readMany(@RequestParam Map<String, String> all
 
     @Override
     @PostMapping
+    @Operation(summary = "Define new user roles.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('user_roles:create')")
     public void create(@Valid @RequestBody UserRolePojo input)
@@ -85,6 +90,7 @@ public void create(@Valid @RequestBody UserRolePojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace user roles data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('user_roles:update')")
     public void update(@Valid @RequestBody UserRolePojo input, @RequestParam Map<String, String> requestParams)
@@ -94,6 +100,7 @@ public void update(@Valid @RequestBody UserRolePojo input, @RequestParam Map<Str
 
     @Override
     @DeleteMapping
+    @Operation(summary = "Remove user roles.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('user_roles:delete')")
     public void delete(@RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataUsersController.java b/src/main/java/org/trebol/api/controllers/DataUsersController.java
index 88439d70..bf199e5a 100644
--- a/src/main/java/org/trebol/api/controllers/DataUsersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataUsersController.java
@@ -21,6 +21,8 @@
 package org.trebol.api.controllers;
 
 import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
 
 @RestController
 @RequestMapping("/data/users")
+@Tag(name = "Users management")
 @PreAuthorize("isAuthenticated()")
 public class DataUsersController
     extends DataCrudGenericController<UserPojo, User> {
@@ -70,6 +73,7 @@ public DataUsersController(
 
     @Override
     @GetMapping
+    @Operation(summary = "List users.")
     @PreAuthorize("hasAuthority('users:read')")
     public DataPagePojo<UserPojo> readMany(@RequestParam Map<String, String> allRequestParams) {
         return super.readMany(allRequestParams);
@@ -77,6 +81,7 @@ public DataPagePojo<UserPojo> readMany(@RequestParam Map<String, String> allRequ
 
     @Override
     @PostMapping
+    @Operation(summary = "Register new users.")
     @ResponseStatus(CREATED)
     @PreAuthorize("hasAuthority('users:create')")
     public void create(@Valid @RequestBody UserPojo input)
@@ -86,6 +91,7 @@ public void create(@Valid @RequestBody UserPojo input)
 
     @Override
     @PutMapping
+    @Operation(summary = "Replace users data.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('users:update')")
     public void update(@Valid @RequestBody UserPojo input, @RequestParam Map<String, String> requestParams)
@@ -94,6 +100,7 @@ public void update(@Valid @RequestBody UserPojo input, @RequestParam Map<String,
     }
 
     @DeleteMapping
+    @Operation(summary = "Remove users.")
     @ResponseStatus(NO_CONTENT)
     @PreAuthorize("hasAuthority('users:delete')")
     public void delete(Principal principal, @RequestParam Map<String, String> requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/PublicAboutController.java b/src/main/java/org/trebol/api/controllers/PublicAboutController.java
index 1672c1e6..28836fb8 100644
--- a/src/main/java/org/trebol/api/controllers/PublicAboutController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicAboutController.java
@@ -20,6 +20,8 @@
 
 package org.trebol.api.controllers;
 
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -29,6 +31,7 @@
 
 @RestController
 @RequestMapping("/public/about")
+@Tag(name = "About")
 public class PublicAboutController {
 
     private final CompanyService companyService;
@@ -39,6 +42,7 @@ public PublicAboutController(CompanyService companyService) {
     }
 
     @GetMapping
+    @Operation(summary = "View information useful to customers regarding the business.")
     public CompanyDetailsPojo readCompanyDetails() {
         return companyService.readDetails();
     }
diff --git a/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java b/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java
index 35126653..b8ad963f 100644
--- a/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java
@@ -22,6 +22,8 @@
 
 import com.querydsl.core.types.Predicate;
 import io.jsonwebtoken.lang.Maps;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.ResponseEntity;
 import org.springframework.lang.Nullable;
@@ -60,6 +62,7 @@
 
 @RestController
 @RequestMapping("/public/checkout")
+@Tag(name = "Checkout")
 public class PublicCheckoutController {
     private final CheckoutService service;
     private final OrdersCrudService ordersCrudService;
@@ -90,6 +93,7 @@ public PublicCheckoutController(
      *                                 payment process
      */
     @PostMapping
+    @Operation(summary = "Submit cart contents to request an order and begin a checkout")
     @PreAuthorize("hasAuthority('" + AUTHORITY_CHECKOUT + "')")
     public PaymentRedirectionDetailsPojo submitCart(@Valid @RequestBody OrderPojo transactionRequest)
         throws BadInputException, PaymentServiceException, EntityExistsException {
@@ -107,6 +111,7 @@ public PaymentRedirectionDetailsPojo submitCart(@Valid @RequestBody OrderPojo tr
      * @throws PaymentServiceException If an error happens during internal API calls
      */
     @GetMapping("/validate")
+    @Operation(summary = "Request that an order status be updated after having begun checkout")
     public ResponseEntity<Void> validateSuccesfulTransaction(@RequestParam Map<String, String> transactionData)
         throws BadInputException, EntityNotFoundException, PaymentServiceException, MailingServiceException {
         if (!transactionData.containsKey(WEBPAY_SUCCESS_TOKEN_HEADER_NAME)) { // success
@@ -134,6 +139,7 @@ public ResponseEntity<Void> validateSuccesfulTransaction(@RequestParam Map<Strin
      * @throws PaymentServiceException If an error happens during internal API calls
      */
     @PostMapping("/validate")
+    @Operation(summary = "Submit failed or aborted state for an order after having begun checkout")
     public ResponseEntity<Void> validateAbortedTransaction(@RequestParam Map<String, String> transactionData)
         throws BadInputException, EntityNotFoundException, PaymentServiceException {
 
@@ -157,6 +163,7 @@ public ResponseEntity<Void> validateAbortedTransaction(@RequestParam Map<String,
      * @throws EntityNotFoundException when no transaction matched the provided token
      */
     @GetMapping("/result/{token}")
+    @Operation(summary = "View information about an order once complete or rejected")
     public OrderPojo getTransactionResultFor(@NotBlank @PathVariable String token)
         throws EntityNotFoundException {
         Map<String, String> tokenMatcher = Maps.of("token", token).build();
diff --git a/src/main/java/org/trebol/api/controllers/PublicReceiptController.java b/src/main/java/org/trebol/api/controllers/PublicReceiptController.java
index 4fc0e506..a218376f 100644
--- a/src/main/java/org/trebol/api/controllers/PublicReceiptController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicReceiptController.java
@@ -20,6 +20,8 @@
 
 package org.trebol.api.controllers;
 
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -34,6 +36,7 @@
 
 @RestController
 @RequestMapping("/public/receipt")
+@Tag(name = "Checkout")
 public class PublicReceiptController {
     private final ReceiptService receiptService;
 
@@ -44,7 +47,16 @@ public PublicReceiptController(
         this.receiptService = receiptService;
     }
 
+    /**
+     * Fetch result of transaction after it has been confirmed and validated
+     *
+     * @param token The token used during the transaction
+     * @return An object with all available data about the transaction
+     * @throws BadInputException when an empty token is provided
+     * @throws EntityNotFoundException when no transaction matches the provided token
+     */
     @GetMapping("/{token}")
+    @Operation(summary = "View a summary of an order once complete or rejected")
     public ReceiptPojo fetchReceiptById(@PathVariable("token") String token)
         throws BadInputException, EntityNotFoundException {
         if (StringUtils.isBlank(token)) {
diff --git a/src/main/java/org/trebol/api/controllers/PublicRegisterController.java b/src/main/java/org/trebol/api/controllers/PublicRegisterController.java
index 6167f062..65a1abd0 100644
--- a/src/main/java/org/trebol/api/controllers/PublicRegisterController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicRegisterController.java
@@ -20,6 +20,8 @@
 
 package org.trebol.api.controllers;
 
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -34,6 +36,7 @@
 
 @RestController
 @RequestMapping("/public/register")
+@Tag(name = "User Accounts")
 public class PublicRegisterController {
     private final RegistrationService registrationService;
 
@@ -45,6 +48,7 @@ public PublicRegisterController(
     }
 
     @PostMapping
+    @Operation(summary = "Request creation of new user account.")
     public void register(@Valid @RequestBody RegistrationPojo userProfile)
         throws BadInputException, EntityExistsException {
         this.registrationService.register(userProfile);
diff --git a/src/main/java/org/trebol/api/controllers/RootController.java b/src/main/java/org/trebol/api/controllers/RootController.java
index 6771d491..1321b6de 100644
--- a/src/main/java/org/trebol/api/controllers/RootController.java
+++ b/src/main/java/org/trebol/api/controllers/RootController.java
@@ -20,14 +20,18 @@
 
 package org.trebol.api.controllers;
 
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
+@Tag(name = "Health check")
 public class RootController {
 
     @GetMapping
+    @Operation(summary = "Non-operating endpoint.")
     public ResponseEntity<Void> defaultMapping() {
         return ResponseEntity.ok().build();
     }