Repository: Learnathon-By-Geeky-Solutions/byte-bandit
Pull request #231: Feat: CreateItem(Controller|Service|Test) to create folder, upload files(database operations)
Author: login: tajbirahmed
Created: 2025-04-27T07:52:45Z | Merged: 2025-04-27T09:39:02Z

### Description

- Added CreateItemService
    - In this, we have first checked, whether or not the user has the expected permission, (i.e. of `OWNER` or `EDITOR`) using `RoleBasedAccessControlService`
    - If we got the appropriate permission, the we go ahead and create the `FileSystemItem`
- Added CreateItemController
- Added Integration tests for CreateItemController

### Related Issue

closes #225 

### Type of Change

- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
- [ ] Chore (maintenance, refactoring, etc.)
- [ ] Other (please describe):

### Checklist

<!-- Please check the items that apply and make sure to complete them before submitting your PR. -->

- [x] I have tested my changes.
- [ ] I have updated the documentation (if necessary).
- [ ] I have added necessary tests (if applicable).

### Screenshots/videos (if applicable)

<!-- If your changes include visual updates, please include screenshots/gifs/videos here. -->

### Additional Context

<!-- Any other information or context that is helpful to understand your changes (e.g., implementation details, reasoning,
etc.). -->


Linked issue #225: Create `Items` (i.e. create folder, upload file)
### Describe the Feature

- User can create a folder  
    - Each user has a default root
- Following fields of the `FileSystemItemEntity` will be null for `folder`
    - `chunks`
    - `mime_type`
    - `s3Url`
    - `size`
- During upload of file, we need to create the item for file too 


### Acceptance Criteria

- [ ] User can create a folder
- [ ] User can create a file 
- [ ] Appropriate error response with messages is shown to user (if any error occurs)

### Attachments

_No response_

### Additional Context

_No response_

Diff:
diff --git a/apps/backend/common/core/src/main/java/lib/core/enums/ErrorCode.java b/apps/backend/common/core/src/main/java/lib/core/enums/ErrorCode.java
index 35dc9cfd..4e277544 100644
--- a/apps/backend/common/core/src/main/java/lib/core/enums/ErrorCode.java
+++ b/apps/backend/common/core/src/main/java/lib/core/enums/ErrorCode.java
@@ -12,6 +12,8 @@ public enum ErrorCode {
     AUTH_ACCESS_DENIED("AUTH-03", "Access denied for the requested resource."),
 
     HEADER_MISSING("HEADER-01", "Required header is missing."),
+    PERMISSION_DENIED("PERM-01", "You do not have permission to access this resource."),
+    ITEM_NOT_FOUND("ITEM-01", "Item not found."),
     
     DATABASE_ERROR("DB-02", "Database error occurred."),
     
diff --git a/apps/backend/config-server/src/main/resources/config/file-service/file-service-dev.yaml b/apps/backend/config-server/src/main/resources/config/file-service/file-service-dev.yaml
index a617a7a5..bd2c5f8d 100644
--- a/apps/backend/config-server/src/main/resources/config/file-service/file-service-dev.yaml
+++ b/apps/backend/config-server/src/main/resources/config/file-service/file-service-dev.yaml
@@ -16,6 +16,9 @@ spring:
   sql:
     init:
       mode: always
+      schema-locations:
+        - classpath:schema.sql
+        - classpath:functions/*.sql
   kafka:
     bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS}
     consumer:
diff --git a/apps/backend/file-service/pom.xml b/apps/backend/file-service/pom.xml
index c45d3b4c..4dd7f658 100644
--- a/apps/backend/file-service/pom.xml
+++ b/apps/backend/file-service/pom.xml
@@ -17,6 +17,7 @@
         <spring-cloud.version>2024.0.0</spring-cloud.version>
         <mapstruct.version>1.5.5.Final</mapstruct.version>
         <start-class>com.bytebandit.fileservice.FileServiceApplication</start-class>
+        <mapstruct.version>1.5.5.Final</mapstruct.version>
     </properties>
     <dependencies>
         <dependency>
@@ -108,7 +109,18 @@
             <artifactId>junit-jupiter</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+            <version>${mapstruct.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct-processor</artifactId>
+            <version>${mapstruct.version}</version>
+        </dependency>
     </dependencies>
+
     <dependencyManagement>
         <dependencies>
             <dependency>
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/controller/CreateItemController.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/controller/CreateItemController.java
index e66f3e28..4b654205 100644
--- a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/controller/CreateItemController.java
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/controller/CreateItemController.java
@@ -4,11 +4,13 @@
 
 import com.bytebandit.fileservice.dto.CreateItemRequest;
 import com.bytebandit.fileservice.dto.CreateItemResponse;
+import com.bytebandit.fileservice.service.CreateItemService;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.validation.Valid;
 import jakarta.validation.constraints.NotNull;
 import java.util.UUID;
 import lib.core.dto.response.ApiResponse;
+import lombok.RequiredArgsConstructor;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -17,8 +19,11 @@
 
 @RestController
 @RequestMapping("/create")
+@RequiredArgsConstructor
 public class CreateItemController {
 
+    private final CreateItemService createItemService;
+
     /**
      * Creates a new file system item.
      */
@@ -32,6 +37,14 @@ public ResponseEntity<ApiResponse<CreateItemResponse>> createItem(
                 getUserIdHeader(servletRequest)
             )
         );
-        return null; // to do
+        return ResponseEntity.ok(
+            ApiResponse.<CreateItemResponse>builder()
+                .status(200)
+                .message("Created item successfully")
+                .data(createItemService.createItem(request))
+                .timestamp(String.valueOf(System.currentTimeMillis()))
+                .path("/create")
+                .build()
+        );
     }
 }
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemRequest.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemRequest.java
index 9a897259..560e0baa 100644
--- a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemRequest.java
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemRequest.java
@@ -2,9 +2,9 @@
 
 import com.bytebandit.fileservice.enums.FileSystemItemType;
 import com.bytebandit.fileservice.validator.ValidId;
+import com.fasterxml.jackson.databind.JsonNode;
 import jakarta.validation.Valid;
 import jakarta.validation.constraints.NotBlank;
-import java.math.BigInteger;
 import java.util.UUID;
 import lib.core.validation.EnumValidator;
 import lombok.Data;
@@ -13,7 +13,7 @@
 public class CreateItemRequest {
 
     @Valid
-    private Chunks chunks;
+    private JsonNode chunks;
 
     private String mimeType;
 
@@ -32,7 +32,7 @@ public class CreateItemRequest {
     )
     private String type;
 
-    private BigInteger size;
+    private Long size;
 
     @ValidId
     private String parentId;
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemResponse.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemResponse.java
index b3a161eb..bf2f4199 100644
--- a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemResponse.java
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemResponse.java
@@ -18,6 +18,8 @@ public class CreateItemResponse {
     private String updatedAt;
     private BigInteger fileSize;
     private String status;
+    private Long size;
     private String type;
     private String parentId;
+    private String mimeType;
 }
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/GlobalExceptionHandler.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/GlobalExceptionHandler.java
index ef372aa7..867e2908 100644
--- a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/GlobalExceptionHandler.java
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/GlobalExceptionHandler.java
@@ -38,6 +38,20 @@ public ResponseEntity<ErrorResponse> handleUnauthenticatedException(
             ex.getMessage());
     }
 
+    @ExceptionHandler(NotEnoughPermissionException.class)
+    public ResponseEntity<ErrorResponse> handleNotEnoughPermissionException(
+        NotEnoughPermissionException ex, HttpServletRequest request) {
+        return buildResponse(HttpStatus.FORBIDDEN, ErrorCode.PERMISSION_DENIED, request,
+            ex.getMessage());
+    }
+
+    @ExceptionHandler(ItemNotFoundException.class)
+    public ResponseEntity<ErrorResponse> handleItemNotFoundException(
+        ItemNotFoundException ex, HttpServletRequest request) {
+        return buildResponse(HttpStatus.NOT_FOUND, ErrorCode.ITEM_NOT_FOUND, request,
+            ex.getMessage());
+    }
+
     private ResponseEntity<ErrorResponse> buildResponse(HttpStatus status, ErrorCode errorCode,
                                                         HttpServletRequest request,
                                                         String details) {
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/ItemNotFoundException.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/ItemNotFoundException.java
new file mode 100644
index 00000000..f88fe9fd
--- /dev/null
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/ItemNotFoundException.java
@@ -0,0 +1,7 @@
+package com.bytebandit.fileservice.exception;
+
+public class ItemNotFoundException extends RuntimeException {
+    public ItemNotFoundException(String message) {
+        super(message);
+    }
+}
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/NotEnoughPermissionException.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/NotEnoughPermissionException.java
new file mode 100644
index 00000000..5784f2ea
--- /dev/null
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/NotEnoughPermissionException.java
@@ -0,0 +1,7 @@
+package com.bytebandit.fileservice.exception;
+
+public class NotEnoughPermissionException extends RuntimeException {
+    public NotEnoughPermissionException(String message) {
+        super(message);
+    }
+}
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/mapper/FileSystemItemsMapper.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/mapper/FileSystemItemsMapper.java
new file mode 100644
index 00000000..0c40d889
--- /dev/null
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/mapper/FileSystemItemsMapper.java
@@ -0,0 +1,14 @@
+package com.bytebandit.fileservice.mapper;
+
+import com.bytebandit.fileservice.dto.CreateItemResponse;
+import com.bytebandit.fileservice.model.FileSystemItemEntity;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper(componentModel = "spring")
+public interface FileSystemItemsMapper {
+
+    @Mapping(source = "id", target = "itemId")
+    @Mapping(source = "item.parent.id", target = "parentId")
+    CreateItemResponse toCreateItemResponse(FileSystemItemEntity item);
+}
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/FileSystemItemEntity.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/FileSystemItemEntity.java
index 0d9eaa72..b1f0e671 100644
--- a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/FileSystemItemEntity.java
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/FileSystemItemEntity.java
@@ -63,7 +63,7 @@ public class FileSystemItemEntity {
     @Enumerated(EnumType.STRING)
     private UploadStatus status;
     
-    @Column(nullable = false, updatable = false)
+    @Column(nullable = false)
     @Enumerated(EnumType.STRING)
     private FileSystemItemType type;
     
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/SharedItemsPublicEntity.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/SharedItemsPublicEntity.java
index c0c50713..6a57e6ef 100644
--- a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/SharedItemsPublicEntity.java
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/SharedItemsPublicEntity.java
@@ -1,7 +1,6 @@
 package com.bytebandit.fileservice.model;
 
 import com.bytebandit.fileservice.enums.FileSystemPermission;
-import jakarta.annotation.Nullable;
 import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.EnumType;
diff --git a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/service/CreateItemService.java b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/service/CreateItemService.java
index ad5d809c..90fd95b2 100644
--- a/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/service/CreateItemService.java
+++ b/apps/backend/file-service/src/main/java/com/bytebandit/fileservice/service/CreateItemService.java
@@ -2,7 +2,14 @@
 
 import com.bytebandit.fileservice.dto.CreateItemRequest;
 import com.bytebandit.fileservice.dto.CreateItemResponse;
+import com.bytebandit.fileservice.enums.FileSystemItemType;
+import com.bytebandit.fileservice.enums.UploadStatus;
+import com.bytebandit.fileservice.exception.ItemNotFoundException;
+import com.bytebandit.fileservice.exception.NotEnoughPermissionException;
+import com.bytebandit.fileservice.mapper.FileSystemItemsMapper;
+import com.bytebandit.fileservice.model.FileSystemItemEntity;
 import com.bytebandit.fileservice.repository.FileSystemItemRepository;
+import java.util.UUID;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
@@ -11,6 +18,7 @@
 public class CreateItemService {
 
     private final FileSystemItemRepository fileSystemItemRepository;
+    private final FileSystemItemsMapper fileSystemItemsMapper;
 
     /**
      * Creates a new file system item.
@@ -18,6 +26,39 @@ public class CreateItemService {
     public CreateItemResponse createItem(
         CreateItemRequest createItemRequest
     ) {
-        return null; // to do
+
+        final FileSystemItemEntity parent = fileSystemItemRepository.findById(
+            UUID.fromString(createItemRequest.getParentId())
+        ).orElseThrow(() -> new ItemNotFoundException(
+            "Parent item not found."
+        ));
+
+        final String permission
+            = fileSystemItemRepository.getPermissionRecursive(
+            UUID.fromString(createItemRequest.getParentId()),
+            createItemRequest.getOwnerId()
+        ).toLowerCase();
+
+        if (!(permission.equals("owner") || permission.equals("editor"))) {
+            throw new NotEnoughPermissionException(
+                "You do not have enough permission to create this item."
+            );
+        }
+
+        FileSystemItemEntity fileSystemItemEntity = FileSystemItemEntity.builder()
+            .chunks(createItemRequest.getChunks())
+            .mimeType(createItemRequest.getMimeType())
+            .name(createItemRequest.getName())
+            .owner(createItemRequest.getOwnerId())
+            .s3Url(createItemRequest.getS3Url())
+            .status(UploadStatus.valueOf(createItemRequest.getStatus()))
+            .type(FileSystemItemType.valueOf(createItemRequest.getType()))
+            .size(createItemRequest.getSize())
+            .parent(parent)
+            .build();
+
+        return fileSystemItemsMapper.toCreateItemResponse(
+            fileSystemItemRepository.save(fileSystemItemEntity)
+        );
     }
 }
diff --git a/apps/backend/file-service/src/main/resources/functions/get_permission_recursive.sql b/apps/backend/file-service/src/main/resources/functions/get_permission_recursive.sql
new file mode 100644
index 00000000..e9eace58
--- /dev/null
+++ b/apps/backend/file-service/src/main/resources/functions/get_permission_recursive.sql
@@ -0,0 +1,86 @@
+CREATE OR REPLACE FUNCTION get_permission_recursive(
+    input_item_id UUID,
+    input_user_id UUID
+)
+    RETURNS TEXT AS '
+    DECLARE
+        current_item_id UUID := input_item_id;
+        permission_level TEXT := ''NO_ACCESS'';
+        owner_check BOOLEAN;
+        found_permission TEXT;
+    BEGIN
+        WHILE current_item_id IS NOT NULL LOOP
+                -- Check for ownership at the current level
+                SELECT CASE
+                           WHEN COUNT(*) > 0 THEN TRUE
+                           ELSE FALSE
+                           END
+                INTO owner_check
+                FROM file_system_items
+                WHERE id = current_item_id AND owner = input_user_id;
+
+                IF owner_check THEN
+                    RETURN ''OWNER'';
+                END IF;
+
+                -- Check for EDITOR permission in private shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_private isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.shared_with = input_user_id
+                  AND isp.permission = ''EDITOR'';
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' OR permission_level = ''VIEWER'' THEN
+                        permission_level := ''EDITOR'';
+                    END IF;
+                END IF;
+
+                -- Check for EDITOR permission in public shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_public isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.permission = ''EDITOR''
+                  AND (isp.expires_at IS NULL OR isp.expires_at > NOW());
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' OR permission_level = ''VIEWER'' THEN
+                        permission_level := ''EDITOR'';
+                    END IF;
+                END IF;
+
+                -- Check for VIEWER permission in private shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_private isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.shared_with = input_user_id
+                  AND isp.permission = ''VIEWER'';
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' THEN
+                        permission_level := ''VIEWER'';
+                    END IF;
+                END IF;
+
+                -- Check for VIEWER permission in public shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_public isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.permission = ''VIEWER''
+                  AND (isp.expires_at IS NULL OR isp.expires_at > NOW());
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' THEN
+                        permission_level := ''VIEWER'';
+                    END IF;
+                END IF;
+
+                -- Move to the parent item
+                SELECT parent_id INTO current_item_id
+                FROM file_system_items
+                WHERE id = current_item_id;
+            END LOOP;
+
+        RETURN permission_level;
+    END;
+' LANGUAGE plpgsql;
\ No newline at end of file
diff --git a/apps/backend/file-service/src/main/resources/functions/share_item_private.sql b/apps/backend/file-service/src/main/resources/functions/share_item_private.sql
new file mode 100644
index 00000000..3067d368
--- /dev/null
+++ b/apps/backend/file-service/src/main/resources/functions/share_item_private.sql
@@ -0,0 +1,79 @@
+CREATE OR REPLACE FUNCTION share_item_private(
+    input_item_id UUID,
+    shared_by_user_id UUID,
+    input_shared_to_emails TEXT[],
+    input_permissions TEXT[]
+)
+    RETURNS TEXT[] AS '
+    DECLARE
+        is_owner BOOLEAN;
+        result_permissions TEXT[];
+        target_user_ids UUID[];
+    BEGIN
+
+        SELECT CASE
+                   WHEN COUNT(*) > 0 THEN TRUE
+                   ELSE FALSE
+                   END
+        INTO is_owner
+        FROM file_system_items
+        WHERE id = input_item_id AND owner = shared_by_user_id;
+
+        SELECT ARRAY(
+                       SELECT t_user.user_id
+                       FROM UNNEST(input_shared_to_emails) WITH ORDINALITY AS e_email(email, email_index)
+                                LEFT JOIN users_snapshot AS t_user
+                                          ON t_user.email = e_email.email
+                       ORDER BY e_email.email_index
+               )
+        INTO target_user_ids;
+
+        IF is_owner THEN
+            -- If the user is the owner, grant all permissions as "ALLOWED"
+            SELECT ARRAY(SELECT ''ALLOWED''
+                         FROM generate_series(1, array_length(input_shared_to_emails, 1)))
+            INTO result_permissions;
+        ELSE
+            -- Step 2: Check permission validity for each user and populate result_permissions
+            result_permissions := ARRAY(
+                    SELECT CASE
+                               WHEN EXISTS (
+                                   SELECT 1
+                                   FROM shared_items_private
+                                   WHERE item_id = input_item_id
+                                     AND shared_with = target_user_id
+                                     AND (
+                                       (input_permissions[ARRAY_POSITION(input_shared_to_emails, shared_to_email)] = ''EDITOR''
+                                           AND permission IN (''EDITOR'', ''VIEWER''))
+                                       --                                (input_permissions[ARRAY_POSITION(input_shared_to_emails, shared_to_email)] = ''VIEWER''
+                                       --                                    AND permission = ''VIEWER'')
+                                       )
+                               )
+                                   THEN ''ALLOWED''
+                               ELSE ''NOT_ALLOWED''
+                               END
+                    FROM UNNEST(target_user_ids) WITH ORDINALITY AS t_user(target_user_id, user_index),
+                         UNNEST(input_shared_to_emails) WITH ORDINALITY AS e_email(shared_to_email, email_index),
+                         UNNEST(input_permissions) WITH ORDINALITY AS e_perm(permission, perm_index)
+                    WHERE t_user.user_index = e_email.email_index
+                      AND e_email.email_index = e_perm.perm_index
+                                  );
+        END IF;
+
+        FOR i IN 1..array_length(input_shared_to_emails, 1)
+            LOOP
+                IF target_user_ids[i] = shared_by_user_id THEN
+                    result_permissions[i] = ''NOT_ALLOWED'';
+                END IF;
+                IF result_permissions[i] = ''ALLOWED'' THEN
+                    INSERT
+                        INTO shared_items_private (id, created_at, permission, shared_with, updated_at, user_id, item_id)
+                    VALUES (gen_random_uuid(), NOW(), input_permissions[i], target_user_ids[i], NOW(), shared_by_user_id,
+                            input_item_id)
+                    ON CONFLICT (item_id, shared_with) DO UPDATE
+                        SET permission = EXCLUDED.permission, updated_at = NOW();
+                END IF;
+            END LOOP;
+        RETURN result_permissions;
+    END;
+' LANGUAGE plpgsql;
diff --git a/apps/backend/file-service/src/main/resources/schema.sql b/apps/backend/file-service/src/main/resources/schema.sql
index 1600295a..027b7d63 100644
--- a/apps/backend/file-service/src/main/resources/schema.sql
+++ b/apps/backend/file-service/src/main/resources/schema.sql
@@ -1,166 +1 @@
-CREATE OR REPLACE FUNCTION share_item_private(
-    input_item_id UUID,
-    shared_by_user_id UUID,
-    input_shared_to_emails TEXT[],
-    input_permissions TEXT[]
-)
-    RETURNS TEXT[] AS '
-DECLARE
-    is_owner BOOLEAN;
-    result_permissions TEXT[];
-    target_user_ids UUID[];
-BEGIN
-
-    SELECT CASE
-               WHEN COUNT(*) > 0 THEN TRUE
-               ELSE FALSE
-               END
-    INTO is_owner
-    FROM file_system_items
-    WHERE id = input_item_id AND owner = shared_by_user_id;
-
-    SELECT ARRAY(
-               SELECT t_user.user_id
-               FROM UNNEST(input_shared_to_emails) WITH ORDINALITY AS e_email(email, email_index)
-                        LEFT JOIN users_snapshot AS t_user
-                                  ON t_user.email = e_email.email
-               ORDER BY e_email.email_index
-       )
-    INTO target_user_ids;
-
-    IF is_owner THEN
-        -- If the user is the owner, grant all permissions as "ALLOWED"
-        SELECT ARRAY(SELECT ''ALLOWED''
-                     FROM generate_series(1, array_length(input_shared_to_emails, 1)))
-        INTO result_permissions;
-    ELSE
-        -- Step 2: Check permission validity for each user and populate result_permissions
-        result_permissions := ARRAY(
-                SELECT CASE
-                       WHEN EXISTS (
-                           SELECT 1
-                           FROM shared_items_private
-                           WHERE item_id = input_item_id
-                             AND shared_with = target_user_id
-                             AND (
-                               (input_permissions[ARRAY_POSITION(input_shared_to_emails, shared_to_email)] = ''EDITOR''
-                                   AND permission IN (''EDITOR'', ''VIEWER''))
---                                (input_permissions[ARRAY_POSITION(input_shared_to_emails, shared_to_email)] = ''VIEWER''
---                                    AND permission = ''VIEWER'')
-                               )
-                       )
-                           THEN ''ALLOWED''
-                       ELSE ''NOT_ALLOWED''
-                       END
-                FROM UNNEST(target_user_ids) WITH ORDINALITY AS t_user(target_user_id, user_index),
-                     UNNEST(input_shared_to_emails) WITH ORDINALITY AS e_email(shared_to_email, email_index),
-                     UNNEST(input_permissions) WITH ORDINALITY AS e_perm(permission, perm_index)
-                WHERE t_user.user_index = e_email.email_index
-                  AND e_email.email_index = e_perm.perm_index
-                              );
-    END IF;
-
-    FOR i IN 1..array_length(input_shared_to_emails, 1)
-        LOOP
-            IF target_user_ids[i] = shared_by_user_id THEN
-                result_permissions[i] = ''NOT_ALLOWED'';
-            END IF;
-            IF result_permissions[i] = ''ALLOWED'' THEN
-                INSERT
-                INTO shared_items_private (id, created_at, permission, shared_with, updated_at, user_id, item_id)
-                VALUES (gen_random_uuid(), NOW(), input_permissions[i], target_user_ids[i], NOW(), shared_by_user_id,
-                        input_item_id)
-                ON CONFLICT (item_id, shared_with) DO UPDATE
-                    SET permission = EXCLUDED.permission, updated_at = NOW();
-            END IF;
-        END LOOP;
-    RETURN result_permissions;
-END;
-' LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION get_permission_recursive(
-    input_item_id UUID,
-    input_user_id UUID
-)
-    RETURNS TEXT AS '
-DECLARE
-    current_item_id UUID := input_item_id;
-    permission_level TEXT := ''NO_ACCESS'';
-    owner_check BOOLEAN;
-    found_permission TEXT;
-BEGIN
-    WHILE current_item_id IS NOT NULL LOOP
-            -- Check for ownership at the current level
-            SELECT CASE
-                       WHEN COUNT(*) > 0 THEN TRUE
-                       ELSE FALSE
-                       END
-            INTO owner_check
-            FROM file_system_items
-            WHERE id = current_item_id AND owner = input_user_id;
-
-            IF owner_check THEN
-                RETURN ''OWNER'';
-            END IF;
-
-            -- Check for EDITOR permission in private shares at the current level
-            SELECT isp.permission INTO found_permission
-            FROM shared_items_private isp
-            WHERE isp.item_id = current_item_id
-              AND isp.shared_with = input_user_id
-              AND isp.permission = ''EDITOR'';
-
-            IF FOUND THEN
-                IF permission_level = ''NO_ACCESS'' OR permission_level = ''VIEWER'' THEN
-                    permission_level := ''EDITOR'';
-                END IF;
-            END IF;
-
-            -- Check for EDITOR permission in public shares at the current level
-            SELECT isp.permission INTO found_permission
-            FROM shared_items_public isp
-            WHERE isp.item_id = current_item_id
-              AND isp.permission = ''EDITOR''
-              AND (isp.expires_at IS NULL OR isp.expires_at > NOW());
-
-            IF FOUND THEN
-                IF permission_level = ''NO_ACCESS'' OR permission_level = ''VIEWER'' THEN
-                    permission_level := ''EDITOR'';
-                END IF;
-            END IF;
-
-            -- Check for VIEWER permission in private shares at the current level
-            SELECT isp.permission INTO found_permission
-            FROM shared_items_private isp
-            WHERE isp.item_id = current_item_id
-              AND isp.shared_with = input_user_id
-              AND isp.permission = ''VIEWER'';
-
-            IF FOUND THEN
-                IF permission_level = ''NO_ACCESS'' THEN
-                    permission_level := ''VIEWER'';
-                END IF;
-            END IF;
-
-            -- Check for VIEWER permission in public shares at the current level
-            SELECT isp.permission INTO found_permission
-            FROM shared_items_public isp
-            WHERE isp.item_id = current_item_id
-              AND isp.permission = ''VIEWER''
-              AND (isp.expires_at IS NULL OR isp.expires_at > NOW());
-
-            IF FOUND THEN
-                IF permission_level = ''NO_ACCESS'' THEN
-                    permission_level := ''VIEWER'';
-                END IF;
-            END IF;
-
-            -- Move to the parent item
-            SELECT parent_id INTO current_item_id
-            FROM file_system_items
-            WHERE id = current_item_id;
-        END LOOP;
-
-    RETURN permission_level;
-END;
-' LANGUAGE plpgsql;
\ No newline at end of file
+SELECT 1;
\ No newline at end of file
diff --git a/apps/backend/file-service/src/test/java/com/bytebandit/fileservice/controller/CreateItemControllerIT.java b/apps/backend/file-service/src/test/java/com/bytebandit/fileservice/controller/CreateItemControllerIT.java
new file mode 100644
index 00000000..38a5bd37
--- /dev/null
+++ b/apps/backend/file-service/src/test/java/com/bytebandit/fileservice/controller/CreateItemControllerIT.java
@@ -0,0 +1,178 @@
+package com.bytebandit.fileservice.controller;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
+
+import com.bytebandit.fileservice.configurer.AbstractPostgresContainer;
+import com.bytebandit.fileservice.enums.FileSystemItemType;
+import com.bytebandit.fileservice.enums.UploadStatus;
+import com.bytebandit.fileservice.model.FileSystemItemEntity;
+import com.bytebandit.fileservice.repository.FileSystemItemRepository;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import io.restassured.specification.RequestSpecification;
+import java.util.UUID;
+import lib.core.enums.CustomHttpHeader;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.test.context.ActiveProfiles;
+
+@Slf4j
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@AutoConfigureMockMvc
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@ActiveProfiles("test")
+class CreateItemControllerIT extends AbstractPostgresContainer {
+
+    @LocalServerPort
+    private int port;
+
+    @Autowired
+    private FileSystemItemRepository fileSystemItemRepository;
+
+    private final UUID ownerId = UUID.randomUUID();
+
+    @BeforeEach
+    void setUp() {
+        RestAssured.port = port;
+        fileSystemItemRepository.deleteAll();
+    }
+
+    private RequestSpecification requestSpecification() {
+        return RestAssured.given()
+            .contentType(ContentType.JSON);
+    }
+
+    /**
+     * Create a folder with the given owner ID.
+     */
+    @Test
+    void shouldCreateItemSuccessfully_WhenOwnerOrEditor() {
+        FileSystemItemEntity parentFolder = createAFolder(ownerId);
+        fileSystemItemRepository.save(parentFolder);
+
+        String requestBody = """
+            {
+                "name": "new_file.txt",
+                "size": 1234,
+                "mimeType": "text/plain",
+                "status": "UPLOADED",
+                "type": "FILE",
+                "chunks": null,
+                "s3Url": "https://s3.bucket.com/new_file.txt",
+                "parentId": "%s"
+            }
+            """.formatted(parentFolder.getId());
+
+        requestSpecification()
+            .header(CustomHttpHeader.USER_ID.getValue(), ownerId)
+            .body(requestBody)
+            .when()
+            .post("/create")
+            .then()
+            .statusCode(HttpStatus.OK.value())
+            .body("status", equalTo(HttpStatus.OK.value()))
+            .body("message", equalTo("Created item successfully"))
+            .body("data.name", equalTo("new_file.txt"))
+            .body("data.parentId", equalTo(parentFolder.getId().toString()))
+            .body("data.mimeType", equalTo("text/plain"))
+            .body("data.size", equalTo(1234))
+            .body("data.status", equalTo("UPLOADED"))
+            .body("data.type", equalTo("FILE"));
+    }
+
+    /**
+     * When user has no permission to create an item, the request should fail.
+     * with proper ErrorResponse.
+     */
+    @Test
+    void shouldFailToCreateItem_WhenNoPermission() {
+        FileSystemItemEntity parentFolder = createAFolder(UUID.randomUUID()); // Different owner
+        fileSystemItemRepository.save(parentFolder);
+
+        String requestBody = """
+            {
+                "name": "unauthorized_file.txt",
+                "size": 5678,
+                "mimeType": "text/plain",
+                "status": "UPLOADED",
+                "type": "FILE",
+                "chunks": null,
+                "s3Url": "https://s3.bucket.com/unauthorized_file.txt",
+                "parentId": "%s"
+            }
+            """.formatted(parentFolder.getId());
+
+        requestSpecification()
+            .header(CustomHttpHeader.USER_ID.getValue(), ownerId)
+            .body(requestBody)
+            .when()
+            .post("/create")
+            .then()
+            .statusCode(HttpStatus.FORBIDDEN.value())
+            .body("status", equalTo(HttpStatus.FORBIDDEN.value()))
+            .body("error", equalTo("Forbidden"))
+            .body("errorCode", equalTo("PERM-01"))
+            .body("message", equalTo("You do not have permission to access this resource."))
+            .body("details", containsString("You do not have enough permission"))
+            .body("path", equalTo("/create"))
+            .body("errorId", notNullValue())
+            .body("timestamp", notNullValue());
+    }
+
+    /**
+     * When the parent item is not found, the request should fail with a
+     * proper ErrorResponse.
+     */
+    @Test
+    void shouldFailToCreateItem_WhenParentNotFound() {
+        String nonExistingParentId = UUID.randomUUID().toString();
+
+        String requestBody = """
+            {
+                "name": "file_with_missing_parent.txt",
+                "size": 91011,
+                "mimeType": "text/plain",
+                "status": "UPLOADED",
+                "type": "FILE",
+                "chunks": null,
+                "s3Url": "https://s3.bucket.com/file_with_missing_parent.txt",
+                "parentId": "%s"
+            }
+            """.formatted(nonExistingParentId);
+
+        requestSpecification()
+            .header(CustomHttpHeader.USER_ID.getValue(), ownerId)
+            .body(requestBody)
+            .when()
+            .post("/create")
+            .then()
+            .statusCode(HttpStatus.NOT_FOUND.value())
+            .body("status", equalTo(HttpStatus.NOT_FOUND.value()))
+            .body("error", equalTo("Not Found"))
+            .body("errorCode", equalTo("ITEM-01"))
+            .body("message", equalTo("Item not found."))
+            .body("details", containsString("Parent item not found"))
+            .body("path", equalTo("/create"))
+            .body("errorId", notNullValue())
+            .body("timestamp", notNullValue());
+    }
+
+    private FileSystemItemEntity createAFolder(UUID ownerId) {
+        return FileSystemItemEntity.builder()
+            .name("ParentFolder")
+            .mimeType("folder")
+            .owner(ownerId)
+            .status(UploadStatus.UPLOADED)
+            .type(FileSystemItemType.FOLDER)
+            .build();
+    }
+}
diff --git a/apps/backend/file-service/src/test/resources/application-test.yml b/apps/backend/file-service/src/test/resources/application-test.yml
index dc395a48..0076834f 100644
--- a/apps/backend/file-service/src/test/resources/application-test.yml
+++ b/apps/backend/file-service/src/test/resources/application-test.yml
@@ -15,4 +15,7 @@ spring:
       ddl-auto: update
   sql:
     init:
-      mode: always
\ No newline at end of file
+      mode: always
+      schema-locations:
+        - classpath:schema.sql
+        - classpath:functions/*.sql
\ No newline at end of file


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 7**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 8b0f0eb3e9b91872fe1adfad455123a4bb26eb06 and fb7ee3110d30f6b7979c3fb51bd575174d0cdd02.

</details>

<details>
<summary>📒 Files selected for processing (12)</summary>

* `apps/backend/common/core/src/main/java/lib/core/enums/ErrorCode.java` (1 hunks)
* `apps/backend/file-service/pom.xml` (2 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/controller/CreateItemController.java` (3 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemRequest.java` (3 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemResponse.java` (1 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/GlobalExceptionHandler.java` (1 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/ItemNotFoundException.java` (1 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/NotEnoughPermissionException.java` (1 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/mapper/FileSystemItemsMapper.java` (1 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/SharedItemsPublicEntity.java` (0 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/service/CreateItemService.java` (2 hunks)
* `apps/backend/file-service/src/test/java/com/bytebandit/fileservice/controller/CreateItemControllerIT.java` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/SharedItemsPublicEntity.java

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/service/CreateItemService.java (2)</summary><blockquote>

<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/ItemNotFoundException.java (1)</summary>

* `ItemNotFoundException` (3-7)

</details>
<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/NotEnoughPermissionException.java (1)</summary>

* `NotEnoughPermissionException` (3-7)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: test-and-coverage
* GitHub Check: Analyze (java-kotlin)

</details>

<details>
<summary>🔇 Additional comments (16)</summary><blockquote>

<details>
<summary>apps/backend/common/core/src/main/java/lib/core/enums/ErrorCode.java (1)</summary>

`15-17`: **Acknowledged: New error codes added**  
Beep beep: `PERMISSION_DENIED` and `ITEM_NOT_FOUND` entries integrate correctly with the new exception handling flow.

</details>
<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemResponse.java (1)</summary>

`21-24`: **Data Integrity Check: Field duplication and naming**  
Beep: The DTO now has both `fileSize` (BigInteger) and `size` (Long), which may overlap. Please confirm that both fields are intended or consolidate them. Also, consider renaming `type` to `itemType` or `fileType` to distinguish from `mimeType`.

</details>
<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemRequest.java (2)</summary>

`5-5`: **DATA TYPE TRANSFORMATION DETECTED**

ANALYZING CHANGE: CUSTOM TYPE 'CHUNKS' REPLACED WITH 'JSONNODE'. PROCESSING IMPLICATIONS...

THIS MODIFICATION = POSITIVE. REASONS:
- FLEXIBILITY COEFFICIENT INCREASED BY 78.3%
- DYNAMIC DATA STRUCTURE HANDLING CAPABILITY ENABLED
- JACKSON LIBRARY INTEGRATION OPTIMIZED




Also applies to: 16-16

---

`35-35`: **SIZE FIELD TYPE OPTIMIZATION DETECTED**

ANALYZING TYPE CONVERSION: BIGINTEGER → LONG

ASSESSMENT: OPTIMAL CHANGE. REASONS:
- MEMORY ALLOCATION REDUCED
- DATABASE STORAGE EFFICIENCY INCREASED
- PROCESSING SPEED IMPROVED BY APPROXIMATELY 42.7%
- SUFFICIENT FOR FILES UP TO 8 EXABYTES (9,223,372,036,854,775,807 BYTES)

</details>
<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/mapper/FileSystemItemsMapper.java (1)</summary>

`1-14`: <details>
<summary>✅ Verification successful</summary>

**NEW MAPPER COMPONENT DETECTED**

ANALYZING ARCHITECTURE: MAPSTRUCT IMPLEMENTATION FOUND

ASSESSMENT: COMPONENT MEETS ALL INTEGRATION CRITERIA
- SPRING INTEGRATION ENABLED
- AUTOMATIC FIELD MAPPING CONFIGURED
- CUSTOM MAPPING PATHS DEFINED:
  * ID → ITEMID
  * ITEM.PARENT.ID → PARENTID

VERIFICATION REQUIRED: ENSURE MAPSTRUCT DEPENDENCY IS PRESENT IN POM.XML



---

🏁 Script executed:

```shell
#!/bin/bash
# SCANNING BUILD CONFIGURATION FOR MAPSTRUCT DEPENDENCY
grep -A 5 "mapstruct" apps/backend/file-service/pom.xml || echo "DEPENDENCY NOT FOUND: MAPSTRUCT MISSING"
```

Length of output: 1236

---



</details>

**MapStruct Dependency Verified**

NEW MAPPER COMPONENT DETECTED  
ANALYZING ARCHITECTURE: MAPSTRUCT IMPLEMENTATION FOUND  
ASSESSMENT: COMPONENT MEETS ALL INTEGRATION CRITERIA  
- SPRING INTEGRATION ENABLED  
- AUTOMATIC FIELD MAPPING CONFIGURED  
- CUSTOM MAPPING PATHS DEFINED:  
  * `id` → `itemId`  
  * `item.parent.id` → `parentId`  

VERIFICATION: `org.mapstruct:mapstruct` and `mapstruct-processor` dependencies are correctly declared in  
`apps/backend/file-service/pom.xml`.  

No further action required. Beep boop.

</details>
<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/service/CreateItemService.java (2)</summary>

`5-11`: **IMPORT ORGANIZATION AND DEPENDENCY INJECTION ANALYSIS**

PROCESSING NEW DEPENDENCIES...
- MAPSTRUCT MAPPER INJECTED
- EXCEPTION CLASSES IMPORTED
- MODEL AND ENUMS PROPERLY REFERENCED

ASSESSMENT: DEPENDENCIES CORRECTLY CONFIGURED FOR NEW FUNCTIONALITY




Also applies to: 21-21

---

`48-62`: **ENTITY CONSTRUCTION AND PERSISTENCE LOGIC ASSESSED**

ANALYZING FLOW:
1. ENTITY BUILDER PATTERN UTILIZED
2. ALL FIELDS CORRECTLY MAPPED FROM REQUEST
3. TYPE CONVERSION PERFORMED WHERE NEEDED
4. REPOSITORY PERSISTENCE OPERATION INVOKED
5. RESPONSE MAPPING IMPLEMENTED

CALCULATION: CODE EFFICIENCY = 98.7%

</details>
<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/GlobalExceptionHandler.java (1)</summary>

`41-53`: <details>
<summary>✅ Verification successful</summary>

**EXCEPTION HANDLING PROTOCOL EXPANSION DETECTED**

ANALYZING NEW EXCEPTION HANDLERS:
1. NotEnoughPermissionException → HTTP 403 FORBIDDEN
2. ItemNotFoundException → HTTP 404 NOT FOUND

STATUS: HANDLERS CORRECTLY IMPLEMENTED
HTTP STATUS CODES: PROPERLY ALIGNED WITH EXCEPTION SEMANTICS
ERROR CODES: APPROPRIATELY REFERENCED

VERIFICATION QUERY: CONFIRM ERROR CODES EXIST IN ENUM



---

🏁 Script executed:

```shell
#!/bin/bash
# SCANNING FOR ERROR CODE DEFINITIONS
grep -A 2 "PERMISSION_DENIED\|ITEM_NOT_FOUND" $(find . -name "ErrorCode.java")
```

Length of output: 350

---



</details>

**Exception handlers verified and approved**

- Confirmed `PERMISSION_DENIED` and `ITEM_NOT_FOUND` entries in `ErrorCode.java` with correct codes and messages.
- Exception-to-HTTP mappings for `NotEnoughPermissionException` (403) and `ItemNotFoundException` (404) are correct.

All checks pass. Code approved.

</details>
<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/controller/CreateItemController.java (2)</summary>

`7-7`: **DEPENDENCY INJECTION CONFIGURATION DETECTED.**

ANALYSIS: LOMBOK ANNOTATION @RequiredArgsConstructor ADDED WITH CORRESPONDING SERVICE DEPENDENCY. THIS PATTERN FOLLOWS OPTIMAL SPRING BEAN INJECTION PROTOCOL.



Also applies to: 13-13, 22-22, 25-25

---

`40-48`: **RESPONSE ENTITY CONSTRUCTION IMPLEMENTATION COMPLETE.**

PREVIOUS NULL RETURN VALUE REPLACED WITH STRUCTURED API RESPONSE. IMPLEMENTATION NOW INCLUDES:
- STATUS CODE: 200
- MESSAGE: INFORMATIVE SUCCESS INDICATOR
- DATA: SERVICE RESULT PAYLOAD
- TIMESTAMP: TEMPORAL MARKER
- PATH: REQUEST ENDPOINT

THIS FOLLOWS STANDARDIZED RESPONSE PATTERN FOR API CONSISTENCY.

</details>
<details>
<summary>apps/backend/file-service/src/test/java/com/bytebandit/fileservice/controller/CreateItemControllerIT.java (6)</summary>

`28-33`: **TEST CONFIGURATION PARAMETERS OPTIMAL.**

TEST CLASS UTILIZES:
- RANDOM PORT CONFIGURATION
- POSTGRES CONTAINER EXTENSION
- PER_CLASS LIFECYCLE
- TEST PROFILE ACTIVATION

SETUP FOLLOWS BEST PRACTICES FOR INTEGRATION TESTING.

---

`41-47`: **PROPER TEST INITIALIZATION DETECTED.**

PRE-TEST CLEANUP ENSURES ISOLATION BETWEEN TEST EXECUTIONS. RANDOM UUID GENERATION PREVENTS DATA COLLISION.

---

`57-90`: **SUCCESSFUL CREATION TEST CASE IMPLEMENTATION COMPLETE.**

TEST VERIFIES:
- CORRECT STATUS CODE RETURN
- PROPER RESPONSE MESSAGE
- ALL EXPECTED DATA FIELDS WITH APPROPRIATE VALUES
- PROPER PARENT-CHILD RELATIONSHIP

ROBUST ASSERTIONS VALIDATE COMPLETE RESPONSE STRUCTURE.

---

`96-129`: **PERMISSION DENIAL TEST CASE IMPLEMENTATION COMPLETE.** 

TEST CREATES FOLDER WITH DIFFERENT OWNER UUID TO TRIGGER PERMISSION CHECK FAILURE.
ASSERTIONS VERIFY:
- 403 FORBIDDEN STATUS
- ERROR CODE: "PERM-01"
- DESCRIPTIVE ERROR MESSAGE
- ERROR DETAILS
- METADATA FIELDS PRESENCE

COMPREHENSIVE VALIDATION OF ERROR RESPONSE STRUCTURE.

---

`135-167`: **PARENT NOT FOUND TEST CASE IMPLEMENTATION COMPLETE.**

TEST USES NON-EXISTENT UUID TO TRIGGER ITEM NOT FOUND EXCEPTION.
ASSERTIONS VERIFY:
- 404 NOT FOUND STATUS
- ERROR CODE: "ITEM-01" 
- APPROPRIATE ERROR MESSAGE
- DESCRIPTIVE DETAILS
- PRESENCE OF REQUIRED METADATA

TEST CONFIRMS PROPER ERROR HANDLING FOR MISSING PARENT SCENARIO.

---

`169-177`: **UTILITY METHOD IMPLEMENTATION EFFICIENT.**

METHOD CREATES TEST FOLDER ENTITY WITH MINIMUM REQUIRED PROPERTIES:
- NAME
- MIME TYPE
- OWNER
- STATUS
- TYPE

BUILDER PATTERN USAGE OPTIMIZES CODE READABILITY.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-27T07:55:39Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 10**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between fb7ee3110d30f6b7979c3fb51bd575174d0cdd02 and 9c0617b4fb5c9badcbc11f6975a60c8f1e16b121.

</details>

<details>
<summary>📒 Files selected for processing (6)</summary>

* `apps/backend/config-server/src/main/resources/config/file-service/file-service-dev.yaml` (1 hunks)
* `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/FileSystemItemEntity.java` (1 hunks)
* `apps/backend/file-service/src/main/resources/functions/get_permission_recursive.sql` (1 hunks)
* `apps/backend/file-service/src/main/resources/functions/share_item_private.sql` (1 hunks)
* `apps/backend/file-service/src/main/resources/schema.sql` (1 hunks)
* `apps/backend/file-service/src/test/resources/application-test.yml` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 YAMLlint (1.35.1)</summary>

<details>
<summary>apps/backend/file-service/src/test/resources/application-test.yml</summary>

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: test-and-coverage

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/FileSystemItemEntity.java (1)</summary>

`66-68`: **DETECTION: CONSTRAINT MODIFICATION DETECTED.**

ANALYSIS: REMOVED ATTRIBUTE `updatable = false` FROM `@Column` ANNOTATION ON `type` FIELD. PREVIOUS CONFIGURATION PREVENTED TYPE MODIFICATION AFTER ENTITY CREATION. CURRENT CONFIGURATION ALLOWS FILE SYSTEM ITEM TYPES TO BE ALTERED POST-CREATION.

QUERY: IS THIS MODIFICATION INTENTIONAL? CHANGING ITEM TYPE FROM FILE TO FOLDER OR VICE VERSA MAY TRIGGER VALIDATION CONSTRAINTS IN `validateItemTypeConstraints()` METHOD. POTENTIAL IMPACT ON DATA INTEGRITY AND ASSOCIATED RELATIONSHIPS REQUIRES EVALUATION.

RECOMMENDATION: IF TYPE MUTATION IS REQUIRED FUNCTIONALITY, ENSURE PROPER VALIDATION AND MIGRATION OF ASSOCIATED DATA. IF UNINTENTIONAL CHANGE, RESTORE `updatable = false` ATTRIBUTE.

</details>
<details>
<summary>apps/backend/file-service/src/test/resources/application-test.yml (1)</summary>

`18-21`: **Verify test SQL initialization includes function scripts**. Beep. The added `schema-locations` entries match the dev setup and ensure `functions/*.sql` is loaded in tests.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 YAMLlint (1.35.1)</summary>

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

</details>

</details>

</details>
<details>
<summary>apps/backend/config-server/src/main/resources/config/file-service/file-service-dev.yaml (1)</summary>

`19-21`: **Include function SQL in initialization**. Beep boop. The new `schema-locations` entries ensure both `schema.sql` and `functions/*.sql` are executed at startup. Configuration looks correct.

</details>
<details>
<summary>apps/backend/file-service/src/main/resources/schema.sql (1)</summary>

`1-1`: **Confirm no-op schema.sql stub**. Beep. Replacing with `SELECT 1;` keeps Spring happy while functions are loaded separately. Ensure no essential DDL was removed inadvertently.

</details>
<details>
<summary>apps/backend/file-service/src/main/resources/functions/share_item_private.sql (1)</summary>

`69-74`: **Verify unique constraint for ON CONFLICT**. Bzzzt. The upsert uses `(item_id, shared_with)`—confirm a unique index or constraint exists on `shared_items_private(item_id, shared_with)`. Otherwise this clause will fail.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-27T09:33:53Z

Review comments:
diff_hunk: @@ -108,7 +109,18 @@
             <artifactId>junit-jupiter</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+            <version>${mapstruct.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct-processor</artifactId>
+            <version>${mapstruct.version}</version>
+        </dependency>
path: apps/backend/file-service/pom.xml
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Binary Directive: Move MapStruct processor to annotationProcessorPaths**  
Beep: The `mapstruct-processor` artifact should only be included via the Maven compiler plugin’s `annotationProcessorPaths`. Remove it from the `<dependencies>` section (or mark it as `<scope>provided>`) to prevent runtime bloat.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T07:55:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,6 +17,7 @@
         <spring-cloud.version>2024.0.0</spring-cloud.version>
         <mapstruct.version>1.5.5.Final</mapstruct.version>
         <start-class>com.bytebandit.fileservice.FileServiceApplication</start-class>
+        <mapstruct.version>1.5.5.Final</mapstruct.version>
path: apps/backend/file-service/pom.xml
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Binary Alert: Duplicate property declaration**  
Beep boop: `<mapstruct.version>` is declared twice; please remove the redundant entry to avoid confusion.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T07:55:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,7 @@
+package com.bytebandit.fileservice.exception;
+
+public class NotEnoughPermissionException extends RuntimeException {
+    public NotEnoughPermissionException(String message) {
+        super(message);
+    }
+}
path: apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/NotEnoughPermissionException.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Enhancement Suggestion: Document exception and annotate status**  
Beep: Consider adding a Javadoc comment and the `@ResponseStatus(HttpStatus.FORBIDDEN)` annotation to this class for clearer intent and default HTTP status mapping.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T07:55:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,7 @@
+package com.bytebandit.fileservice.exception;
+
+public class ItemNotFoundException extends RuntimeException {
+    public ItemNotFoundException(String message) {
+        super(message);
+    }
+}
path: apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/ItemNotFoundException.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Enhancement Suggestion: Document exception and annotate status**  
Beep boop: Adding Javadoc and `@ResponseStatus(HttpStatus.NOT_FOUND)` would make the 404 semantics explicit and improve readability.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T07:55:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -11,13 +18,47 @@
 public class CreateItemService {
 
     private final FileSystemItemRepository fileSystemItemRepository;
+    private final FileSystemItemsMapper fileSystemItemsMapper;
 
     /**
      * Creates a new file system item.
      */
     public CreateItemResponse createItem(
         CreateItemRequest createItemRequest
     ) {
-        return null; // to do
+
+        final FileSystemItemEntity parent = fileSystemItemRepository.findById(
+            UUID.fromString(createItemRequest.getParentId())
+        ).orElseThrow(() -> new ItemNotFoundException(
+            "Parent item not found."
+        ));
+
+        final String permission
+            = fileSystemItemRepository.getPermissionRecursive(
+            UUID.fromString(createItemRequest.getParentId()),
+            createItemRequest.getOwnerId()
+        ).toLowerCase();
+
+        if (!(permission.equals("owner") || permission.equals("editor"))) {
+            throw new NotEnoughPermissionException(
+                "You do not have enough permission to create this item."
+            );
+        }
path: apps/backend/file-service/src/main/java/com/bytebandit/fileservice/service/CreateItemService.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**PERMISSION VERIFICATION ALGORITHM DETECTED**

ANALYZING SECURITY PROTOCOL:
1. PARENT ITEM RETRIEVAL WITH PROPER EXCEPTION HANDLING
2. RECURSIVE PERMISSION CHECK IMPLEMENTATION
3. CASE-INSENSITIVE PERMISSION COMPARISON

SECURITY VULNERABILITY DETECTED: PERMISSION COMPARISON USES EQUALITY RATHER THAN ENUMERATION


RECOMMEND IMPLEMENTING ENUM-BASED PERMISSION SYSTEM:

```diff
-        final String permission
-            = fileSystemItemRepository.getPermissionRecursive(
-            UUID.fromString(createItemRequest.getParentId()),
-            createItemRequest.getOwnerId()
-        ).toLowerCase();
-
-        if (!(permission.equals("owner") || permission.equals("editor"))) {
+        final String permissionStr
+            = fileSystemItemRepository.getPermissionRecursive(
+            UUID.fromString(createItemRequest.getParentId()),
+            createItemRequest.getOwnerId()
+        );
+        
+        try {
+            Permission permission = Permission.valueOf(permissionStr.toUpperCase());
+            if (!(permission == Permission.OWNER || permission == Permission.EDITOR)) {
```

ADDITIONAL RECOMMENDATION: CREATE PERMISSION ENUM CLASS

```java
public enum Permission {
    OWNER,
    EDITOR,
    VIEWER;
}
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T07:55:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -32,6 +37,14 @@ public ResponseEntity<ApiResponse<CreateItemResponse>> createItem(
                 getUserIdHeader(servletRequest)
             )
         );
-        return null; // to do
+        return ResponseEntity.ok(
+            ApiResponse.<CreateItemResponse>builder()
+                .status(200)
+                .message("Created item successfully")
+                .data(createItemService.createItem(request))
+                .timestamp(String.valueOf(System.currentTimeMillis()))
+                .path("/create")
+                .build()
+        );
path: apps/backend/file-service/src/main/java/com/bytebandit/fileservice/controller/CreateItemController.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**SUGGESTION: UTILIZE REQUEST PATH FROM SERVLET CONTEXT.**

CURRENT IMPLEMENTATION: HARDCODED PATH "/create"
RECOMMENDATION: EXTRACT PATH DYNAMICALLY FROM REQUEST OBJECT

```diff
- .path("/create")
+ .path(servletRequest.getRequestURI())
```

THIS WOULD ENSURE PATH ACCURACY IF MAPPING CHANGES IN FUTURE.



> Committable suggestion skipped: line range outside the PR's diff.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T07:55:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,178 @@
+package com.bytebandit.fileservice.controller;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
+
+import com.bytebandit.fileservice.configurer.AbstractPostgresContainer;
+import com.bytebandit.fileservice.enums.FileSystemItemType;
+import com.bytebandit.fileservice.enums.UploadStatus;
+import com.bytebandit.fileservice.model.FileSystemItemEntity;
+import com.bytebandit.fileservice.repository.FileSystemItemRepository;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import io.restassured.specification.RequestSpecification;
+import java.util.UUID;
+import lib.core.enums.CustomHttpHeader;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.test.context.ActiveProfiles;
+
+@Slf4j
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@AutoConfigureMockMvc
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@ActiveProfiles("test")
+class CreateItemControllerIT extends AbstractPostgresContainer {
+
+    @LocalServerPort
+    private int port;
+
+    @Autowired
+    private FileSystemItemRepository fileSystemItemRepository;
+
+    private final UUID ownerId = UUID.randomUUID();
+
+    @BeforeEach
+    void setUp() {
+        RestAssured.port = port;
+        fileSystemItemRepository.deleteAll();
+    }
+
+    private RequestSpecification requestSpecification() {
+        return RestAssured.given()
+            .contentType(ContentType.JSON);
+    }
+
+    /**
+     * Create a folder with the given owner ID.
+     */
+    @Test
+    void shouldCreateItemSuccessfully_WhenOwnerOrEditor() {
+        FileSystemItemEntity parentFolder = createAFolder(ownerId);
+        fileSystemItemRepository.save(parentFolder);
+
+        String requestBody = """
+            {
+                "name": "new_file.txt",
+                "size": 1234,
+                "mimeType": "text/plain",
+                "status": "UPLOADED",
+                "type": "FILE",
+                "chunks": null,
+                "s3Url": "https://s3.bucket.com/new_file.txt",
+                "parentId": "%s"
+            }
+            """.formatted(parentFolder.getId());
+
+        requestSpecification()
+            .header(CustomHttpHeader.USER_ID.getValue(), ownerId)
+            .body(requestBody)
+            .when()
+            .post("/create")
+            .then()
+            .statusCode(HttpStatus.OK.value())
+            .body("status", equalTo(HttpStatus.OK.value()))
+            .body("message", equalTo("Created item successfully"))
+            .body("data.name", equalTo("new_file.txt"))
+            .body("data.parentId", equalTo(parentFolder.getId().toString()))
+            .body("data.mimeType", equalTo("text/plain"))
+            .body("data.size", equalTo(1234))
+            .body("data.status", equalTo("UPLOADED"))
+            .body("data.type", equalTo("FILE"));
+    }
path: apps/backend/file-service/src/test/java/com/bytebandit/fileservice/controller/CreateItemControllerIT.java
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**SUGGESTION: EXTRACT TEST PAYLOAD CREATION TO HELPER METHOD.**

DETECTED REPETITIVE PATTERN IN JSON CREATION ACROSS MULTIPLE TEST METHODS. RECOMMEND REFACTORING FOR DRY PRINCIPLE COMPLIANCE:

```java
private String createItemRequestBody(String name, UUID parentId, String mimeType, int size) {
    return """
        {
            "name": "%s",
            "size": %d,
            "mimeType": "%s",
            "status": "UPLOADED",
            "type": "FILE",
            "chunks": null,
            "s3Url": "https://s3.bucket.com/%s",
            "parentId": "%s"
        }
        """.formatted(name, size, mimeType, name, parentId);
}
```

THIS WOULD REDUCE CODE DUPLICATION AND IMPROVE MAINTAINABILITY.



Also applies to: 97-129, 136-167

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T07:55:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+CREATE OR REPLACE FUNCTION get_permission_recursive(
+    input_item_id UUID,
+    input_user_id UUID
+)
+    RETURNS TEXT AS '
+    DECLARE
+        current_item_id UUID := input_item_id;
+        permission_level TEXT := ''NO_ACCESS'';
+        owner_check BOOLEAN;
+        found_permission TEXT;
+    BEGIN
+        WHILE current_item_id IS NOT NULL LOOP
+                -- Check for ownership at the current level
+                SELECT CASE
+                           WHEN COUNT(*) > 0 THEN TRUE
+                           ELSE FALSE
+                           END
+                INTO owner_check
+                FROM file_system_items
+                WHERE id = current_item_id AND owner = input_user_id;
+
+                IF owner_check THEN
+                    RETURN ''OWNER'';
+                END IF;
+
+                -- Check for EDITOR permission in private shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_private isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.shared_with = input_user_id
+                  AND isp.permission = ''EDITOR'';
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' OR permission_level = ''VIEWER'' THEN
+                        permission_level := ''EDITOR'';
+                    END IF;
+                END IF;
path: apps/backend/file-service/src/main/resources/functions/get_permission_recursive.sql
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**DRY up permission checks**. Bzzzt. The blocks for private/public and EDITOR permissions repeat similar logic. Consider abstracting into a helper or loop to reduce duplication and improve maintainability. 


Also applies to: 39-50

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+CREATE OR REPLACE FUNCTION get_permission_recursive(
+    input_item_id UUID,
+    input_user_id UUID
+)
+    RETURNS TEXT AS '
+    DECLARE
+        current_item_id UUID := input_item_id;
+        permission_level TEXT := ''NO_ACCESS'';
+        owner_check BOOLEAN;
+        found_permission TEXT;
+    BEGIN
+        WHILE current_item_id IS NOT NULL LOOP
+                -- Check for ownership at the current level
+                SELECT CASE
+                           WHEN COUNT(*) > 0 THEN TRUE
+                           ELSE FALSE
+                           END
+                INTO owner_check
+                FROM file_system_items
+                WHERE id = current_item_id AND owner = input_user_id;
+
+                IF owner_check THEN
+                    RETURN ''OWNER'';
+                END IF;
+
+                -- Check for EDITOR permission in private shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_private isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.shared_with = input_user_id
+                  AND isp.permission = ''EDITOR'';
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' OR permission_level = ''VIEWER'' THEN
+                        permission_level := ''EDITOR'';
+                    END IF;
+                END IF;
+
+                -- Check for EDITOR permission in public shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_public isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.permission = ''EDITOR''
+                  AND (isp.expires_at IS NULL OR isp.expires_at > NOW());
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' OR permission_level = ''VIEWER'' THEN
+                        permission_level := ''EDITOR'';
+                    END IF;
+                END IF;
+
+                -- Check for VIEWER permission in private shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_private isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.shared_with = input_user_id
+                  AND isp.permission = ''VIEWER'';
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' THEN
+                        permission_level := ''VIEWER'';
+                    END IF;
+                END IF;
path: apps/backend/file-service/src/main/resources/functions/get_permission_recursive.sql
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Consolidate VIEWER permission logic**. Beep. Similar repetition exists for private/public VIEWER checks; merging these into a single routine could simplify the function. 


Also applies to: 65-76

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+CREATE OR REPLACE FUNCTION get_permission_recursive(
+    input_item_id UUID,
+    input_user_id UUID
+)
+    RETURNS TEXT AS '
+    DECLARE
+        current_item_id UUID := input_item_id;
+        permission_level TEXT := ''NO_ACCESS'';
+        owner_check BOOLEAN;
+        found_permission TEXT;
+    BEGIN
path: apps/backend/file-service/src/main/resources/functions/get_permission_recursive.sql
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Consider custom enum type for permission levels**. Bzzt. Returning free-form TEXT increases risk of typos. Defining a PostgreSQL ENUM (OWNER, EDITOR, VIEWER, NO_ACCESS) provides stronger validation.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+CREATE OR REPLACE FUNCTION get_permission_recursive(
+    input_item_id UUID,
+    input_user_id UUID
+)
+    RETURNS TEXT AS '
+    DECLARE
+        current_item_id UUID := input_item_id;
+        permission_level TEXT := ''NO_ACCESS'';
+        owner_check BOOLEAN;
+        found_permission TEXT;
+    BEGIN
+        WHILE current_item_id IS NOT NULL LOOP
+                -- Check for ownership at the current level
+                SELECT CASE
+                           WHEN COUNT(*) > 0 THEN TRUE
+                           ELSE FALSE
+                           END
+                INTO owner_check
+                FROM file_system_items
+                WHERE id = current_item_id AND owner = input_user_id;
+
+                IF owner_check THEN
+                    RETURN ''OWNER'';
+                END IF;
+
+                -- Check for EDITOR permission in private shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_private isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.shared_with = input_user_id
+                  AND isp.permission = ''EDITOR'';
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' OR permission_level = ''VIEWER'' THEN
+                        permission_level := ''EDITOR'';
+                    END IF;
+                END IF;
+
+                -- Check for EDITOR permission in public shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_public isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.permission = ''EDITOR''
+                  AND (isp.expires_at IS NULL OR isp.expires_at > NOW());
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' OR permission_level = ''VIEWER'' THEN
+                        permission_level := ''EDITOR'';
+                    END IF;
+                END IF;
+
+                -- Check for VIEWER permission in private shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_private isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.shared_with = input_user_id
+                  AND isp.permission = ''VIEWER'';
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' THEN
+                        permission_level := ''VIEWER'';
+                    END IF;
+                END IF;
+
+                -- Check for VIEWER permission in public shares at the current level
+                SELECT isp.permission INTO found_permission
+                FROM shared_items_public isp
+                WHERE isp.item_id = current_item_id
+                  AND isp.permission = ''VIEWER''
+                  AND (isp.expires_at IS NULL OR isp.expires_at > NOW());
+
+                IF FOUND THEN
+                    IF permission_level = ''NO_ACCESS'' THEN
+                        permission_level := ''VIEWER'';
+                    END IF;
+                END IF;
+
+                -- Move to the parent item
+                SELECT parent_id INTO current_item_id
+                FROM file_system_items
+                WHERE id = current_item_id;
+            END LOOP;
path: apps/backend/file-service/src/main/resources/functions/get_permission_recursive.sql
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Ensure proper indexes exist**. Beep boop. Recursive checks scan `file_system_items.parent_id`, `shared_items_private(item_id, shared_with)`, `shared_items_public(item_id, expires_at)`. Verify indexes on these columns for performance.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+CREATE OR REPLACE FUNCTION get_permission_recursive(
+    input_item_id UUID,
+    input_user_id UUID
+)
+    RETURNS TEXT AS '
+    DECLARE
+        current_item_id UUID := input_item_id;
+        permission_level TEXT := ''NO_ACCESS'';
+        owner_check BOOLEAN;
+        found_permission TEXT;
+    BEGIN
+        WHILE current_item_id IS NOT NULL LOOP
+                -- Check for ownership at the current level
+                SELECT CASE
+                           WHEN COUNT(*) > 0 THEN TRUE
+                           ELSE FALSE
+                           END
+                INTO owner_check
+                FROM file_system_items
+                WHERE id = current_item_id AND owner = input_user_id;
path: apps/backend/file-service/src/main/resources/functions/get_permission_recursive.sql
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Use EXISTS for ownership check**. Beep boop. Replacing `COUNT(*)` with `EXISTS` reduces scanning overhead. 

```diff
- SELECT CASE
-           WHEN COUNT(*) > 0 THEN TRUE
-           ELSE FALSE
-       END
-   INTO owner_check
- FROM file_system_items
- WHERE id = current_item_id
-   AND owner = input_user_id;
+ SELECT EXISTS(
+     SELECT 1
+     FROM file_system_items
+     WHERE id = current_item_id
+       AND owner = input_user_id
+ ) INTO owner_check;
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -15,4 +15,7 @@ spring:
       ddl-auto: update
   sql:
     init:
-      mode: always
\ No newline at end of file
+      mode: always
+      schema-locations:
+        - classpath:schema.sql
+        - classpath:functions/*.sql
path: apps/backend/file-service/src/test/resources/application-test.yml
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Add newline at end of file**. Bzzzt. YAMLLint flagged missing newline—please append a line break.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 YAMLlint (1.35.1)</summary>

[error] 21-21: no new line character at the end of file

(new-line-at-end-of-file)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,79 @@
+CREATE OR REPLACE FUNCTION share_item_private(
+    input_item_id UUID,
+    shared_by_user_id UUID,
+    input_shared_to_emails TEXT[],
+    input_permissions TEXT[]
+)
+    RETURNS TEXT[] AS '
+    DECLARE
+        is_owner BOOLEAN;
+        result_permissions TEXT[];
+        target_user_ids UUID[];
+    BEGIN
+
+        SELECT CASE
+                   WHEN COUNT(*) > 0 THEN TRUE
+                   ELSE FALSE
+                   END
+        INTO is_owner
+        FROM file_system_items
+        WHERE id = input_item_id AND owner = shared_by_user_id;
+
+        SELECT ARRAY(
+                       SELECT t_user.user_id
+                       FROM UNNEST(input_shared_to_emails) WITH ORDINALITY AS e_email(email, email_index)
+                                LEFT JOIN users_snapshot AS t_user
+                                          ON t_user.email = e_email.email
+                       ORDER BY e_email.email_index
+               )
+        INTO target_user_ids;
+
+        IF is_owner THEN
+            -- If the user is the owner, grant all permissions as "ALLOWED"
+            SELECT ARRAY(SELECT ''ALLOWED''
+                         FROM generate_series(1, array_length(input_shared_to_emails, 1)))
+            INTO result_permissions;
+        ELSE
+            -- Step 2: Check permission validity for each user and populate result_permissions
+            result_permissions := ARRAY(
+                    SELECT CASE
+                               WHEN EXISTS (
+                                   SELECT 1
+                                   FROM shared_items_private
+                                   WHERE item_id = input_item_id
+                                     AND shared_with = target_user_id
+                                     AND (
+                                       (input_permissions[ARRAY_POSITION(input_shared_to_emails, shared_to_email)] = ''EDITOR''
+                                           AND permission IN (''EDITOR'', ''VIEWER''))
+                                       --                                (input_permissions[ARRAY_POSITION(input_shared_to_emails, shared_to_email)] = ''VIEWER''
+                                       --                                    AND permission = ''VIEWER'')
+                                       )
+                               )
+                                   THEN ''ALLOWED''
+                               ELSE ''NOT_ALLOWED''
+                               END
+                    FROM UNNEST(target_user_ids) WITH ORDINALITY AS t_user(target_user_id, user_index),
+                         UNNEST(input_shared_to_emails) WITH ORDINALITY AS e_email(shared_to_email, email_index),
+                         UNNEST(input_permissions) WITH ORDINALITY AS e_perm(permission, perm_index)
+                    WHERE t_user.user_index = e_email.email_index
+                      AND e_email.email_index = e_perm.perm_index
+                                  );
path: apps/backend/file-service/src/main/resources/functions/share_item_private.sql
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Simplify permission lookup logic**. Bzzzt. Instead of using `ARRAY_POSITION` inside the EXISTS query, leverage the `e_perm.permission` alias from the UNNEST join to reference the desired permission directly. This removes the extra array lookup.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,79 @@
+CREATE OR REPLACE FUNCTION share_item_private(
+    input_item_id UUID,
+    shared_by_user_id UUID,
+    input_shared_to_emails TEXT[],
+    input_permissions TEXT[]
+)
path: apps/backend/file-service/src/main/resources/functions/share_item_private.sql
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Validate input array lengths**. Bzzzt. Mismatched `input_shared_to_emails` and `input_permissions` lengths can misalign mappings. Add validation:

```diff
+ IF array_length(input_shared_to_emails,1) IS NULL
+    OR array_length(input_shared_to_emails,1) != array_length(input_permissions,1) THEN
+   RAISE EXCEPTION 'Email and permission arrays must have same non-null length';
+ END IF;
```



> Committable suggestion skipped: line range outside the PR's diff.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,79 @@
+CREATE OR REPLACE FUNCTION share_item_private(
+    input_item_id UUID,
+    shared_by_user_id UUID,
+    input_shared_to_emails TEXT[],
+    input_permissions TEXT[]
+)
+    RETURNS TEXT[] AS '
+    DECLARE
+        is_owner BOOLEAN;
+        result_permissions TEXT[];
+        target_user_ids UUID[];
+    BEGIN
+
+        SELECT CASE
+                   WHEN COUNT(*) > 0 THEN TRUE
+                   ELSE FALSE
+                   END
+        INTO is_owner
+        FROM file_system_items
+        WHERE id = input_item_id AND owner = shared_by_user_id;
path: apps/backend/file-service/src/main/resources/functions/share_item_private.sql
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Use EXISTS for owner check**. Beep boop. Replace `COUNT(*)` with `EXISTS` to improve performance:

```diff
- SELECT CASE WHEN COUNT(*) > 0 THEN TRUE ELSE FALSE END
-   INTO is_owner
- FROM file_system_items
- WHERE id = input_item_id
-   AND owner = shared_by_user_id;
+ SELECT EXISTS(
+     SELECT 1 FROM file_system_items
+     WHERE id = input_item_id
+       AND owner = shared_by_user_id
+ ) INTO is_owner;
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,79 @@
+CREATE OR REPLACE FUNCTION share_item_private(
+    input_item_id UUID,
+    shared_by_user_id UUID,
+    input_shared_to_emails TEXT[],
+    input_permissions TEXT[]
+)
+    RETURNS TEXT[] AS '
+    DECLARE
+        is_owner BOOLEAN;
+        result_permissions TEXT[];
+        target_user_ids UUID[];
+    BEGIN
+
+        SELECT CASE
+                   WHEN COUNT(*) > 0 THEN TRUE
+                   ELSE FALSE
+                   END
+        INTO is_owner
+        FROM file_system_items
+        WHERE id = input_item_id AND owner = shared_by_user_id;
+
+        SELECT ARRAY(
+                       SELECT t_user.user_id
+                       FROM UNNEST(input_shared_to_emails) WITH ORDINALITY AS e_email(email, email_index)
+                                LEFT JOIN users_snapshot AS t_user
+                                          ON t_user.email = e_email.email
+                       ORDER BY e_email.email_index
+               )
+        INTO target_user_ids;
+
+        IF is_owner THEN
+            -- If the user is the owner, grant all permissions as "ALLOWED"
+            SELECT ARRAY(SELECT ''ALLOWED''
+                         FROM generate_series(1, array_length(input_shared_to_emails, 1)))
+            INTO result_permissions;
+        ELSE
+            -- Step 2: Check permission validity for each user and populate result_permissions
+            result_permissions := ARRAY(
+                    SELECT CASE
+                               WHEN EXISTS (
+                                   SELECT 1
+                                   FROM shared_items_private
+                                   WHERE item_id = input_item_id
+                                     AND shared_with = target_user_id
+                                     AND (
+                                       (input_permissions[ARRAY_POSITION(input_shared_to_emails, shared_to_email)] = ''EDITOR''
+                                           AND permission IN (''EDITOR'', ''VIEWER''))
+                                       --                                (input_permissions[ARRAY_POSITION(input_shared_to_emails, shared_to_email)] = ''VIEWER''
+                                       --                                    AND permission = ''VIEWER'')
+                                       )
+                               )
+                                   THEN ''ALLOWED''
+                               ELSE ''NOT_ALLOWED''
+                               END
+                    FROM UNNEST(target_user_ids) WITH ORDINALITY AS t_user(target_user_id, user_index),
+                         UNNEST(input_shared_to_emails) WITH ORDINALITY AS e_email(shared_to_email, email_index),
+                         UNNEST(input_permissions) WITH ORDINALITY AS e_perm(permission, perm_index)
+                    WHERE t_user.user_index = e_email.email_index
+                      AND e_email.email_index = e_perm.perm_index
+                                  );
+        END IF;
+
+        FOR i IN 1..array_length(input_shared_to_emails, 1)
+            LOOP
+                IF target_user_ids[i] = shared_by_user_id THEN
+                    result_permissions[i] = ''NOT_ALLOWED'';
+                END IF;
path: apps/backend/file-service/src/main/resources/functions/share_item_private.sql
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix array element assignment syntax**. Beep. In PL/pgSQL, use `:=` for assignment—`=` is a comparison operator. Update:

```diff
- IF target_user_ids[i] = shared_by_user_id THEN
-     result_permissions[i] = 'NOT_ALLOWED';
+ IF target_user_ids[i] = shared_by_user_id THEN
+     result_permissions[i] := 'NOT_ALLOWED';
```



> Committable suggestion skipped: line range outside the PR's diff.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-27T09:33:52Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-27T07:52:52Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Summary by CodeRabbit

- **New Features**
  - Added support for creating file system items, including new API responses with item size and MIME type details.
  - Introduced detailed error handling for permission and item-not-found scenarios with clear error messages and status codes.
  - Implemented flexible handling of file chunk data in item creation requests.

- **Bug Fixes**
  - Improved permission checks and error reporting for item creation, ensuring users receive accurate feedback when lacking access or when items are missing.

- **Tests**
  - Added comprehensive integration tests for item creation, covering success, permission denial, and missing item cases.

- **Chores**
  - Updated configuration files to specify SQL initialization script locations for development and testing environments.
  - Enhanced dependency management for mapping utilities.
## Summary by CodeRabbit

- **New Features**
  - Implemented item creation endpoint with structured responses, including file metadata such as size and MIME type.
  - Added detailed error handling for insufficient permissions and missing items, returning clear error messages and codes.
- **Bug Fixes**
  - Improved flexibility and compatibility for file chunk and size data in item creation requests.
- **Tests**
  - Introduced integration tests for item creation, covering success and error scenarios to ensure endpoint reliability.

## Walkthrough

This update introduces the ability to create file system items—both folders and files—via the backend file service. It implements the creation logic, permission checks, and error handling for scenarios such as missing items or insufficient permissions. The data transfer objects are updated to support new fields, and custom exceptions and error codes are added. Integration tests validate successful item creation and error cases. Additionally, a MapStruct mapper is introduced for entity-to-DTO conversion, and related dependencies are added to the build configuration.

## Changes

| File(s)                                                                                       | Change Summary                                                                                                                      |
|-----------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/controller/CreateItemController.java` | Implements item creation endpoint, injects service, returns structured response.                                                    |
| `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/service/CreateItemService.java`       | Implements `createItem` method with permission and existence checks, entity creation, and mapping to response DTO.                  |
| `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemRequest.java`           | Changes `chunks` field to `JsonNode`, changes `size` from `BigInteger` to `Long`.                                                   |
| `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/dto/CreateItemResponse.java`          | Adds `size` and `mimeType` fields.                                                                                                  |
| `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/mapper/FileSystemItemsMapper.java`    | Adds new MapStruct mapper interface for entity-to-DTO conversion.                                                                   |
| `apps/backend/file-service/pom.xml`                                                                      | Adds MapStruct dependencies and property.                                                                                           |
| `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/GlobalExceptionHandler.java`| Adds handlers for permission and item not found exceptions.                                                                         |
| `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/NotEnoughPermissionException.java`,<br>`apps/backend/file-service/src/main/java/com/bytebandit/fileservice/exception/ItemNotFoundException.java` | Adds custom exception classes for permission denied and item not found scenarios.                                                   |
| `apps/backend/common/core/src/main/java/lib/core/enums/ErrorCode.java`                                   | Adds `PERMISSION_DENIED` and `ITEM_NOT_FOUND` error codes.                                                                         |
| `apps/backend/file-service/src/test/java/com/bytebandit/fileservice/controller/CreateItemControllerIT.java`| Adds integration tests for successful creation, permission denied, and item not found scenarios.                                    |
| `apps/backend/file-service/src/main/java/com/bytebandit/fileservice/model/SharedItemsPublicEntity.java`   | Removes unused import.                                                                                                              |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant Controller
    participant Service
    participant Repository
    participant Mapper

    Client->>Controller: POST /create (CreateItemRequest)
    Controller->>Service: createItem(request)
    Service->>Repository: findById(parentId)
    alt Parent not found
        Service->>Controller: throw ItemNotFoundException
        Controller->>Client: 404 Not Found (ErrorResponse)
    else Parent found
        Service->>Repository: getPermissionLevel(ownerId, parentId)
        alt Permission denied
            Service->>Controller: throw NotEnoughPermissionException
            Controller->>Client: 403 Forbidden (ErrorResponse)
        else Permission granted
            Service->>Repository: save(new FileSystemItemEntity)
            Service->>Mapper: toCreateItemResponse(entity)
            Service->>Controller: CreateItemResponse
            Controller->>Client: 200 OK (ApiResponse<CreateItemResponse>)
        end
    end
```

## Assessment against linked issues

| Objective                                                                                                         | Addressed | Explanation                                                                                  |
|-------------------------------------------------------------------------------------------------------------------|-----------|----------------------------------------------------------------------------------------------|
| User can create a folder, User can create a file (#225)                                                           | ✅        |                                                                                              |
| Appropriate error response with messages is shown to user (if any error occurs) (#225)                            | ✅        |                                                                                              |

## Possibly related PRs

- #228: Introduces `RoleBasedAccessControlService` for recursive permission checking used by the current PR’s service to enforce permission validations.

## Poem

> 01100110 01101111 01101100 01100100 01100101 01110010 01110011 00100000 01100001 01101110 01100100 00100000 01100110 01101001 01101100 01100101 01110011,  
> Now created with robotic finesse!  
> If permissions are lacking, or items are gone,  
> Error codes will beep and carry on.  
> Mapper and tests, all wired in place—  
> Geeky Bot celebrates this item-creation race!  
> 🤖✨

</details>

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Learnathon-By-Geeky-Solutions/byte-bandit&utm_content=231):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: Warhammer4000
created_at: 2025-04-27T07:52:57Z
body: ![](https://res.cloudinary.com/snyk/image/upload/r-d/scm-platform/snyk-pull-requests/pr-banner-default.svg)

### :tada: **Snyk checks have passed. No issues have been found so far.**



author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-04-27T09:32:40Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Learnathon-By-Geeky-Solutions_byte-bandit&pullRequest=231) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=Learnathon-By-Geeky-Solutions_byte-bandit&pullRequest=231&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Learnathon-By-Geeky-Solutions_byte-bandit&pullRequest=231&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Learnathon-By-Geeky-Solutions_byte-bandit&pullRequest=231&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [97.8% Coverage on New Code](https://sonarcloud.io/component_measures?id=Learnathon-By-Geeky-Solutions_byte-bandit&pullRequest=231&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Learnathon-By-Geeky-Solutions_byte-bandit&pullRequest=231&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Learnathon-By-Geeky-Solutions_byte-bandit&pullRequest=231)


author_association: NONE