diff --git a/public/components/Pagination.php b/public/components/Pagination.php
new file mode 100644
index 0000000000000000000000000000000000000000..87965a8a75e027293beefd66f006d399ef4eb008
--- /dev/null
+++ b/public/components/Pagination.php
@@ -0,0 +1,45 @@
+<?php
+// PREREKUISIT UNTUK PAKE FUNGSI INI:
+// 1. Redirect user ke /page 1 kalo di query ga ada page nummber
+// 2. Di controller sebelum render page, query total count dari database simpan di variabel $_count.
+// 3. Pastiin di service/repo ada fungsi buat ngurusin order by, limit, dst.
+// For more information, refer to GET /cats di cats controller.
+function generatePaginationLinks($currentPage, $totalPages)
+{
+    $html = '<div class="pagination">';
+
+    // Previous button
+    if ($currentPage > 1) {
+        $html .= '<a href="?pageNo=' . ($currentPage - 1) . '&pageSize=10" class="prev-page">Previous</a>';
+    }
+
+    for ($i = 1; $i <= $totalPages; $i++) {
+        if ($i === $currentPage) {
+            $html .= '<span class="current-page">' . $i . '</span>';
+        } else {
+            $html .= '<a href="?pageNo=' . $i . '&pageSize=10">' . $i . '</a>';
+        }
+    }
+
+    // Next button
+    if ($currentPage < $totalPages) {
+        $html .= '<a href="?pageNo=' . ($currentPage + 1) . '&pageSize=10" class="next-page">Next</a>';
+    }
+
+    $html .= '</div>';
+    return $html;
+}
+
+$totalCount = $_count; // Total number of cats
+$pageSize = 10; // Number of cats per page
+$totalPages = ceil($totalCount / $pageSize);
+$currentPage = isset($_GET['pageNo']) ? intval($_GET['pageNo']) : 1;
+
+$paginationHtml = generatePaginationLinks($currentPage, $totalPages);
+
+?>
+
+
+<div class="pagination-container">
+    <?php echo $paginationHtml; ?>
+</div>
\ No newline at end of file
diff --git a/public/css/styles.css b/public/css/styles.css
index 28485548e491495d1d611bc4f79aed32dac7e441..51ac1b4fedfc3f40cdcba55758e4e576869f6891 100644
--- a/public/css/styles.css
+++ b/public/css/styles.css
@@ -345,3 +345,54 @@ button[type="submit"] {
     font-weight: bold;
 }
 
+/* Pagination styles */
+.pagination {
+    text-align: center;
+    margin-top: 20px;
+}
+
+.pagination a,
+.pagination .current-page {
+    display: inline-block;
+    padding: 5px 10px;
+    margin: 2px;
+    border: 1px solid #ccc;
+    text-decoration: none;
+    color: #333;
+    background-color: #fff;
+    border-radius: 4px;
+    font-weight: bold;
+}
+
+.pagination a:hover {
+    background-color: #eee;
+}
+
+.pagination .current-page {
+    background-color: #007BFF;
+    color: #fff;
+}
+
+.pagination .prev-page,
+.pagination .next-page {
+    padding: 5px 10px;
+    margin: 2px;
+    border: 1px solid #007BFF;
+    background-color: #007BFF;
+    color: #fff;
+    border-radius: 4px;
+    font-weight: bold;
+    text-decoration: none;
+}
+
+.pagination .prev-page:hover,
+.pagination .next-page:hover {
+    background-color: #0056b3;
+}
+
+.pagination-container {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-top: 20px; 
+}
\ No newline at end of file
diff --git a/public/view/cats.php b/public/view/cats.php
index ebc936e8961b499e4ead8bf7aeab9cbfdce3730e..af45f9985078056293b7a4ae487c5e2668d7b45d 100644
--- a/public/view/cats.php
+++ b/public/view/cats.php
@@ -54,8 +54,8 @@
             </div>
         <?php endforeach; ?>
     </div>
+    <?php require_once(PROJECT_ROOT_PATH . '/public/components/Pagination.php'); ?>
     <div>
-
         <div id="edit-cat-modal" class="modal">
             <div class="modal-content">
                 <span class="close" onclick="closeEditCatModal()">&times;</span>
diff --git a/src/bases/BaseRepository.php b/src/bases/BaseRepository.php
index 03f2f7a04fc51d11f35020d9bfc0ffa057047b93..32c1ac290c011e6c452bcf1471a00a96ec589930 100644
--- a/src/bases/BaseRepository.php
+++ b/src/bases/BaseRepository.php
@@ -4,86 +4,75 @@ require_once PROJECT_ROOT_PATH . "/src/db/DBConnection.php";
 
 abstract class BaseRepository
 {
-  protected static $instance;
-  protected $pdo;
-  protected $tableName = '';
-
-  protected function __construct()
-  {
-    $this->pdo = DBConnection::getInstance()->getPDO();
-  }
-
-  public static function getInstance()
-  {
-    if (!isset(self::$instance)) {
-      self::$instance = new static();
+    protected static $instance;
+    protected $pdo;
+    protected $tableName = '';
+
+    protected function __construct()
+    {
+        $this->pdo = DBConnection::getInstance()->getPDO();
     }
-    return self::$instance;
-  }
 
-  public function getPDO()
-  {
-    return $this->pdo;
-  }
+    public static function getInstance()
+    {
+        if (!isset(self::$instance)) {
+            self::$instance = new static();
+        }
+        return self::$instance;
+    }
+
+    public function getPDO()
+    {
+        return $this->pdo;
+    }
 
-    public function insert($data, $paramTypes) {
+    public function insert($data, $paramTypes)
+    {
 
         // Filter the $data array to include only the keys present in $paramTypes
         $filteredData = array_intersect_key($data, $paramTypes);
 
-        // Prepare the SQL statement
         $columns = implode(', ', array_keys($filteredData));
         $placeholders = ':' . implode(', :', array_keys($filteredData));
 
         $sql = "INSERT INTO $this->tableName ($columns) VALUES ($placeholders)";
 
-        // Prepare the PDO statement
         $stmt = $this->pdo->prepare($sql);
 
-        // Bind parameters with data types
         foreach ($filteredData as $key => $value) {
             $stmt->bindValue(':' . $key, $value, $paramTypes[$key]);
         }
 
-        // Execute the query
         if ($stmt->execute()) {
             return $this->pdo->lastInsertId();
         } else {
-            return false; // Insert failed
+            return false;
         }
     }
 
-        public function selectOne($columns = "*", $where = [])
+    public function selectOne($columns = "*", $where = [])
     {
-        // Start building the query
         $query = "SELECT $columns FROM $this->tableName";
 
-        // Add WHERE clause if provided
         if (!empty($where)) {
             $query .= " WHERE " . implode(" AND ", $where);
         }
         $query .= ";";
 
-//        echo $query;
-        // Prepare and execute the query
         $stmt = $this->pdo->prepare($query);
         $stmt->execute();
 
-        // Fetch and return the results
         return $stmt->fetch();
     }
 
     public function select($columns = "*", $where = [], $orderBy = [], $page = 1, $perPage = 10, $isDesc = false)
     {
-        // Start building the query
         $query = "SELECT $columns FROM $this->tableName";
 
-        // Add WHERE clause if provided
         if (!empty($where)) {
             $query .= " WHERE " . implode(" AND ", $where);
         }
 
-        // Add ORDER BY clause if provided
         if (!empty($orderBy)) {
             $query .= " ORDER BY " . implode(", ", $orderBy);
             if (!empty($isDesc)) {
@@ -91,55 +80,54 @@ abstract class BaseRepository
             }
         }
 
-        if(!empty($perPage)) {
-        // Add LIMIT and OFFSET for pagination
-        $offset = ($page - 1) * $perPage;
-        $query .= " LIMIT $perPage OFFSET $offset";
+        if (!empty($perPage)) {
+            $offset = ($page - 1) * $perPage;
+            $query .= " LIMIT $perPage OFFSET $offset";
         }
 
         echo $query;
 
-        // Prepare and execute the query
         $stmt = $this->pdo->prepare($query);
         $stmt->execute();
 
-        // Fetch and return the results
         return $stmt->fetchAll(PDO::FETCH_ASSOC);
     }
 
     public function update($id_col, $id, $data, $paramTypes)
     {
-    // Filter the data array to include only the keys present in $paramTypes
-    $filteredData = array_intersect_key($data, $paramTypes);
-
-    // Prepare the SET clause for the update query
-    $setClause = implode(', ', array_map(function ($key) {
-        return "$key = :$key";
-    }, array_keys($filteredData)));
-
-    // Prepare the SQL statement
-    $sql = "UPDATE $this->tableName SET $setClause WHERE $id_col = $id";
-
-    // Bind parameters with data types
-    $stmt = $this->pdo->prepare($sql);
-    foreach ($filteredData as $key => $value) {
-        echo $value;
-        $stmt->bindValue(':' . $key, $value, $paramTypes[$key]);
-    }
+        $filteredData = array_intersect_key($data, $paramTypes);
 
-    // Execute the query
-    return $stmt->execute();
+        $setClause = implode(', ', array_map(function ($key) {
+            return "$key = :$key";
+        }, array_keys($filteredData)));
+
+        $sql = "UPDATE $this->tableName SET $setClause WHERE $id_col = $id";
+
+        $stmt = $this->pdo->prepare($sql);
+        foreach ($filteredData as $key => $value) {
+            echo $value;
+            $stmt->bindValue(':' . $key, $value, $paramTypes[$key]);
+        }
+
+        return $stmt->execute();
     }
 
     public function delete($id_col, $id)
     {
-    // Prepare the SQL statement
-    $sql = "DELETE FROM $this->tableName WHERE $id_col = $id";
+        $sql = "DELETE FROM $this->tableName WHERE $id_col = $id";
 
-    // Bind the ID parameter
-    $stmt = $this->pdo->prepare($sql);
+        $stmt = $this->pdo->prepare($sql);
+
+        return $stmt->execute();
+    }
+
+    public function count()
+    {
+        $query = "SELECT count(*) FROM $this->tableName";
+        $stmt = $this->pdo->prepare($query);
+        $stmt->execute();
+
+        return $stmt->fetch();
 
-    // Execute the query
-    return $stmt->execute();
     }
 }
\ No newline at end of file
diff --git a/src/controllers/cat/CatController.php b/src/controllers/cat/CatController.php
index a9042578145339d5bde5da17877c39751193395d..567619907ca256a4500aa88c5e6c4fef63b8aeb5 100644
--- a/src/controllers/cat/CatController.php
+++ b/src/controllers/cat/CatController.php
@@ -26,6 +26,9 @@ class CatController extends BaseController
   public function get($urlParams)
   {
     if (!$urlParams) {
+      if (!$_GET["pageNo"] || !$_GET["pageSize"]) {
+        header("Location: /cat?pageNo=1&pageSize=10");
+      }
       $cats = $this->srv->getAll([
         "search" => $_GET['search'] ?? null,
         "gender" => $_GET['gender'] ?? null,
@@ -35,6 +38,7 @@ class CatController extends BaseController
         "pageSize" => $_GET['pageSize'] ?? null,
         "isDesc" => $_GET['isDesc'] ?? null
       ]);
+      $_count = $this->srv->countCats()[0];
 
       $responseCats = array_map(function ($cat) {
         return $cat->toResponse();
diff --git a/src/services/CatSrv.php b/src/services/CatSrv.php
index 40dd6a017924d4a347d05abdd42a52c999e43e46..275829aaae4ff40d04bf960febce9ab7267ed5fa 100644
--- a/src/services/CatSrv.php
+++ b/src/services/CatSrv.php
@@ -24,6 +24,11 @@ class CatSrv extends BaseSrv
         return self::$instance;
     }
 
+    public function countCats()
+    {
+        return $this->repository->count();
+    }
+
     public function getAll($config)
     {
         $search = $config['search'];
@@ -45,8 +50,8 @@ class CatSrv extends BaseSrv
         $catsResult = $this->repository->select('*', $where, $order, $config["pageNo"], $config['pageSize'], $config['isDesc']);
         $cats = [];
         foreach ($catsResult as $catResult) {
-          $cat = new CatModel();
-          $cats[] = $cat->constructFromArray($catResult);
+            $cat = new CatModel();
+            $cats[] = $cat->constructFromArray($catResult);
         }
         return $cats;
     }
@@ -93,4 +98,4 @@ class CatSrv extends BaseSrv
         $this->repository->delete("cat_id", $catId);
         return $cat;
     }
-}
+}
\ No newline at end of file