diff --git a/README.md b/README.md
index 61295d00f3ca25e30216e3c4006a24f4c88e32bd..ce689966568c5744ecd08a575b627c50d38818b4 100644
--- a/README.md
+++ b/README.md
@@ -23,34 +23,28 @@ cp ./.env.template.local ./.env.production.local
 - [PM2](https://pm2.keymetrics.io/)
 
 # Routes
-- [ ] check routes
-  - [x] AUTH
-    - [x] register
-    - [x] confirm register
-    - [x] resend register token
-    - [x] login
-    - [x] renew JWT
-    - [x] logout
-    - [x] request password reset
-    - [x] password reset
-  - [ ] AI
-    - [ ] status
-    - [ ] get models
-    - [ ] get model
-    - [ ] install model [admin only]
-    - [ ] delete model [admin only]
-    - [ ] chat
-    - [ ] list chats
-  - [ ] EMBEDDINGS
-    - [ ] delete vector db [admin only]
-    - [ ] get vector db [admin only]
-    - [ ] update embeddings [admin only]
+- [x] AUTH
+  - [x] register
+  - [x] confirm register
+  - [x] resend register token
+  - [x] login
+  - [x] renew JWT
+  - [x] logout
+  - [x] request password reset
+  - [x] password reset
+- [x] AI
+  - [x] status
+  - [x] get models
+  - [x] get model
+  - [x] install model [admin only]
+  - [x] delete model [admin only]
+  - [x] chat
+  - [x] list chats
+- [x] EMBEDDINGS
+  - [x] status [admin only]
+  - [x] delete vector db [admin only]
+  - [x] update embeddings [admin only]
 
 # Roadmap
-- [ ] complete pages
-  - [ ] resend verification code
-  - [ ] onboarding / RAGChat
-  - [ ] admin-login
-  - [ ] admin-page with LLM options
 - [ ] fix errors
   - [ ] check width of label & submit on cleanLayout
\ No newline at end of file
diff --git a/README_tmp.html b/README_tmp.html
index 2dc272fe0c6d6d4dfd67602bbf5ddf1bf12dfda4..726e54b313e956aa3f6569eb05b15b4ed41a2b87 100644
--- a/README_tmp.html
+++ b/README_tmp.html
@@ -389,54 +389,42 @@ cp ./.env.template.local ./.env.production.local
 </ul>
 <h1 id="routes">Routes</h1>
 <ul>
-<li><input type="checkbox" id="checkbox0"><label for="checkbox0">check routes</label>
+<li><input type="checkbox" id="checkbox0" checked="true"><label for="checkbox0">AUTH</label>
 <ul>
-<li><input type="checkbox" id="checkbox1" checked="true"><label for="checkbox1">AUTH</label>
-<ul>
-<li><input type="checkbox" id="checkbox2" checked="true"><label for="checkbox2">register</label></li>
-<li><input type="checkbox" id="checkbox3" checked="true"><label for="checkbox3">confirm register</label></li>
-<li><input type="checkbox" id="checkbox4" checked="true"><label for="checkbox4">resend register token</label></li>
-<li><input type="checkbox" id="checkbox5" checked="true"><label for="checkbox5">login</label></li>
-<li><input type="checkbox" id="checkbox6" checked="true"><label for="checkbox6">renew JWT</label></li>
-<li><input type="checkbox" id="checkbox7" checked="true"><label for="checkbox7">logout</label></li>
-<li><input type="checkbox" id="checkbox8" checked="true"><label for="checkbox8">request password reset</label></li>
-<li><input type="checkbox" id="checkbox9" checked="true"><label for="checkbox9">password reset</label></li>
+<li><input type="checkbox" id="checkbox1" checked="true"><label for="checkbox1">register</label></li>
+<li><input type="checkbox" id="checkbox2" checked="true"><label for="checkbox2">confirm register</label></li>
+<li><input type="checkbox" id="checkbox3" checked="true"><label for="checkbox3">resend register token</label></li>
+<li><input type="checkbox" id="checkbox4" checked="true"><label for="checkbox4">login</label></li>
+<li><input type="checkbox" id="checkbox5" checked="true"><label for="checkbox5">renew JWT</label></li>
+<li><input type="checkbox" id="checkbox6" checked="true"><label for="checkbox6">logout</label></li>
+<li><input type="checkbox" id="checkbox7" checked="true"><label for="checkbox7">request password reset</label></li>
+<li><input type="checkbox" id="checkbox8" checked="true"><label for="checkbox8">password reset</label></li>
 </ul>
 </li>
-<li><input type="checkbox" id="checkbox10"><label for="checkbox10">AI</label>
+<li><input type="checkbox" id="checkbox9" checked="true"><label for="checkbox9">AI</label>
 <ul>
-<li><input type="checkbox" id="checkbox11"><label for="checkbox11">status</label></li>
-<li><input type="checkbox" id="checkbox12"><label for="checkbox12">get models</label></li>
-<li><input type="checkbox" id="checkbox13"><label for="checkbox13">get model</label></li>
-<li><input type="checkbox" id="checkbox14"><label for="checkbox14">install model [admin only]</label></li>
-<li><input type="checkbox" id="checkbox15"><label for="checkbox15">delete model [admin only]</label></li>
-<li><input type="checkbox" id="checkbox16"><label for="checkbox16">chat</label></li>
-<li><input type="checkbox" id="checkbox17"><label for="checkbox17">list chats</label></li>
+<li><input type="checkbox" id="checkbox10" checked="true"><label for="checkbox10">status</label></li>
+<li><input type="checkbox" id="checkbox11" checked="true"><label for="checkbox11">get models</label></li>
+<li><input type="checkbox" id="checkbox12" checked="true"><label for="checkbox12">get model</label></li>
+<li><input type="checkbox" id="checkbox13" checked="true"><label for="checkbox13">install model [admin only]</label></li>
+<li><input type="checkbox" id="checkbox14" checked="true"><label for="checkbox14">delete model [admin only]</label></li>
+<li><input type="checkbox" id="checkbox15" checked="true"><label for="checkbox15">chat</label></li>
+<li><input type="checkbox" id="checkbox16" checked="true"><label for="checkbox16">list chats</label></li>
 </ul>
 </li>
-<li><input type="checkbox" id="checkbox18"><label for="checkbox18">EMBEDDINGS</label>
+<li><input type="checkbox" id="checkbox17" checked="true"><label for="checkbox17">EMBEDDINGS</label>
 <ul>
-<li><input type="checkbox" id="checkbox19"><label for="checkbox19">delete vector db [admin only]</label></li>
-<li><input type="checkbox" id="checkbox20"><label for="checkbox20">get vector db [admin only]</label></li>
-<li><input type="checkbox" id="checkbox21"><label for="checkbox21">update embeddings [admin only]</label></li>
-</ul>
-</li>
+<li><input type="checkbox" id="checkbox18" checked="true"><label for="checkbox18">status [admin only]</label></li>
+<li><input type="checkbox" id="checkbox19" checked="true"><label for="checkbox19">delete vector db [admin only]</label></li>
+<li><input type="checkbox" id="checkbox20" checked="true"><label for="checkbox20">update embeddings [admin only]</label></li>
 </ul>
 </li>
 </ul>
 <h1 id="roadmap">Roadmap</h1>
 <ul>
-<li><input type="checkbox" id="checkbox22"><label for="checkbox22">complete pages</label>
-<ul>
-<li><input type="checkbox" id="checkbox23"><label for="checkbox23">resend verification code</label></li>
-<li><input type="checkbox" id="checkbox24"><label for="checkbox24">onboarding / RAGChat</label></li>
-<li><input type="checkbox" id="checkbox25"><label for="checkbox25">admin-login</label></li>
-<li><input type="checkbox" id="checkbox26"><label for="checkbox26">admin-page with LLM options</label></li>
-</ul>
-</li>
-<li><input type="checkbox" id="checkbox27"><label for="checkbox27">fix errors</label>
+<li><input type="checkbox" id="checkbox21"><label for="checkbox21">fix errors</label>
 <ul>
-<li><input type="checkbox" id="checkbox28"><label for="checkbox28">check width of label &amp; submit on cleanLayout</label></li>
+<li><input type="checkbox" id="checkbox22"><label for="checkbox22">check width of label &amp; submit on cleanLayout</label></li>
 </ul>
 </li>
 </ul>
diff --git a/package-lock.json b/package-lock.json
index cf180e712b315a06b67cd243d0279cb8d654c9f4..2921d794596c6b48a7e2a01b4b6cebdeb8adbe64 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,8 +9,13 @@
       "version": "0.0.0",
       "dependencies": {
         "@hookform/resolvers": "^3.6.0",
+        "@radix-ui/react-dialog": "^1.1.1",
+        "@radix-ui/react-dropdown-menu": "^2.1.1",
+        "@tanstack/react-table": "^8.20.1",
         "axios": "^1.7.2",
+        "class-variance-authority": "^0.7.0",
         "hamburger-react": "^2.5.1",
+        "lucide-react": "^0.424.0",
         "react": "^18.3.1",
         "react-dom": "^18.3.1",
         "react-helmet-async": "^2.0.5",
@@ -900,6 +905,44 @@
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
     },
+    "node_modules/@floating-ui/core": {
+      "version": "1.6.5",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.5.tgz",
+      "integrity": "sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/utils": "^0.2.5"
+      }
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "1.6.8",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz",
+      "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/core": "^1.6.0",
+        "@floating-ui/utils": "^0.2.5"
+      }
+    },
+    "node_modules/@floating-ui/react-dom": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz",
+      "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/dom": "^1.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0",
+        "react-dom": ">=16.8.0"
+      }
+    },
+    "node_modules/@floating-ui/utils": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz",
+      "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==",
+      "license": "MIT"
+    },
     "node_modules/@hookform/resolvers": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.6.0.tgz",
@@ -1096,6 +1139,556 @@
         "node": ">=14"
       }
     },
+    "node_modules/@radix-ui/primitive": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz",
+      "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==",
+      "license": "MIT"
+    },
+    "node_modules/@radix-ui/react-arrow": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz",
+      "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-primitive": "2.0.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-collection": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz",
+      "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-slot": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
+      "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-context": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz",
+      "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-dialog": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz",
+      "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.0",
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-dismissable-layer": "1.1.0",
+        "@radix-ui/react-focus-guards": "1.1.0",
+        "@radix-ui/react-focus-scope": "1.1.0",
+        "@radix-ui/react-id": "1.1.0",
+        "@radix-ui/react-portal": "1.1.1",
+        "@radix-ui/react-presence": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-slot": "1.1.0",
+        "@radix-ui/react-use-controllable-state": "1.1.0",
+        "aria-hidden": "^1.1.1",
+        "react-remove-scroll": "2.5.7"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-direction": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
+      "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-dismissable-layer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz",
+      "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.0",
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-use-callback-ref": "1.1.0",
+        "@radix-ui/react-use-escape-keydown": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-dropdown-menu": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz",
+      "integrity": "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.0",
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-id": "1.1.0",
+        "@radix-ui/react-menu": "2.1.1",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-use-controllable-state": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-focus-guards": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz",
+      "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-focus-scope": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz",
+      "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-use-callback-ref": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-id": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
+      "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-menu": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.1.tgz",
+      "integrity": "sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.0",
+        "@radix-ui/react-collection": "1.1.0",
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-direction": "1.1.0",
+        "@radix-ui/react-dismissable-layer": "1.1.0",
+        "@radix-ui/react-focus-guards": "1.1.0",
+        "@radix-ui/react-focus-scope": "1.1.0",
+        "@radix-ui/react-id": "1.1.0",
+        "@radix-ui/react-popper": "1.2.0",
+        "@radix-ui/react-portal": "1.1.1",
+        "@radix-ui/react-presence": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-roving-focus": "1.1.0",
+        "@radix-ui/react-slot": "1.1.0",
+        "@radix-ui/react-use-callback-ref": "1.1.0",
+        "aria-hidden": "^1.1.1",
+        "react-remove-scroll": "2.5.7"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-popper": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz",
+      "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/react-dom": "^2.0.0",
+        "@radix-ui/react-arrow": "1.1.0",
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-use-callback-ref": "1.1.0",
+        "@radix-ui/react-use-layout-effect": "1.1.0",
+        "@radix-ui/react-use-rect": "1.1.0",
+        "@radix-ui/react-use-size": "1.1.0",
+        "@radix-ui/rect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-portal": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz",
+      "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-presence": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz",
+      "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-primitive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
+      "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-slot": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz",
+      "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.0",
+        "@radix-ui/react-collection": "1.1.0",
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-direction": "1.1.0",
+        "@radix-ui/react-id": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-use-callback-ref": "1.1.0",
+        "@radix-ui/react-use-controllable-state": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-slot": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
+      "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-callback-ref": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
+      "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-controllable-state": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
+      "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-callback-ref": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-escape-keydown": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
+      "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-callback-ref": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-layout-effect": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",
+      "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-rect": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz",
+      "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/rect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-size": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz",
+      "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/rect": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",
+      "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==",
+      "license": "MIT"
+    },
     "node_modules/@remix-run/router": {
       "version": "1.17.0",
       "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.0.tgz",
@@ -1577,6 +2170,39 @@
         "@svgr/core": "*"
       }
     },
+    "node_modules/@tanstack/react-table": {
+      "version": "8.20.1",
+      "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.1.tgz",
+      "integrity": "sha512-PJK+07qbengObe5l7c8vCdtefXm8cyR4i078acWrHbdm8JKw1ES7YpmOtVt9ALUVEEFAHscdVpGRhRgikgFMbQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@tanstack/table-core": "8.20.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/tannerlinsley"
+      },
+      "peerDependencies": {
+        "react": ">=16.8",
+        "react-dom": ">=16.8"
+      }
+    },
+    "node_modules/@tanstack/table-core": {
+      "version": "8.20.1",
+      "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.1.tgz",
+      "integrity": "sha512-5Ly5TIRHnWH7vSDell9B/OVyV380qqIJVg7H7R7jU4fPEmOD4smqAX7VRflpYI09srWR8aj5OLD2Ccs1pI5mTg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/tannerlinsley"
+      }
+    },
     "node_modules/@types/babel__core": {
       "version": "7.20.5",
       "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1633,14 +2259,14 @@
       "version": "15.7.12",
       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
       "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
-      "dev": true,
+      "devOptional": true,
       "license": "MIT"
     },
     "node_modules/@types/react": {
       "version": "18.3.3",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
       "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==",
-      "dev": true,
+      "devOptional": true,
       "license": "MIT",
       "dependencies": {
         "@types/prop-types": "*",
@@ -1651,7 +2277,7 @@
       "version": "18.3.0",
       "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz",
       "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==",
-      "dev": true,
+      "devOptional": true,
       "license": "MIT",
       "dependencies": {
         "@types/react": "*"
@@ -1782,6 +2408,18 @@
       "dev": true,
       "license": "Python-2.0"
     },
+    "node_modules/aria-hidden": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz",
+      "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/array-buffer-byte-length": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
@@ -2207,6 +2845,27 @@
         "node": ">= 6"
       }
     },
+    "node_modules/class-variance-authority": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz",
+      "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "clsx": "2.0.0"
+      },
+      "funding": {
+        "url": "https://joebell.co.uk"
+      }
+    },
+    "node_modules/class-variance-authority/node_modules/clsx": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
+      "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/clsx": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
@@ -2328,7 +2987,7 @@
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
-      "dev": true,
+      "devOptional": true,
       "license": "MIT"
     },
     "node_modules/data-view-buffer": {
@@ -2455,6 +3114,12 @@
         "node": ">=0.4.0"
       }
     },
+    "node_modules/detect-node-es": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+      "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
+      "license": "MIT"
+    },
     "node_modules/didyoumean": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -3385,6 +4050,15 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/get-nonce": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+      "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/get-symbol-description": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
@@ -4316,6 +4990,15 @@
         "yallist": "^3.0.2"
       }
     },
+    "node_modules/lucide-react": {
+      "version": "0.424.0",
+      "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.424.0.tgz",
+      "integrity": "sha512-x2Nj2aytk1iOyHqt4hKenfVlySq0rYxNeEf8hE0o+Yh0iE36Rqz0rkngVdv2uQtjZ70LAE73eeplhhptYt9x4Q==",
+      "license": "ISC",
+      "peerDependencies": {
+        "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
+      }
+    },
     "node_modules/merge2": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -5143,6 +5826,53 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/react-remove-scroll": {
+      "version": "2.5.7",
+      "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz",
+      "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==",
+      "license": "MIT",
+      "dependencies": {
+        "react-remove-scroll-bar": "^2.3.4",
+        "react-style-singleton": "^2.2.1",
+        "tslib": "^2.1.0",
+        "use-callback-ref": "^1.3.0",
+        "use-sidecar": "^1.1.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-remove-scroll-bar": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz",
+      "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==",
+      "license": "MIT",
+      "dependencies": {
+        "react-style-singleton": "^2.2.1",
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/react-router": {
       "version": "6.24.0",
       "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.0.tgz",
@@ -5175,6 +5905,29 @@
         "react-dom": ">=16.8"
       }
     },
+    "node_modules/react-style-singleton": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
+      "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
+      "license": "MIT",
+      "dependencies": {
+        "get-nonce": "^1.0.0",
+        "invariant": "^2.2.4",
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/react-toastify": {
       "version": "10.0.5",
       "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz",
@@ -5992,7 +6745,6 @@
       "version": "2.6.3",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
       "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
-      "dev": true,
       "license": "0BSD"
     },
     "node_modules/type-check": {
@@ -6155,6 +6907,49 @@
         "punycode": "^2.1.0"
       }
     },
+    "node_modules/use-callback-ref": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz",
+      "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/use-sidecar": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
+      "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==",
+      "license": "MIT",
+      "dependencies": {
+        "detect-node-es": "^1.1.0",
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
diff --git a/package.json b/package.json
index c775795dce78b41586d151303469ab2a004c8231..9420af1afd1c5a195c368ef082c31e773c60b15c 100644
--- a/package.json
+++ b/package.json
@@ -12,8 +12,13 @@
   },
   "dependencies": {
     "@hookform/resolvers": "^3.6.0",
+    "@radix-ui/react-dialog": "^1.1.1",
+    "@radix-ui/react-dropdown-menu": "^2.1.1",
+    "@tanstack/react-table": "^8.20.1",
     "axios": "^1.7.2",
+    "class-variance-authority": "^0.7.0",
     "hamburger-react": "^2.5.1",
+    "lucide-react": "^0.424.0",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "react-helmet-async": "^2.0.5",
diff --git a/src/components/boxes/ConfirmBox.jsx b/src/components/boxes/ConfirmBox.jsx
index 1df510d3685bf83e9795cd24127fd7d7254c239d..b64f3ed55a0e483671bb6b525e956dc7b088c34e 100644
--- a/src/components/boxes/ConfirmBox.jsx
+++ b/src/components/boxes/ConfirmBox.jsx
@@ -8,7 +8,7 @@ import {
   DialogHeader,
   DialogTitle,
   DialogTrigger,
-} from "@/components/ui/dialog";
+} from "/src/components/ui/dialog";
 import { Button } from '../ui/button';
 import Heading from '../font/Heading';
 
diff --git a/src/components/boxes/InfoBox.jsx b/src/components/boxes/InfoBox.jsx
new file mode 100755
index 0000000000000000000000000000000000000000..309d02b1980ab148d3d75a5fd136ac9f1ed928dc
--- /dev/null
+++ b/src/components/boxes/InfoBox.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import {
+  Dialog,
+  DialogClose,
+  DialogContent,
+  DialogDescription,
+  DialogFooter,
+  DialogHeader,
+  DialogTitle,
+  DialogTrigger,
+} from "/src/components/ui/dialog";
+import { Button } from '../ui/button';
+import JsonToHtmlDL from './JsonToHtmlDL';
+
+function InfoBox({ infoDialog, closeDialog, item, ...props }) {
+  // #################################
+  // HOOKS
+  // #################################
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <Dialog open={infoDialog.open} onOpenChange={closeDialog}>
+      <DialogContent className="max-w-[95%] grid-rows-[auto_minmax(0,1fr)_auto] p-0 max-h-[90dvh]">
+        <DialogHeader className='p-6 pb-0'>
+          <DialogTitle>{infoDialog.title}</DialogTitle>
+          <DialogDescription>
+            {infoDialog.description}
+          </DialogDescription>
+        </DialogHeader>
+        <div className="grid gap-4 py-4 overflow-y-auto px-6">
+          <div className="flex flex-col justify-between h-[300dvh]">
+            <JsonToHtmlDL jsonContent={infoDialog.body} />
+          </div>
+        </div>
+        <DialogFooter className="sm:justify-start gap-2 p-6 pt-0">
+          <DialogClose asChild>
+            <Button>
+              close
+            </Button>
+          </DialogClose>
+        </DialogFooter>
+      </DialogContent>
+    </Dialog >
+  );
+}
+
+export default React.memo(InfoBox);
\ No newline at end of file
diff --git a/src/components/boxes/Infobox.jsx b/src/components/boxes/Infobox.jsx
deleted file mode 100755
index 4b259140cb2fdf83064d4ef0b8fb3902ce7b5e74..0000000000000000000000000000000000000000
--- a/src/components/boxes/Infobox.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import { twMerge } from 'tailwind-merge';
-
-function Infobox({ children, className, type, ...props }) {
-  // #################################
-  // HOOKS
-  // #################################
-
-  // #################################
-  // FUNCTIONS
-  // #################################
-  // ### MERGE CLASSNAMES
-  // static class names every item should have
-  let staticClassName = 'box-border border border-UhhBlue p-4 my-4 md:inline-block';
-  // dynamic class names depending on the type
-  const typeClassName = () => {
-    switch (type) {
-      case 'warning': {
-        return 'border-orange-300 bg-orange-100/20';
-      }
-      case 'alert': {
-        return 'border-UhhRed bg-red-100/20';
-      }
-      default: {
-        return '';
-      }
-    }
-  };
-  // merge static and dynamic class names with className from props
-  const mergedClassName = twMerge(staticClassName, typeClassName(), className);
-
-  // #################################
-  // OUTPUT
-  // #################################
-  return (
-    <div>
-      <div className={mergedClassName}>{children}</div>
-    </div>
-  );
-}
-
-export default React.memo(Infobox);
\ No newline at end of file
diff --git a/src/components/boxes/JsonToHtmlDL.jsx b/src/components/boxes/JsonToHtmlDL.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..ca1a03ea88adb2ac1460ef6d80e475a6d90b27a0
--- /dev/null
+++ b/src/components/boxes/JsonToHtmlDL.jsx
@@ -0,0 +1,36 @@
+import React from 'react';
+
+function JsonToHtmlDL({ jsonContent }) {
+  // #################################
+  // HOOKS
+  // #################################
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+  const renderDL = (obj) => {
+    if (obj === null || typeof obj !== 'object') {
+      return null;
+    }
+
+    return (
+      <dl className='ml-2'>
+        {Object.entries(obj).map(([key, value]) => (
+          <React.Fragment key={key}>
+            <dt className='text-UhhRed uppercase'>{key}</dt>
+            <dd className='ml-4 whitespace-pre'>
+              {typeof value === 'object' && value !== null ? renderDL(value) : (value ? value.toString() : '')}
+            </dd>
+          </React.Fragment>
+        ))}
+      </dl>
+    );
+  };
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return <div>{renderDL(jsonContent)}</div>;
+}
+
+export default React.memo(JsonToHtmlDL);
\ No newline at end of file
diff --git a/src/components/form/Select.jsx b/src/components/form/Select.jsx
index cd16a7021fe0cc81cc46da0837a06e3fe798c806..3299f0cd8e56216ce93cbbe051794705846b85f0 100755
--- a/src/components/form/Select.jsx
+++ b/src/components/form/Select.jsx
@@ -15,9 +15,6 @@ function Select({ options, name, title, defaultValue, className, tooltip, type,
     formState: { errors }
   } = useFormContext();
 
-
-
-
   // GENERATE RANDOM UUID
   const id = useId();
 
diff --git a/src/components/form/Submit.jsx b/src/components/form/Submit.jsx
index f244f1bacdfe1de1c19e80f8aa8ddcf1e58ad752..141eab111457581b3f9f9e19d84d7e4f1ac68a8c 100755
--- a/src/components/form/Submit.jsx
+++ b/src/components/form/Submit.jsx
@@ -1,8 +1,10 @@
+import { cva } from 'class-variance-authority';
 import React from 'react';
 import { useFormContext } from 'react-hook-form';
 import { twMerge } from 'tailwind-merge';
+import { cn } from '../../utils';
 
-function Submit({ value, type, className, ...props }) {
+function Submit({ value, type, className, variant, size, ...props }) {
   // #################################
   // HOOKS
   // #################################
@@ -24,6 +26,73 @@ function Submit({ value, type, className, ...props }) {
       }
     }
   };
+
+  const buttonVariants = cva([
+    "inline-block",
+    "w-full",
+    "mb-4",
+    "box-border",
+    "border",
+    "border-UhhBlue",
+    "text-center",
+    "align-middle",
+    "bg-UhhBlue",
+    "border-UhhBlue",
+    "text-UhhWhite",
+    "font-UhhBC",
+    "cursor-pointer",
+    "disabled:cursor-not-allowed",
+    "disabled:opacity-60",
+    "lg:min-w-xs",
+    "lg:w-[calc(1/2*100%-(1*1rem/2))]",
+    "xl:w-[calc((1/4*100%)-(3*1rem/4))]",
+    "hover:text-UhhBlue",
+    "hover:bg-UhhWhite"],
+    {
+      variants: {
+        variant: {
+          default: ["border-primary",
+            "bg-primary",
+            "text-primary-foreground",
+            "hover:bg-UhhWhite",
+            "hover:text-primary"],
+          destructive:
+            ["border-destructive",
+              "bg-destructive",
+              "text-destructive-foreground",
+              "hover:bg-UhhWhite",
+              "hover:text-destructive"],
+          outline:
+            ["border",
+              "border-input",
+              "bg-background",
+              "hover:bg-accent",
+              "hover:text-accent-foreground"],
+          secondary:
+            ["bg-secondary",
+              "text-secondary-foreground",
+              "hover:bg-secondary/80"],
+          ghost: ["hover:bg-accent",
+            "hover:text-accent-foreground"],
+          link: ["text-primary",
+            "underline-offset-4",
+            "hover:underline"],
+        },
+        size: {
+          default: "h-16",
+          sm: "h-12 w-fit px-4",
+          lg: "h-16 px-8",
+          xl: "h-20 px-12",
+          icon: "h-10 w-10",
+        },
+      },
+      defaultVariants: {
+        variant: "default",
+        size: "default",
+      },
+    }
+  );
+
   // merge static and dynamic class names with className from props
   const mergedClassName = twMerge(staticClassName, typeClassName(), className);
   // #################################
@@ -32,7 +101,7 @@ function Submit({ value, type, className, ...props }) {
   return (
     <>
       {/* <input type="submit" className={mergedClassName} value={value} disabled={isSubmitting} /> */}
-      <input type="submit" className={mergedClassName} value={value} disabled={!isValid || isSubmitting} {...props} />
+      <input type="submit" className={cn(buttonVariants({ variant, size, className }))} value={value} disabled={!isValid || isSubmitting} {...props} />
     </>
   );
 }
diff --git a/src/components/table/DataTableViewOptions.jsx b/src/components/table/DataTableViewOptions.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..967d5acb4247fd71f1d4bd1e79bf880a7fb4261f
--- /dev/null
+++ b/src/components/table/DataTableViewOptions.jsx
@@ -0,0 +1,61 @@
+import React, { useState } from 'react';
+import { Button } from '../ui/button';
+import {
+  DropdownMenu,
+  DropdownMenuCheckboxItem,
+  DropdownMenuContent,
+  DropdownMenuTrigger,
+} from "/src/components/ui/dropdown-menu";
+
+function DataTableViewOptions({ table }) {
+  // #################################
+  // HOOKS
+  // #################################
+  // force rerender to toggle visibility in dropdown
+  const [rerender, setRerender] = useState(0);
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+  // ### GET HIDEABLE COLUMNS
+  const hideableCols = () => {
+    return table.getAllColumns().filter(column => typeof column.accessorFn !== "undefined" && column.getCanHide());
+  };
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <>
+      {hideableCols().length > 0 &&
+        <DropdownMenu>
+          <DropdownMenuTrigger asChild>
+            <Button variant="outline" className="ml-auto">
+              Columns
+            </Button>
+          </DropdownMenuTrigger>
+          <DropdownMenuContent align="end">
+            {hideableCols()
+              .map((column) => {
+                return (
+                  <DropdownMenuCheckboxItem
+                    key={column.id}
+                    className="capitalize"
+                    checked={column.getIsVisible()}
+                    onCheckedChange={(value) => {
+                      setRerender(rerender + 1);
+                      column.toggleVisibility(!!value);
+                    }
+                    }
+                  >
+                    {column.id}
+                  </DropdownMenuCheckboxItem>
+                );
+              })}
+          </DropdownMenuContent>
+        </DropdownMenu>
+      }
+    </>
+  );
+}
+
+export default React.memo(DataTableViewOptions);
\ No newline at end of file
diff --git a/src/components/table/Pagination.jsx b/src/components/table/Pagination.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..34e757d1dc2d51c87e92eb2e05862186e7d50f06
--- /dev/null
+++ b/src/components/table/Pagination.jsx
@@ -0,0 +1,49 @@
+import React from 'react';
+import { Button } from '../ui/button';
+import { RiSkipLeftLine, RiSkipRightLine } from 'react-icons/ri';
+
+function Pagination({ table }) {
+  // #################################
+  // HOOKS
+  // #################################
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <div className="flex items-center justify-between">
+      {/* ITEM COUNT */}
+      <span className='text-xs'>{table.getFilteredRowModel().rows.length} Items</span>
+      {/* PAGE COUNT */}
+      <span className='text-xs'>Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}</span>
+      {/* PAGINATION */}
+      <span className='flex items-center justify-end space-x-2 py-4'>
+        <Button
+          type="button"
+          variant="outline"
+          size="sm"
+          onClick={() => table.previousPage()}
+          disabled={!table.getCanPreviousPage()}
+        >
+          <RiSkipLeftLine />
+        </Button>
+
+        <Button
+          type="button"
+          variant="outline"
+          size="sm"
+          onClick={() => table.nextPage()}
+          disabled={!table.getCanNextPage()}
+        >
+          <RiSkipRightLine />
+        </Button>
+      </span>
+    </div>
+  );
+}
+
+export default Pagination;
\ No newline at end of file
diff --git a/src/components/table/TBody.jsx b/src/components/table/TBody.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..f097e921814a00307ee5032836dbf8184aa61523
--- /dev/null
+++ b/src/components/table/TBody.jsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import { TableBody, TableCell, TableRow } from '../ui/table';
+import { flexRender } from '@tanstack/react-table';
+
+function TBody({ table }) {
+  // #################################
+  // HOOKS
+  // #################################
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <TableBody>
+      {table.getRowModel().rows.map(row => {
+        return (
+          <TableRow key={row.id}>
+            {row.getVisibleCells().map(cell => {
+              return (
+                <TableCell key={cell.id} className={cell.column.columnDef.meta?.cellClassName}>
+                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
+                </TableCell>
+              );
+            })}
+          </TableRow>
+        );
+      })}
+    </TableBody>
+  );
+}
+
+export default TBody;
\ No newline at end of file
diff --git a/src/components/table/THead.jsx b/src/components/table/THead.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..e11b01a270e5fad725f2beb64350c55bc8d147ef
--- /dev/null
+++ b/src/components/table/THead.jsx
@@ -0,0 +1,101 @@
+import React, { Fragment } from 'react';
+import { TableHead, TableHeader, TableRow } from '../ui/table';
+import { RiLineHeight, RiSearchLine, RiSortAsc, RiSortDesc } from 'react-icons/ri';
+
+
+
+function THead({ table, setColumnFilters, ...props }) {
+  // #################################
+  // HOOKS
+  // #################################
+
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+  // ### RENDER TITLE CELL
+  const renderTitleCell = (header) => {
+    if (header.column.getCanSort()) {
+      // return title cell with sorting icon
+      return (
+        <TableHead key={header.id} className={`${header.column.columnDef.meta?.headerClassName} cursor-pointer group bg-UhhWhite bg-clip-padding`} onClick={header.column.getToggleSortingHandler()}>
+          <span className='flex justify-between items-center pointer-events-none'>
+            {header.column.columnDef.header}
+            {renderOrderIcon(header.column.getIsSorted())}
+          </span>
+        </TableHead>);
+    } else {
+      // prevent error on columns without header
+      const title = (typeof header.column.columnDef.header === 'string') ? header.column.columnDef.header : '';
+      return <TableHead key={header.id} className={`${header.column.columnDef.meta?.headerClassName} cursor-pointer group bg-UhhWhite bg-clip-padding`}>{title}</TableHead>;
+    }
+  };
+
+  // ### RENDER ORDER ICON
+  const renderOrderIcon = (sorted) => {
+    // check if this is the ordered column
+    switch (sorted) {
+      case 'asc':
+        return <RiSortDesc className='pointer-events-none' />;
+      case 'desc':
+        return <RiSortAsc className='pointer-events-none' />;
+      default:
+        // if it's not the ordered column, return a different icon
+        return <span className='text-muted group-hover:text-muted-foreground'>
+          <RiLineHeight className='pointer-events-none rotate-180' />
+        </span>;
+    }
+  };
+
+
+  // ### GET FILTERABLE COLUMNS
+  const filterableCols = () => {
+    return table.getAllColumns().filter(column => column.getCanFilter() || false);
+  };
+
+  // ### RENDER FILTER CELL
+  const renderFilterCell = (header) => {
+    if (header.column.columnDef.enableColumnFilter) {
+      return <TableHead key={header.id}>
+        <span className='flex items-center'>
+          <RiSearchLine className='text-UhhBlue' />
+          <input type="search" name={header.column.columnDef.accessorKey} placeholder={`filter ${header.column.columnDef.header}`}
+            className='p-1 w-full outline-none border-none bg-transparent focus:ring-0 font-UhhR text-xs text-UhhRed' onChange={(e) => { onFilterChange(e.target.name, e.target.value); }} />
+        </span>
+      </TableHead>;
+    }
+    // if it's not filterable, return an empty cell
+    return <TableHead key={header.id}></TableHead>;
+  };
+
+  // ### CHANGE FILTER
+  const onFilterChange = (id, value) => setColumnFilters(
+    prev => prev.filter(f => f.id !== id).concat({ id, value })
+  );
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <TableHeader className='sticky top-0'>
+      {/* TITLES */}
+      {table.getHeaderGroups().map(headerGroup => {
+        return (
+          <Fragment key={headerGroup.id}>
+            <TableRow>
+              {headerGroup.headers.map(header => {
+                return renderTitleCell(header);
+              })}
+            </TableRow>
+            {/* FILTERS */}
+            {filterableCols().length > 0 && <TableRow>
+              {headerGroup.headers.map((header) => renderFilterCell(header))}
+            </TableRow>}
+          </Fragment>
+        );
+      })}
+    </TableHeader>
+  );
+}
+
+export default THead;
\ No newline at end of file
diff --git a/src/components/table/customTable.jsx b/src/components/table/customTable.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..07c5742b17494ff8856e15167ad527d6e57bec3f
--- /dev/null
+++ b/src/components/table/customTable.jsx
@@ -0,0 +1,79 @@
+import React, { useState } from 'react';
+import { getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table';
+import { Table } from "/src/components/ui/table";
+import Heading from '../font/Heading';
+import DataTableViewOptions from './DataTableViewOptions';
+import THead from './THead';
+import Pagination from './Pagination';
+import TBody from './TBody';
+
+
+function CustomTable({ columns = [], data = {}, title = '' }) {
+  // #################################
+  // HOOKS
+  // #################################
+
+  // ### INIT FILTERS
+  const [columnFilters, setColumnFilters] = useState([]);
+  // ### INIT VISIBILITY
+  const [columnVisibility, setColumnVisibility] = useState({});
+  // ### INIT TABLE
+  const table = useReactTable({
+    data,
+    columns,
+    state: {
+      columnFilters,
+      columnVisibility
+    },
+    getFilteredRowModel: getFilteredRowModel(),
+    getSortedRowModel: getSortedRowModel(),
+    getPaginationRowModel: getPaginationRowModel(),
+    getCoreRowModel: getCoreRowModel(),
+    onColumnVisibilityChange: setColumnVisibility,
+    // define custom filter functions
+    filterFns: {
+      regex: (rows, columnIds, filterValue) => {
+        try {
+          console.log("🚀 ~ CustomTable ~ rows.getValue(columnIds):", rows.getValue(columnIds));
+
+          const regex = new RegExp(filterValue, 'i');
+          return rows.getValue(columnIds).toString().match(regex) ? true : false;
+        } catch (error) {
+          console.error(error);
+          return false;
+        }
+      }
+    }
+  });
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <>
+      {/* title line incl.  */}
+      <Heading level="4" className='flex justify between'>
+        {title}
+        {/* HIDE COLUMNS */}
+        <DataTableViewOptions table={table} />
+      </Heading>
+      <Table className='w-full border-collapse table-auto border border-UhhLightGrey'>
+        {/* HEADER */}
+        <THead table={table} setColumnFilters={setColumnFilters} />
+        {/* BODY */}
+        {table.getRowModel().rows.length > 0 && <TBody table={table} />}
+      </Table>
+      {table.getRowModel().rows.length === 0 && <div className='text-center'>No matching data found</div>}
+
+      {/* FOOTER */}
+      {table.getRowModel().rows.length > 0 && <Pagination table={table} />}
+
+    </>
+  );
+};
+
+export default React.memo(CustomTable);
\ No newline at end of file
diff --git a/src/components/ui/button.jsx b/src/components/ui/button.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..46f3ccb4c0749027c6ca96dd0c26e0693e930cae
--- /dev/null
+++ b/src/components/ui/button.jsx
@@ -0,0 +1,47 @@
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva } from "class-variance-authority";
+
+import { cn } from "/src/utils";
+
+const buttonVariants = cva(
+  "inline-flex items-center justify-center text-sm font-UhhBC ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 box-border border",
+  {
+    variants: {
+      variant: {
+        default: "border-primary bg-primary text-primary-foreground hover:bg-UhhWhite hover:text-primary",
+        destructive:
+          "border-destructive bg-destructive text-destructive-foreground hover:bg-UhhWhite hover:text-destructive",
+        outline:
+          "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
+        secondary:
+          "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+        ghost: "hover:bg-accent hover:text-accent-foreground",
+        link: "text-primary underline-offset-4 hover:underline",
+      },
+      size: {
+        default: "h-10 px-4 py-2",
+        sm: "h-9 px-3",
+        lg: "h-11 px-8",
+        icon: "h-10 w-10",
+      },
+    },
+    defaultVariants: {
+      variant: "default",
+      size: "default",
+    },
+  }
+);
+
+const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
+  const Comp = asChild ? Slot : "button";
+  return (
+    (<Comp
+      className={cn(buttonVariants({ variant, size, className }))}
+      ref={ref}
+      {...props} />)
+  );
+});
+Button.displayName = "Button";
+
+export { Button, buttonVariants };
diff --git a/src/components/ui/dialog.jsx b/src/components/ui/dialog.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..838e77053c73f515ae4b1738a4937b615612d067
--- /dev/null
+++ b/src/components/ui/dialog.jsx
@@ -0,0 +1,94 @@
+import * as React from "react";
+import * as DialogPrimitive from "@radix-ui/react-dialog";
+import { X } from "lucide-react";
+
+import { cn } from "/src/utils";
+
+const Dialog = DialogPrimitive.Root;
+
+const DialogTrigger = DialogPrimitive.Trigger;
+
+const DialogPortal = DialogPrimitive.Portal;
+
+const DialogClose = DialogPrimitive.Close;
+
+const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (
+  <DialogPrimitive.Overlay
+    ref={ref}
+    className={cn(
+      "fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
+      className
+    )}
+    {...props} />
+));
+DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
+
+const DialogContent = React.forwardRef(({ className, children, ...props }, ref) => (
+  <DialogPortal>
+    <DialogOverlay />
+    <DialogPrimitive.Content
+      ref={ref}
+      className={cn(
+        "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full",
+        className
+      )}
+      {...props}>
+      {children}
+      <DialogPrimitive.Close
+        className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
+        <X className="h-4 w-4" />
+        <span className="sr-only">Close</span>
+      </DialogPrimitive.Close>
+    </DialogPrimitive.Content>
+  </DialogPortal>
+));
+DialogContent.displayName = DialogPrimitive.Content.displayName;
+
+const DialogHeader = ({
+  className,
+  ...props
+}) => (
+  <div
+    className={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)}
+    {...props} />
+);
+DialogHeader.displayName = "DialogHeader";
+
+const DialogFooter = ({
+  className,
+  ...props
+}) => (
+  <div
+    className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
+    {...props} />
+);
+DialogFooter.displayName = "DialogFooter";
+
+const DialogTitle = React.forwardRef(({ className, ...props }, ref) => (
+  <DialogPrimitive.Title
+    ref={ref}
+    className={cn("text-lg font-semibold leading-none tracking-tight", className)}
+    {...props} />
+));
+DialogTitle.displayName = DialogPrimitive.Title.displayName;
+
+const DialogDescription = React.forwardRef(({ className, ...props }, ref) => (
+  <DialogPrimitive.Description
+    ref={ref}
+    className={cn("text-sm text-muted-foreground", className)}
+    {...props} />
+));
+DialogDescription.displayName = DialogPrimitive.Description.displayName;
+
+export {
+  Dialog,
+  DialogPortal,
+  DialogOverlay,
+  DialogClose,
+  DialogTrigger,
+  DialogContent,
+  DialogHeader,
+  DialogFooter,
+  DialogTitle,
+  DialogDescription,
+};
diff --git a/src/components/ui/dropdown-menu.jsx b/src/components/ui/dropdown-menu.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..790db69f9a216f945b41910daf6a8ea6a2309d4e
--- /dev/null
+++ b/src/components/ui/dropdown-menu.jsx
@@ -0,0 +1,155 @@
+import * as React from "react";
+import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
+import { Check, ChevronRight, Circle } from "lucide-react";
+
+import { cn } from "/src/utils";
+
+const DropdownMenu = DropdownMenuPrimitive.Root;
+
+const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
+
+const DropdownMenuGroup = DropdownMenuPrimitive.Group;
+
+const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
+
+const DropdownMenuSub = DropdownMenuPrimitive.Sub;
+
+const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
+
+const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }, ref) => (
+  <DropdownMenuPrimitive.SubTrigger
+    ref={ref}
+    className={cn(
+      "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
+      inset && "pl-8",
+      className
+    )}
+    {...props}>
+    {children}
+    <ChevronRight className="ml-auto h-4 w-4" />
+  </DropdownMenuPrimitive.SubTrigger>
+));
+DropdownMenuSubTrigger.displayName =
+  DropdownMenuPrimitive.SubTrigger.displayName;
+
+const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) => (
+  <DropdownMenuPrimitive.SubContent
+    ref={ref}
+    className={cn(
+      "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
+      className
+    )}
+    {...props} />
+));
+DropdownMenuSubContent.displayName =
+  DropdownMenuPrimitive.SubContent.displayName;
+
+const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (
+  <DropdownMenuPrimitive.Portal>
+    <DropdownMenuPrimitive.Content
+      ref={ref}
+      sideOffset={sideOffset}
+      className={cn(
+        "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
+        className
+      )}
+      {...props} />
+  </DropdownMenuPrimitive.Portal>
+));
+DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
+
+const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => (
+  <DropdownMenuPrimitive.Item
+    ref={ref}
+    className={cn(
+      "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
+      inset && "pl-8",
+      className
+    )}
+    {...props} />
+));
+DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
+
+const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checked, ...props }, ref) => (
+  <DropdownMenuPrimitive.CheckboxItem
+    ref={ref}
+    className={cn(
+      "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
+      className
+    )}
+    checked={checked}
+    {...props}>
+    <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
+      <DropdownMenuPrimitive.ItemIndicator>
+        <Check className="h-4 w-4" />
+      </DropdownMenuPrimitive.ItemIndicator>
+    </span>
+    {children}
+  </DropdownMenuPrimitive.CheckboxItem>
+));
+DropdownMenuCheckboxItem.displayName =
+  DropdownMenuPrimitive.CheckboxItem.displayName;
+
+const DropdownMenuRadioItem = React.forwardRef(({ className, children, ...props }, ref) => (
+  <DropdownMenuPrimitive.RadioItem
+    ref={ref}
+    className={cn(
+      "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
+      className
+    )}
+    {...props}>
+    <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
+      <DropdownMenuPrimitive.ItemIndicator>
+        <Circle className="h-2 w-2 fill-current" />
+      </DropdownMenuPrimitive.ItemIndicator>
+    </span>
+    {children}
+  </DropdownMenuPrimitive.RadioItem>
+));
+DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
+
+const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }, ref) => (
+  <DropdownMenuPrimitive.Label
+    ref={ref}
+    className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
+    {...props} />
+));
+DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
+
+const DropdownMenuSeparator = React.forwardRef(({ className, ...props }, ref) => (
+  <DropdownMenuPrimitive.Separator
+    ref={ref}
+    className={cn("-mx-1 my-1 h-px bg-muted", className)}
+    {...props} />
+));
+DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
+
+const DropdownMenuShortcut = ({
+  className,
+  ...props
+}) => {
+  return (
+    (<span
+      className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
+      {...props} />)
+  );
+};
+DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
+
+export {
+  DropdownMenu,
+  DropdownMenuTrigger,
+  DropdownMenuContent,
+  DropdownMenuItem,
+  DropdownMenuCheckboxItem,
+  DropdownMenuRadioItem,
+  DropdownMenuLabel,
+  DropdownMenuSeparator,
+  DropdownMenuShortcut,
+  DropdownMenuGroup,
+  DropdownMenuPortal,
+  DropdownMenuSub,
+  DropdownMenuSubContent,
+  DropdownMenuSubTrigger,
+  DropdownMenuRadioGroup,
+};
diff --git a/src/components/ui/table.jsx b/src/components/ui/table.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..9fdceb5596ba762a1a5594e8b88cb2193907d764
--- /dev/null
+++ b/src/components/ui/table.jsx
@@ -0,0 +1,83 @@
+import * as React from "react";
+
+import { cn } from "/src/utils";
+
+const Table = React.forwardRef(({ className, ...props }, ref) => (
+  // <div className="relative w-full overflow-auto">
+  <table
+    ref={ref}
+    className={cn("w-full caption-bottom border-separate border-spacing-0 table-auto", className)}
+    {...props} />
+  // </div>
+));
+Table.displayName = "Table";
+
+const TableHeader = React.forwardRef(({ className, ...props }, ref) => (
+  <thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
+));
+TableHeader.displayName = "TableHeader";
+
+const TableBody = React.forwardRef(({ className, ...props }, ref) => (
+  <tbody
+    ref={ref}
+    className={cn("[&_tr:last-child]:border-0", className)}
+    {...props} />
+));
+TableBody.displayName = "TableBody";
+
+const TableFooter = React.forwardRef(({ className, ...props }, ref) => (
+  <tfoot
+    ref={ref}
+    className={cn("bg-primary font-medium text-primary-foreground", className)}
+    {...props} />
+));
+TableFooter.displayName = "TableFooter";
+
+const TableRow = React.forwardRef(({ className, ...props }, ref) => (
+  <tr
+    ref={ref}
+    className={cn(
+      "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
+      className
+    )}
+    {...props} />
+));
+TableRow.displayName = "TableRow";
+
+const TableHead = React.forwardRef(({ className, ...props }, ref) => (
+  <th
+    ref={ref}
+    className={cn(
+      "border border-UhhLightGray font-UhhSLC px-1 text-left [&:has([role=checkbox])]:pr-0",
+      className
+    )}
+    {...props} />
+));
+TableHead.displayName = "TableHead";
+
+const TableCell = React.forwardRef(({ className, ...props }, ref) => (
+  <td
+    ref={ref}
+    className={cn("border border-UhhLightGray p-1 align-middle [&:has([role=checkbox])]:pr-0", className)}
+    {...props} />
+));
+TableCell.displayName = "TableCell";
+
+const TableCaption = React.forwardRef(({ className, ...props }, ref) => (
+  <caption
+    ref={ref}
+    className={cn("mt-4 text-sm text-muted-foreground", className)}
+    {...props} />
+));
+TableCaption.displayName = "TableCaption";
+
+export {
+  Table,
+  TableHeader,
+  TableBody,
+  TableFooter,
+  TableHead,
+  TableRow,
+  TableCell,
+  TableCaption,
+};
diff --git a/src/pages/Config/AI/Models.jsx b/src/pages/Config/AI/Models.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..3a36ab592b2f274b911555cf8c0ab2eeb3b0f1e9
--- /dev/null
+++ b/src/pages/Config/AI/Models.jsx
@@ -0,0 +1,169 @@
+import React, { useState } from 'react';
+import { useAuth } from '/src/contexts/Auth/AuthState';
+import api from '/src/utils/AxiosConfig';
+import ConfirmBox from '/src/components/boxes/ConfirmBox';
+import InfoBox from '/src/components/boxes/InfoBox';
+import CustomTable from '/src/components/table/customTable';
+import { mergeBackendValidation, setFlashMsg } from '/src/utils/ErrorHandling';
+import {
+  DropdownMenu,
+  DropdownMenuContent,
+  DropdownMenuItem,
+  DropdownMenuLabel,
+  DropdownMenuSeparator,
+  DropdownMenuTrigger,
+} from "/src/components/ui/dropdown-menu";
+import { Button } from '/src/components/ui/button';
+import { RiDeleteBinLine, RiFileInfoLine, RiMoreLine, RiRefreshLine } from 'react-icons/ri';
+
+
+function Models({ data, setData }) {
+  // #################################
+  // HOOKS
+  // #################################
+  // ### CONNECT AUTH CONTEXT
+  const { currentUser } = useAuth();
+  // ### CONFIRM DIALOG
+  const [confirmDialog, setConfirmDialog] = useState({ open: false, item: {} });
+  // ### INFO DIALOG
+  const [infoDialog, setInfoDialog] = useState({ open: false, title: '', description: '', body: '', item: {} });
+
+  // ### HANDLE DELETE ITEM
+  const handleDelete = async (model) => {
+    try {
+      // remove item from backend
+      const result = await api.delete('/ai/models', { data: { model } });
+      // remove item from current display
+      const filteredData = data.filter(item => item.name !== model);
+      setData(filteredData);
+      // show message from backend
+      setFlashMsg(result?.data?.message);
+    } catch (error) {
+      mergeBackendValidation(error.response.status, error.response.data);
+    }
+  };
+
+  // ### HANDLE UPDATE ITEM
+  const handleUpdate = async (model) => {
+    try {
+      // install item in backend
+      const result = await api.put('/ai/models', { model });
+      // show message from backend
+      setFlashMsg(result?.data?.message);
+    } catch (error) {
+      mergeBackendValidation(error.response.status, error.response.data);
+    }
+  };
+
+  // ### HANDLE ITEM DETAILS
+  const handleDetails = async (model) => {
+    try {
+      // install item in backend
+      const result = await api.post('/ai/model', { model });
+      // show message from backend
+      setInfoDialog({ open: true, title: model, description: 'model details', body: result?.data });
+    } catch (error) {
+      mergeBackendValidation(error.response.status, error.response.data);
+    }
+  };
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+  // ### DEFINE TABLE ROWS
+  const columns = [
+    {
+      accessorKey: 'name',
+      header: 'name',
+      enableColumnFilter: true,
+      enableHiding: false,
+      filterFn: 'regex',
+      // cell: (props) => <span>{props.getValue()}</span>
+      cell: (props) => {
+        return (props.row.original.name);
+      }
+
+    }, {
+      accessorKey: 'size',
+      header: 'size in bytes',
+      enableColumnFilter: true,
+      enableHiding: true,
+      filterFn: 'includesString',
+      cell: (props) => <span>{Number(props.getValue())}</span>
+      // cell: (props) => {
+      //   return (Number(props.row.original.size) / 1024 / 1024 / 1024).toFixed(2).toString();
+      // }
+    }, {
+      id: 'details.parameter_size',
+      accessorKey: 'details.parameter_size',
+      header: 'parameters',
+      enableColumnFilter: true,
+      enableHiding: true,
+      filterFn: 'regex',
+      cell: (props) => <span>{props.getValue()}</span>
+      // cell: (props) => {
+      //   return (props.row.original.details.parameter_size);
+      // }
+
+    }, {
+      id: "actions",
+      enableHiding: false,
+      meta: {
+        cellClassName: 'text-center w-16',
+      },
+      cell: ({ row }) => {
+        const item = row.original;
+        return (
+          <DropdownMenu>
+            <DropdownMenuTrigger asChild>
+              <Button title="open menu">
+                <span className="sr-only">Open menu</span>
+                <RiMoreLine />
+              </Button>
+            </DropdownMenuTrigger>
+            <DropdownMenuContent align="end">
+              <DropdownMenuLabel>Actions</DropdownMenuLabel>
+              <DropdownMenuItem className='flex items-center space-x-2 w-full' onClick={() => handleDetails(item.name)}>
+                <span><RiFileInfoLine /></span>
+                <span>show details</span>
+              </DropdownMenuItem>
+              {currentUser.role > 2 ?
+                <>
+                  <DropdownMenuItem className='cursor-pointer flex items-center space-x-2 w-full' onClick={() => handleUpdate(item.name)}>
+                    <span><RiRefreshLine /></span>
+                    <span>update model</span>
+                  </DropdownMenuItem>
+                  <DropdownMenuSeparator />
+                  <DropdownMenuItem className='cursor-pointer text-UhhRed hover:text-UhhWhite hover:bg-UhhRed' onClick={() => setConfirmDialog({ open: true, idToDelete: item.name, displayName: item.name })}>
+                    <span className='flex items-center space-x-2 w-full'>
+                      <span><RiDeleteBinLine /></span>
+                      <span>delete model</span>
+                    </span>
+                  </DropdownMenuItem>
+                </>
+                : null}
+            </DropdownMenuContent>
+          </DropdownMenu>
+        );
+      },
+    }
+  ];
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <div>
+      {/* table */}
+      <CustomTable columns={columns} data={data} title='installed models' />
+
+      {/* confirmDialog */}
+      <ConfirmBox confirmDialog={confirmDialog} closeDialog={() => setConfirmDialog({ ...confirmDialog, open: false })} handleProceed={() => { handleDelete(confirmDialog.idToDelete); }} />
+
+      {/* infoDialog */}
+      <InfoBox infoDialog={infoDialog} closeDialog={() => setInfoDialog({ ...infoDialog, open: false })} />
+
+    </div>
+  );
+}
+
+export default React.memo(Models);
\ No newline at end of file
diff --git a/src/pages/Config/AI/NewModel.jsx b/src/pages/Config/AI/NewModel.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..3e41ab24e0c61d450bd631d7a97b7aca943b6676
--- /dev/null
+++ b/src/pages/Config/AI/NewModel.jsx
@@ -0,0 +1,67 @@
+import React, { useEffect, useState } from 'react';
+import { useAuth } from '/src/contexts/Auth/AuthState';
+import api from '/src/utils/AxiosConfig';
+import Heading from '/src/components/font/Heading';
+import { mergeBackendValidation, setFlashMsg } from '/src/utils/ErrorHandling';
+import { z } from 'zod';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { FormProvider, useForm, useFormContext } from 'react-hook-form';
+import Input from '/src/components/form/Input';
+import Submit from '/src/components/form/Submit';
+import { Link } from 'react-router-dom';
+
+function NewModel({ data, setData }) {
+  // #################################
+  // HOOKS
+  // #################################
+  // ### CONNECT AUTH CONTEXT
+  const { currentUser } = useAuth();
+
+  // ### SCHEMA
+  const schema = z.object({
+    model: z.string().min(1),
+  });
+
+  // ### FORM HOOKS
+  const methods = useForm({
+    resolver: zodResolver(schema),
+    mode: 'onSubmit'
+  });
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+  // ### HANDLE INSTALL ITEM
+  const handleInstall = async (inputs) => {
+    try {
+      // install item in backend
+      const result = await api.put('/ai/models', { model: inputs.model });
+      // add new model to the list
+      setData([...data, result.data.model[0]]);
+      // show message from backend
+      setFlashMsg(result?.data?.message);
+    } catch (error) {
+      mergeBackendValidation(error.response.status, error.response.data);
+    }
+  };
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <>
+      {(currentUser?.role >= 2) ?
+        <FormProvider {...methods} >
+          <Heading level="4">install new model</Heading>
+          <form onSubmit={methods.handleSubmit(handleInstall)} className='md:w-1/3'>
+            <Input name='model' type='text' title='Model Name' className='h-16' required={true} tooltip={<Link to='https://ollama.com/library' target='_blank' rel='noopener noreferrer'>Ollama Library</Link>} />
+            <Submit size='sm' value={methods.formState.isSubmitting ? 'installing...' : 'install model'} />
+          </form>
+        </FormProvider>
+        : null}
+
+    </>
+  );
+}
+
+export default React.memo(NewModel);
\ No newline at end of file
diff --git a/src/pages/Config/AI/Status.jsx b/src/pages/Config/AI/Status.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..c6f52227e10b102df0d4e146923064daca7c8150
--- /dev/null
+++ b/src/pages/Config/AI/Status.jsx
@@ -0,0 +1,54 @@
+import React, { useEffect, useState } from 'react';
+import { mergeBackendValidation } from '../../../utils/ErrorHandling';
+import api from '../../../utils/AxiosConfig';
+import { RiWifiFill, RiWifiOffFill } from "react-icons/ri";
+import Heading from '../../../components/font/Heading';
+
+function AIStatus() {
+  // #################################
+  // HOOKS
+  // #################################
+  // ### SET STATUS
+  const [status, setStatus] = useState({});
+
+  // ### FETCH STATUS
+  useEffect(() => {
+    // ### on run exec this code
+    const controller = new AbortController();
+    const getStatus = async () => {
+      try {
+        // fetch all items and store them in state
+        const result = await api.get('/ai/status', {
+          signal: controller.signal
+        });
+
+        setStatus(result.data.running);
+      } catch (error) {
+        mergeBackendValidation(error.response.status, error.response.data);
+      }
+    };
+    getStatus();
+    // ### return will be executed on unmounting this component
+    return () => {
+      // on unmount abort request
+      controller.abort();
+    };
+    // ### opt. 2. argument: when to run this hook
+  }, []);
+  // #################################
+  // FUNCTIONS
+  // #################################
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <Heading level="4">status:
+      {status ?
+        <RiWifiFill className='ml-4 text-UhhBlue' title='AI backend reachable' />
+        : <RiWifiOffFill className='ml-4 text-UhhRed' title='AI backend offline' />}
+    </Heading>
+  );
+}
+
+export default React.memo(AIStatus);
\ No newline at end of file
diff --git a/src/pages/Config/AIModels.jsx b/src/pages/Config/AIModels.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7eb9bf1408c6bec1e25b7118da890739ba2691f3
--- /dev/null
+++ b/src/pages/Config/AIModels.jsx
@@ -0,0 +1,84 @@
+import React, { useEffect, useState } from 'react';
+import api from '../../utils/AxiosConfig';
+import { mergeBackendValidation } from '../../utils/ErrorHandling';
+import NewModel from './AI/NewModel';
+import Models from './AI/Models';
+import AIStatus from './AI/Status';
+
+function AIModels() {
+  // #################################
+  // HOOKS
+  // #################################
+  // ### SET TABLE DATA
+  const [data, setData] = useState({});
+
+  // ### FETCH MODELS
+  useEffect(() => {
+    // ### on run exec this code
+    const controller = new AbortController();
+    const getDocument = async () => {
+      try {
+        // fetch all items and store them in state
+        const items = await api.post('/ai/models', { filter: '' }, {
+          signal: controller.signal
+        });
+
+        setData(items.data.models);
+      } catch (error) {
+        mergeBackendValidation(error.response.status, error.response.data);
+      }
+    };
+    getDocument();
+    // ### return will be executed on unmounting this component
+    return () => {
+      // on unmount abort request
+      controller.abort();
+    };
+    // ### opt. 2. argument: when to run this hook
+  }, []);
+
+
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+
+
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <>
+      {/* AI */}
+      <section>
+        {/* <!-- header --> */}
+        <div className="group sticky top-0 bg-UhhWhite z-10 mb-4 font-UhhBC text-2xl">
+          {/* <!-- number --> */}
+          <span className="text-UhhRed">01 </span>
+          {/* <!-- title --> */}
+          AI
+          {/* <!-- line --> */}
+          <div className="absolute w-[50vw] right-[50%] h-1 bg-UhhRed"></div>
+        </div>
+
+        <div className='max-h-full flex flex-col'>
+          <div>
+            <AIStatus />
+          </div>
+          <div>
+            <NewModel data={data} setData={setData} />
+          </div>
+          <div className='overflow-y-auto'>
+            <Models data={data} setData={setData} />
+          </div>
+        </div>
+
+
+
+      </section>
+    </>
+  );
+}
+
+export default React.memo(AIModels);
\ No newline at end of file
diff --git a/src/pages/Config/Config.jsx b/src/pages/Config/Config.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..b3bc0e0d99820eda692b45c018036571fa2a2ae1
--- /dev/null
+++ b/src/pages/Config/Config.jsx
@@ -0,0 +1,34 @@
+import React, { useEffect, useState } from 'react';
+import { Helmet } from 'react-helmet-async';
+import { useAuth } from '../../contexts/Auth/AuthState';
+import AIModels from './AIModels';
+import Embeddings from './Embeddings';
+
+
+function Config() {
+  // #################################
+  // HOOKS
+  // #################################
+  // ### CONNECT AUTH CONTEXT
+  const { currentUser } = useAuth();
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <>
+      {/* render page title */}
+      <Helmet><title>[{import.meta.env.VITE_APP_NAME}] Config</title></Helmet>
+      {/* AI */}
+      <AIModels />
+      {/* RAG */}
+      <Embeddings />
+    </>
+  );
+}
+
+export default React.memo(Config);
\ No newline at end of file
diff --git a/src/pages/Config/Embeddings.jsx b/src/pages/Config/Embeddings.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..80bc05b0f77ba92c1247daae241b86d1e5a9051f
--- /dev/null
+++ b/src/pages/Config/Embeddings.jsx
@@ -0,0 +1,76 @@
+import React, { useEffect, useState } from 'react';
+import Status from './Embeddings/Status';
+import { mergeBackendValidation } from '../../utils/ErrorHandling';
+import api from '../../utils/AxiosConfig';
+import Update from './Embeddings/Update';
+import Delete from './Embeddings/Delete';
+
+function Embeddings() {
+  // #################################
+  // HOOKS
+  // #################################
+  // ### SET DATA
+  const [status, setStatus] = useState({});
+
+  // ### FETCH MODELS
+  useEffect(() => {
+    // ### on run exec this code
+    const controller = new AbortController();
+    const getStatus = async () => {
+      try {
+        // fetch all items and store them in state
+        const result = await api.get('/embeddings', {
+          signal: controller.signal
+        });
+        setStatus(result.data);
+      } catch (error) {
+        mergeBackendValidation(error.response.status, error.response.data);
+      }
+    };
+    getStatus();
+    // ### return will be executed on unmounting this component
+    return () => {
+      // on unmount abort request
+      controller.abort();
+    };
+    // ### opt. 2. argument: when to run this hook
+  }, []);
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <section>
+      {/* <!-- header --> */}
+      <div className="group sticky top-0 bg-UhhWhite z-10 mb-4 font-UhhBC text-2xl">
+        {/* <!-- number --> */}
+        <span className="text-UhhRed">02 </span>
+        {/* <!-- title --> */}
+        Embeddings
+        {/* <!-- line --> */}
+        <div className="absolute w-[50vw] right-[50%] h-1 bg-UhhRed"></div>
+      </div>
+
+      <div className='max-h-full flex flex-col'>
+        <div>
+          {/* rag status */}
+          <Status status={status} />
+        </div>
+        <div>
+          {/* update embeddings */}
+          <Update setStatus={setStatus} />
+        </div>
+        <div>
+          {/* delete embeddings */}
+          <Delete setStatus={setStatus} />
+        </div>
+      </div>
+    </section>
+  );
+}
+
+export default React.memo(Embeddings);
\ No newline at end of file
diff --git a/src/pages/Config/Embeddings/Delete.jsx b/src/pages/Config/Embeddings/Delete.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..928d9cfbcdfdaac984f0e97311129d24fd3b9b1f
--- /dev/null
+++ b/src/pages/Config/Embeddings/Delete.jsx
@@ -0,0 +1,75 @@
+import React, { useState } from 'react';
+import { useAuth } from '../../../contexts/Auth/AuthState';
+import { FormProvider, useForm } from 'react-hook-form';
+import Heading from '../../../components/font/Heading';
+import Input from '../../../components/form/Input';
+import Submit from '../../../components/form/Submit';
+import ConfirmBox from '../../../components/boxes/ConfirmBox';
+import { mergeBackendValidation, setFlashMsg } from '../../../utils/ErrorHandling';
+import api from '../../../utils/AxiosConfig';
+
+function Delete({ setStatus }) {
+  // #################################
+  // HOOKS
+  // #################################
+  // ### CONNECT AUTH CONTEXT
+  const { currentUser } = useAuth();
+  // ### FORM HOOKS
+  const methods = useForm();
+  // ### CONFIRM DIALOG
+  const [confirmDialog, setConfirmDialog] = useState({ open: false, item: {} });
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+  // security
+  const handleConfirm = () => {
+    setConfirmDialog({ open: true, displayName: 'Vector Database' });
+  };
+
+  // ### HANDLE INSTALL ITEM
+  const handleDelete = async () => {
+    try {
+      // install item in backend
+      const result = await api.delete('/embeddings');
+
+      console.log("🚀 ~ handleDelete ~ result:", result);
+
+      // renew status
+      setStatus(result.data);
+      // show message from backend
+      setFlashMsg(result?.data?.message);
+    } catch (error) {
+
+      console.log("🚀 ~ handleDelete ~ error:", error);
+
+
+      mergeBackendValidation(error.response.status, error.response.data);
+    }
+  };
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <div>
+      {(currentUser?.role >= 2) ?
+        <>
+          <FormProvider {...methods} >
+            <Heading level="4">Delete Embedding Collection</Heading>
+            <form onSubmit={methods.handleSubmit(handleConfirm)} className='md:w-1/3'>
+              <Submit variant='destructive' size='sm' value={methods.formState.isSubmitting ? 'deleting...' : 'delete'} />
+            </form>
+          </FormProvider>
+
+
+          <ConfirmBox confirmDialog={confirmDialog} closeDialog={() => setConfirmDialog({ ...confirmDialog, open: false })} handleProceed={() => { handleDelete(confirmDialog.idToDelete); }} />
+
+        </>
+
+        : null}
+    </div>
+  );
+}
+
+export default React.memo(Delete);
\ No newline at end of file
diff --git a/src/pages/Config/Embeddings/Status.jsx b/src/pages/Config/Embeddings/Status.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..f54a2d95b27b3bcb13b5ddf3f17105cdf08b69ba
--- /dev/null
+++ b/src/pages/Config/Embeddings/Status.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import JsonToHtmlDL from '../../../components/boxes/JsonToHtmlDL';
+import Heading from '../../../components/font/Heading';
+
+function Status({ status }) {
+  // #################################
+  // HOOKS
+  // #################################
+
+  // #################################
+  // FUNCTIONS
+  // #################################
+
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <div>
+      <Heading level="4">Status</Heading>
+      <JsonToHtmlDL jsonContent={status} />
+    </div>
+  );
+}
+
+export default React.memo(Status);
\ No newline at end of file
diff --git a/src/pages/Config/Embeddings/Update.jsx b/src/pages/Config/Embeddings/Update.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..b2a2564e3eb8626ce6117e158706e029c8fdb18e
--- /dev/null
+++ b/src/pages/Config/Embeddings/Update.jsx
@@ -0,0 +1,69 @@
+import React, { useState } from 'react';
+import { Button } from '../../../components/ui/button';
+import Heading from '../../../components/font/Heading';
+import Tooltip from '../../../components/boxes/Tooltip';
+import api from '../../../utils/AxiosConfig';
+import { useAuth } from '../../../contexts/Auth/AuthState';
+import { FormProvider, useForm } from 'react-hook-form';
+import Submit from '../../../components/form/Submit';
+import { mergeBackendValidation, setFlashMsg } from '../../../utils/ErrorHandling';
+import JsonToHtmlDL from '../../../components/boxes/JsonToHtmlDL';
+
+function Update({ setStatus }) {
+  // #################################
+  // HOOKS
+  // #################################
+  // ### CONNECT AUTH CONTEXT
+  const { currentUser } = useAuth();
+
+  // ### SET DATA
+  const [data, setData] = useState({});
+
+  // ### FORM HOOKS
+  const methods = useForm();
+  // #################################
+  // FUNCTIONS
+  // #################################
+  // ### UPDATE EMBEDDINGS
+  const handleUpdate = async () => {
+    try {
+      // update
+      const update = await api.patch('/embeddings');
+      // renew status
+      setData(update.data);
+
+      // renew status
+      const status = await api.get('/embeddings');
+      setStatus(status.data);
+
+
+      // show message from backend
+      setFlashMsg(update.data?.message);
+    } catch (error) {
+      mergeBackendValidation(error.response.status, error.response.data);
+    }
+  };
+  // #################################
+  // OUTPUT
+  // #################################
+  return (
+    <>
+      {(currentUser?.role >= 2) ?
+        <FormProvider {...methods}>
+          <Heading level="4">Update Embeddings
+            <Tooltip><p className='text-base'>based on local RAG Files</p></Tooltip>
+          </Heading>
+          <form onSubmit={methods.handleSubmit(handleUpdate)} className='md:w-1/3'>
+            <Submit size='sm' value={methods.formState.isSubmitting ? 'updating...' : 'update'} />
+          </form>
+          <details className='py-4 border-b border-grey-lighter'>
+            <summary>Update Result</summary>
+            <JsonToHtmlDL jsonContent={data} />
+          </details>
+        </FormProvider>
+        : null}
+    </>
+  );
+}
+
+export default React.memo(Update);
\ No newline at end of file
diff --git a/src/routes/Sitemap.jsx b/src/routes/Sitemap.jsx
index 17567fff259867dc23a2aff8433d9e7efd6e3242..72b095386acd7ccf140d2cb71aa853cd9b09faf4 100644
--- a/src/routes/Sitemap.jsx
+++ b/src/routes/Sitemap.jsx
@@ -27,6 +27,17 @@ export const sitemap = [{
 
         ]
       },
+      // ADMIN
+      {
+        title: 'Config',
+        path: '/config',
+        handle: { crumb: () => <Link to="/config">Config</Link> },
+        children: [
+          { index: true, element: loadComponent('Config/Config') },
+          { title: 'Chat', path: ':id', element: loadComponent('Config/Onboarding') }
+
+        ]
+      },
       // LOGOUT
       {
         title: 'Logout',