diff --git a/src/migration/db.sql b/src/migration/db.sql
index 432c9cb3e159b46022b028f7e8cf1fae1e2bcec5..14fc6159cb1cb3697b2f5810931d6c8acbf82a7c 100644
--- a/src/migration/db.sql
+++ b/src/migration/db.sql
@@ -7,7 +7,7 @@ END
 $$;
 
 CREATE TABLE IF NOT EXISTS users (
-    id SERIAL PRIMARY KEY AUTO_INCREMENT=2,
+    id SERIAL PRIMARY KEY,
     uuid VARCHAR(36) NOT NULL UNIQUE,
     name VARCHAR(40) NOT NULL,
     password VARCHAR(255) NOT NULL,
@@ -196,4 +196,36 @@ CREATE TABLE IF NOT EXISTS watchlist_tag (
     FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
 );
 
-INSERT INTO users (id, uuid, name, password, email, role) VALUES (1, '01c9b7cee28bc050', 'admin', 'admin', 'admin@drawl.com', 'ADMIN'); 
\ No newline at end of file
+INSERT INTO users (uuid, name, password, email, role) VALUES ('72c5a265715fa26c', 'admin', '$2y$10$rAfDHA4M4ftn8K7Wx82wf.fFODD7PCE/t9CVnBwdLnTDBYjnq7ZnO', 'admin@drawl.com', 'ADMIN');
+INSERT INTO tags(name) VALUES ('ACTION'),
+                              ('ADVENTURE'),
+                              ('ANIMALS'),
+                              ('BUSINESS'),
+                              ('COMEDY'),
+                              ('CRIME'),
+                              ('DETECTIVE'),
+                              ('DOCUMENTARY'),
+                              ('DRAMA'),
+                              ('FAMILY'),
+                              ('FANTASY'),
+                              ('FOOD'),
+                              ('HISTORICAL'),
+                              ('HORROR'),
+                              ('LAW'),
+                              ('LIFE'),
+                              ('MANGA'),
+                              ('MEDICAL'),
+                              ('MATURE'),
+                              ('MYSTERY'),
+                              ('MUSIC'),
+                              ('MILITARY'),
+                              ('MELODRAMA'),
+                              ('PSYCHOLOGICAL'),
+                              ('ROMANCE'),
+                              ('SCHOOL'),
+                              ('SCI-FI'),
+                              ('SPORTS'),
+                              ('SUPERNATURAL'),
+                              ('THRILLER'),
+                              ('YOUTH')
+;
\ No newline at end of file
diff --git a/src/public/assets/icons/user.php b/src/public/assets/icons/user.php
new file mode 100644
index 0000000000000000000000000000000000000000..0084567817ae83f90d4986c308c750df18a81dbc
--- /dev/null
+++ b/src/public/assets/icons/user.php
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="21" height="22" viewBox="0 0 21 22" fill="none">
+    <path
+        d="M10.5 1.5C5.25329 1.5 1 5.75329 1 11C1 16.2467 5.25329 20.5 10.5 20.5C15.7467 20.5 20 16.2467 20 11C20 5.75329 15.7467 1.5 10.5 1.5Z"
+        stroke="#1E2124" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+    <path d="M3.15747 17.0284C3.15747 17.0284 5.27504 14.325 10.5 14.325C15.725 14.325 17.8427 17.0284 17.8427 17.0284"
+        stroke="#1E2124" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+    <path
+        d="M10.4999 11C12.074 11 13.3499 9.7241 13.3499 8.15005C13.3499 6.57604 12.074 5.30005 10.4999 5.30005C8.92585 5.30005 7.6499 6.57604 7.6499 8.15005C7.6499 9.7241 8.92585 11 10.4999 11Z"
+        stroke="#1E2124" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+</svg>
\ No newline at end of file
diff --git a/src/public/css/catalog-detail.css b/src/public/css/catalog-detail.css
index b3357a7b1f53ac326250fcaf95dae9e5a2e31f92..9c1716ce00c6d8012fdd077ceb00c34f9ecebc1b 100644
--- a/src/public/css/catalog-detail.css
+++ b/src/public/css/catalog-detail.css
@@ -25,12 +25,6 @@
     overflow-wrap: break-word;
 }
 
-.catalog-trailer {
-    width: 80%;
-    max-width: 600px;
-    align-self: stretch;
-}
-
 .poster {
     margin-top: -100px;
     margin-left: 12px;
@@ -77,7 +71,7 @@
 
     .button-container {
         bottom: 40px;
-        right: 160px;
+        right: 3rem;
         gap: 10px;
     }
 }
diff --git a/src/public/css/components/alert.css b/src/public/css/components/alert.css
deleted file mode 100644
index b754f83ebe39def252b892bb9b0be7183f5bc0f3..0000000000000000000000000000000000000000
--- a/src/public/css/components/alert.css
+++ /dev/null
@@ -1,96 +0,0 @@
-.alert {
-    display: flex;
-    padding: 16px 6px;
-    justify-content: space-between;
-    align-items: flex-start;
-    align-self: stretch;
-    border-radius: 6px;
-}
-
-.alert[data-type="error"] {
-    background-color: var(--error-background);
-}
-
-.alert[data-type="error"] h3 {
-    color: var(--error-foreground);
-}
-
-.alert[data-type="error"] p {
-    color: var(--error-foreground);
-}
-
-.alert[data-type="error"] svg path {
-    stroke: var(--error-foreground);
-}
-
-.alert[data-type="info"] {
-    background-color: var(--info-background);
-}
-
-.alert[data-type="info"] h3 {
-    color: var(--info-foreground);
-}
-
-.alert[data-type="error"] p {
-    color: var(--error-foreground);
-}
-
-.alert[data-type="info"] svg path {
-    stroke: var(--info-foreground);
-}
-
-.alert[data-type="success"] {
-    background-color: var(--success-background);
-}
-
-.alert[data-type="success"] h3 {
-    color: var(--success-foreground);
-}
-
-.alert[data-type="success"] svg path {
-    stroke: var(--success-foreground);
-}
-
-.alert div {
-    display: flex;
-    padding: 0px 12px;
-    flex-direction: column;
-    align-items: flex-start;
-    gap: 6px;
-    flex: 1 0 0;
-}
-
-.alert h3 {
-    font-size: 0.875rem;
-}
-
-.alert p {
-    font-size: 0.625rem;
-}
-
-.alert>svg {
-    display: none;
-}
-
-@media screen and (min-width: 640px) {
-    .alert {
-        padding: 24px 20px;
-    }
-
-    .alert h3 {
-        font-size: 1rem;
-    }
-
-    .alert p {
-        font-size: 0.875rem;
-    }
-
-    .alert>svg {
-        display: block;
-    }
-
-    .alert div {
-        padding: 0px 24px;
-        gap: 10px;
-    }
-}
\ No newline at end of file
diff --git a/src/public/css/components/button.css b/src/public/css/components/button.css
deleted file mode 100644
index b00a447113164684dc88eb06f7efce00c554e2e4..0000000000000000000000000000000000000000
--- a/src/public/css/components/button.css
+++ /dev/null
@@ -1,101 +0,0 @@
-button {
-    background: none;
-    border: none;
-    cursor: pointer;
-    border-radius: 6px;
-    padding: 8px 16px;
-    gap: 8px;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    font-weight: 600;
-    white-space: nowrap;
-    text-transform: uppercase;
-}
-
-button:hover {
-    background-color: var(--accent-300);
-    transition: all;
-    transition-duration: 400ms;
-    transition-timing-function: ease-in-out;
-}
-
-.btn {
-    background: none;
-    border: none;
-    font: inherit;
-    color: inherit;
-    cursor: pointer;
-    border-radius: 6px;
-    padding: 8px 16px;
-    gap: 8px;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    font-weight: 600;
-    white-space: nowrap;
-    text-transform: uppercase;
-}
-
-.btn:hover {
-    background-color: var(--accent-300);
-    transition: all;
-    transition-duration: 400ms;
-    transition-timing-function: ease-in-out;
-}
-
-.btn-icon {
-    padding: 10px 10px;
-}
-
-.btn-bold {
-    background: var(--accent-1100, #421B50);
-    color: var(--accent-100, #FBF7FD);
-}
-
-.btn-bold:hover {
-    background-color: var(--accent-1000, #5F346F);
-    transition: all;
-    transition-duration: 400ms;
-    transition-timing-function: ease-in-out;
-}
-
-.btn-primary {
-    display: inline-flex;
-    width: 100%;
-    max-width: fit-content;
-    text-decoration: none;
-    color: var(--primary-400);
-    background-color: var(--accent-300);
-    padding: 8px 12px;
-    border-radius: 5px;
-    border: none;
-    cursor: pointer;
-    align-items: center;
-    justify-content: center;
-    gap: 0.4rem;
-    font-size: 1rem;
-}
-
-.btn-primary:hover {
-    background-color: var(--accent-300);
-    transition: all;
-    transition-duration: 400ms;
-    transition-timing-function: ease-in-out;
-}
-
-.btn-text {
-    color: var(--accent-800);
-}
-
-.btn-ghost:hover {
-    background-color: transparent;
-}
-
-.btn-outline {
-    border: 1px solid rgba(0,0,0,.1);
-}
-
-.btn-outline:hover {
-    background-color: var(--accent-100);
-}
\ No newline at end of file
diff --git a/src/public/css/components/card.css b/src/public/css/components/card.css
deleted file mode 100644
index abe72d8d54bf4ca0c4d0b4340f6449168a77e178..0000000000000000000000000000000000000000
--- a/src/public/css/components/card.css
+++ /dev/null
@@ -1,52 +0,0 @@
-.card {
-    width: 100%;
-    display: flex;
-    flex-direction: column;
-    align-items: flex-end;
-    align-self: stretch;
-    justify-content: space-between;
-    padding-bottom: 24px;
-    gap: 24px;
-    border-bottom: 1px solid var(--slate-100, #CBD5E1);
-}
-
-.card-content {
-    width: 100%;
-    display: flex;
-    align-items: flex-start;
-    gap: 24px;
-}
-
-.card-body {
-    display: flex;
-    flex-direction: column;
-    align-items: flex-start;
-    gap: 10px;
-    flex: 1 0 0;
-}
-
-.card-body > p {
-    overflow: hidden;
-    display: -webkit-box;
-    -webkit-box-orient: vertical;
-    -webkit-line-clamp: 3;
-}
-
-.card-button-container {
-    display: flex;
-    align-items: flex-start;
-    gap: 24px;
-}
-
-.card-comment .card-content .card-body .header {
-    display: flex;
-    align-items: center;
-    gap: 10px;
-}
-
-@media screen and (min-width: 640px) {
-    .card {
-        flex-direction: row;
-        align-items: flex-start;
-    }
-}
\ No newline at end of file
diff --git a/src/public/css/components/dialog.css b/src/public/css/components/dialog.css
deleted file mode 100644
index 98d7c6c7bc10f8687c12309abf7693d5d319b7fc..0000000000000000000000000000000000000000
--- a/src/public/css/components/dialog.css
+++ /dev/null
@@ -1,40 +0,0 @@
-.dialog {
-    position: fixed;
-    z-index: 100;
-    top: 0;
-    left: 0;
-    display: none;
-    width: 100vw;
-    height: 100vh;
-    justify-content: center;
-    align-items: center;
-    background: rgba(15, 23, 42, 0.20);
-}
-
-.dialog-content {
-    display: flex;
-    max-width: 900px;
-    padding: 32px 40px;
-    flex-direction: column;
-    align-items: flex-start;
-    gap: 20px;
-    flex-shrink: 0;
-    border-radius: 10px;
-    background: #FFF;
-}
-
-.dialog-button-container {
-    width: 100%;
-    display: flex;
-    justify-content: flex-end;
-    gap: 10px;
-    margin-top: 20px;
-}
-
-.is-active {
-    display: flex;
-}
-
-body:has(.dialog.is-active) {
-    overflow: hidden;
-}
\ No newline at end of file
diff --git a/src/public/css/components/form.css b/src/public/css/components/form.css
deleted file mode 100644
index a09bf3c4c947f52fd041fb95b4a90ef298eb0f1f..0000000000000000000000000000000000000000
--- a/src/public/css/components/form.css
+++ /dev/null
@@ -1,30 +0,0 @@
-.form-default {
-    display: flex;
-    flex-direction: column;
-    width: 100%;
-    gap: 1rem;
-}
-
-.form-input-default {
-    display: flex;
-    flex-direction: column;
-    gap: 0.4rem;
-}
-
-.form-input-radio-default {
-    display: flex;
-    align-items: center;
-    gap: 0.8rem;
-}
-
-.input-default {
-    padding: 0.75rem;
-    border-radius: 0.4rem;
-    border: 1px solid rgba(0,0,0,.1);
-    width: 100%;
-}
-
-.input-default:focus {
-    outline: none;
-    outline: 1px solid var(--accent-800);
-}
\ No newline at end of file
diff --git a/src/public/css/components/icon.css b/src/public/css/components/icon.css
deleted file mode 100644
index 6842951beeef1e0b636d05ed4b4f0eb1b72f1eb2..0000000000000000000000000000000000000000
--- a/src/public/css/components/icon.css
+++ /dev/null
@@ -1,21 +0,0 @@
-.icon-heart:hover {
-    fill: var(--accent-600);
-    transition: all;
-    transition-duration: 400ms;
-    transition-timing-function: ease-in-out;
-}
-
-.icon-heart[data-type="filled"] {
-    fill: var(--accent-600);
-}
-
-.icon-bookmark:hover {
-    fill: var(--accent-600);
-    transition: all;
-    transition-duration: 400ms;
-    transition-timing-function: ease-in-out;
-}
-
-.icon-bookmark[data-type="filled"] {
-    fill: var(--accent-600);
-}
\ No newline at end of file
diff --git a/src/public/css/components/input.css b/src/public/css/components/input.css
deleted file mode 100644
index cf697682b68fc3d5a7d111d375f67d0d1c266c3b..0000000000000000000000000000000000000000
--- a/src/public/css/components/input.css
+++ /dev/null
@@ -1,46 +0,0 @@
-.input-group {
-    display: flex;
-    flex-direction: column;
-    align-items: flex-start;
-    gap: 10px;
-}
-
-.input-required::after {
-    content: '*';
-    color: #FC7979;
-    margin-left: 8px; 
-}
-
-input {
-    width: 100%;
-    display: flex;
-    height: 36px;
-    padding: 8px 56px 8px 12px;
-    align-items: flex-start;
-    align-self: stretch;
-    border-radius: 6px;
-    border: 1px solid var(--slate-200, #CBD5E1);
-    background: #FFF;
-    font-size: 1rem;
-    font-style: normal;
-}
-
-label {
-    color: var(--slate-900, #0F172A);
-    font-size: 0.875rem;
-    font-style: normal;
-    font-weight: 400;
-}
-
-textarea {
-    display: flex;
-    min-height: 100px;
-    padding: 8px 56px 8px 12px;
-    align-items: flex-start;
-    flex: 1 0 0;
-    align-self: stretch;
-    border-radius: 6px;
-    border: 1px solid var(--slate-200, #CBD5E1);
-    background: #FFF;
-    font-size: 1rem;
-}
\ No newline at end of file
diff --git a/src/public/css/components/modal.css b/src/public/css/components/modal.css
deleted file mode 100644
index 488bbf5c0344f16bc0c0e929c79739a6ebf0b7ea..0000000000000000000000000000000000000000
--- a/src/public/css/components/modal.css
+++ /dev/null
@@ -1,54 +0,0 @@
-.modal {
-    width: 100%;
-    display: flex;
-    align-items: center;
-    flex-direction: column;
-}
-
-.modal__trigger {
-    width: 100%;
-}
-
-
-.modal__content {
-    display: flex;
-    gap: 1rem;
-    position: relative;
-    width: 100%;
-    max-width: 40rem;
-    margin: 1rem;
-    flex-direction: column;
-    padding: 1rem;
-    background-color: white;
-    border-radius: 0.4rem;
-    max-height: 90vh;
-    overflow: auto;
-    box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
-}
-
-.modal__backdrop {
-    position: fixed;
-    display: none;
-    align-items: center;
-    justify-content: center;
-    top: 50%;
-    left: 50%;
-    transform: translate(-50%, -50%);
-    z-index: 1000;
-    width: 100%;
-    height: 100vh;
-    background-color: rgba(255, 255, 255, .5);
-    backdrop-filter: blur(4px);
-}
-
-.modal__close {
-    position: absolute;
-    top: 10px;
-    right: 10px;
-    max-width: fit-content;
-    padding: 0;
-}
-
-.icon-x {
-    color: rgba(0,0,0,.4);
-}
\ No newline at end of file
diff --git a/src/public/css/components/pagination.css b/src/public/css/components/pagination.css
deleted file mode 100644
index 9793a3d58f4c8ac94fab31dbaaefd73fc933249f..0000000000000000000000000000000000000000
--- a/src/public/css/components/pagination.css
+++ /dev/null
@@ -1,46 +0,0 @@
-.pagination {
-    width: 100%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    margin-top: 80px;
-}
-
-.pagination-elips {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    gap: 10px;
-    border-radius: 8px;
-    width: 36px;
-    height: 36px;
-}
-
-.pagination-item {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    gap: 10px;
-    border-radius: 8px;
-    width: 36px;
-    height: 36px;
-}
-
-.pagination-item:hover {
-    background-color: var(--accent-300);
-    transition: all;
-    transition-duration: 400ms;
-    transition-timing-function: ease-in-out;
-}
-
-.pagination-item[data-type="active"] {
-    background: var(--accent-300, #EDDEF6);
-}
-
-.pagination-item.prev {
-    transform: rotate(90deg);
-}
-
-.pagination-item.next {
-    transform: rotate(-90deg);
-}
\ No newline at end of file
diff --git a/src/public/css/components/select.css b/src/public/css/components/select.css
deleted file mode 100644
index f31d8847eac3024e80a2fcd9652ee2c929b48c5e..0000000000000000000000000000000000000000
--- a/src/public/css/components/select.css
+++ /dev/null
@@ -1,44 +0,0 @@
-.c-select-menu {
-    min-width: 200px;
-    width: 100%;
-    position: relative;
-}
-
-.c-select-menu .c-select-btn {
-    display: flex;
-    padding: 0.35rem;
-    border: 1px solid rgba(0,0,0,.1);
-    border-radius: 0.4rem;
-    align-items: center;
-    justify-content: space-between;
-    cursor: pointer;
-    position: relative;
-}
-
-.c-select-menu .c-select-options {
-    position: absolute;
-    padding: 0.4rem;
-    top: 3rem;
-    background-color: #fff;
-    border: 1px solid rgba(0,0,0,0.1);
-    border-radius: 0.4rem;
-    min-width: 200px;
-    width: 100%;
-    z-index: 50;
-}
-
-.c-select-options .c-select-option {
-    display: flex;
-    padding: 0.6rem;
-    cursor: pointer;
-    align-items: center;
-    border-radius: 0.4rem;
-}
-
-.c-select-options .c-select-option:hover {
-    background-color: var(--accent-100);
-}
-
-.c-select-hide {
-    display: none;
-}
\ No newline at end of file
diff --git a/src/public/css/components/textarea.css b/src/public/css/components/textarea.css
deleted file mode 100644
index 3381a355f56400673c67128142287afef647430b..0000000000000000000000000000000000000000
--- a/src/public/css/components/textarea.css
+++ /dev/null
@@ -1,3 +0,0 @@
-textarea {
-    font-size: 1rem;
-}
\ No newline at end of file
diff --git a/src/public/css/global.css b/src/public/css/global.css
index d265d12fba64cf32d30820bd02be9e9876008853..3587c8b678006575469d9a200fe00c50f48ca85d 100644
--- a/src/public/css/global.css
+++ b/src/public/css/global.css
@@ -367,6 +367,31 @@ button:hover {
     display: none;
 }
 
+.navbar-menu .profile-menu {
+    width: 100%;
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    justify-content: center;
+    gap: 1rem;
+    background-color: #FFF;
+}
+
+.navbar-menu .profile-menu a,
+.navbar-menu .profile-menu button {
+    width: 100%;
+    align-items: flex-start;
+    justify-content: flex-start;
+}
+
+.navbar-menu .profile-menu.collapsed {
+    display: flex;
+}
+
+.navbar-menu:not(.collapsed) .profile-icon {
+    display: none;
+}
+
 .navbar-menu a {
     width: 100%;
     align-items: flex-start;
@@ -387,16 +412,29 @@ button:hover {
         background-color: transparent;
         position: static;
         flex-direction: row;
-        align-items: flex-end;
+        align-items: center;
         justify-content: flex-end;
         box-shadow: none;
         gap: 0;
     }
 
+    .navbar-menu .profile-menu {
+        width: fit-content;
+        position: absolute;
+        top: 80px;
+        padding: 1rem 1.5rem;
+        border-radius: 6px;
+        box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
+    }
+
     .navbar-menu.collapsed {
         display: flex;
     }
 
+    .navbar-menu .profile-menu.collapsed {
+        display: none;
+    }
+
     .navbar-menu a {
         width: auto;
     }
@@ -682,6 +720,8 @@ button:hover {
     min-width: 200px;
     width: 100%;
     z-index: 50;
+    max-height: 20rem;
+    overflow: auto;
 }
 
 .c-select-options .c-select-option {
@@ -1018,6 +1058,7 @@ textarea:focus {
     display: flex;
     flex-direction: row;
     gap: 0.6rem;
+    flex-wrap: wrap;
 }
 
 .watchlist__meta {
@@ -1150,4 +1191,100 @@ textarea:focus {
 
 .no-item__container span {
     filter: blur(2px);
+}
+
+/* Toast */
+
+.toast {
+    min-width: 250px;
+    max-width: 80vw;
+    background-color: var(--error-background);
+    color: var(--error-foreground);
+    text-align: center;
+    border-radius: 6px;
+    display: flex;
+    padding: 16px 6px;
+    justify-content: space-between;
+    align-items: flex-start;
+    align-self: stretch;
+    position: fixed;
+    z-index: 100;
+    margin: 0 auto;
+    left: 0;
+    right: 0;
+    top: 8px;
+}
+
+.toast[data-type="error"] {
+    background-color: var(--error-background);
+}
+
+.toast[data-type="error"] h3 {
+    color: var(--error-foreground);
+}
+
+.toast[data-type="error"] p {
+    color: var(--error-foreground);
+}
+
+.toast[data-type="error"] svg path {
+    stroke: var(--error-foreground);
+}
+
+.toast[data-type="info"] {
+    background-color: var(--info-background);
+}
+
+.toast[data-type="info"] h3 {
+    color: var(--info-foreground);
+}
+
+.toast[data-type="error"] p {
+    color: var(--error-foreground);
+}
+
+.toast[data-type="info"] svg path {
+    stroke: var(--info-foreground);
+}
+
+.toast[data-type="success"] {
+    background-color: var(--success-background);
+}
+
+.toast[data-type="success"] h3 {
+    color: var(--success-foreground);
+}
+
+.toast[data-type="success"] svg path {
+    stroke: var(--success-foreground);
+}
+
+.toast div {
+    display: flex;
+    padding: 0px 12px;
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 6px;
+    flex: 1 0 0;
+}
+
+
+.toast p {
+    text-align: start;
+}
+
+.toast > svg {
+    display: none;
+}
+
+@media screen and (min-width: 640px) {
+    .toast {
+        max-width: 400px;
+    }
+}
+
+.catalog-trailer {
+    width: 80%;
+    max-width: 600px;
+    align-self: stretch;
 }
\ No newline at end of file
diff --git a/src/public/css/signIn.css b/src/public/css/signIn.css
index 125d794051b95d1d61730526fb611775053dde1f..d71a618dc5842cd69e27dfc4e3939be0dd851b10 100644
--- a/src/public/css/signIn.css
+++ b/src/public/css/signIn.css
@@ -9,6 +9,7 @@
 }
 
 .signin-poster {
+    display: none;
     width: 50%;
     height: 100vh;
     object-fit: cover;
@@ -25,13 +26,15 @@
 }
 
 .main-container {
+    max-width: 500px;
+    width: 90%;
     padding: 24px;
     background: white;
     border-radius: 6px;
     flex-direction: column;
     justify-content: center;
     align-items: center;
-    gap: 80px;
+    gap: 40px;
     display: flex;
 }
 
@@ -80,17 +83,8 @@
     margin-bottom: 20px;
 }
 
-
-
-input {
-    align-self: stretch;
-    padding: 8px 8px 12px 56px;
-    background: white;
-    border-radius: 6px;
-    border: 1px #cbd5e1 solid;
-    justify-content: flex-start;
-    align-items: center;
-    display: inline-flex;
+form p:has(a) {
+    text-align: center;
 }
 
 
@@ -102,7 +96,7 @@ input {
 }
 
 @media screen and (min-width: 1024px) {
-    .signup-poster {
+    .signin-poster {
         display: block;
     }
 }
diff --git a/src/public/css/signUp.css b/src/public/css/signUp.css
index 2ab624121da843ec783ff0432ca885ebddfb7d8b..c13558166cf80593adfb3a075e2a3534b2b682a6 100644
--- a/src/public/css/signUp.css
+++ b/src/public/css/signUp.css
@@ -9,6 +9,7 @@
 }
 
 .signup-poster {
+    display: none;
     width: 50%;
     height: 100vh;
     object-fit: cover;
@@ -25,13 +26,15 @@
 }
 
 .main-container {
+    max-width: 500px;
+    width: 90%;
     padding: 24px;
     background: white;
     border-radius: 6px;
     flex-direction: column;
     justify-content: center;
     align-items: center;
-    gap: 80px;
+    gap: 40px;
     display: flex;
 }
 
@@ -78,19 +81,11 @@
 
 
 
-input {
-    align-self: stretch;
-    padding: 8px 8px 12px 56px;
-    background: white;
-    border-radius: 6px;
-    border: 1px #cbd5e1 solid;
-    justify-content: flex-start;
-    align-items: center;
-    display: inline-flex;
+form p:has(a) {
+    text-align: center;
 }
 
 
-
 @media screen and (min-width: 640px) {
     .welcome-text__h2 {
         font-size: 2rem;
@@ -102,3 +97,9 @@ input {
         display: block;
     }
 }
+
+.signin-link {
+    color: var(--accent-800);
+    font-size: 14px;
+    text-decoration: underline;
+}
\ No newline at end of file
diff --git a/src/public/css/watchlist-detail.css b/src/public/css/watchlist-detail.css
index 64226f73f911b8d4ada95106e0197513d21a0070..99a0a6d9c05c8d8c0d069540fb03f87a8672922f 100644
--- a/src/public/css/watchlist-detail.css
+++ b/src/public/css/watchlist-detail.css
@@ -22,8 +22,10 @@ article.header .container-subtitle {
 }
 
 article.header .container-button {
+    width: 100%;
     display: flex;
     align-items: flex-start;
+    justify-content: center;
 }
 
 .container-btn-love {
@@ -84,7 +86,11 @@ form {
         gap: 10px;
     }
 
+    article.header .container-button {
+        justify-content: flex-end;
+    }
+
     article.header .detail {
         width: 80%;
-    }   
+    }
 }
diff --git a/src/public/css/watchlistCreate.css b/src/public/css/watchlistCreate.css
index 0dc427fe85b705166af111a418e32d85e3ed2a5b..03c12711d09cc3847fd4d1ebd98e09d151afaa5c 100644
--- a/src/public/css/watchlistCreate.css
+++ b/src/public/css/watchlistCreate.css
@@ -20,6 +20,25 @@
     gap: 0.6rem;
 }
 
+.tags {
+    display: grid;
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+    gap: 0.2rem;
+    margin: 0.2rem 0;
+}
+
+.checkbox {
+    max-width: fit-content;
+}
+
+.input-tag {
+    display: flex;
+    flex-direction: row-reverse;
+    align-items: center;
+    justify-content: start;
+    gap: 1rem;
+}
+
 .watchlist-items__title {
     margin: 1rem 0 0 0;
 }
@@ -62,11 +81,18 @@
     flex-grow: 1;
 }
 
+@media screen and (min-width: 784px) {
+    .tags {
+        grid-template-columns: repeat(5, minmax(0, 1fr));
+    }
+}
+
 
 @media screen and (min-width: 1024px) {
     .container__create-watchlist {
         flex-direction: row;
     }
+
     .actions {
         position: sticky;
         top: 8rem;
diff --git a/src/public/js/components/dialog.js b/src/public/js/components/dialog.js
deleted file mode 100644
index 534c1a3245ae959df55a1e105ab174d071c6cd8e..0000000000000000000000000000000000000000
--- a/src/public/js/components/dialog.js
+++ /dev/null
@@ -1,26 +0,0 @@
-dialogTriggers = document.getElementsByClassName("dialog-trigger");
-dialogs = document.getElementsByClassName("dialog");
-
-for (let i = 0; i < dialogTriggers.length; i++) {
-  dialogTriggers[i].addEventListener("click", () => {
-    dialogs[i].classList.remove("hidden");
-  });
-}
-
-for (let i = 0; i < dialogs.length; i++) {
-  dialogs[i].querySelector("#cancel").addEventListener("click", () => {
-    dialogs[i].classList.add("hidden");
-  });
-}
-// if (dialogTrigger) {
-//   dialogTrigger.addEventListener("click", () => {
-//     document.querySelector(".dialog").classList.add("is-active");
-//   });
-// }
-
-// dialogClose = document.querySelector(".dialog #cancel");
-// if (dialogClose) {
-//   dialogClose.addEventListener("click", () => {
-//     document.querySelector(".dialog").classList.remove("is-active");
-//   });
-// }
diff --git a/src/public/js/components/modal/watchlistAddItem.js b/src/public/js/components/modal/watchlistAddItem.js
index 268473bfadd4c6bae5586155d7238c139e7148e2..4668a35799599bf35be756f12234aea0ec7d7d09 100644
--- a/src/public/js/components/modal/watchlistAddItem.js
+++ b/src/public/js/components/modal/watchlistAddItem.js
@@ -22,6 +22,13 @@ function deleteItemAction(id) {
             btnAddToList.innerHTML = PLUS_ICON;
         }
         item.remove();
+
+        if (catalogSelected.length === 0) {
+            const itemsPlaceholder = document.createElement("p");
+            itemsPlaceholder.classList.add("items-placeholder");
+            itemsPlaceholder.textContent = "No items selected.";
+            watchlistItemContainer.appendChild(itemsPlaceholder);
+        }
     }
 }
 
@@ -113,6 +120,8 @@ function fetchSearch(replace = false) {
                         const xhttp = new XMLHttpRequest();
                         xhttp.onreadystatechange = function () {
                             if (xhttp.readyState === 4) {
+                                const itemsPlaceholder = document.querySelector("p.items-placeholder");
+                                itemsPlaceholder.remove();
                                 const wrapper = document.createElement('div');
                                 wrapper.classList.add('watchlist-item');
                                 wrapper.draggable = "true";
@@ -193,8 +202,4 @@ btnAddItem.addEventListener('click', () => {
 
 drag();
 getCatalogSelected();
-deleteItem();
-
-
-console.log(catalogSelected);
-
+deleteItem();
\ No newline at end of file
diff --git a/src/public/js/components/navbar.js b/src/public/js/components/navbar.js
index b95cbebe24315a199f462ffec53463137ba41c35..c46ff5597fde538d9f9952ca44a4e3092bca7684 100644
--- a/src/public/js/components/navbar.js
+++ b/src/public/js/components/navbar.js
@@ -14,7 +14,11 @@ if (navbarToggle) {
   });
 
   navbarToggle.addEventListener("blur", function (e) {
-    if (e.relatedTarget && e.relatedTarget.parentElement.id === "navbar-menu") {
+    if (
+      e.relatedTarget &&
+      (e.relatedTarget.parentElement.id === "navbar-menu" ||
+        e.relatedTarget.parentElement.id === "profile-menu")
+    ) {
       return;
     } else {
       navbarMenu = document.getElementById("navbar-menu");
@@ -24,3 +28,33 @@ if (navbarToggle) {
     }
   });
 }
+
+profileMenuToggle = document.getElementById("profile-menu-toggle");
+if (profileMenuToggle) {
+  profileMenuToggle.addEventListener("click", function () {
+    profileMenu = document.getElementById("profile-menu");
+    if (profileMenu.classList.contains("collapsed")) {
+      profileMenu.classList.remove("collapsed");
+      profileMenuToggle.focus();
+      this.setAttribute("aria-expanded", "true");
+    } else {
+      profileMenu.classList.add("collapsed");
+      profileMenuToggle.blur();
+      this.setAttribute("aria-expanded", "false");
+    }
+  });
+
+  profileMenuToggle.addEventListener("blur", function (e) {
+    if (
+      e.relatedTarget &&
+      e.relatedTarget.parentElement.id === "profile-menu"
+    ) {
+      return;
+    } else {
+      profileMenu = document.getElementById("profile-menu");
+      profileMenu.classList.add("collapsed");
+      profileMenuToggle.blur();
+      this.setAttribute("aria-expanded", "false");
+    }
+  });
+}
diff --git a/src/public/js/deleteCatalog.js b/src/public/js/deleteCatalog.js
new file mode 100644
index 0000000000000000000000000000000000000000..6671a08ee4aea6f48cd77ed74e65a1308538f9e2
--- /dev/null
+++ b/src/public/js/deleteCatalog.js
@@ -0,0 +1,47 @@
+function deleteCatalog(uuid, title) {
+  const xhttp = new XMLHttpRequest();
+  xhttp.open("DELETE", `/api/catalog/${uuid}/delete`, true);
+  xhttp.setRequestHeader("Content-Type", "application/json");
+
+  xhttp.onreadystatechange = function () {
+    if (xhttp.readyState === 4) {
+      if (xhttp.status === 200) {
+        showToast("Success", `Catalog ${title} deleted`, "success");
+        setTimeout(() => {
+          window.location.reload();
+        }, 1000);
+      } else {
+        try {
+          const response = JSON.parse(xhttp.responseText);
+          showToast("Error", response.message, "error");
+        } catch (error) {
+          showToast("Error", "Something went wrong", "error");
+        }
+      }
+    }
+  };
+
+  xhttp.send();
+}
+
+const deleteTriggerButtons = document.querySelectorAll(
+  `.catalog-delete-trigger`
+);
+deleteTriggerButtons.forEach((deleteTriggerButton) => {
+  if (deleteTriggerButton) {
+    deleteTriggerButton.addEventListener("click", () => {
+      const uuid = deleteTriggerButton.getAttribute("data-uuid");
+      const title = deleteTriggerButton.getAttribute("data-title");
+      dialog(
+        "Delete Catalog",
+        `Are you sure you want to delete ${title}?`,
+        uuid,
+        "delete",
+        "Delete",
+        () => {
+          deleteCatalog(uuid, title);
+        }
+      );
+    });
+  }
+});
diff --git a/src/public/js/editCatalog.js b/src/public/js/editCatalog.js
new file mode 100644
index 0000000000000000000000000000000000000000..8926631df87497c5cdf576b2c4e31f9e377123e5
--- /dev/null
+++ b/src/public/js/editCatalog.js
@@ -0,0 +1,47 @@
+function updateCatalog(form) {
+  const urlParts = window.location.pathname.split("/");
+  const uuidIndex = urlParts.indexOf("catalog") + 1;
+  const uuid = urlParts[uuidIndex];
+  const apiUrl = `/api/catalog/${uuid}/update`;
+  const formData = new FormData(form);
+
+  const xhttp = new XMLHttpRequest();
+  xhttp.open("POST", apiUrl, true);
+
+  xhttp.onreadystatechange = function () {
+    if (xhttp.readyState === 4) {
+      if (xhttp.status === 200) {
+        showToast("Success", "Catalog updated", "success");
+        setTimeout(() => {
+          window.location.href = `/catalog/${uuid}`;
+        }, [1000]);
+      } else {
+        try {
+          const response = JSON.parse(xhttp.responseText);
+          showToast("Error", response.message);
+        } catch (e) {
+          showToast("Error", "Something went wrong", "error");
+        }
+      }
+    }
+  };
+
+  xhttp.send(formData);
+}
+
+const form = document.getElementById("catalog-edit-form");
+
+form.addEventListener("submit", function (event) {
+  event.preventDefault();
+
+  dialog(
+    "Update Catalog",
+    `Are you sure you want to update this catalog?`,
+    "update",
+    "update",
+    "Confirm",
+    () => {
+      updateCatalog(form);
+    }
+  );
+});
diff --git a/src/public/js/global.js b/src/public/js/global.js
index 1ab8b7f097e3262e7914bc6f3e6f6ba6b35844de..dfbb814ff0122f0d1f1efd62a876108a3ca7185f 100644
--- a/src/public/js/global.js
+++ b/src/public/js/global.js
@@ -1,3 +1,63 @@
+function showToast(title, message, type = "error") {
+    const toast = document.getElementById("toast");
+    if (toast) {
+        toast.classList.remove("hidden");
+        toast.setAttribute("data-type", type);
+        h3 = toast.querySelector("h3");
+        h3.textContent = title;
+        p = toast.querySelector("p");
+        p.textContent = message;
+    }
+}
+
+function dialog(
+    title,
+    message,
+    dialogId,
+    actionId,
+    actionButtonText,
+    onaction
+) {
+    const body = document.querySelector("body");
+
+    const dialog = document.createElement("div");
+    dialog.classList.add("dialog");
+    dialog.id = `dialog-${dialogId}`;
+    dialog.innerHTML = `
+        <div class="dialog__content">
+            <h2>
+                ${title}
+            </h2>
+            <p>
+                ${message}
+            </p>
+            <div class="dialog__button-container">
+                <button id="cancel">
+                    Cancel
+                </button>
+                <button id=${actionId} class="btn-bold">
+                    ${actionButtonText}
+                </button>
+            </div>
+        </div>
+    `;
+
+    body.appendChild(dialog);
+
+    const cancelButton = dialog.querySelector("#cancel");
+    cancelButton.addEventListener("click", () => {
+        dialog.remove();
+    });
+
+    const actionButton = dialog.querySelector(`#${actionId}`);
+    actionButton.addEventListener("click", () => {
+        dialog.remove();
+        onaction();
+    });
+}
+
+// Lik and Save Watchlist
+
 function like() {
     const btnLikes = document.querySelectorAll(".btn__like");
     btnLikes.forEach(btn => {
@@ -69,4 +129,42 @@ function save() {
             })
         }
     })
-}
\ No newline at end of file
+}
+
+toastClose = document.querySelector("#toast button");
+
+if (toastClose) {
+    toastClose.addEventListener("click", () => {
+        const toast = document.querySelector("#toast");
+        toast.classList.add("hidden");
+    });
+}
+
+logoutBtn = document.querySelector("button#logout");
+if (logoutBtn) {
+    logoutBtn.addEventListener("click", () => {
+        const xhttp = new XMLHttpRequest();
+        xhttp.open("POST", "/api/auth/logout", true);
+        xhttp.setRequestHeader("Content-Type", "application/json");
+
+        xhttp.onreadystatechange = function () {
+            if (this.readyState === 4) {
+                if (xhttp.status === 200) {
+                    showToast("Success", "Logout success", "success");
+                    setTimeout(() => {
+                        window.location.href = `/`;
+                    }, [1000]);
+                } else {
+                    try {
+                        const response = JSON.parse(xhttp.responseText);
+                        showToast("Error", response.message);
+                    } catch (e) {
+                        showToast("Error", "Something went wrong", "error");
+                    }
+                }
+            }
+        };
+
+        xhttp.send();
+    });
+}
diff --git a/src/public/js/home.js b/src/public/js/home.js
index 22471e5b37c0df0ffeebbca2a33d15dc955b9997..a0a4c89ee4aa6fa833e21cf6d746b2e3a08b15d2 100644
--- a/src/public/js/home.js
+++ b/src/public/js/home.js
@@ -72,5 +72,4 @@ search = debounce(search, 500);
 inputSearch.addEventListener("keyup", search);
 
 like();
-save();
-
+save();
\ No newline at end of file
diff --git a/src/public/js/profile.js b/src/public/js/profile.js
new file mode 100644
index 0000000000000000000000000000000000000000..23e1e12ed3cc5541ca97d6f1a5d8f59fe256b11d
--- /dev/null
+++ b/src/public/js/profile.js
@@ -0,0 +1,89 @@
+function deleteAccount() {
+  const xhttp = new XMLHttpRequest();
+  xhttp.open("DELETE", `/api/auth/delete`, true);
+  xhttp.setRequestHeader("Content-Type", "application/json");
+
+  xhttp.onreadystatechange = function () {
+    if (xhttp.readyState === 4) {
+      if (xhttp.status === 200) {
+        showToast("Success", `User deleted`, "success");
+        setTimeout(() => {
+          window.location.reload();
+        }, 1000);
+      } else {
+        try {
+          const response = JSON.parse(xhttp.responseText);
+          showToast("Error", response.message, "error");
+        } catch (error) {
+          showToast("Error", "Something went wrong", "error");
+        }
+      }
+    }
+  };
+
+  xhttp.send();
+}
+
+const deleteTriggerButton = document.getElementById("delete-account");
+if (deleteTriggerButton) {
+  deleteTriggerButton.addEventListener("click", () => {
+    dialog(
+      "Delete Account",
+      `Are you sure you want to delete your account?`,
+      "delete-account",
+      "delete",
+      "Delete",
+      () => {
+        deleteAccount();
+      }
+    );
+  });
+}
+
+function updateAccount(form) {
+  const xhttp = new XMLHttpRequest();
+  xhttp.open("POST", `/api/auth/update`, true);
+  xhttp.setRequestHeader("Content-Type", "application/json");
+
+  xhttp.onreadystatechange = function () {
+    if (xhttp.readyState === 4) {
+      const response = JSON.parse(xhttp.responseText);
+      if (xhttp.status === 200 && response.status === 200) {
+        showToast("Success", `Profile updated`, "success");
+        nameText = document.getElementById("name");
+        nameText.innerText = response.name;
+      } else {
+        try {
+          const response = JSON.parse(xhttp.responseText);
+          showToast("Error", response.message, "error");
+        } catch (error) {
+          showToast("Error", "Something went wrong", "error");
+        }
+      }
+    }
+  };
+
+  xhttp.send(
+    JSON.stringify({
+      name: form.name.value,
+      oldPassword: form.oldPassword.value,
+      newPassword: form.newPassword.value,
+    })
+  );
+}
+
+const form = document.getElementById("profile-edit-form");
+form.addEventListener("submit", function (event) {
+  event.preventDefault();
+
+  dialog(
+    "Update Account",
+    `Are you sure you want to update your account?`,
+    "update",
+    "update",
+    "Confirm",
+    () => {
+      updateAccount(form);
+    }
+  );
+});
diff --git a/src/public/js/watchlist/createUpdate.js b/src/public/js/watchlist/createUpdate.js
index 1ed7e05f49560a8058e804e35f8e72d25f33c4cc..1f848c0e167a00d31c6ba296f95115f843c74bf8 100644
--- a/src/public/js/watchlist/createUpdate.js
+++ b/src/public/js/watchlist/createUpdate.js
@@ -1,8 +1,65 @@
 const formUpdateWatchlist = document.querySelector("form#update-watchlist");
+const VISIBILITY = ["PUBLIC", "PRIVATE"];
 
-formUpdateWatchlist.addEventListener("submit", e => {
-    e.preventDefault();
+function validateWatchlistCreateUpdateRequest(request) {
+    if (!request.title || request.title.trim() === "") {
+        return {
+            valid: false,
+            message: "Title is required."
+        };
+    }
+    if (request.title.length > 40) {
+        return {
+            valid: false,
+            message: "Title is too long. Maximum 40 chars."
+        }
+    }
+    if (request.description && request.description.length > 255) {
+        return {
+            valid: false,
+            message: "Description is too long. Maximum 255 chars."
+        }
+    }
+    if (!request.visibility || !VISIBILITY.includes(request.visibility.trim())) {
+        return {
+            valid: false,
+            message: "Visibility is invalid."
+        }
+    }
+    if (!request.items || request.items.length === 0) {
+        return {
+            valid: false,
+            message: "Watchlist must contain 1 item."
+        }
+    }
+    if (request.items.length > 50) {
+        return {
+            valid: false,
+            message: "Too many items. Maximum 50 items."
+        }
+    }
+
+    let maxDescExceeded = false;
+    let title;
+    for (let i = 0; i < request.items.length; i++) {
+        if (request.items[i].description.length > 255) {
+            title = request.items[i].title;
+            maxDescExceeded = true;
+            break;
+        }
+    }
+    if (maxDescExceeded) {
+        return {
+            valid: false,
+            message: `Description is too long for item ${title}. Maximum 255 chars.`
+        }
+    }
+    return {
+        valid: true
+    }
+}
 
+function createEditWatchlist() {
     // Parse url
     const currentUrl = window.location.href;
     const url = new URL(currentUrl);
@@ -13,11 +70,13 @@ formUpdateWatchlist.addEventListener("submit", e => {
     const descriptionEl = document.querySelector("textarea#description");
     const visibilityEl = document.querySelector("input#visibility");
     const itemsEl = document.querySelectorAll("div.watchlist-item");
+    const tagsEl = document.querySelectorAll("input.watchlist-tag");
 
     const title = titleEl.value;
     const description = descriptionEl.value;
     const visibility = visibilityEl.value;
     const items = [];
+    const tags = [];
 
     itemsEl.forEach(item => {
         const itemDescEl = item.querySelector("textarea.watchlist-item__description");
@@ -38,15 +97,30 @@ formUpdateWatchlist.addEventListener("submit", e => {
         })
     })
 
-    // ajax request
+    tagsEl.forEach(item => {
+        if (item.checked) {
+            tags.push({
+                id: item.value
+            })
+        }
+    })
 
+    // validate request
     let data = {
         title,
         description,
         visibility,
-        items
+        items,
+        tags
+    }
+
+    let validationResult = validateWatchlistCreateUpdateRequest(data);
+    if (!validationResult.valid) {
+        showToast("Invalid Request", validationResult.message);
+        return;
     }
 
+    // ajax request
     if (action === "edit") {
         data["watchlistUUID"] = url.pathname.split("/")[2];
     }
@@ -60,17 +134,38 @@ formUpdateWatchlist.addEventListener("submit", e => {
 
     xhttp.onreadystatechange = function () {
         if (xhttp.readyState === 4) {
+            const response = JSON.parse(xhttp.response);
             if (xhttp.status !== 200) {
-                document.body.innerHTML = xhttp.response;
+                showToast("Invalid Request", response.message)
             } else {
-                const response = JSON.parse(xhttp.response);
-                if (response.redirectTo !== null && response.redirectTo !== undefined) {
-                    window.history.pushState({}, "", "/signin");
-                    window.location.reload();
-                }
+                showToast("Success", response.message, "success");
+                setTimeout(() => {
+                    if (response.redirectTo !== null && response.redirectTo !== undefined) {
+                        window.location.href = response.redirectTo;
+                        window.history.pushState({}, "", response.redirectTo);
+                        window.location.reload();
+                    }
+                }, 1000)
             }
         }
     }
 
     xhttp.send(data);
+}
+
+formUpdateWatchlist.addEventListener("submit", e => {
+    e.preventDefault();
+
+    dialog(
+        "Update Watchlist",
+        `Are you sure you want to update this watchlist?`,
+        "update",
+        "update",
+        "Confirm",
+        () => {
+            createEditWatchlist();
+        }
+    );
+
+
 })
\ No newline at end of file
diff --git a/src/public/js/watchlist/delete.js b/src/public/js/watchlist/delete.js
new file mode 100644
index 0000000000000000000000000000000000000000..88cf402962925ef6181e5a2b611ff70ee9aae884
--- /dev/null
+++ b/src/public/js/watchlist/delete.js
@@ -0,0 +1,33 @@
+const btnDelete = document.querySelector("button.btn__delete");
+
+btnDelete.addEventListener("click", () => {
+    let data = {
+        watchlistUUID: btnDelete.dataset.id,
+    }
+    data = JSON.stringify(data);
+
+    const xhttp = new XMLHttpRequest();
+
+    xhttp.open("DELETE", "/api/watchlist", true);
+    xhttp.setRequestHeader("Content-Type", "application/json");
+
+    xhttp.onreadystatechange = function () {
+        if (xhttp.readyState === 4) {
+            const response = JSON.parse(xhttp.response);
+            if (xhttp.status !== 200) {
+                showToast("Failed to Delete Watchlist", response.message);
+            } else {
+                showToast("Success", response.message, "success");
+                setTimeout(() => {
+                    if (response.redirectTo !== null && response.redirectTo !== undefined) {
+                        window.location.href = response.redirectTo;
+                        window.history.pushState({}, "", response.redirectTo);
+                        window.location.reload();
+                    }
+                }, 1000)
+            }
+        }
+    }
+
+    xhttp.send(data);
+})
\ No newline at end of file
diff --git a/src/public/js/watchlist/detail.js b/src/public/js/watchlist/detail.js
new file mode 100644
index 0000000000000000000000000000000000000000..71a4d25cd6fa850104a300ddf893d2938534ec3d
--- /dev/null
+++ b/src/public/js/watchlist/detail.js
@@ -0,0 +1,2 @@
+like();
+save();
\ No newline at end of file
diff --git a/src/server/app/App/View.php b/src/server/app/App/View.php
index b455d1d62a7dd1b8f730123aed2c83ff80d30f3b..4278869ca138a1d8064a429c8838ffcb2f749ad0 100644
--- a/src/server/app/App/View.php
+++ b/src/server/app/App/View.php
@@ -8,6 +8,7 @@ class View
     {
         $user = $sessionService ? $sessionService->current() : null;
 
+        require __DIR__ . '/../View/components/toast.php';
         require __DIR__ . '/../View/components/header.php';
         if (!isset($_SERVER['PATH_INFO']) || ($_SERVER['PATH_INFO'] != '/signin' && $_SERVER['PATH_INFO'] != '/signup')) {
             require __DIR__ . '/../View/components/navbar.php';
@@ -21,4 +22,4 @@ class View
         header("Location: $url");
         exit();
     }
-}
+}
\ No newline at end of file
diff --git a/src/server/app/Controller/BookmarkController.php b/src/server/app/Controller/BookmarkController.php
new file mode 100644
index 0000000000000000000000000000000000000000..4a131ebc40d4aaf3b6a353dfa141f90ef765ee89
--- /dev/null
+++ b/src/server/app/Controller/BookmarkController.php
@@ -0,0 +1,72 @@
+<?php
+require_once __DIR__ . '/../Config/Database.php';
+require_once __DIR__ . '/../App/View.php';
+require_once __DIR__ . '/../Exception/ValidationException.php';
+
+require_once __DIR__ . '/../Repository/WatchlistSaveRepository.php';
+
+require_once __DIR__ . '/../Service/BookmarkService.php';
+require_once __DIR__ . '/../Service/SessionService.php';
+
+require_once __DIR__ . '/../Model/bookmark/BookmarkGetRequest.php';
+
+class BookmarkController
+{
+    private BookmarkService $bookmarkService;
+    private SessionService $sessionService;
+
+    public function __construct()
+    {
+        $connection = Database::getConnection();
+        $watchlistSaveRepository = new WatchlistSaveRepository($connection);
+        $this->bookmarkService = new BookmarkService($watchlistSaveRepository);
+
+        $sessionRepository = new SessionRepository($connection);
+        $userRepository = new UserRepository($connection);
+        $this->sessionService = new SessionService($sessionRepository, $userRepository);
+    }
+
+    public function self()
+    {
+        $page = $_GET['page'] ?? 1;
+        $pageSize = $_GET['pageSize'] ?? 10;
+
+        $user = $this->sessionService->current();
+        $request = new BookmarkGetRequest();
+        $request->userId = $user ? $user->id : null;
+        $request->page = $page;
+        $request->pageSize = $pageSize;
+
+        $result = $this->bookmarkService->findByUser($request);
+
+        function posterCompare($element1, $element2)
+        {
+            return $element1["rank"] - $element2["rank"];
+        }
+
+        $bookmarks = [];
+
+        foreach ($result["items"] as $item) {
+            $posters = json_decode($item["posters"], true);
+            $tags = json_decode($item["tags"], true);
+            $tags = array_filter($tags, function ($value) {
+                return $value["id"] !== null;
+            });
+            usort($posters, "posterCompare");
+            $item["posters"] = $posters;
+            $item["tags"] = $tags;
+
+            array_push($bookmarks, $item);
+        }
+
+        $result["items"] = $bookmarks;
+
+        View::render('profile/bookmark', [
+            'title' => 'Bookmark',
+            'data' => [
+                'bookmarks' => $result,
+                'userUUID' => $user ? $user->uuid : null,
+            ],
+        ], $this->sessionService);
+    }
+}
\ No newline at end of file
diff --git a/src/server/app/Controller/CatalogController.php b/src/server/app/Controller/CatalogController.php
index bf68439463a8608a9527840153e6b8c194f30249..c77b6a9f786b44bc56bda12287b79d1dc2c1766d 100644
--- a/src/server/app/Controller/CatalogController.php
+++ b/src/server/app/Controller/CatalogController.php
@@ -12,6 +12,7 @@ require_once __DIR__ . '/../Repository/UserRepository.php';
 require_once __DIR__ . '/../Repository/SessionRepository.php';
 
 require_once __DIR__ . '/../Model/CatalogCreateRequest.php';
+require_once __DIR__ . '/../Model/catalog/CatalogUpdateRequest.php';
 require_once __DIR__ . '/../Model/CatalogSearchRequest.php';
 
 class CatalogController
@@ -36,16 +37,21 @@ class CatalogController
         $page = $_GET['page'] ?? 1;
         $category = $_GET['category'] ?? "MIXED";
 
+        $user = $this->sessionService->current();
+
         View::render('catalog/index', [
             'title' => 'Catalog',
             'styles' => [
                 '/css/catalog.css',
             ],
+            'js' => [
+                '/js/deleteCatalog.js'
+            ],
             'data' => [
                 'catalogs' => $this->catalogService->findAll($page, $category),
-                'category' => strtoupper(trim($category))
-            ],
-            'is_admin' => true
+                'category' => strtoupper(trim($category)),
+                'userRole' => $user ? $user->role : null
+            ]
         ], $this->sessionService);
     }
 
@@ -65,19 +71,17 @@ class CatalogController
         $catalog = $this->catalogService->findByUUID($uuid);
 
         if (!$catalog) {
-            View::render('catalog/not-found', [
-                'title' => 'Catalog Not Found',
-                'styles' => [
-                    '/css/catalog-not-found.css',
-                ],
-            ], $this->sessionService);
+            View::redirect('/404');
         }
 
-        View::render('catalog/form', [
+        View::render('catalog/edit', [
             'title' => 'Edit Catalog',
             'styles' => [
                 '/css/catalog-form.css',
             ],
+            'js' => [
+                '/js/editCatalog.js'
+            ],
             'type' => 'edit',
             'data' => $catalog->toArray()
         ], $this->sessionService);
@@ -87,16 +91,24 @@ class CatalogController
     {
         $catalog = $this->catalogService->findByUUID($uuid);
 
+
         if (!$catalog) {
             View::redirect('/404');
         }
 
+        $user = $this->sessionService->current();
         View::render('catalog/detail', [
             'title' => 'Catalog Detail',
             'styles' => [
                 '/css/catalog-detail.css',
             ],
-            'data' => $catalog->toArray()
+            'js' => [
+                '/js/deleteCatalog.js'
+            ],
+            'data' => [
+                'item' => $catalog->toArray(),
+                'userRole' => $user ? $user->role : null
+            ]
         ], $this->sessionService);
     }
 
@@ -138,47 +150,6 @@ class CatalogController
         }
     }
 
-    public function postEdit($uuid): void
-    {
-        $request = new CatalogCreateRequest();
-        $request->title = $_POST['title'];
-        $request->description = $_POST['description'];
-        $request->category = $_POST['category'];
-
-        if (isset($_FILES['poster'])) {
-            $request->poster = $_FILES['poster'];
-        }
-
-        if (isset($_FILES['trailer'])) {
-            $request->trailer = $_FILES['trailer'];
-        }
-
-        try {
-            $this->catalogService->update($uuid, $request);
-            View::redirect('/catalog/' . $uuid);
-        } catch (ValidationException $exception) {
-            $catalog = $this->catalogService->findByUUID($uuid);
-            $catalog->title = $request->title;
-            $catalog->description = $request->description;
-            $catalog->category = $request->category;
-            View::render('catalog/form', [
-                'title' => 'Edit Catalog',
-                'error' => $exception->getMessage(),
-                'styles' => [
-                    '/css/catalog-form.css',
-                ],
-                'type' => 'edit',
-                'data' => $catalog->toArray()
-            ], $this->sessionService);
-        }
-    }
-
-    public function postDelete($uuid): void
-    {
-        $this->catalogService->deleteByUUID($uuid);
-        View::redirect('/catalog');
-    }
-
     public function search()
     {
         $request = new CatalogSearchRequest();
@@ -197,4 +168,92 @@ class CatalogController
             require __DIR__ . '/../View/components/modal/watchlistAddSearchItem.php';
         }
     }
+
+    public function update($uuid): void
+    {
+        $user = $this->sessionService->current();
+        try {
+            if (!$user || $user->role !== 'ADMIN') {
+                throw new ValidationException("You are not authorized to update this catalog.");
+            }
+
+            $request = new CatalogUpdateRequest();
+
+            $request->uuid = $uuid;
+            $request->title = $_POST['title'];
+            $request->description = $_POST['description'];
+            $request->category = $_POST['category'];
+
+            if (isset($_FILES['poster'])) {
+                $request->poster = $_FILES['poster'];
+            }
+
+            if (isset($_FILES['trailer'])) {
+                $request->trailer = $_FILES['trailer'];
+            }
+
+            $this->catalogService->update($request);
+            http_response_code(200);
+            $response = [
+                "status" => 200,
+                "message" => "Successfully update catalog",
+            ];
+
+            echo json_encode($response);
+        } catch (ValidationException $exception) {
+            http_response_code(400);
+            $response = [
+                "status" => 400,
+                "message" => $exception->getMessage(),
+            ];
+
+            echo json_encode($response);
+        } catch (\Exception $exception) {
+            http_response_code(500);
+            $response = [
+                "status" => 500,
+                "message" => "Something went wrong.",
+            ];
+
+            echo json_encode($response);
+        }
+    }
+
+    public function delete(string $uuid)
+    {
+        $user = $this->sessionService->current();
+
+        try {
+            if ($user && $user->role === 'ADMIN') {
+                $this->catalogService->deleteByUUID($uuid);
+                http_response_code(200);
+
+                $response = [
+                    "status" => 200,
+                    "message" => "Successfully delete catalog",
+                ];
+
+                echo json_encode($response);
+            } else {
+                throw new ValidationException("You are not authorized to delete this catalog.");
+            }
+        } catch (ValidationException $exception) {
+            http_response_code(400);
+
+            $response = [
+                "status" => 400,
+                "message" => $exception->getMessage(),
+            ];
+
+            echo json_encode($response);
+        } catch (\Exception $exception) {
+            http_response_code(500);
+            $response = [
+                "status" => 500,
+                "message" => "Something went wrong.",
+            ];
+
+            echo json_encode($response);
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/server/app/Controller/HomeController.php b/src/server/app/Controller/HomeController.php
index 1e00f0fe79f48a6bb3535ca6c51e676ea98c4d40..3cbc1151903c1805988c8665c318ba0e7a6ba279 100644
--- a/src/server/app/Controller/HomeController.php
+++ b/src/server/app/Controller/HomeController.php
@@ -3,12 +3,14 @@ require_once __DIR__ . '/../App/View.php';
 require_once __DIR__ . '/../Config/Database.php';
 
 require_once __DIR__ . '/../Service/SessionService.php';
+require_once __DIR__ . '/../Service/TagService.php';
 
 require_once __DIR__ . '/../Repository/UserRepository.php';
 require_once __DIR__ . '/../Repository/SessionRepository.php';
 require_once __DIR__ . '/../Repository/WatchlistRepository.php';
 require_once __DIR__ . '/../Repository/WatchlistLikeRepository.php';
 require_once __DIR__ . '/../Repository/WatchlistSaveRepository.php';
+require_once __DIR__ . '/../Repository/WatchlistTagRepository.php';
 
 require_once __DIR__ . '/../Model/WatchlistsGetRequest.php';
 
@@ -16,6 +18,7 @@ class HomeController
 {
     private SessionService $sessionService;
     private WatchlistService $watchlistService;
+    private TagService $tagService;
 
     public function __construct()
     {
@@ -29,7 +32,11 @@ class HomeController
         $watchlistItemRepository = new WatchlistItemRepository($connection);
         $watchlistLikeRepository = new WatchlistLikeRepository($connection);
         $watchlistSaveRepository = new WatchlistSaveRepository($connection);
-        $this->watchlistService = new WatchlistService($watchlistRepository, $watchlistItemRepository, $watchlistLikeRepository, $watchlistSaveRepository);
+        $watchlistTagRepository = new WatchlistTagRepository($connection);
+        $this->watchlistService = new WatchlistService($watchlistRepository, $watchlistItemRepository, $watchlistLikeRepository, $watchlistSaveRepository, $watchlistTagRepository);
+
+        $tagRepository = new TagRepository($connection);
+        $this->tagService = new TagService($tagRepository);
     }
 
     public function index(): void
@@ -83,6 +90,13 @@ class HomeController
         // Get current user
         $user = $this->sessionService->current();
 
+        $tags = $this->tagService->findAll();
+        $tagsInit = [];
+
+        foreach ($tags["items"] as $tag) {
+            array_push($tagsInit, $tag->name);
+        }
+
         // Get watchlists
         $request = new WatchlistsGetRequest();
         $request->category = $_GET["category"] ?? "";
@@ -90,6 +104,8 @@ class HomeController
         $request->sortBy = $_GET["sortBy"] ?? "";
         $request->order = $_GET["order"] ?? "";
         $request->page = $_GET["page"] ?? 1;
+        $request->tag = $_GET["tag"] ?? "";
+        $request->tagsInit = $tagsInit;
         $request->search = isset($_GET["search"]) ? strtolower($_GET["search"]) : "";
         $request->userId = $user->id ?? -1;
 
@@ -106,12 +122,18 @@ class HomeController
             "page" => $result["page"],
             "pageTotal" => $result["pageTotal"],
             "userUUID" => $user->uuid ?? "",
+            "tags" => $tagsInit
         ];
 
         foreach ($result["items"] as $item) {
             $posters = json_decode($item["posters"], true);
+            $tags = json_decode($item["tags"], true);
+            $tags = array_filter($tags, function ($value) {
+                return $value["id"] !== null;
+            });
             usort($posters, "posterCompare");
             $item["posters"] = $posters;
+            $item["tags"] = $tags;
 
             array_push($data["items"], $item);
         }
diff --git a/src/server/app/Controller/UserController.php b/src/server/app/Controller/UserController.php
index 3ce5b0869ef8664efbd2b9b2cdaf0520984df2f7..54a9f7361f2e000b3a8428d449690ca104ac3609 100644
--- a/src/server/app/Controller/UserController.php
+++ b/src/server/app/Controller/UserController.php
@@ -120,16 +120,47 @@ class UserController
 
     public function showEditProfile(): void
     {
-        $currentUser = $this->userService->findByEmail("m17@gmail.com");
+        $currentUser = $this->sessionService->current();
         View::render('user/editProfile', [
             'title' => 'Drawl | Edit Profile',
             'styles' => [
                 '/css/editProfile.css',
             ],
+            'js' => [
+                '/js/profile.js'
+            ],
             'data' => ['name' => $currentUser->name, 'email' => $currentUser->email]
         ], $this->sessionService);
     }
 
+    public function logout(): void
+    {
+        try {
+            $this->sessionService->destroy();
+            http_response_code(200);
+            $response = [
+                "status" => 200,
+                "message" => "Logout success.",
+            ];
+        } catch (ValidationException $exception) {
+            http_response_code(400);
+            $response = [
+                "status" => 400,
+                "message" => $exception->getMessage(),
+            ];
+
+            echo json_encode($response);
+        } catch (\Exception $exception) {
+            http_response_code(500);
+            $response = [
+                "status" => 500,
+                "message" => "Something went wrong.",
+            ];
+
+            echo json_encode($response);
+        }
+    }
+
     public function postEditProfile(): void
     {
         $request = new UserEditRequest();
@@ -138,48 +169,117 @@ class UserController
         $request->oldPassword = $_POST['oldPassword'];
         $request->newPassword = $_POST['newPassword'];
 
-        $currentUser = $this->userService->findByEmail("m17@gmail.com");
-
-
-        if (isset($_POST['update_button'])) {
-            //update action
-            try {
-                $this->userService->update($currentUser, $request);
-                View::redirect('/editProfile');
-            } catch (ValidationException $exception) {
-                //throw $th;
-                View::render('user/editProfile', [
-                    'title' => 'Drawl | Edit Profile',
-                    'error' => $exception->getMessage(),
-                    'styles' => [
-                        '/css/editProfile.css',
-                    ],
-                    'data' => [
-                        'name' => $currentUser->name,
-                        'email' => $currentUser->email
-                    ],
-                ], $this->sessionService);
-            }
-        } else if (isset($_POST['delete_button'])) {
-            //delete action
-            $this->userService->deleteBySession($currentUser->email);
-            $this->userService->deleteByEmail($currentUser->email);
+        $currentUser = $this->sessionService->current();
 
-            $this->sessionService->destroy();
-            View::redirect('/signin');
+        try {
+            $this->userService->update($currentUser, $request);
+            View::redirect('/profile');
+        } catch (ValidationException $exception) {
+            View::render('user/editProfile', [
+                'title' => 'Drawl | Edit Profile',
+                'error' => $exception->getMessage(),
+                'styles' => [
+                    '/css/editProfile.css',
+                ],
+                'data' => [
+                    'name' => $currentUser->name,
+                    'email' => $currentUser->email
+                ],
+            ], $this->sessionService);
         }
     }
 
-    public function deleteProfile(): void
+    public function update(): void
     {
-        // Get email dari $this->sessionService->current();
-        $this->userService->deleteByEmail($email);
-        View::redirect('/signin');
+        $request = new UserEditRequest();
+
+        $json = file_get_contents('php://input');
+        $data = json_decode($json);
+
+        if ($data === null) {
+            http_response_code(400);
+            $response = [
+                "status" => 400,
+                "message" => "Invalid request.",
+            ];
+
+            echo json_encode($response);
+            return;
+        }
+
+
+        $request->name = $data->name;
+        $request->oldPassword = $data->oldPassword;
+        $request->newPassword = $data->newPassword;
+
+        $currentUser = $this->sessionService->current();
+
+        try {
+            $this->userService->update($currentUser, $request);
+            http_response_code(200);
+            $response = [
+                "status" => 200,
+                "message" => "Successfully update user",
+                "name" => $request->name,
+            ];
+
+            echo json_encode($response);
+        } catch (ValidationException $exception) {
+            http_response_code($exception->getCode() ?? 400);
+
+            $response = [
+                "status" => $exception->getCode() ?? 400,
+                "message" => $exception->getMessage(),
+            ];
+
+            echo json_encode($response);
+        } catch (\Exception $exception) {
+            http_response_code(500);
+            $response = [
+                "status" => 500,
+                "message" => "Something went wrong.",
+            ];
+
+            echo json_encode($response);
+        }
     }
 
-    public function logOut(): void
+    public function delete(): void
     {
-        $this->sessionService->destroy();
-        View::redirect("/signin");
+        $currentUser = $this->sessionService->current();
+
+        try {
+
+            if (!$currentUser) {
+                throw new ValidationException("Unauthorized.", 401);
+            }
+            $this->userService->deleteBySession($currentUser->email);
+            $this->userService->deleteByEmail($currentUser->email);
+            http_response_code(200);
+
+            $response = [
+                "status" => 200,
+                "message" => "Successfully delete user",
+            ];
+
+            echo json_encode($response);
+        } catch (ValidationException $exception) {
+            http_response_code($exception->getCode() ?? 400);
+
+            $response = [
+                "status" => $exception->getCode() ?? 400,
+                "message" => $exception->getMessage(),
+            ];
+
+            echo json_encode($response);
+        } catch (\Exception $exception) {
+            http_response_code(500);
+            $response = [
+                "status" => 500,
+                "message" => "Something went wrong.",
+            ];
+
+            echo json_encode($response);
+        }
     }
-}
+}
\ No newline at end of file
diff --git a/src/server/app/Controller/WatchlistController.php b/src/server/app/Controller/WatchlistController.php
index 9bc7d5498deb3c413b4857befb176dc79f5c6928..b1ae74b9011581b21467454217b6920c1ef79334 100644
--- a/src/server/app/Controller/WatchlistController.php
+++ b/src/server/app/Controller/WatchlistController.php
@@ -8,25 +8,30 @@ require_once __DIR__ . '/../Repository/WatchlistRepository.php';
 require_once __DIR__ . '/../Repository/WatchlistItemRepository.php';
 require_once __DIR__ . '/../Repository/WatchlistLikeRepository.php';
 require_once __DIR__ . '/../Repository/WatchlistSaveRepository.php';
+require_once __DIR__ . '/../Repository/TagRepository.php';
+require_once __DIR__ . '/../Repository/WatchlistTagRepository.php';
 
 require_once __DIR__ . '/../Service/CatalogService.php';
 require_once __DIR__ . '/../Service/WatchlistService.php';
 require_once __DIR__ . '/../Service/SessionService.php';
+require_once __DIR__ . '/../Service/TagService.php';
 
 require_once __DIR__ . '/../Model/CatalogCreateRequest.php';
 require_once __DIR__ . '/../Model/WatchlistAddItemRequest.php';
 require_once __DIR__ . '/../Model/WatchlistCreateRequest.php';
-require_once __DIR__ . '/../Model/watchlist/WatchlistGetSelfRequest.php';
+require_once __DIR__ . '/../Model/watchlist/WatchlistGetOneByUserRequest.php';
 require_once __DIR__ . '/../Model/watchlist/WatchlistGetOneRequest.php';
 require_once __DIR__ . '/../Model/watchlist/WatchlistLikeRequest.php';
 require_once __DIR__ . '/../Model/watchlist/WatchlistSaveRequest.php';
 require_once __DIR__ . '/../Model/watchlist/WatchlistEditRequest.php';
+require_once __DIR__ . '/../Model/watchlist/WatchlistDeleteRequest.php';
 
 class WatchlistController
 {
     private CatalogService $catalogService;
     private WatchlistService $watchlistService;
     private SessionService $sessionService;
+    private TagService $tagService;
 
     public function __construct()
     {
@@ -38,18 +43,27 @@ class WatchlistController
         $watchlistItemRepository = new WatchlistItemRepository($connection);
         $watchlistLikeRepository = new WatchlistLikeRepository($connection);
         $watchlistSaveRepository = new WatchlistSaveRepository($connection);
-        $this->watchlistService = new WatchlistService($watchlistRepository, $watchlistItemRepository, $watchlistLikeRepository, $watchlistSaveRepository);
+        $watchlistTagRepository = new WatchlistTagRepository($connection);
+        $this->watchlistService = new WatchlistService($watchlistRepository, $watchlistItemRepository, $watchlistLikeRepository, $watchlistSaveRepository, $watchlistTagRepository);
 
         $sessionRepository = new SessionRepository($connection);
         $userRepository = new UserRepository($connection);
         $this->sessionService = new SessionService($sessionRepository, $userRepository);
+
+        $tagRepository = new TagRepository($connection);
+        $this->tagService = new TagService($tagRepository);
     }
 
     public function create(): void
     {
+        $tags = $this->tagService->findAll();
+
         View::render('watchlist/createUpdate', [
             'title' => 'Create Watchlist',
             'description' => 'Create new watchlist',
+            "data" => [
+                "tags" => $tags["items"],
+            ],
             'styles' => [
                 '/css/watchlistCreate.css',
                 '/css/components/watchlist/watchlistItem.css',
@@ -72,12 +86,16 @@ class WatchlistController
         $dataRaw = file_get_contents("php://input");
         $data = json_decode($dataRaw, true);
 
+        $tags = $this->tagService->findAll();
+
         $request = new WatchlistCreateRequest();
         $request->title = $data["title"];
         $request->description = $data["description"];
         $request->visibility = $data["visibility"];
         $request->items = $data["items"];
+        $request->tags = $data["tags"];
         $request->userId = $user->id;
+        $request->initialTags = $tags["items"];
 
         try {
             $this->watchlistService->create($request);
@@ -85,7 +103,7 @@ class WatchlistController
             $response = [
                 "status" => 200,
                 "message" => "Watchlist successfully created",
-                "redirectTo" => "/",
+                "redirectTo" => "/profile/watchlist",
             ];
 
             print_r(json_encode($response));
@@ -94,7 +112,7 @@ class WatchlistController
 
             $response = [
                 "status" => 500,
-                "message" => "Internal server error. Please try again later."
+                "message" => $exception->getMessage()
             ];
 
             print_r(json_encode($response));
@@ -105,6 +123,8 @@ class WatchlistController
     {
         $user = $this->sessionService->current();
 
+        $tags = $this->tagService->findAll();
+
         $getRequest = new WatchlistsGetOneRequest();
         $getRequest->uuid = $uuid;
         $getRequest->page = 1;
@@ -124,7 +144,9 @@ class WatchlistController
                 "title" => $watchlist["title"],
                 "description" => $watchlist["description"],
                 "visibility" => $watchlist["visibility"],
-                "catalogs" => $watchlist["catalogs"]
+                "catalogs" => $watchlist["catalogs"],
+                "tagsSelected" => $watchlist["tags"],
+                "tags" => $tags["items"],
             ],
             'styles' => [
                 '/css/watchlistCreate.css',
@@ -166,6 +188,8 @@ class WatchlistController
             print_r(json_encode($response));
         }
 
+        $tags = $this->tagService->findAll();
+
         $request = new WatchlistEditRequest();
         $request->watchlist = $watchlist;
         $request->userId = $user->id;
@@ -173,14 +197,16 @@ class WatchlistController
         $request->description = $data["description"];
         $request->visibility = $data["visibility"];
         $request->items = $data["items"];
+        $request->tags = $data["tags"];
+        $request->initialTags = $tags["items"];
 
         try {
             $this->watchlistService->edit($request);
 
             $response = [
                 "status" => 200,
-                "message" => "Success",
-                "redirectTo" => "",
+                "message" => "Watchlist edited successfully",
+                "redirectTo" => "/watchlist/{$watchlist["watchlist_uuid"]}",
             ];
 
             print_r(json_encode($response));
@@ -198,21 +224,30 @@ class WatchlistController
 
     public function detail(string $uuid): void
     {
+        $user = $this->sessionService->current();
         $request = new WatchlistsGetOneRequest();
         $request->uuid = $uuid;
         $request->page = $_GET["page"] ?? 1;
+        $request->userId = $user ? $user->id : -1;
 
         $result = $this->watchlistService->findByUUID($request);
         if ($result == null) {
             View::redirect('/404');
         }
+
         View::render('watchlist/detail', [
             'title' => 'Watchlist',
             'styles' => [
                 '/css/watchlist-detail.css',
             ],
-            'data' => $result,
-            'editable' => true,
+            'js' => [
+                '/js/watchlist/detail.js',
+                '/js/watchlist/delete.js',
+            ],
+            'data' => [
+                'item' => $result,
+                'userUUID' => $user ? $user->uuid : null
+            ]
         ], $this->sessionService);
     }
 
@@ -236,10 +271,11 @@ class WatchlistController
     {
         $user = $this->sessionService->current();
 
-        $request = new WatchlistsGetSelfRequest();
+        $request = new WatchlistGetOneByUserRequest();
         $request->visibility = $_GET["visibility"] ?? "";
+        $request->userId = $user->id;
 
-        $result = $this->watchlistService->findUserBookmarks($request);
+        $result = $this->watchlistService->findByUser($request);
 
         function posterCompare($element1, $element2)
         {
@@ -250,15 +286,20 @@ class WatchlistController
 
         foreach ($result["items"] as $item) {
             $posters = json_decode($item["posters"], true);
+            $tags = json_decode($item["tags"], true);
+            $tags = array_filter($tags, function ($value) {
+                return $value["id"] !== null;
+            });
             usort($posters, "posterCompare");
             $item["posters"] = $posters;
+            $item["tags"] = $tags;
 
             array_push($watchlists, $item);
         }
 
         $result["items"] = $watchlists;
 
-        View::render('watchlist/self', [
+        View::render('profile/watchlist', [
             'title' => 'My Watchlist',
             'description' => 'My watchlist',
             'styles' => [
@@ -281,8 +322,7 @@ class WatchlistController
             $response = [
                 "message" => "Please login before liking this watchlist.",
             ];
-            $response = json_encode($response);
-            echo $response;
+            print_r(json_encode($response));
             return;
         }
 
@@ -295,6 +335,13 @@ class WatchlistController
 
         try {
             $this->watchlistService->like($watchlistLikeRequest);
+
+            $response = [
+                "status" => 200,
+                "message" => "Success",
+            ];
+
+            print_r(json_encode($response));
         } catch (ValidationException $exception) {
             http_response_code(500);
 
@@ -303,7 +350,7 @@ class WatchlistController
                 "message" => $exception->getMessage(),
             ];
 
-            echo json_encode($response);
+            print_r(json_encode($response));
         }
 
     }
@@ -321,6 +368,13 @@ class WatchlistController
 
         try {
             $this->watchlistService->bookmark($watchlistSaveRequest);
+
+            $response = [
+                "status" => 200,
+                "message" => "Success",
+            ];
+
+            print_r(json_encode($response));
         } catch (ValidationException $exception) {
             http_response_code(500);
 
@@ -329,7 +383,57 @@ class WatchlistController
                 "message" => $exception->getMessage(),
             ];
 
-            echo json_encode($response);
+            print_r(json_encode($response));
+        }
+    }
+
+    public function delete()
+    {
+        $user = $this->sessionService->current();
+
+        $dataRaw = file_get_contents("php://input");
+        $data = json_decode($dataRaw, true);
+
+        $getRequest = new WatchlistsGetOneRequest();
+        $getRequest->uuid = $data["watchlistUUID"];
+        $getRequest->page = 1;
+        $getRequest->pageSize = 100;
+
+        $watchlist = $this->watchlistService->findByUUID($getRequest);
+
+        if ($watchlist == null || $user->uuid !== $watchlist["creator_uuid"]) {
+            http_response_code(400);
+
+            $response = [
+                "status" => 400,
+                "message" => "Watchlist not found.",
+            ];
+
+            print_r(json_encode($response));
+        }
+
+        $request = new WatchlistDeleteRequest();
+        $request->watchlistUUID = $data["watchlistUUID"];
+
+        try {
+            $this->watchlistService->deleteByUUID($request);
+
+            $response = [
+                "status" => 200,
+                "message" => "Watchlist deleted successfully",
+                "redirectTo" => "/profile/watchlist",
+            ];
+
+            print_r(json_encode($response));
+        } catch (Exception $exception) {
+            http_response_code(500);
+
+            $response = [
+                "status" => 500,
+                "message" => "Failed to delete watchlist. " . $exception->getMessage(),
+            ];
+
+            print_r(json_encode($response));
         }
     }
 }
\ No newline at end of file
diff --git a/src/server/app/Domain/Tag.php b/src/server/app/Domain/Tag.php
new file mode 100644
index 0000000000000000000000000000000000000000..f48a5e42741c754d928de95c2d5eb527aa9ac221
--- /dev/null
+++ b/src/server/app/Domain/Tag.php
@@ -0,0 +1,42 @@
+<?php
+
+require_once __DIR__ . '/../App/Domain.php';
+
+class Tag extends Domain
+{
+    public int|string $id;
+    public string $name;
+    public string $createdAt;
+
+    public function toArray(): array
+    {
+        $array = [
+            "name" => $this->name,
+        ];
+
+        if (isset($this->id)) {
+            $array["id"] = $this->id;
+        }
+
+        if (isset($this->createdAt)) {
+            $array["created_at"] = $this->createdAt;
+        }
+
+        return $array;
+    }
+
+    public function fromArray(array $data)
+    {
+        if (isset($data["id"])) {
+            $this->id = $data["id"];
+        }
+
+        if (isset($data["name"])) {
+            $this->name = $data["name"];
+        }
+
+        if (isset($data["created_at"])) {
+            $this->createdAt = $data["created_at"];
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/server/app/Domain/WatchlistSave.php b/src/server/app/Domain/WatchlistSave.php
new file mode 100644
index 0000000000000000000000000000000000000000..4a631e6217e71cd6a4159df6c2b74c71fa1f5933
--- /dev/null
+++ b/src/server/app/Domain/WatchlistSave.php
@@ -0,0 +1,39 @@
+<?php
+
+require_once __DIR__ . '/../App/Domain.php';
+
+class WatchlistSave extends Domain
+{
+    public int|string $id;
+    public int $user_id;
+    public int $watchlist_id;
+
+    public function toArray(): array
+    {
+        $array = [
+            'user_id' => $this->user_id,
+            'watchlist_id' => $this->watchlist_id,
+        ];
+
+        if (isset($this->id)) {
+            $array['id'] = $this->id;
+        }
+
+        return $array;
+    }
+
+    public function fromArray(array $data)
+    {
+        if (isset($data["id"])) {
+            $this->id = $data["id"];
+        }
+
+        if (isset($data["user_id"])) {
+            $this->user_id = $data["user_id"];
+        }
+
+        if (isset($data["watchlist_id"])) {
+            $this->watchlist_id = $data["watchlist_id"];
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/server/app/Domain/WatchlistTag.php b/src/server/app/Domain/WatchlistTag.php
new file mode 100644
index 0000000000000000000000000000000000000000..989ddda1e3fb28227d46de65b9b08e55c67840f2
--- /dev/null
+++ b/src/server/app/Domain/WatchlistTag.php
@@ -0,0 +1,39 @@
+<?php
+
+require_once __DIR__ . '/../App/Domain.php';
+
+class WatchlistTag extends Domain
+{
+    public int|string $id;
+    public int $tagId;
+    public int $watchlistId;
+
+    public function toArray(): array
+    {
+        $array = [
+            "tag_id" => $this->tagId,
+            "watchlist_id" => $this->watchlistId
+        ];
+
+        if (isset($this->id)) {
+            $array["id"] = $this->id;
+        }
+
+        return $array;
+    }
+
+    public function fromArray(array $data)
+    {
+        if (isset($data["id"])) {
+            $this->id = $data["id"];
+        }
+
+        if (isset($data["tag_id"])) {
+            $this->tagId = $data["tag_id"];
+        }
+
+        if (isset($data["watchlist_id"])) {
+            $this->watchlistId = $data["watchlist_id"];
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/server/app/Exception/ValidationException.php b/src/server/app/Exception/ValidationException.php
index 49b82c1e3ba3da127fa2522c6e783d47819bde89..94f0c43539b3f2327b041a5a980bef130da92745 100644
--- a/src/server/app/Exception/ValidationException.php
+++ b/src/server/app/Exception/ValidationException.php
@@ -2,5 +2,12 @@
 
 class ValidationException extends \Exception
 {
-
-}
+    public function __construct(
+        $message,
+        int|null $code = 0,
+        Throwable|null $previous = null
+    ) {
+        parent::__construct($message, $code, $previous);
+        $this->code = 400;
+    }
+}
\ No newline at end of file
diff --git a/src/server/app/Model/CatalogCreateRequest.php b/src/server/app/Model/CatalogCreateRequest.php
index 9ceb0f3fec592f76e970f195c11980c4414cf624..13ccdaaa0c8144b8a6bbf65bf64d56bee001b159 100644
--- a/src/server/app/Model/CatalogCreateRequest.php
+++ b/src/server/app/Model/CatalogCreateRequest.php
@@ -2,9 +2,9 @@
 
 class CatalogCreateRequest
 {
-    public ?string $title = null;
-    public ?string $description = null;
+    public string $title;
+    public string $description;
     public $poster = null;
     public $trailer = null;
-    public ?string $category = null;
+    public string $category;
 }
\ No newline at end of file
diff --git a/src/server/app/Model/WatchlistCreateRequest.php b/src/server/app/Model/WatchlistCreateRequest.php
index 35bda1139f54c8c9bfbe588a93b5174138397c7a..66e93e891de398931dec9805c6f7427ee3aacb03 100644
--- a/src/server/app/Model/WatchlistCreateRequest.php
+++ b/src/server/app/Model/WatchlistCreateRequest.php
@@ -7,4 +7,6 @@ class WatchlistCreateRequest
     public ?string $description;
     public ?string $visibility;
     public ?array $items;
+    public ?array $tags;
+    public ?array $initialTags;
 }
diff --git a/src/server/app/Model/WatchlistsGetRequest.php b/src/server/app/Model/WatchlistsGetRequest.php
index f2f301b5e8d02ad740ba33b2db2181e0966ec0be..47471033e758e583a56fbf2af3a8316c9bb77023 100644
--- a/src/server/app/Model/WatchlistsGetRequest.php
+++ b/src/server/app/Model/WatchlistsGetRequest.php
@@ -5,7 +5,8 @@ class WatchlistsGetRequest
     public ?int $userId;
     public ?string $search;
     public ?string $category;
-    public ?string $tags;
+    public ?string $tag;
+    public ?array $tagsInit;
     public ?string $sortBy;
     public ?string $order;
     public ?int $page;
diff --git a/src/server/app/Model/bookmark/BookmarkGetRequest.php b/src/server/app/Model/bookmark/BookmarkGetRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..971d81536ca19d4216a6fe01d869c3cc31370aad
--- /dev/null
+++ b/src/server/app/Model/bookmark/BookmarkGetRequest.php
@@ -0,0 +1,8 @@
+<?php
+
+class BookmarkGetRequest
+{
+    public int $userId;
+    public int $page = 1;
+    public int $pageSize = 10;
+}
\ No newline at end of file
diff --git a/src/server/app/Model/catalog/CatalogUpdateRequest.php b/src/server/app/Model/catalog/CatalogUpdateRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2f07d18d5988950bfca1742ce1d20eb4ad253b92
--- /dev/null
+++ b/src/server/app/Model/catalog/CatalogUpdateRequest.php
@@ -0,0 +1,11 @@
+<?php
+
+class CatalogUpdateRequest
+{
+    public string $uuid;
+    public string $title;
+    public string $description;
+    public $poster = null;
+    public $trailer = null;
+    public string $category;
+}
\ No newline at end of file
diff --git a/src/server/app/Model/watchlist/WatchlistDeleteRequest.php b/src/server/app/Model/watchlist/WatchlistDeleteRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..723cbf52bf9198c5097c42a4165f50013be89b73
--- /dev/null
+++ b/src/server/app/Model/watchlist/WatchlistDeleteRequest.php
@@ -0,0 +1,6 @@
+<?php
+
+class WatchlistDeleteRequest
+{
+    public ?string $watchlistUUID;
+}
\ No newline at end of file
diff --git a/src/server/app/Model/watchlist/WatchlistEditRequest.php b/src/server/app/Model/watchlist/WatchlistEditRequest.php
index 3e7feadb95d300a9978a0accde0a8cf809b448c8..d5caaeddc2fc321a6716087a800d84955f05d52e 100644
--- a/src/server/app/Model/watchlist/WatchlistEditRequest.php
+++ b/src/server/app/Model/watchlist/WatchlistEditRequest.php
@@ -8,4 +8,6 @@ class WatchlistEditRequest
     public ?string $description;
     public ?string $visibility;
     public ?array $items;
+    public ?array $tags;
+    public ?array $initialTags;
 }
\ No newline at end of file
diff --git a/src/server/app/Model/watchlist/WatchlistGetOneByUserRequest.php b/src/server/app/Model/watchlist/WatchlistGetOneByUserRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..908494ee4f54842871813c499948d383d8a8a69d
--- /dev/null
+++ b/src/server/app/Model/watchlist/WatchlistGetOneByUserRequest.php
@@ -0,0 +1,7 @@
+<?php
+
+class WatchlistGetOneByUserRequest
+{
+    public int $userId;
+    public ?string $visibility;
+}
\ No newline at end of file
diff --git a/src/server/app/Model/watchlist/WatchlistGetOneRequest.php b/src/server/app/Model/watchlist/WatchlistGetOneRequest.php
index 50c9200d60e181f10b0d8766e80863d9bc7f3b49..15e04b8876d921294b5069915ea59fd9bddb695f 100644
--- a/src/server/app/Model/watchlist/WatchlistGetOneRequest.php
+++ b/src/server/app/Model/watchlist/WatchlistGetOneRequest.php
@@ -2,6 +2,7 @@
 
 class WatchlistsGetOneRequest
 {
+    public ?int $userId = null;
     public string $uuid;
     public int $page = 1;
     public int $pageSize = 10;
diff --git a/src/server/app/Model/watchlist/WatchlistGetSelfRequest.php b/src/server/app/Model/watchlist/WatchlistGetSelfRequest.php
deleted file mode 100644
index b51548056328ce95d00f6bde63c01443f02d6e1f..0000000000000000000000000000000000000000
--- a/src/server/app/Model/watchlist/WatchlistGetSelfRequest.php
+++ /dev/null
@@ -1,6 +0,0 @@
-<?php
-
-class WatchlistsGetSelfRequest
-{
-    public ?string $visibility;
-}
\ No newline at end of file
diff --git a/src/server/app/Repository/TagRepository.php b/src/server/app/Repository/TagRepository.php
new file mode 100644
index 0000000000000000000000000000000000000000..b2be3393966503e918e8664e1690eb3e1628867f
--- /dev/null
+++ b/src/server/app/Repository/TagRepository.php
@@ -0,0 +1,44 @@
+<?php
+
+require_once __DIR__ . '/../App/Repository.php';
+
+require_once __DIR__ . '/../Domain/Tag.php';
+
+class TagRepository extends Repository
+{
+    protected string $table = "tags";
+
+    public function __construct(PDO $connection)
+    {
+        parent::__construct($connection);
+    }
+
+    public function findAll(array $projection = [], int|null $page = null, int|null $pageSize = null): array
+    {
+        $result = parent::findAll($projection, $page, $pageSize);
+
+        $result['items'] = array_map(
+            function ($row) {
+                $tags = new Tag();
+                $tags->fromArray($row);
+                return $tags;
+            },
+            $result['items']
+        );
+        return $result;
+    }
+
+    public function findOne($key, $value, $projection = [])
+    {
+        $result = parent::findOne($key, $value, $projection);
+
+        if ($result != null) {
+            $user = new User();
+            $user->fromArray($result);
+
+            return $user;
+        } else {
+            return null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/server/app/Repository/UserRepository.php b/src/server/app/Repository/UserRepository.php
index 507209d52219c98a089d300a7bc579320cf2c6a1..a29dc04a6e938c8eb7dd407a9a17860d6088284e 100644
--- a/src/server/app/Repository/UserRepository.php
+++ b/src/server/app/Repository/UserRepository.php
@@ -48,70 +48,7 @@ class UserRepository extends Repository
         return $user;
     }
 
-    // Bisa lansung pakai method findOne
-    public function findById(int $id): ?User
-    {
-        $statement = $this->connection->prepare("SELECT id, name, password, email, role FROM users WHERE id = ?");
-        $statement->execute([$id]);
-
-        try {
-            if ($row = $statement->fetch()) {
-                $user = new User();
-                $user->id = $row['id'];
-                $user->name = $row['name'];
-                $user->password = $row['password'];
-                $user->email = $row['email'];
-                $user->role = $row['role'];
-
-                return $user;
-            } else {
-                return null;
-            }
-        } finally {
-            $statement->closeCursor();
-        }
-    }
-
-    // Bisa lansung pakai method findOne
-    public function findByEmail(string $email): ?User
-    {
-        $statement = $this->connection->prepare("SELECT id, name, password, email, role FROM users WHERE email = ?");
-        $statement->execute([$email]);
-
-        try {
-            if ($row = $statement->fetch()) {
-                $user = new User();
-                $user->id = $row['id'];
-                $user->name = $row['name'];
-                $user->password = $row['password'];
-                $user->email = $row['email'];
-                $user->role = $row['role'];
-
-                return $user;
-            } else {
-                return null;
-            }
-        } finally {
-            $statement->closeCursor();
-        }
-    }
-
-    // Bisa lansung pakai method delete yang ada di repository
-    public function deleteByUUID(string $UUID): void
-    {
-        $statement = $this->connection->prepare("DELETE FROM users WHERE uuid = ?");
-        $statement->execute([$UUID]);
-        $statement->closeCursor();
-    }
-
-    public function deleteByEmail(string $email): void
-    {
-        $statement = $this->connection->prepare("DELETE FROM users WHERE email = ?");
-        $statement->execute([$email]);
-        $statement->closeCursor();
-    }
 
-    // Bisa langsung pakai method delete yang ada di repository
     public function deleteBySession(string $email)
     {
         $statement = $this->connection->prepare("DELETE FROM sessions WHERE user_id IN
diff --git a/src/server/app/Repository/WatchlistLikeRepository.php b/src/server/app/Repository/WatchlistLikeRepository.php
index 8cef6e2b08686edca6223b86330721314c0f29c5..fab36084bc8a1d82b7808de292401f2abca292dc 100644
--- a/src/server/app/Repository/WatchlistLikeRepository.php
+++ b/src/server/app/Repository/WatchlistLikeRepository.php
@@ -1,5 +1,7 @@
 <?php
 
+require_once __DIR__ . '/../App/Repository.php';
+
 class WatchlistLikeRepository extends Repository
 {
     protected string $table = "watchlist_like";
diff --git a/src/server/app/Repository/WatchlistRepository.php b/src/server/app/Repository/WatchlistRepository.php
index 1b4844e8423591919ac4edf0e1f3db0e9fbbfe76..8245c38a7d128eb7b1ea436aa45133ab3624ff3d 100644
--- a/src/server/app/Repository/WatchlistRepository.php
+++ b/src/server/app/Repository/WatchlistRepository.php
@@ -42,19 +42,36 @@ class WatchlistRepository extends Repository
         }
     }
 
-    public function findAllCustom(string $userId, string $search, string $category, string $sortBy, string $order, int $page = 1, int $pageSize = 10)
+    public function findAllCustom(string $userId, string $search, string $category, string $sortBy, string $order, string $tag, int $page = 1, int $pageSize = 10)
     {
         if ($category != "")
             $category = " AND category = '$category'";
 
         // Queries
-        $selectQuery = "
-            SELECT w.id AS watchlist_id, json_agg(json_build_object(
+        $selectFirstQuery = "
+            WITH first_agg AS (
+            SELECT w.id AS watchlist_id, jsonb_agg(jsonb_build_object(
                 'rank', rank,
                 'poster', poster,
                 'catalog_uuid', c.uuid
-                )) AS posters, w.uuid AS watchlist_uuid, name AS creator, u.uuid AS creator_uuid, item_count, loved, saved, w.title, w.description, w.category, visibility, love_count, w.created_at AS created_at    
+                )) AS posters, w.uuid AS watchlist_uuid, u.name AS creator, u.uuid AS creator_uuid, item_count, loved, saved, w.title, w.description, w.category, visibility, love_count, w.created_at AS created_at    
             ";
+        $selectSecondQuery = "
+            )
+            SELECT 
+                jsonb_agg(jsonb_build_object(
+                'id', t.id,
+                'name', t.name
+                )) AS tags, w.watchlist_id, w.posters as posters, w.watchlist_uuid, w.creator, w.creator_uuid, w.item_count, w.loved, w.saved, w.title, w.description, w.category, w.visibility, w.love_count, w.created_at
+            FROM first_agg AS w
+            LEFT JOIN watchlist_tag as wt ON wt.watchlist_id = w.watchlist_id
+            LEFT JOIN tags as t ON t.id = wt.tag_id
+            GROUP BY
+                w.watchlist_id, w.watchlist_uuid, w.posters, w.creator, w.creator_uuid, w.item_count, w.loved, w.saved, w.title, w.description, w.category, w.visibility, w.love_count, w.created_at
+            ORDER BY
+                $sortBy $order,
+                w.created_at DESC
+        ";
         $countQuery = "WITH rows AS (SELECT COUNT(*)";
         $mainQuery = "
             FROM (
@@ -95,16 +112,39 @@ class WatchlistRepository extends Repository
                 u.name ILIKE :creator
                 OR w.title ILIKE :watchlist_title
             GROUP BY
-                w.id, w.uuid, u.name, w.title, name, u.uuid, item_count, loved, saved, w.description, w.category, visibility, love_count, w.created_at
+                w.id, w.uuid, u.name, w.title, u.name, u.uuid, item_count, loved, saved, w.description, w.category, visibility, love_count, w.created_at
             ORDER BY
                 $sortBy $order,
                 w.created_at DESC
-            LIMIT :limit
-            OFFSET :offset
             ";
 
-        $selectStatement = $this->connection->prepare($selectQuery . $mainQuery);
-        $pageCountStatement = $this->connection->prepare($countQuery . $mainQuery . ") SELECT COUNT(*) FROM rows");
+        if ($tag) {
+            $selectStatement = $this->connection->prepare("WITH outer_query AS (" .
+                $selectFirstQuery . $mainQuery . $selectSecondQuery .
+                ") SELECT * FROM outer_query as o
+                   WHERE EXISTS 
+                   (SELECT 1 
+                    FROM jsonb_array_elements(o.tags) 
+                    AS elem WHERE elem @> '{\"name\": \"$tag\"}'::jsonb)
+                    LIMIT :limit
+                    OFFSET :offset
+                    ");
+            $pageCountStatement = $this->connection->prepare("WITH outer_query AS (" .
+                $selectFirstQuery . $mainQuery . $selectSecondQuery .
+                ") SELECT COUNT(*) FROM outer_query as o
+                   WHERE EXISTS 
+                   (SELECT 1 
+                    FROM jsonb_array_elements(o.tags) 
+                    AS elem WHERE elem @> '{\"name\": \"$tag\"}'::jsonb)
+                    LIMIT :limit
+                    OFFSET :offset
+                    ");
+        } else {
+            $selectStatement = $this->connection->prepare($selectFirstQuery . $mainQuery . $selectSecondQuery . "                     LIMIT :limit
+                    OFFSET :offset");
+            $pageCountStatement = $this->connection->prepare($countQuery . $mainQuery . ") SELECT COUNT(*) FROM rows");
+        }
+
 
         // Binding select
         $selectStatement->bindValue(":user_id", $userId);
@@ -116,8 +156,10 @@ class WatchlistRepository extends Repository
         // Binding count
         $pageCountStatement->bindValue(":user_id", $userId);
         $pageCountStatement->bindValue(":watchlist_title", '%' . $search . '%');
-        $pageCountStatement->bindValue(":limit", PHP_INT_MAX);
-        $pageCountStatement->bindValue(":offset", 0);
+        if ($tag) {
+            $pageCountStatement->bindValue(":limit", PHP_INT_MAX);
+            $pageCountStatement->bindValue(":offset", 0);
+        }
         $pageCountStatement->bindValue(":creator", '%' . $search . '%');
 
         $selectStatement->execute();
@@ -135,7 +177,7 @@ class WatchlistRepository extends Repository
         }
     }
 
-    public function findUserBookmarks(int $userId, string|null $visibility, int $page = null, int $pageSize = null)
+    public function findByUser(int $userId, string|null $visibility, int $page = null, int $pageSize = null)
     {
         $query = "
         FROM (
@@ -148,7 +190,7 @@ class WatchlistRepository extends Repository
                         WHERE user_id = :user_id
                     ) THEN TRUE
                     ELSE FALSE
-                END AS like_status
+                END AS liked
             FROM
                 watchlists
             WHERE
@@ -159,18 +201,32 @@ class WatchlistRepository extends Repository
             JOIN (SELECT * FROM watchlist_items WHERE rank < 5) AS wi ON wi.watchlist_id = w.id
             JOIN catalogs AS c ON c.id = wi.catalog_id
         ";
-
-
-        $selectQuery = "SELECT  w.id AS watchlist_id, json_agg(json_build_object(
+        $selectFirstQuery = "
+        WITH first_agg AS (
+        SELECT w.id AS watchlist_id, jsonb_agg(jsonb_build_object(
             'rank', rank,
             'poster', poster,
             'catalog_uuid', c.uuid
-            )) AS posters, w.uuid AS watchlist_uuid, name AS creator, u.uuid AS creator_uuid, item_count, like_status, w.title, w.description, w.category, visibility, like_count, w.updated_at AS updated_at, w.created_at AS created_at ";
-
+            )) AS posters, w.uuid AS watchlist_uuid, name AS creator, u.uuid AS creator_uuid, item_count, liked, w.title, w.description, w.category, visibility, like_count, w.updated_at AS updated_at, w.created_at AS created_at";
+        $selectSecondQuery = "
+            )
+            SELECT 
+                jsonb_agg(jsonb_build_object(
+                'id', t.id,
+                'name', t.name
+                )) AS tags, fa.watchlist_id, fa.posters as posters, fa.watchlist_uuid, fa.creator, fa.creator_uuid, fa.item_count, fa.liked, fa.title, fa.description, fa.category, fa.visibility, fa.like_count, fa.created_at
+            FROM first_agg AS fa
+            LEFT JOIN watchlist_tag as wt ON wt.watchlist_id = fa.watchlist_id
+            LEFT JOIN tags as t ON t.id = wt.tag_id
+            GROUP BY
+                fa.watchlist_id, fa.watchlist_uuid, fa.posters, fa.creator, fa.creator_uuid, fa.item_count, fa.liked, fa.title, fa.description, fa.category, fa.visibility, fa.like_count, fa.created_at
+            ORDER BY
+                fa.created_at DESC
+        ";
         $pageCountQuery = "SELECT COUNT(*) ";
 
-        $selectStatement = $this->connection->prepare($selectQuery . $query . "GROUP BY
-        watchlist_id, watchlist_uuid, creator, u.uuid, w.title, w.uuid, name, item_count, like_status, w.id, w.description, w.category, visibility, like_count, w.updated_at, w.created_at;");
+        $selectStatement = $this->connection->prepare($selectFirstQuery . $query . "GROUP BY
+        watchlist_id, watchlist_uuid, creator, u.uuid, w.title, w.uuid, u.name, item_count, liked, w.id, w.description, w.category, visibility, like_count, w.updated_at, w.created_at" . $selectSecondQuery);
         $selectStatement->bindValue(':user_id', $userId, PDO::PARAM_INT);
         $selectStatement->bindValue(':limit', $pageSize, PDO::PARAM_INT);
         $offset = ($page - 1) * $pageSize;
@@ -204,17 +260,18 @@ class WatchlistRepository extends Repository
     public function findByUUID(string $uuid, int|null $user_id, int $page = 1, int $pageSize = 10)
     {
         $selectQuery = "
+        WITH first_agg AS (
         WITH w AS (
             SELECT
-                id, uuid, title, description, category, visibility, like_count, item_count, user_id, updated_at " .
-            ($user_id === null ? "" : ", CASE
+                id, uuid, title, description, category, visibility, like_count, item_count, user_id, created_at
+                ,CASE
                     WHEN id IN (
                         SELECT watchlist_id
                         FROM watchlist_like
                         WHERE user_id = :user_id
                     ) THEN TRUE
                     ELSE FALSE
-                END AS like_status,
+                END AS liked,
                 CASE
                     WHEN id IN (
                         SELECT watchlist_id
@@ -222,13 +279,14 @@ class WatchlistRepository extends Repository
                         WHERE user_id = :user_id
                     ) THEN TRUE
                     ELSE FALSE
-                END AS save_status ") . "
+                END AS saved
             FROM
                 watchlists
             WHERE
                 watchlists.uuid = :uuid
-            LIMIT 1)
-        SELECT w.id AS watchlist_id, json_agg(json_build_object(
+            LIMIT 1
+            )
+        SELECT w.id AS watchlist_id, jsonb_agg(jsonb_build_object(
             'rank', rank,
             'poster', poster,
             'catalog_uuid', c.uuid,
@@ -236,14 +294,28 @@ class WatchlistRepository extends Repository
             'description', wi.description,
             'title', c.title,
             'category', c.category
-            )) AS catalogs, w.uuid AS watchlist_uuid, name AS creator, item_count, w.title, w.description, w.category, visibility, like_count, w.updated_at AS updated_at, u.uuid AS creator_uuid"
-            . ($user_id === null ? "" : ", like_status, save_status") . "
+            )) AS catalogs, w.uuid AS watchlist_uuid, name AS creator, item_count, w.title, w.description, w.category, visibility, like_count, w.created_at, u.uuid AS creator_uuid
+            ,liked, saved
         FROM w JOIN users AS u ON w.user_id = u.id
             , (SELECT * FROM watchlist_items WHERE watchlist_id IN (SELECT id FROM w) ORDER BY rank LIMIT :limit OFFSET :offset) AS wi
             JOIN catalogs AS c ON c.id = wi.catalog_id
             GROUP BY
-            watchlist_id, watchlist_uuid, creator, w.title, w.uuid, name, item_count, w.id, w.description, w.category, visibility, like_count, w.updated_at, u.uuid"
-            . ($user_id === null ? "" : ", like_status, save_status ");
+            watchlist_id, watchlist_uuid, creator, w.title, w.uuid, name, item_count, w.id, w.description, w.category, visibility, like_count, w.created_at, u.uuid
+            ,liked, saved
+        ) 
+        SELECT 
+            jsonb_agg(jsonb_build_object(
+            'id', t.id,
+            'name', t.name
+            )) AS tags, fa.watchlist_id, fa.catalogs, fa.watchlist_uuid, fa.creator, fa.creator_uuid, fa.item_count, fa.liked, fa.saved, fa.title, fa.description, fa.category, fa.visibility, fa.like_count, fa.created_at
+        FROM first_agg AS fa
+        LEFT JOIN watchlist_tag as wt ON wt.watchlist_id = fa.watchlist_id
+        LEFT JOIN tags as t ON t.id = wt.tag_id
+        GROUP BY
+            fa.watchlist_id, fa.watchlist_uuid, fa.catalogs, fa.creator, fa.creator_uuid, fa.item_count, fa.liked, fa.saved, fa.title, fa.description, fa.category, fa.visibility, fa.like_count, fa.created_at
+        ORDER BY
+            fa.created_at DESC
+        ";
 
         $pageCountQuery = "
         SELECT COUNT(*) 
@@ -258,21 +330,16 @@ class WatchlistRepository extends Repository
             JOIN catalogs AS c ON c.id = wi.catalog_id
         ";
 
-
         $selectStatement = $this->connection->prepare($selectQuery);
-        $selectStatement->bindValue(':uuid', $uuid, PDO::PARAM_STR);
-        $selectStatement->bindValue(':limit', $pageSize, PDO::PARAM_INT);
+        $selectStatement->bindParam(':uuid', $uuid, PDO::PARAM_STR);
+        $selectStatement->bindParam(':limit', $pageSize, PDO::PARAM_INT);
         $offset = ($page - 1) * $pageSize;
-        $selectStatement->bindValue(':offset', $offset, PDO::PARAM_INT);
-        if (!empty($user_id)) {
-            $selectStatement->bindValue(':user_id', $user_id, PDO::PARAM_INT);
-        }
+        $selectStatement->bindParam(':offset', $offset, PDO::PARAM_INT);
+        $selectStatement->bindParam(':user_id', $user_id, PDO::PARAM_INT);
+
 
         $pageCountStatement = $this->connection->prepare($pageCountQuery);
-        $pageCountStatement->bindValue(':uuid', $uuid, PDO::PARAM_STR);
-        if (!empty($user_id)) {
-            $pageCountStatement->bindValue(':user_id', $user_id, PDO::PARAM_INT);
-        }
+        $pageCountStatement->bindParam(':uuid', $uuid, PDO::PARAM_STR);
 
         $selectStatement->execute();
         $pageCountStatement->execute();
@@ -286,7 +353,12 @@ class WatchlistRepository extends Repository
             $totalPage = $pageSize > 0 ? ceil($pageCountStatement->fetchColumn() / $pageSize) : 1;
             if ($rows = $selectStatement->fetch()) {
                 $catalogs = json_decode($rows["catalogs"], true);
+                $tags = json_decode($rows["tags"], true);
+                $tags = array_filter($tags, function ($value) {
+                    return $value["id"] !== null;
+                });
                 usort($catalogs, "catalogCompare");
+                $rows["tags"] = $tags;
 
                 $rows["catalogs"] = [
                     "items" => $catalogs,
diff --git a/src/server/app/Repository/WatchlistSaveRepository.php b/src/server/app/Repository/WatchlistSaveRepository.php
index 40df0057f25450503706a051e328ccd2418ea5e8..cc9778ade84217ec89b3a53ab25c03da41471059 100644
--- a/src/server/app/Repository/WatchlistSaveRepository.php
+++ b/src/server/app/Repository/WatchlistSaveRepository.php
@@ -9,6 +9,108 @@ class WatchlistSaveRepository extends Repository
         parent::__construct($connection);
     }
 
+    public function findByUser(string $userId, int $page, int $pageSize)
+    {
+        $selectQuery = "
+        WITH first_agg AS (
+            SELECT
+                w.id AS watchlist_id,
+                jsonb_agg(
+                    jsonb_build_object(
+                        'rank', rank,
+                        'poster', poster,
+                        'catalog_uuid', c.uuid
+                    )
+                ) AS posters,
+                w.uuid AS watchlist_uuid, name AS creator, u.uuid AS creator_uuid, item_count,
+                liked, w.title, w.description, w.category, visibility, 
+                like_count, w.created_at AS created_at, w.updated_at AS updated_at
+            FROM
+                (
+                SELECT
+                    w.id, uuid, title, description, category, 
+                    visibility, like_count, item_count, w.user_id, 
+                    created_at, updated_at, 
+                    CASE WHEN w.id IN(
+                        SELECT watchlist_id
+                        FROM watchlist_like
+                        WHERE user_id = :user_id
+                    ) THEN TRUE ELSE FALSE
+                    END AS liked
+                FROM watchlists w
+                JOIN watchlist_save wv ON
+                    w.id = wv.watchlist_id
+                WHERE wv.user_id = :user_id
+                LIMIT :limit 
+                OFFSET :offset
+            ) AS w
+            JOIN users AS u ON
+                w.user_id = u.id
+            JOIN(
+                SELECT *
+                FROM watchlist_items
+                WHERE rank < 5
+            ) AS wi
+            ON wi.watchlist_id = w.id
+            JOIN catalogs AS c
+            ON c.id = wi.catalog_id
+            GROUP BY w.id, w.uuid, creator,
+                w.title, name, u.uuid, item_count, liked, w.description,
+                w.category, visibility, like_count, w.created_at, w.updated_at
+        )
+        SELECT 
+            jsonb_agg(jsonb_build_object(
+            'id', t.id,
+            'name', t.name
+            )) AS tags, fa.watchlist_id, fa.posters as posters, fa.watchlist_uuid, fa.creator, fa.creator_uuid, fa.item_count, fa.liked, fa.title, fa.description, fa.category, fa.visibility, fa.like_count, fa.created_at
+        FROM first_agg AS fa
+        LEFT JOIN watchlist_tag as wt ON wt.watchlist_id = fa.watchlist_id
+        LEFT JOIN tags as t ON t.id = wt.tag_id
+        GROUP BY
+            fa.watchlist_id, fa.watchlist_uuid, fa.posters, fa.creator, fa.creator_uuid, fa.item_count, fa.liked, fa.title, fa.description, fa.category, fa.visibility, fa.like_count, fa.created_at
+        ORDER BY
+            fa.created_at DESC
+        ";
+
+        $pageCountQuery = "
+            SELECT COUNT(*)
+            FROM (
+                SELECT w.id, w.user_id
+                FROM watchlists w 
+                JOIN watchlist_save wv 
+                ON w.id = wv.watchlist_id
+                WHERE wv.user_id = :user_id
+            ) AS w JOIN users AS u 
+            ON w.user_id = u.id
+            JOIN (SELECT * FROM watchlist_items WHERE rank < 5) AS wi ON wi.watchlist_id = w.id
+            JOIN catalogs AS c ON c.id = wi.catalog_id   
+        ";
+
+        $selectStatement = $this->connection->prepare($selectQuery);
+        $selectStatement->bindParam(":user_id", $userId, PDO::PARAM_INT);
+        $selectStatement->bindParam(":limit", $pageSize, PDO::PARAM_INT);
+        $selectStatement->bindValue(":offset", ($page - 1) * $pageSize, PDO::PARAM_INT);
+        $selectStatement->execute();
+
+        $pageCountStatement = $this->connection->prepare($pageCountQuery);
+        $pageCountStatement->bindParam(":user_id", $userId, PDO::PARAM_INT);
+        $pageCountStatement->execute();
+
+        try {
+            $result = $selectStatement->fetchAll(PDO::FETCH_ASSOC);
+            $pageCount = $pageCountStatement->fetchColumn();
+
+            return [
+                'items' => $result,
+                'page' => max(1, $page),
+                'totalPage' => $pageSize > 0 ? ceil($pageCount / $pageSize) : 1
+            ];
+        } finally {
+            $selectStatement->closeCursor();
+            $pageCountStatement->closeCursor();
+        }
+    }
+
     public function saveByWatchlistAndUser(string $watchlistId, string $userId)
     {
         $statement = $this->connection->prepare("INSERT INTO $this->table (watchlist_id, user_id) VALUES (:watchlist_id, :user_id)");
diff --git a/src/server/app/Repository/WatchlistTagRepository.php b/src/server/app/Repository/WatchlistTagRepository.php
new file mode 100644
index 0000000000000000000000000000000000000000..6e30dbc467ea439fbff7961932eaae4eb4bf98fc
--- /dev/null
+++ b/src/server/app/Repository/WatchlistTagRepository.php
@@ -0,0 +1,13 @@
+<?php
+
+require_once __DIR__ . '/../App/Repository.php';
+
+class WatchlistTagRepository extends Repository
+{
+    protected string $table = "watchlist_tag";
+
+    public function __construct(PDO $connection)
+    {
+        parent::__construct($connection);
+    }
+}
\ No newline at end of file
diff --git a/src/server/app/Service/BookmarkService.php b/src/server/app/Service/BookmarkService.php
new file mode 100644
index 0000000000000000000000000000000000000000..077f6d58632999d112ab53897974f600af96e1d0
--- /dev/null
+++ b/src/server/app/Service/BookmarkService.php
@@ -0,0 +1,26 @@
+<?php
+require_once __DIR__ . '/../Config/Database.php';
+require_once __DIR__ . '/../Exception/ValidationException.php';
+require_once __DIR__ . '/../Utils/UUIDGenerator.php';
+
+require_once __DIR__ . '/../Domain/WatchlistSave.php';
+
+require_once __DIR__ . '/../Repository/WatchlistSaveRepository.php';
+
+require_once __DIR__ . '/../Model/bookmark/BookmarkGetRequest.php';
+
+class BookmarkService
+{
+    private WatchlistSaveRepository $watchlistSaveRepository;
+
+    public function __construct(WatchlistSaveRepository $watchlistSaveRepository)
+    {
+        $this->watchlistSaveRepository = $watchlistSaveRepository;
+    }
+
+    public function findByUser(BookmarkGetRequest $request)
+    {
+        $result = $this->watchlistSaveRepository->findByUser($request->userId, $request->page, $request->pageSize);
+        return $result;
+    }
+}
\ No newline at end of file
diff --git a/src/server/app/Service/CatalogService.php b/src/server/app/Service/CatalogService.php
index 32e82b83f3d9c05539d8e6a52b27660d439c6046..cc946570077ff8180b671de4511eea67f0983195 100644
--- a/src/server/app/Service/CatalogService.php
+++ b/src/server/app/Service/CatalogService.php
@@ -6,6 +6,7 @@ require_once __DIR__ . '/../Utils/FileUploader.php';
 require_once __DIR__ . '/../Utils/UUIDGenerator.php';
 
 require_once __DIR__ . '/../Model/CatalogCreateRequest.php';
+require_once __DIR__ . '/../Model/catalog/CatalogUpdateRequest.php';
 require_once __DIR__ . '/../Model/CatalogSearchRequest.php';
 
 require_once __DIR__ . '/../Model/CatalogCreateResponse.php';
@@ -48,7 +49,12 @@ class CatalogService
 
     public function deleteByUUID(string $uuid): void
     {
-        $this->catalogRepository->deleteBy('uuid', $uuid);
+        $catalog = $this->catalogRepository->findOne('uuid', $uuid);
+        if ($catalog) {
+            $this->catalogRepository->deleteBy('uuid', $uuid);
+        } else {
+            throw new ValidationException("Catalog not found.");
+        }
     }
 
     public function deleteById(int $id): void
@@ -111,12 +117,18 @@ class CatalogService
         }
     }
 
-    public function update(string $uuid, CatalogCreateRequest $request)
+    public function update(CatalogUpdateRequest $request)
     {
+        $this->validateCatalogUpdateRequest($request);
+
         try {
             Database::beginTransaction();
 
-            $catalog = $this->catalogRepository->findOne('uuid', $uuid);
+            $catalog = $this->catalogRepository->findOne('uuid', $request->uuid);
+
+            if (!$catalog) {
+                throw new ValidationException("Catalog not found.");
+            }
 
             $catalog->title = trim($request->title);
             $catalog->description = trim($request->description);
@@ -147,6 +159,23 @@ class CatalogService
         }
     }
 
+    private function validateCatalogUpdateRequest(CatalogUpdateRequest $request)
+    {
+        if ($request->uuid == null || trim($request->uuid) == "") {
+            throw new ValidationException("UUID cannot be blank.");
+        }
+
+        if (
+            $request->title == null || trim($request->title) == ""
+        ) {
+            throw new ValidationException("Title cannot be blank.");
+        }
+
+        if ($request->category == null || trim($request->category) == "") {
+            throw new ValidationException("Category cannot be blank.");
+        }
+    }
+
     public function search(CatalogSearchRequest $catalogSearchRequest): CatalogSearchResponse
     {
         $this->validateCatalogSearchRequest($catalogSearchRequest);
diff --git a/src/server/app/Service/TagService.php b/src/server/app/Service/TagService.php
new file mode 100644
index 0000000000000000000000000000000000000000..7923586703f3b12646372e74bfde5db0017e2bde
--- /dev/null
+++ b/src/server/app/Service/TagService.php
@@ -0,0 +1,19 @@
+<?php
+
+class TagService
+{
+    private TagRepository $tagRepository;
+
+    public function __construct(TagRepository $tagRepository)
+    {
+        $this->tagRepository = $tagRepository;
+    }
+
+    public function findAll()
+    {
+        $query = $this->tagRepository->query();
+        $projection = ["id", "name"];
+        $tags = $query->get($projection, 1, 100);
+        return $tags;
+    }
+}
\ No newline at end of file
diff --git a/src/server/app/Service/UserService.php b/src/server/app/Service/UserService.php
index 8da2aa77f29f4c236668e63e75f4d5dc93db25a8..f3f768014bead8cdcd6e7dcc393e3819b7939d40 100644
--- a/src/server/app/Service/UserService.php
+++ b/src/server/app/Service/UserService.php
@@ -135,9 +135,10 @@ class UserService
         }
     }
 
-    public function validateEditProfileRequest(UserEditRequest $request)
+    public function validateEditProfileRequest(User $currentuser, UserEditRequest $request)
     {
-        if (($request->oldPassword == null || trim($request->oldPassword) == "")
+        if (
+            ($request->oldPassword == null || trim($request->oldPassword) == "")
             && ($request->newPassword == null || trim($request->newPassword) == "")
             && ($request->name == null || trim($request->name == ""))
         ) {
@@ -168,7 +169,8 @@ class UserService
             throw new ValidationException("Old password cannot be blank.");
         }
 
-        if ((!($request->oldPassword == null || trim($request->oldPassword) == "")
+        if (
+            (!($request->oldPassword == null || trim($request->oldPassword) == "")
                 && !($request->newPassword == null || trim($request->newPassword) == "")) &&
             ($request->oldPassword == $request->newPassword)
         ) {
@@ -183,19 +185,18 @@ class UserService
         }
     }
 
-
-
     public function findByEmail(string $email): User
     {
-        return $this->userRepository->findByEmail($email);
+        return $this->userRepository->findOne('email', $email);
     }
 
     public function deleteByEmail(string $email)
     {
-        $this->userRepository->deleteByEmail($email);
+        $this->userRepository->deleteBy('email', $email);
     }
+
     public function deleteBySession(string $email)
     {
         $this->userRepository->deleteBySession($email);
     }
-}
+}
\ No newline at end of file
diff --git a/src/server/app/Service/WatchlistService.php b/src/server/app/Service/WatchlistService.php
index 3cc443af292c809d900ef8d3300a7cc9efaa535a..5ccd7f52c4a1a64095792ee98e91c86b347ca398 100644
--- a/src/server/app/Service/WatchlistService.php
+++ b/src/server/app/Service/WatchlistService.php
@@ -6,18 +6,21 @@ require_once __DIR__ . '/../Utils/UUIDGenerator.php';
 require_once __DIR__ . '/../Domain/Watchlist.php';
 require_once __DIR__ . '/../Domain/WatchlistItem.php';
 require_once __DIR__ . '/../Domain/WatchlistLike.php';
+require_once __DIR__ . '/../Domain/WatchlistTag.php';
 
 require_once __DIR__ . '/../Repository/WatchlistRepository.php';
 require_once __DIR__ . '/../Repository/WatchlistItemRepository.php';
 require_once __DIR__ . '/../Repository/WatchlistLikeRepository.php';
+require_once __DIR__ . '/../Repository/WatchlistTagRepository.php';
 
 require_once __DIR__ . '/../Model/WatchlistsGetRequest.php';
 require_once __DIR__ . '/../Model/WatchlistCreateRequest.php';
-require_once __DIR__ . '/../Model/watchlist/WatchlistGetSelfRequest.php';
+require_once __DIR__ . '/../Model/watchlist/WatchlistGetOneByUserRequest.php';
 require_once __DIR__ . '/../Model/watchlist/WatchlistLikeRequest.php';
 require_once __DIR__ . '/../Model/watchlist/WatchlistSaveRequest.php';
 require_once __DIR__ . '/../Model/watchlist/WatchlistGetOneRequest.php';
 require_once __DIR__ . '/../Model/watchlist/WatchlistEditRequest.php';
+require_once __DIR__ . '/../Model/watchlist/WatchlistDeleteRequest.php';
 
 class WatchlistService
 {
@@ -25,13 +28,15 @@ class WatchlistService
     private WatchlistItemRepository $watchlistItemRepository;
     private WatchlistLikeRepository $watchlistLikeRepository;
     private WatchlistSaveRepository $watchlistSaveRepository;
+    private WatchlistTagRepository $watchlistTagRepository;
 
-    public function __construct(WatchlistRepository $watchlistRepository, WatchlistItemRepository $watchlistItemRepository, WatchlistLikeRepository $watchlistLikeRepository, WatchlistSaveRepository $watchlistSaveRepository)
+    public function __construct(WatchlistRepository $watchlistRepository, WatchlistItemRepository $watchlistItemRepository, WatchlistLikeRepository $watchlistLikeRepository, WatchlistSaveRepository $watchlistSaveRepository, WatchlistTagRepository $watchlistTagRepository)
     {
         $this->watchlistRepository = $watchlistRepository;
         $this->watchlistItemRepository = $watchlistItemRepository;
         $this->watchlistLikeRepository = $watchlistLikeRepository;
         $this->watchlistSaveRepository = $watchlistSaveRepository;
+        $this->watchlistTagRepository = $watchlistTagRepository;
     }
 
 
@@ -72,18 +77,27 @@ class WatchlistService
             // save the items
             $currRank = 1;
             foreach ($watchlistCreateRequest->items as $item) {
-                $watchlist_item = new WatchlistItem();
-                $watchlist_item->uuid = UUIDGenerator::uuid4();
-                $watchlist_item->rank = $currRank;
-                $watchlist_item->description = $item["description"];
-                $watchlist_item->watchlistId = $watchlistNew->id;
-                $watchlist_item->catalogId = $item["id"];
+                $watchlistItem = new WatchlistItem();
+                $watchlistItem->uuid = UUIDGenerator::uuid4();
+                $watchlistItem->rank = $currRank;
+                $watchlistItem->description = $item["description"];
+                $watchlistItem->watchlistId = $watchlistNew->id;
+                $watchlistItem->catalogId = $item["id"];
 
-                $this->watchlistItemRepository->save($watchlist_item);
+                $this->watchlistItemRepository->save($watchlistItem);
 
                 $currRank++;
             }
 
+            // save the tags
+            foreach ($watchlistCreateRequest->tags as $tag) {
+                $watchlistTag = new WatchlistTag();
+                $watchlistTag->tagId = $tag["id"];
+                $watchlistTag->watchlistId = $watchlist->id;
+
+                $this->watchlistTagRepository->save($watchlistTag);
+            }
+
             Database::commitTransaction();
         } catch (\Exception $exception) {
             Database::rollbackTransaction();
@@ -144,6 +158,18 @@ class WatchlistService
                 $currRank++;
             }
 
+            // delete all tags with corresponding watchlistId
+            $this->watchlistTagRepository->deleteBy("watchlist_id", $watchlistNew->id);
+
+            // save the tags
+            foreach ($watchlistEditRequest->tags as $tag) {
+                $watchlistTag = new WatchlistTag();
+                $watchlistTag->tagId = $tag["id"];
+                $watchlistTag->watchlistId = $watchlist->id;
+
+                $this->watchlistTagRepository->save($watchlistTag);
+            }
+
             Database::commitTransaction();
         } catch (\Exception $exception) {
             Database::rollbackTransaction();
@@ -162,29 +188,32 @@ class WatchlistService
         if (!isset($watchlistsGetRequest->sortBy) || !in_array(strtoupper(trim($watchlistsGetRequest->sortBy)), ["DATE", "LOVE"])) {
             $watchlistsGetRequest->sortBy = "LOVE";
         }
+        if (!isset($watchlistsGetRequest->tag) || !in_array(strtoupper(trim($watchlistsGetRequest->tag)), $watchlistsGetRequest->tagsInit)) {
+            $watchlistsGetRequest->tag = "";
+        }
 
         if ($watchlistsGetRequest->sortBy == "LOVE")
             $watchlistsGetRequest->sortBy = "love_count";
         if ($watchlistsGetRequest->sortBy == "DATE")
             $watchlistsGetRequest->sortBy = "w.created_at";
 
-        $result = $this->watchlistRepository->findAllCustom($watchlistsGetRequest->userId, $watchlistsGetRequest->search, $watchlistsGetRequest->category, $watchlistsGetRequest->sortBy, $watchlistsGetRequest->order, $watchlistsGetRequest->page, 2);
+        $result = $this->watchlistRepository->findAllCustom($watchlistsGetRequest->userId, $watchlistsGetRequest->search, $watchlistsGetRequest->category, $watchlistsGetRequest->sortBy, $watchlistsGetRequest->order, $watchlistsGetRequest->tag, $watchlistsGetRequest->page, 2);
         return $result;
     }
 
-    public function findUserBookmarks(WatchlistsGetSelfRequest $request)
+    public function findByUser(WatchlistGetOneByUserRequest $request)
     {
         if (!isset($request->visibility) || !in_array(strtoupper(trim($request->visibility)), ["ALL", "PUBLIC", "PRIVATE"]) || strtoupper($request->visibility) == "ALL") {
             $request->visibility = "";
         }
 
-        $result = $this->watchlistRepository->findUserBookmarks(1, strtoupper($request->visibility), 1, 10);
+        $result = $this->watchlistRepository->findByUser($request->userId, strtoupper($request->visibility), 1, 10);
         return $result;
     }
 
     public function findByUUID(WatchlistsGetOneRequest $request)
     {
-        $result = $this->watchlistRepository->findByUUID($request->uuid, null, $request->page, $request->pageSize);
+        $result = $this->watchlistRepository->findByUUID($request->uuid, $request->userId, $request->page, $request->pageSize);
         return $result;
     }
 
@@ -245,27 +274,50 @@ class WatchlistService
         }
     }
 
+    public function deleteByUUID(WatchlistDeleteRequest $watchlistDeleteRequest)
+    {
+        $this->watchlistRepository->deleteBy("uuid", $watchlistDeleteRequest->watchlistUUID);
+    }
+
     private function validateWatchlistCreateEditRequest(WatchlistCreateRequest|WatchlistEditRequest $watchlistCreateUpdateRequest)
     {
         if (!isset($watchlistCreateUpdateRequest->title) || trim($watchlistCreateUpdateRequest->title) == "") {
-            throw new ValidationException("Title is required");
+            throw new ValidationException("Title is required.");
+        }
+        if (strlen($watchlistCreateUpdateRequest->title) > 40) {
+            throw new ValidationException("Title is too long. Maximum 40 chars.");
         }
         if (!isset($watchlistCreateUpdateRequest->visibility) || !in_array($watchlistCreateUpdateRequest->visibility, ["PUBLIC", "PRIVATE"])) {
-            throw new ValidationException("Invalid visibility");
+            throw new ValidationException("Visibility is invalid.");
         }
         if (isset($watchlistCreateUpdateRequest->description) && strlen($watchlistCreateUpdateRequest->description) > 255) {
-            throw new ValidationException("Description is too long. Maximum 255 characters");
+            throw new ValidationException("Description is too long. Maximum 255 characters.");
         }
         if (!isset($watchlistCreateUpdateRequest->items) || count($watchlistCreateUpdateRequest->items) == 0) {
-            throw new ValidationException("Watchlist must contain 1 item");
+            throw new ValidationException("Watchlist must contain 1 item.");
         }
         if (count($watchlistCreateUpdateRequest->items) > 50) {
-            throw new ValidationException("Watchlist contains maximum 50 items");
+            throw new ValidationException("Too many items. Maximum 50 items.");
         }
 
         foreach ($watchlistCreateUpdateRequest->items ?? [] as $item) {
             if (strlen($item["description"]) > 255) {
-                throw new ValidationException("Item description for" . $item["title"] . "is too long. Maximum 255 characters.");
+                throw new ValidationException("Description is too long for item ${item["title"]}. Maximum 255 chars.");
+            }
+        }
+
+        $selectedTags = [];
+        foreach ($watchlistCreateUpdateRequest->tags ?? [] as $tag) {
+            $found = false;
+            foreach ($watchlistCreateUpdateRequest->initialTags ?? [] as $initTag) {
+                if ($tag["id"] == $initTag->id && !in_array($initTag->id, $selectedTags)) {
+                    array_push($selectedTags, $initTag->id);
+                    $found = true;
+                    break;
+                }
+            }
+            if (!$found) {
+                throw new ValidationException("Tags is invalid.");
             }
         }
     }
diff --git a/src/server/app/View/catalog/detail.php b/src/server/app/View/catalog/detail.php
index 55f0514e9f9bcea5898156ee75884dc7bb8afbee..181a5cba49a09829da9b10b8b3f0fbbf5e680155 100644
--- a/src/server/app/View/catalog/detail.php
+++ b/src/server/app/View/catalog/detail.php
@@ -1,60 +1,42 @@
 <?php
-$data = $model['data']
+$catalog = $model['data']['item'];
+$userRole = $model['data']['userRole'];
 ?>
 
 <main>
     <div class="catalog-detail-header">
         <div class="catalog-detail-header-poster"></div>
-        <img class="poster" src="<?= '/assets/images/catalogs/posters/' . $data['poster'] ?>"
-             alt="<?= 'Poster of ' . $data['title'] ?>">
+        <img class="poster" src="<?= '/assets/images/catalogs/posters/' . $catalog['poster'] ?>"
+            alt="<?= 'Poster of ' . $catalog['title'] ?>">
     </div>
     <article class="catalog-detail-content">
         <h2>
-            <?= $data['title'] ?>
+            <?= $catalog['title'] ?>
         </h2>
         <div class="tag">
-            <?= $data['category'] ?>
+            <?= $catalog['category'] ?>
         </div>
         <p>
-            <?= $data['description'] ?? "No description" ?>
+            <?= (!isset($catalog['description']) || empty($catalog['description'])) ? "No description" : $catalog['description'] ?>
         </p>
-        <?php if (isset($data['trailer']) && $data['trailer'] !== null): ?>
+        <?php if (isset($catalog['trailer']) && $catalog['trailer'] !== null): ?>
             <h3>Trailer</h3>
             <video class="catalog-trailer" controls>
-                <source src="<?= '/assets/videos/catalogs/trailers/' . $data['trailer'] ?>" type="video/mp4">
+                <source src="<?= '/assets/videos/catalogs/trailers/' . $catalog['trailer'] ?>" type="video/mp4">
             </video>
         <?php endif; ?>
     </article>
-    <div class="button-container">
-        <a href="/catalog/<?= $data['uuid'] ?>/edit" id="edit" aria-label="Edit <?= $data['title'] ?>" class="btn-icon">
-            <?php require PUBLIC_PATH . 'assets/icons/edit.php' ?>
-        </a>
-        <button type="submit" aria-label="Delete <?= $data['title'] ?>" class="dialog-trigger btn-icon">
-            <?php require PUBLIC_PATH . 'assets/icons/trash.php' ?>
-        </button>
-    </div>
-</main>
-
-
-<div class="dialog hidden">
-    <div class="dialog__content">
-        <h2>
-            Delete Catalog
-        </h2>
-        <p>
-            Are you sure you want to delete <span class="dialog-title">
-                <?= $data['title'] ?>
-            </span>?
-        </p>
-        <div class="dialog__button-container">
-            <button id="cancel">
-                Cancel
+    <?php if ($userRole && $userRole === "ADMIN"): ?>
+        <div class="button-container">
+            <a href="/catalog/<?= $catalog['uuid'] ?>/edit" id="edit" aria-label="Edit <?= $catalog['title'] ?>"
+                class="btn-icon">
+                <?php require PUBLIC_PATH . 'assets/icons/edit.php' ?>
+            </a>
+            <button id="delete-trigger" type="submit" data-uuid="<?= $catalog['uuid'] ?>"
+                data-title="<?= $catalog['title'] ?>" aria-label="Delete <?= $catalog['title'] ?>"
+                class="catalog-delete-trigger dialog-trigger btn-icon">
+                <?php require PUBLIC_PATH . 'assets/icons/trash.php' ?>
             </button>
-            <form action="/catalog/<?= $model['data']['uuid'] ?>/delete" method="POST">
-                <button id="delete" class="btn-bold" type="submit">
-                    Delete
-                </button>
-            </form>
         </div>
-    </div>
-</div>
\ No newline at end of file
+    <?php endif; ?>
+</main>
\ No newline at end of file
diff --git a/src/server/app/View/catalog/edit.php b/src/server/app/View/catalog/edit.php
new file mode 100644
index 0000000000000000000000000000000000000000..5525bd2a388515ec66156535ae217a649f37738b
--- /dev/null
+++ b/src/server/app/View/catalog/edit.php
@@ -0,0 +1,52 @@
+<?php function selectCategory($selected)
+{
+    $id = 'category';
+    $placeholder = 'Select Category';
+    $content = [
+        "DRAMA",
+        "ANIME"
+    ];
+    require __DIR__ . '/../components/select.php';
+}
+?>
+
+<main>
+    <h2>
+        <?= $model['title'] ?>
+    </h2>
+    <form id="catalog-edit-form" enctype="multipart/form-data">
+        <div class="input-group">
+            <label class="input-required">Category</label>
+            <?php selectCategory($model['data']['category'] ?? 'ANIME'); ?>
+        </div>
+        <div class="input-group">
+            <label for="titleField" class="input-required">Title</label>
+            <input type="text" id="titleField" name="title" placeholder="Title"
+                value="<?= $model['data']['title'] ?? "" ?>" maxlength="40" required>
+        </div>
+        <div class="input-group">
+            <label for="descriptionField">Description</label>
+            <textarea placeholder="Enter description" name="description" id="descriptionField" maxlength="255"><?php if (isset($model['data'])) {
+                echo $model['data']['description'];
+            } ?></textarea>
+        </div>
+        <div class="input-group">
+            <label for="posterField" class="input-required">Poster</label>
+            <img class="poster" src="<?= '/assets/images/catalogs/posters/' . $model['data']['poster'] ?>"
+                alt="<?= 'Poster of ' . $model['data']['title'] ?>">
+            <input type="file" id="posterField" name="poster" accept="image/*">
+        </div>
+        <div class="input-group">
+            <?php if (isset($model['data']['trailer']) && $model['data']['trailer'] !== null): ?>
+                <video class="catalog-trailer" controls>
+                    <source src="<?= '/assets/videos/catalogs/trailers/' . $model['data']['trailer'] ?>" type="video/mp4">
+                </video>
+            <?php endif; ?>
+            <label for="trailerField">Trailer</label>
+            <input type="file" id="trailerField" name="trailer" accept="video/mp4">
+        </div>
+        <button id="edit" class="btn-bold" type="submit">
+            Edit
+        </button>
+    </form>
+</main>
\ No newline at end of file
diff --git a/src/server/app/View/catalog/form.php b/src/server/app/View/catalog/form.php
index 60f2a1794e6a3537aa1aabfd16c1461f17ddf7dc..20e49bd945603c37be56ec70c26c54dd29feef44 100644
--- a/src/server/app/View/catalog/form.php
+++ b/src/server/app/View/catalog/form.php
@@ -59,7 +59,7 @@ function alert($title, $message)
         </div>
         <div class="input-group">
             <label for="trailerField">Trailer</label>
-            <input type="file" id="trailerField" name="trailer" accept="trailer/mp4">
+            <input type="file" id="trailerField" name="trailer" accept="video/mp4">
         </div>
 
         <button class="btn-bold" type="submit">
diff --git a/src/server/app/View/catalog/index.php b/src/server/app/View/catalog/index.php
index 6bc19a3a652ab217e2a515e7b39970e97825de4a..a6df824829344d67024db762795792956b11baeb 100644
--- a/src/server/app/View/catalog/index.php
+++ b/src/server/app/View/catalog/index.php
@@ -11,7 +11,7 @@ function selectCategory($selected)
     require __DIR__ . '/../components/select.php';
 }
 
-function catalogCard(Catalog $catalog, bool $is_admin)
+function catalogCard(Catalog $catalog, bool $isAdmin = false)
 {
     $title = $catalog->title;
     $poster = $catalog->poster;
@@ -19,6 +19,7 @@ function catalogCard(Catalog $catalog, bool $is_admin)
     $description = $catalog->description;
     $uuid = $catalog->uuid;
     $id = $catalog->id;
+    $editable = $isAdmin;
     require __DIR__ . '/../components/card/catalogCard.php';
 }
 
@@ -38,12 +39,14 @@ function pagination(int $currentPage, int $totalPage)
                 Apply
             </button>
         </form>
-        <a href="/catalog/create" class="btn btn-bold">
-            <span class="icon-new">
-                <?php require PUBLIC_PATH . 'assets/icons/plus.php' ?>
-            </span>
-            Add Catalog
-        </a>
+        <?php if ($model['data']['userRole'] && $model['data']['userRole'] === "ADMIN"): ?>
+            <a href="/catalog/create" class="btn btn-bold">
+                <span class="icon-new">
+                    <?php require PUBLIC_PATH . 'assets/icons/plus.php' ?>
+                </span>
+                Add Catalog
+            </a>
+        <?php endif; ?>
     </section>
     <?php if (count($model['data']['catalogs']['items']) == 0): ?>
         <div class="no-item__container">
@@ -56,7 +59,7 @@ function pagination(int $currentPage, int $totalPage)
     <?php endif; ?>
     <section class="content">
         <?php foreach ($model['data']['catalogs']['items'] ?? [] as $catalog): ?>
-            <?php catalogCard($catalog, $model['is_admin']); ?>
+            <?php catalogCard($catalog, $model['data']['userRole'] && $model['data']['userRole'] === "ADMIN"); ?>
         <?php endforeach; ?>
         <?php pagination($model['data']['catalogs']['page'], $model['data']['catalogs']['totalPage']); ?>
     </section>
diff --git a/src/server/app/View/components/card/catalogCard.php b/src/server/app/View/components/card/catalogCard.php
index 977ff25398d303b4d2b4e7ea32ba2879c693fd47..7fd441154cc70666d2fac417cfbf7fbf08649446 100644
--- a/src/server/app/View/components/card/catalogCard.php
+++ b/src/server/app/View/components/card/catalogCard.php
@@ -1,8 +1,15 @@
+<?php
+if (!file_exists('assets/images/catalogs/posters/' . $poster)) {
+    $poster = 'no-poster.webp';
+}
+?>
+
 <div id="card-<?= $uuid ?>" class="card card-catalog">
     <div class="card-content">
         <a href="/catalog/<?= $uuid ?>">
-            <img width="86.4" height="128" src="<?= "/assets/images/catalogs/posters/" . $poster ?>" alt=<?= $title ?>
-                class="poster" alt="<?= $title ?>" />
+            <img width="86.4" height="128" onerror="this.src = '/assets/images/catalogs/posters/no-poster.webp'"
+                src="<?= "/assets/images/catalogs/posters/" . $poster ?>" alt=<?= $title ?> class="poster"
+                alt="<?= $title ?>" />
         </a>
         <div class="card-body">
             <a href="/catalog/<?= $uuid ?>">
@@ -18,38 +25,15 @@
             </p>
         </div>
     </div>
-    <?php if (isset($is_admin) && $is_admin): ?>
+    <?php if (isset($editable) && $editable): ?>
         <div class="card-button-container">
             <a aria-label="Edit <?= $title ?>" href="/catalog/<?= $uuid ?>/edit" id="edit-<?= $uuid ?>" class="btn-icon">
                 <?php require PUBLIC_PATH . 'assets/icons/edit.php' ?>
             </a>
-            <button aria-label="Delete <?= $title ?>" id="delete-<?= $uuid ?>" class="dialog-trigger btn-icon">
+            <button aria-label="Delete <?= $title ?>" id="delete-trigger-<?= $uuid ?>" data-uuid="<?= $uuid ?>"
+                data-title="<?= $title ?>" class="catalog-delete-trigger dialog-trigger btn-icon">
                 <?php require PUBLIC_PATH . 'assets/icons/trash.php' ?>
             </button>
         </div>
     <?php endif; ?>
-</div>
-
-<?php if (isset($is_admin) && $is_admin): ?>
-    <div id="dialog-<?= $uuid ?>" class="dialog hidden">
-        <div class="dialog__content">
-            <h2>
-                Delete Catalog
-            </h2>
-            <p>
-                Are you sure you want to delete
-                <?= $title ?>?
-            </p>
-            <div class="dialog__button-container">
-                <button id="cancel">
-                    Cancel
-                </button>
-                <form action="/catalog/<?= $uuid ?>/delete" method="POST">
-                    <button id="delete" class="btn-bold" type="submit">
-                        Delete
-                    </button>
-                </form>
-            </div>
-        </div>
-    </div>
-<?php endif; ?>
\ No newline at end of file
+</div>
\ No newline at end of file
diff --git a/src/server/app/View/components/card/watchlistCard.php b/src/server/app/View/components/card/watchlistCard.php
index c666174f56efe33977fd89c454a9b9ae8df9c43e..2ea3518bbb9cd92b8e075e2b394070408474bd8b 100644
--- a/src/server/app/View/components/card/watchlistCard.php
+++ b/src/server/app/View/components/card/watchlistCard.php
@@ -24,13 +24,19 @@ if (!function_exists("likeAndSave")) {
     <div class="card-content">
         <div class="list__poster">
             <?php for ($i = 0; $i < 4; $i++): ?>
-                <?php if (!isset($posters[3 - $i])): ?>
+                <?php
+                if (!isset($posters[3 - $i])): ?>
                     <div>
                         <img loading=<?= $loading ?? 'eager' ?>
                              src="<?= "/assets/images/catalogs/posters/" . (isset($posters[3 - $i]) ? $posters[3 - $i]["poster"] : "no-poster.webp") ?>"
                              alt="Anime or Drama Poster" class="poster"/>
                     </div>
                 <?php else: ?>
+                    <?php
+                    if (!file_exists('assets/images/catalogs/posters/' . $posters[3 - $i]['poster'])) {
+                        $posters[3 - $i]['poster'] = 'no-poster.webp';
+                    }
+                    ?>
                     <a href="/catalog<?= isset($posters[3 - $i]) ? "/" . $posters[3 - $i]["catalog_uuid"] : "" ?>">
                         <img loading=<?= $loading ?? 'eager' ?>
                              src="<?= "/assets/images/catalogs/posters/" . (isset($posters[3 - $i]) ? $posters[3 - $i]["poster"] : "no-poster.webp") ?>"
@@ -59,6 +65,9 @@ if (!function_exists("likeAndSave")) {
                     <span class="tag">
                         <?= $category ?>
                     </span>
+                    <?php for ($i = 0; $i < min(3, count($item["tags"])); $i++): ?>
+                        <span class="tag"><?= $item["tags"][$i]["name"] ?></span>
+                    <?php endfor; ?>
                     <span class="subtitle">by <span class="author-name">
                             <?= $creator ?>
                         </span></span>
@@ -66,6 +75,7 @@ if (!function_exists("likeAndSave")) {
                 <span class="subtitle">
                     <?= formatDate($createdAt); ?>
                 </span>
+
             </div>
             <p class="watchlist__description">
                 <?= $description ?>
diff --git a/src/server/app/View/components/header.php b/src/server/app/View/components/header.php
index a6f09da2b0a337652e6018341fad1c8dfccee3e9..7462e99aa2871161367df291d89f8bb259698110 100644
--- a/src/server/app/View/components/header.php
+++ b/src/server/app/View/components/header.php
@@ -4,7 +4,7 @@
 <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <meta name="description" content="<?= $description ?? '#1 Drama and Anime Watch List Website' ?>"/>
+    <meta name="description" content="<?= $description ?? '#1 Drama and Anime Watch List Website' ?>" />
 
     <title>
         <?= 'Drawl | ' . $model['title'] ?? '🌸' ?>
@@ -23,7 +23,7 @@
     <link rel="stylesheet" href="/css/components/modal.css">
     <link rel='stylesheet' href='/css/components/alert.css'> -->
 
-    <?php foreach ($model['styles'] ?? [] as $style) : ?>
+    <?php foreach ($model['styles'] ?? [] as $style): ?>
         <link rel='stylesheet' href='<?= $style ?>'>
     <?php endforeach; ?>
 
@@ -33,9 +33,8 @@
     <script type="text/javascript" src="/js/components/select.js" defer></script>
     <script type="text/javascript" src="/js/components/modal.js" defer></script>
     <script type='text/javascript' src='/js/components/alert.js' defer></script>
-    <script type='text/javascript' src='/js/components/dialog.js' defer></script>
 
-    <?php foreach ($model['js'] ?? [] as $js) : ?>
+    <?php foreach ($model['js'] ?? [] as $js): ?>
         <script type='text/javascript' src='<?= $js ?>' defer></script>
     <?php endforeach; ?>
 </head>
diff --git a/src/server/app/View/components/navbar.php b/src/server/app/View/components/navbar.php
index 9bde832c4e66a4a02c3b2d56bef14dfc551850fc..5238aabb8e4c4c5d20926492c95285af1a0c12cb 100644
--- a/src/server/app/View/components/navbar.php
+++ b/src/server/app/View/components/navbar.php
@@ -5,18 +5,26 @@
                 <a href='/' class="brand__title">Drawl</a>
             </div>
             <button aria-label="Open Menu" id="navbar-toggle" class="navbar-toggle" aria-expanded="false"
-                    aria-controls="navbar-menu">
+                aria-controls="navbar-menu">
                 <?php require PUBLIC_PATH . 'assets/icons/menu.php' ?>
             </button>
         </div>
         <div id="navbar-menu" class="navbar-menu collapsed" aria-labelledby="navbar-toggle">
             <a href="/" class="btn">Discover</a>
             <a href="/catalog" class="btn">Catalog</a>
-            <a href="/profile/watchlist" class="btn">My Watch List</a>
             <?php if ($user == null): ?>
                 <a href="/signin" class="btn">Sign In</a>
             <?php else: ?>
-                <a href="/profile" class="btn"><?= $user->name ?></a>
+                <button id="profile-menu-toggle" class="profile-icon" aria-label="Open Profile Dropdown"
+                    aria-expanded="false">
+                    <?php require PUBLIC_PATH . 'assets/icons/user.php' ?>
+                </button>
+                <div id="profile-menu" class="profile-menu collapsed" aria-labelledby="profile-menu-toggle">
+                    <a href="/profile" class="btn">Profile</a>
+                    <a href="/profile/watchlist" class="btn">My Watchlist</a>
+                    <a href="/profile/bookmark" class="btn">My Bookmark</a>
+                    <button id="logout" class="btn">Logout</button>
+                </div>
             <?php endif; ?>
         </div>
     </div>
diff --git a/src/server/app/View/components/toast.php b/src/server/app/View/components/toast.php
new file mode 100644
index 0000000000000000000000000000000000000000..03e0577a8e9e2cc3574585020d4d4949f1e024dc
--- /dev/null
+++ b/src/server/app/View/components/toast.php
@@ -0,0 +1,9 @@
+<div id="toast" class="toast hidden" data-type="error">
+    <div>
+        <h3></h3>
+        <p></p>
+    </div>
+    <button id="close" class="btn-ghost">
+        <?php require PUBLIC_PATH . "assets/icons/cancel.php" ?>
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/server/app/View/home/index.php b/src/server/app/View/home/index.php
index a9b44a3abdee57bdeb8345e926020b0e43414237..cffdcb3a89d6f213740e2a96c2abdd9dcd9f6e65 100644
--- a/src/server/app/View/home/index.php
+++ b/src/server/app/View/home/index.php
@@ -24,6 +24,16 @@ function sortBy()
     require __DIR__ . '/../components/select.php';
 }
 
+function tags($tags)
+{
+    $id = 'tag';
+    $placeholder = 'Select Tag';
+    $content = $tags;
+    $selected = validateQueryParams($id, $content);
+
+    require __DIR__ . '/../components/select.php';
+}
+
 function vallidateOrder(): ?string
 {
     if (!isset($_GET["order"]) || ($_GET["order"] != "asc" && $_GET["order"] != "desc"))
@@ -71,6 +81,7 @@ function pagination(int $currentPage, int $totalPage)
                    value="<?= trim($_GET['search'] ?? '') ?? '' ?>"/>
         </div>
         <div class="filter">
+            <?php tags($model["data"]["tags"]); ?>
             <?php selectCategory(); ?>
             <div class="filter__sort">
                 <?php sortBy(); ?>
diff --git a/src/server/app/View/profile/bookmark.php b/src/server/app/View/profile/bookmark.php
new file mode 100644
index 0000000000000000000000000000000000000000..4915cc04da0cbc1de03d50c883c85d9aa8855996
--- /dev/null
+++ b/src/server/app/View/profile/bookmark.php
@@ -0,0 +1,46 @@
+<?php
+
+function watchlistCard(array $item, string $userUUID, bool $saved = true, bool $loved = false, string $loading = "eager")
+{
+    $uuid = $item["watchlist_uuid"];
+    $posters = $item["posters"];
+    $visibility = $item["visibility"];
+    $title = $item["title"];
+    $category = $item["category"];
+    $creator = $item["creator"];
+    $createdAt = $item["created_at"];
+    $description = $item["description"];
+    $itemCount = $item["item_count"];
+    $loveCount = $item["like_count"];
+    $self = ($userUUID == $item["creator_uuid"]);
+
+
+    require __DIR__ . '/../components/card/watchlistCard.php';
+}
+
+function pagination(int $currentPage, int $totalPage)
+{
+    require __DIR__ . '/../components/pagination.php';
+}
+
+?>
+
+<main class="watchlist-self">
+    <section class="search-filter">
+        <h2>My Bookmark</h2>
+    </section>
+    <?php if (count($model['data']['bookmarks']['items']) == 0): ?>
+        <div class="no-item__container">
+            <h1>Oops! 😣</h1>
+            <div>
+                <h2>There's No Bookmark Yet...</h2>
+            </div>
+        </div>
+    <?php endif; ?>
+    <section class="content">
+        <?php for ($i = 0; $i < count($model['data']['bookmarks']['items']); $i++): ?>
+            <?php watchlistCard($model['data']['bookmarks']['items'][$i], $model["data"]["userUUID"], true, false, $i < 4 ? "eager" : "lazy"); ?>
+        <?php endfor; ?>
+        <?php pagination($model['data']['bookmarks']['page'], $model['data']['bookmarks']['totalPage']); ?>
+    </section>
+</main>
\ No newline at end of file
diff --git a/src/server/app/View/watchlist/self.php b/src/server/app/View/profile/watchlist.php
similarity index 98%
rename from src/server/app/View/watchlist/self.php
rename to src/server/app/View/profile/watchlist.php
index 9c9e5d5333fd6c7e46139f721ba64e70f507556e..f4a4a066cfd56baeb9f8858db4eb2a0127146e1e 100644
--- a/src/server/app/View/watchlist/self.php
+++ b/src/server/app/View/profile/watchlist.php
@@ -8,7 +8,6 @@ function watchlistCard(array $item, string $userUUID, bool $saved = false, bool
     $title = $item["title"];
     $category = $item["category"];
     $creator = $item["creator"];
-    $updatedAt = $item["updated_at"];
     $createdAt = $item["created_at"];
     $description = $item["description"];
     $itemCount = $item["item_count"];
diff --git a/src/server/app/View/user/editProfile.php b/src/server/app/View/user/editProfile.php
index aa393e8a8c8885dbc89d84ee69484f29a4ce7445..300694a9dd25b2cc26d93a670656aa5da0c34199 100644
--- a/src/server/app/View/user/editProfile.php
+++ b/src/server/app/View/user/editProfile.php
@@ -1,17 +1,37 @@
+<?php
+function alert($title, $message, $type = 'error')
+{
+    require __DIR__ . '/../components/alert.php';
+}
+
+?>
+
+
 <main>
     <div class="edit-parameters">
         <div class="my-profile-container">
-            <h2><?= $model['data']['name'] ?> - Profile</h2>
+            <h2>
+                <?= $model['data']['name'] ?> - Profile
+            </h2>
         </div>
-        <form class="form-default" action="/editProfile" method="post">
+        <?php if (isset($model['error'])): ?>
+            <?php alert('Failed to Update', $model['error']); ?>
+        <?php endif; ?>
+        <?php if (isset($model['success'])): ?>
+            <?php alert('Success', $model['success'], 'success'); ?>
+        <?php endif; ?>
+        <form id="profile-edit-form" class="form-default">
             <div class="display-name">
                 <h3>Name</h3>
+                <p id="name">
+                    <?= $model['data']['name'] ?>
+                </p>
             </div>
             <p>Change name</p>
             <div class="input-container">
                 <div class="input-box">
-                    <input class="input" name="name">
-                    </input>
+                    <input class="input" name="name" placeholder="Enter new name"
+                        value="<?= $model['data']['name'] ?>" />
                 </div>
             </div>
             <div class="display-name">
@@ -31,8 +51,8 @@
                             </div>
                             <div class="input-container">
                                 <div class="input-box">
-                                    <input class="input" type="password" name="oldPassword">
-                                    </input>
+                                    <input class="input" type="password" name="oldPassword"
+                                        placeholder="Enter old password" />
                                 </div>
                             </div>
                         </div>
@@ -43,34 +63,20 @@
                             </div>
                             <div class="input-container">
                                 <div class="input-box">
-                                    <input class="input" type="password" name="newPassword">
-
-                                    </input>
+                                    <input class="input" type="password" name="newPassword"
+                                        placeholder="Enter new password" />
                                 </div>
                             </div>
                         </div>
                     </div>
                 </div>
-                <input class="btn-primary" name="update_button" type="submit" value="SAVE">
-
-                </input>
-                <input class="btn-primary" name="delete_button" type="submit" value="DELETE ACCOUNT">
-
-                </input>
-
+                <button id="update-account" class="btn-primary save" name="update_button" type="submit">
+                    save
+                </button>
+                <button id="delete-account" class="btn-bold" type="button">
+                    Delete Account
+                </button>
         </form>
-        <?php if (isset($model['error'])) { ?>
-            <div class="alert-error">
-                <p>
-                    <?= $model['error'] ?>
-                </p>
-            </div>
-        <?php } ?>
     </div>
-
-
-
     </div>
-
-
 </main>
\ No newline at end of file
diff --git a/src/server/app/View/user/signIn.php b/src/server/app/View/user/signIn.php
index 8d0603f0887cb89e79f27a995fa2899f3e3a8b08..e633706dac1291e10d9613bcb16dd42a40cf8078 100644
--- a/src/server/app/View/user/signIn.php
+++ b/src/server/app/View/user/signIn.php
@@ -1,35 +1,41 @@
+<?php
+function alert($title, $message)
+{
+    $type = 'error';
+    require __DIR__ . '/../components/alert.php';
+}
+
+?>
+
+
 <div class="signin-container row">
-    <img src="/assets/images/Suzume.webp" alt="Sign In Image" class="signin-poster"/>
+    <img src="/assets/images/Suzume.webp" alt="Sign In Image" class="signin-poster" />
     <div class="right-side">
         <div class="main-container">
             <div class="welcome-text">
                 <h2 class="welcome-text__h2">Hello Again!</h2>
                 <p class="welcome-text__h1">Welcome back! Please provide your details</p>
             </div>
+            <?php if (isset($model['error'])): ?>
+                <?php alert('Failed to Sign in', $model['error']); ?>
+            <?php endif; ?>
 
             <form class="inputs" action="/signin" method="post">
                 <div class="parameter">
                     <label for="email" class="input-required">Email</label>
-                    <input type="email" name="email" id="email" class="input-default"
-                           value="<?= $model['data']['email'] ?? "" ?>">
+                    <input type="email" name="email" id="email" class="input-default" placeholder="Enter email"
+                        value="<?= $model['data']['email'] ?? "" ?>">
                 </div>
                 <div class="parameter">
                     <label for="password" class="input-required">Password</label>
-                    <input type="password" name="password" id="password" class="input-default">
+                    <input type="password" name="password" id="password" class="input-default"
+                        placeholder="Enter password">
                 </div>
                 <button class="btn-bold" type="submit">
                     Sign In
                 </button>
-                <p>Don't have an account? </p> <a href="/signup" class="signup-link">Sign up</a>
-
+                <p>Don't have an account? <a href="/signup" class="signup-link">Sign up</a></p>
             </form>
-            <?php if (isset($model['error'])) { ?>
-                <div class="alert-error">
-                    <p>
-                        <?= $model['error'] ?>
-                    </p>
-                </div>
-            <?php } ?>
         </div>
     </div>
 </div>
\ No newline at end of file
diff --git a/src/server/app/View/user/signUp.php b/src/server/app/View/user/signUp.php
index b9cf731b49ba2efa26b81031064d1ca11d2edc5c..a9e507ea5650688a549ca6ccd404e140312a2e45 100644
--- a/src/server/app/View/user/signUp.php
+++ b/src/server/app/View/user/signUp.php
@@ -1,39 +1,46 @@
+<?php
+function alert($title, $message)
+{
+    $type = 'error';
+    require __DIR__ . '/../components/alert.php';
+}
+
+?>
+
 <div class="signup-container row">
     <img src="/assets/images/Tomorrow.webp" alt="Sign Up Image" class="signup-poster" />
     <div class="right-side">
         <div class="main-container">
             <div class="welcome-text">
-                <h2 class="welcome-text__h2">Let’s Get Started!</h2>
+                <h2 class="welcome-text__h2">Let's Get Started!</h2>
                 <p class="welcome-text__h1">Glad to see you joining us! Please provide your details</p>
             </div>
 
+            <?php if (isset($model['error'])): ?>
+                <?php alert('Failed to Sign up', $model['error']); ?>
+            <?php endif; ?>
+
             <form class="inputs" action="/signup" method="post">
                 <div class="parameter">
                     <label for="email" class="input-required">Email</label>
-                    <input type="email" name="email" id="email" class="input-default" required>
+                    <input type="email" name="email" id="email" class="input-default" required
+                        placeholder="Enter email">
                 </div>
                 <div class="parameter">
                     <label for="password" class="input-required">Password</label>
-                    <input type="password" name="password" id="password" class="input-default" required />
+                    <input type="password" name="password" id="password" class="input-default" required
+                        placeholder="Enter password" />
                 </div>
                 <div class="parameter">
                     <label for="passwordConfirm" class="input-required">Confirm Password</label>
-                    <input type="password" name="passwordConfirm" id="passwordConfirm" class="input-default" required />
+                    <input type="password" name="passwordConfirm" id="passwordConfirm" class="input-default" required
+                        placeholder="Enter confirm password" />
                 </div>
                 <button class="btn-bold" type="submit">
                     Sign Up
                 </button>
-
+                <p>Already have an account? <a href="/signin" class="signin-link">Sign in</a></p>
             </form>
-
-            <?php if (isset($model['error'])) { ?>
-                <div class="alert-error">
-                    <p>
-                        <?= $model['error'] ?>
-                    </p>
-                </div>
-            <?php } ?>
-
         </div>
     </div>
 </div>
\ No newline at end of file
diff --git a/src/server/app/View/watchlist/createUpdate.php b/src/server/app/View/watchlist/createUpdate.php
index a60af9442b6d4cdee6ec918f82ce6033d1c525bf..12709f9a3b94217c5b4c4e4ca012054c9e3181a5 100644
--- a/src/server/app/View/watchlist/createUpdate.php
+++ b/src/server/app/View/watchlist/createUpdate.php
@@ -53,23 +53,46 @@ function watchlistItem($poster, $title, $id, $uuid, $category, $description)
                     <input type="text" name="title" id="title" class="input-default" placeholder="Best Anime and Drama"
                            value="<?= $model["data"]["title"] ?? '' ?>" required/>
                 </div>
+
                 <div class="form-input-default">
                     <label for="description">Description</label>
                     <textarea name="description" id="description" class="input-default" maxlength="255"
                               placeholder="Enter your watchlist description"><?= $model["data"]["description"] ?? '' ?></textarea>
                 </div>
+
                 <div class="form-input-default">
                     <label for="visibility" class="input-required">Visibility</label>
-                    <?php visibility(isset($model["data"]) ? $model["data"]["visibility"] : null); ?>
+                    <?php visibility(isset($model["data"]["visibility"]) ? $model["data"]["visibility"] : null); ?>
+                </div>
+
+                <div class="form-input-default">
+                    <label for="tags">Tags</label>
+                    <div class="tags">
+                        <?php foreach ($model["data"]["tags"] ?? [] as $tag): ?>
+                            <?php $selected = false ?>
+                            <?php foreach ($model["data"]["tagsSelected"] ?? [] as $ts): ?>
+                                <?php if ($tag->id == $ts["id"]) $selected = true; ?>
+                            <?php endforeach; ?>
+                            <div class="input-tag">
+                                <label for="tag_<?= $tag->name ?>"><?= $tag->name ?></label>
+                                <input type="checkbox" id="tag_<?= $tag->name ?>" name="<?= $tag->name ?>"
+                                       value="<?= $tag->id ?>" class="checkbox watchlist-tag"
+                                    <?= $selected ? "checked" : "" ?>/>
+                            </div>
+                        <?php endforeach; ?>
+                    </div>
                 </div>
 
                 <h3 class="watchlist-items__title">Items</h3>
                 <div class="watchlist-items">
-                    <?php foreach ((isset($model["data"]) ? $model["data"]["catalogs"]["items"] : []) as $item): ?>
+                    <?php foreach ((isset($model["data"]["catalogs"]["items"]) ? $model["data"]["catalogs"]["items"] : []) as $item): ?>
                         <div class="watchlist-item" draggable="true" data-id="<?= $item["catalog_uuid"] ?>">
                             <?php watchlistItem($item["poster"], $item["title"], $item["catalog_id"], $item["catalog_uuid"], $item["category"], $item["description"]); ?>
                         </div>
                     <?php endforeach; ?>
+                    <?php if (!isset($model["data"]["catalogs"]["items"])): ?>
+                        <p class="items-placeholder">No items selected.</p>
+                    <?php endif; ?>
                 </div>
 
                 <input id="input-submit" type="submit" class="hidden"/>
diff --git a/src/server/app/View/watchlist/detail.php b/src/server/app/View/watchlist/detail.php
index 21d2d12dc75c2f4309a23ad86cc550feadacc2e5..60a8a54a233701a6eb857ea91d2c0931a84fcc15 100644
--- a/src/server/app/View/watchlist/detail.php
+++ b/src/server/app/View/watchlist/detail.php
@@ -1,12 +1,19 @@
 <?php
 
+if (!function_exists("formatDate")) {
+    function formatDate($createdAt)
+    {
+        require __DIR__ . '/../../../config/dateFormat.php';
+    }
+}
+
 function catalogCard($catalog)
 {
-    $is_admin = false;
     $title = $catalog['title'];
     $poster = $catalog['poster'];
     $category = $catalog['category'];
     $description = $catalog['description'];
+    $uuid = $catalog['catalog_uuid'];
     require __DIR__ . '/../components/card/catalogCard.php';
 }
 
@@ -14,58 +21,94 @@ function pagination($currentPage, $totalPage)
 {
     require __DIR__ . '/../components/pagination.php';
 }
+
+if (!function_exists("likeAndSave")) {
+
+    function likeAndSave($class, $icon)
+    {
+        $triggerClasses = "btn-ghost $class";
+        $triggerText = "";
+        $triggerIcon = $icon;
+        $title = "Sign In Required";
+        $content = 'signInRequired';
+        require __DIR__ . '/../components/modal.php';
+    }
+}
+
 ?>
 
 <main>
     <article class="header">
         <div class="detail">
             <h2>
-                <?= $model['data']['title'] ?>
+                <?= $model['data']['item']['title'] ?>
             </h2>
             <div class="container-subtitle">
                 <div class="tag">
-                    <?= $model['data']['category'] ?>
+                    <?= $model['data']['item']['category'] ?>
                 </div>
                 <p class="subtitle">
-                    <?= $model['data']['creator'] ?> |
-                    <?= $model['data']['updated_at'] ?>
+                    <?= $model['data']['item']['creator'] ?> |
+                    <?= formatDate($model['data']['item']['created_at']) ?>
                 </p>
             </div>
+            <div class="watchlist__wrapper-type-author">
+                <?php foreach ($model["data"]["item"]["tags"] as $tag): ?>
+                    <span class="tag"><?= $tag["name"] ?></span>
+                <?php endforeach; ?>
+            </div>
             <p>
-                <?= $model['data']['description'] ?>
+                <?= $model['data']['item']['description'] ?>
             </p>
         </div>
         <div class="container-button">
             <div class="container-btn-love">
-                <button class="btn-ghost">
-                    <?php
-                    $type = (isset($model['data']['like_status']) && $model['data']['like_status']) ? "filled" : "unfilled";
-                    require PUBLIC_PATH . 'assets/icons/love.php' ?>
-                </button>
-                <span>
-                    <?= $model['data']['like_count'] ?>
+                <?php if ($model['data']['userUUID'] == ""): ?>
+                    <?php likeAndSave("btn__like", "love"); ?>
+                <?php else: ?>
+                    <button class="btn-ghost btn__like" data-id="<?= $model["data"]["item"]["watchlist_uuid"] ?>"
+                            data-liked="<?= $model["data"]["item"]["liked"] ?>">
+                        <?php
+                        $type = (isset($model['data']["item"]['liked']) && $model['data']["item"]['liked']) ? "filled" : "unfilled";
+                        require PUBLIC_PATH . 'assets/icons/love.php' ?>
+                    </button>
+                <?php endif; ?>
+                <span data-id="<?= $model["data"]["item"]["watchlist_uuid"] ?>">
+                    <?= $model['data']['item']['like_count'] ?>
                 </span>
             </div>
-            <button class="btn-ghost">
-                <?php
-                $type = (isset($model['data']['save_status']) && $model['data']['save_status']) ? "filled" : "unfilled";
-                require PUBLIC_PATH . 'assets/icons/bookmark.php' ?>
-            </button>
+            <div class="container-btn-love">
+                <?php if (!isset($model['data']['userUUID']) || $model['data']['userUUID'] != $model['data']['item']['creator_uuid']): ?>
+                    <?php if ($model['data']['userUUID'] == ""): ?>
+                        <?php likeAndSave("btn__save", "bookmark"); ?>
+                    <?php else: ?>
+                        <button class="btn-ghost btn__save" data-id="<?= $model["data"]["item"]["watchlist_uuid"] ?>"
+                                data-saved="<?= $model["data"]["item"]["saved"] ?>"
+                        >
+                            <?php
+                            $type = (isset($model['data']['item']['saved']) && $model['data']['item']['saved']) ? "filled" : "unfilled";
+                            require PUBLIC_PATH . 'assets/icons/bookmark.php' ?>
+                        </button>
+                    <?php endif; ?>
+                <?php endif; ?>
+            </div>
         </div>
     </article>
     <article id="catalogs" class="content">
-        <?php foreach ($model['data']['catalogs']['items'] ?? [] as $catalog): ?>
+        <?php foreach ($model['data']['item']['catalogs']['items'] ?? [] as $catalog): ?>
             <?php catalogCard($catalog); ?>
         <?php endforeach; ?>
-        <?php pagination($model['data']['catalogs']['page'], $model['data']['catalogs']['totalPage']); ?>
+        <?php pagination($model['data']['item']['catalogs']['page'], $model['data']['item']['catalogs']['totalPage']); ?>
     </article>
-    <?php if (isset($model['editable']) && $model['editable']): ?>
+    <?php if (isset($model['data']['userUUID']) && $model['data']['userUUID'] === $model['data']['item']['creator_uuid']): ?>
         <div class="watchlist-detail__button-container">
-            <a href="<?= "/watchlist/" . $model['data']['watchlist_uuid'] . "/edit" ?>" id="edit"
-                aria-label="Edit <?= $model['data']['title'] ?>" class="btn-icon">
+            <a href="<?= "/watchlist/" . $model['data']['item']['watchlist_uuid'] . "/edit" ?>" id="edit"
+               aria-label="Edit <?= $model['data']['item']['title'] ?>" class="btn-icon">
                 <?php require PUBLIC_PATH . 'assets/icons/edit.php' ?>
             </a>
-            <button type="submit" aria-label="Delete <?= $model['data']['title'] ?>" class="dialog-trigger btn-icon">
+            <button type="submit" aria-label="Delete <?= $model['data']['item']['title'] ?>"
+                    class="dialog-trigger btn-icon btn__delete"
+                    data-id="<?= $model["data"]["item"]["watchlist_uuid"] ?>">
                 <?php require PUBLIC_PATH . 'assets/icons/trash.php' ?>
             </button>
         </div>
diff --git a/src/server/config/database.php b/src/server/config/database.php
index bd9a825eaf7c687febf4e0f88829f27091e51963..b0482b033cdd7ba5fadcc817ba5ac812be11a1d8 100644
--- a/src/server/config/database.php
+++ b/src/server/config/database.php
@@ -13,7 +13,6 @@ function getDatabaseConfig(): array
                 'username' => getenv('DB_USER'),
                 'password' => getenv('DB_PASSWORD'),
             ],
-            "prod" => [],
         ],
     ];
 }
diff --git a/src/server/routes/view.php b/src/server/routes/view.php
index 5ae2e254278e520b5b1d5a6975cc1600cbabda47..ea94b3e86be137c7459e0794b9a8f185ec698754 100644
--- a/src/server/routes/view.php
+++ b/src/server/routes/view.php
@@ -6,6 +6,7 @@ require_once __DIR__ . "/../app/Controller/UserController.php";
 require_once __DIR__ . "/../app/Controller/CatalogController.php";
 require_once __DIR__ . '/../app/Controller/WatchlistController.php';
 require_once __DIR__ . '/../app/Controller/ErrorPageController.php';
+require_once __DIR__ . '/../app/Controller/BookmarkController.php';
 
 require_once __DIR__ . '/../app/Middleware/UserAuthMiddleware.php';
 require_once __DIR__ . '/../app/Middleware/AdminAuthMiddleware.php';
@@ -23,11 +24,12 @@ Router::add('GET', '/signup', UserController::class, 'signUp', []);
 Router::add('POST', '/signup', UserController::class, 'postSignUp', []);
 Router::add('GET', '/signin', UserController::class, 'signIn', []);
 Router::add('POST', '/signin', UserController::class, 'postSignIn', []);
-Router::add('GET', '/editProfile', UserController::class, 'showEditProfile', [UserAuthMiddleware::class]);
-Router::add('POST', '/editProfile', UserController::class, 'postEditProfile', [UserAuthMiddleware::class]);
+Router::add('POST', '/api/auth/logout', UserController::class, 'logout', [UserAuthMiddleware::class]);
+Router::add('DELETE', '/api/auth/delete', UserController::class, 'delete', [UserAuthMiddleware::class]);
+Router::add('POST', '/api/auth/update', UserController::class, 'update', [UserAuthMiddleware::class]);
 
 // Catalog controllers
-Router::add('GET', '/catalog', CatalogController::class, 'index', [AdminAuthMiddleware::class]);
+Router::add('GET', '/catalog', CatalogController::class, 'index', []);
 Router::add('GET', '/catalog/create', CatalogController::class, 'create', [AdminAuthMiddleware::class]);
 Router::add('POST', '/catalog/create', CatalogController::class, 'postCreate', [AdminAuthMiddleware::class]);
 Router::add('GET', '/catalog/([A-Za-z0-9]*)/edit', CatalogController::class, 'edit', [AdminAuthMiddleware::class]);
@@ -35,6 +37,8 @@ Router::add('POST', '/catalog/([A-Za-z0-9]*)/edit', CatalogController::class, 'p
 Router::add('POST', '/catalog/([A-Za-z0-9]*)/delete', CatalogController::class, 'postDelete', [AdminAuthMiddleware::class]);
 Router::add('GET', '/catalog/([A-Za-z0-9]*)', CatalogController::class, 'detail', []);
 Router::add('GET', '/api/catalog', CatalogController::class, "search", [UserAuthApiMiddleware::class]);
+Router::add("DELETE", "/api/catalog/([A-Za-z0-9]*)/delete", CatalogController::class, "delete", [AdminAuthMiddleware::class]);
+Router::add("POST", '/api/catalog/([A-Za-z0-9]*)/update', CatalogController::class, 'update', [AdminAuthMiddleware::class]);
 
 // Watchlist controllers
 Router::add("GET", "/watchlist/create", WatchlistController::class, 'create', [UserAuthMiddleware::class]);
@@ -43,11 +47,14 @@ Router::add("GET", "/watchlist/([A-Za-z0-9]*)", WatchlistController::class, 'det
 
 Router::add("POST", "/api/watchlist", WatchlistController::class, "postCreate", [UserAuthApiMiddleware::class]);
 Router::add("PUT", "/api/watchlist", WatchlistController::class, "putEdit", [UserAuthApiMiddleware::class]);
+Router::add("DELETE", "/api/watchlist", WatchlistController::class, "delete", [UserAuthApiMiddleware::class]);
 Router::add("GET", "/api/watchlist/item", WatchlistController::class, 'item', [UserAuthApiMiddleware::class]);
 Router::add("POST", "/api/watchlist/like", WatchlistController::class, "like", [UserAuthApiMiddleware::class]);
 Router::add("POST", "/api/watchlist/save", WatchlistController::class, "bookmark", [UserAuthApiMiddleware::class]);
 
 
+Router::add('GET', '/profile', UserController::class, 'showEditProfile', [UserAuthMiddleware::class]);
+Router::add('GET', '/profile/bookmark', BookmarkController::class, 'self', [UserAuthMiddleware::class]);
 Router::add('GET', '/profile/watchlist', WatchlistController::class, 'self', [UserAuthMiddleware::class]);
 
 // Error page
@@ -55,4 +62,4 @@ Router::add('GET', '/404', ErrorPageController::class, 'fourohfour', []);
 Router::add('GET', '/500', ErrorPageController::class, 'fivehundred', []);
 
 // Execute
-Router::run();
+Router::run();
\ No newline at end of file