diff --git a/diplomas/package-lock.json b/diplomas/package-lock.json
index 7d3d824..e4946ec 100644
--- a/diplomas/package-lock.json
+++ b/diplomas/package-lock.json
@@ -20,8 +20,11 @@
         "@supabase/supabase-js": "^2.49.4",
         "class-variance-authority": "^0.7.1",
         "clsx": "^2.1.1",
+        "cors": "^2.8.5",
         "diplomas": "file:",
+        "express": "^5.1.0",
         "lucide-react": "^0.488.0",
+        "mysql2": "^3.14.1",
         "next": "15.3.0",
         "papaparse": "^5.5.2",
         "react": "^19.0.0",
@@ -2809,6 +2812,18 @@
         "win32"
       ]
     },
+    "node_modules/accepts": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+      "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+      "dependencies": {
+        "mime-types": "^3.0.0",
+        "negotiator": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/acorn": {
       "version": "8.14.1",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
@@ -3075,6 +3090,14 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/aws-ssl-profiles": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
+      "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
     "node_modules/axe-core": {
       "version": "4.10.3",
       "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz",
@@ -3099,6 +3122,25 @@
       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
       "dev": true
     },
+    "node_modules/body-parser": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+      "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+      "dependencies": {
+        "bytes": "^3.1.2",
+        "content-type": "^1.0.5",
+        "debug": "^4.4.0",
+        "http-errors": "^2.0.0",
+        "iconv-lite": "^0.6.3",
+        "on-finished": "^2.4.1",
+        "qs": "^6.14.0",
+        "raw-body": "^3.0.0",
+        "type-is": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -3132,6 +3174,14 @@
         "node": ">=10.16.0"
       }
     },
+    "node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/call-bind": {
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
@@ -3154,7 +3204,6 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
       "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
-      "dev": true,
       "dependencies": {
         "es-errors": "^1.3.0",
         "function-bind": "^1.1.2"
@@ -3167,7 +3216,6 @@
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
       "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
-      "dev": true,
       "dependencies": {
         "call-bind-apply-helpers": "^1.0.2",
         "get-intrinsic": "^1.3.0"
@@ -3314,6 +3362,25 @@
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "dev": true
     },
+    "node_modules/content-disposition": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+      "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+      "dependencies": {
+        "safe-buffer": "5.2.1"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/content-type": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+      "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/cookie": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
@@ -3322,6 +3389,26 @@
         "node": ">=18"
       }
     },
+    "node_modules/cookie-signature": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+      "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+      "engines": {
+        "node": ">=6.6.0"
+      }
+    },
+    "node_modules/cors": {
+      "version": "2.8.5",
+      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+      "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+      "dependencies": {
+        "object-assign": "^4",
+        "vary": "^1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/crc-32": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
@@ -3408,7 +3495,6 @@
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
       "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
-      "dev": true,
       "dependencies": {
         "ms": "^2.1.3"
       },
@@ -3461,6 +3547,22 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/denque": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+      "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/detect-libc": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
@@ -3495,7 +3597,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
       "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
-      "dev": true,
       "dependencies": {
         "call-bind-apply-helpers": "^1.0.1",
         "es-errors": "^1.3.0",
@@ -3505,12 +3606,25 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+    },
     "node_modules/emoji-regex": {
       "version": "9.2.2",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
       "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
       "dev": true
     },
+    "node_modules/encodeurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+      "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/enhanced-resolve": {
       "version": "5.18.1",
       "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
@@ -3593,7 +3707,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
       "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       }
@@ -3602,7 +3715,6 @@
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
       "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       }
@@ -3638,7 +3750,6 @@
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
       "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
-      "dev": true,
       "dependencies": {
         "es-errors": "^1.3.0"
       },
@@ -3690,6 +3801,11 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+    },
     "node_modules/escape-string-regexp": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -4106,6 +4222,63 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/express": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+      "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+      "dependencies": {
+        "accepts": "^2.0.0",
+        "body-parser": "^2.2.0",
+        "content-disposition": "^1.0.0",
+        "content-type": "^1.0.5",
+        "cookie": "^0.7.1",
+        "cookie-signature": "^1.2.1",
+        "debug": "^4.4.0",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "etag": "^1.8.1",
+        "finalhandler": "^2.1.0",
+        "fresh": "^2.0.0",
+        "http-errors": "^2.0.0",
+        "merge-descriptors": "^2.0.0",
+        "mime-types": "^3.0.0",
+        "on-finished": "^2.4.1",
+        "once": "^1.4.0",
+        "parseurl": "^1.3.3",
+        "proxy-addr": "^2.0.7",
+        "qs": "^6.14.0",
+        "range-parser": "^1.2.1",
+        "router": "^2.2.0",
+        "send": "^1.1.0",
+        "serve-static": "^2.2.0",
+        "statuses": "^2.0.1",
+        "type-is": "^2.0.1",
+        "vary": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/express/node_modules/cookie": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+      "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -4185,6 +4358,22 @@
         "node": ">=8"
       }
     },
+    "node_modules/finalhandler": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+      "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+      "dependencies": {
+        "debug": "^4.4.0",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "on-finished": "^2.4.1",
+        "parseurl": "^1.3.3",
+        "statuses": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/find-up": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -4235,6 +4424,14 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/forwarded": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/frac": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
@@ -4243,11 +4440,18 @@
         "node": ">=0.8"
       }
     },
+    "node_modules/fresh": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+      "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/function-bind": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
       "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-      "dev": true,
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
@@ -4281,11 +4485,18 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/generate-function": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
+      "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
+      "dependencies": {
+        "is-property": "^1.0.2"
+      }
+    },
     "node_modules/get-intrinsic": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
       "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
-      "dev": true,
       "dependencies": {
         "call-bind-apply-helpers": "^1.0.2",
         "es-define-property": "^1.0.1",
@@ -4317,7 +4528,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
       "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
-      "dev": true,
       "dependencies": {
         "dunder-proto": "^1.0.1",
         "es-object-atoms": "^1.0.0"
@@ -4399,7 +4609,6 @@
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
       "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       },
@@ -4471,7 +4680,6 @@
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
       "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       },
@@ -4498,7 +4706,6 @@
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
       "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
-      "dev": true,
       "dependencies": {
         "function-bind": "^1.1.2"
       },
@@ -4506,6 +4713,32 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/http-errors": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+      "dependencies": {
+        "depd": "2.0.0",
+        "inherits": "2.0.4",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "toidentifier": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/ignore": {
       "version": "5.3.2",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -4540,6 +4773,11 @@
         "node": ">=0.8.19"
       }
     },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
     "node_modules/internal-slot": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -4554,6 +4792,14 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/is-array-buffer": {
       "version": "3.0.5",
       "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -4787,6 +5033,16 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-promise": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+      "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
+    },
+    "node_modules/is-property": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+      "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="
+    },
     "node_modules/is-regex": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -5313,6 +5569,11 @@
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
       "dev": true
     },
+    "node_modules/long": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
+      "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="
+    },
     "node_modules/loose-envify": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -5325,6 +5586,28 @@
         "loose-envify": "cli.js"
       }
     },
+    "node_modules/lru-cache": {
+      "version": "7.18.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+      "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/lru.min": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz",
+      "integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==",
+      "engines": {
+        "bun": ">=1.0.0",
+        "deno": ">=1.30.0",
+        "node": ">=8.0.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wellwelwel"
+      }
+    },
     "node_modules/lucide-react": {
       "version": "0.488.0",
       "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.488.0.tgz",
@@ -5337,11 +5620,29 @@
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
       "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       }
     },
+    "node_modules/media-typer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+      "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/merge-descriptors": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+      "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/merge2": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -5364,6 +5665,25 @@
         "node": ">=8.6"
       }
     },
+    "node_modules/mime-db": {
+      "version": "1.54.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+      "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+      "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+      "dependencies": {
+        "mime-db": "^1.54.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -5388,8 +5708,37 @@
     "node_modules/ms": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-      "dev": true
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+    },
+    "node_modules/mysql2": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.14.1.tgz",
+      "integrity": "sha512-7ytuPQJjQB8TNAYX/H2yhL+iQOnIBjAMam361R7UAL0lOVXWjtdrmoL9HYKqKoLp/8UUTRcvo1QPvK9KL7wA8w==",
+      "dependencies": {
+        "aws-ssl-profiles": "^1.1.1",
+        "denque": "^2.1.0",
+        "generate-function": "^2.3.1",
+        "iconv-lite": "^0.6.3",
+        "long": "^5.2.1",
+        "lru.min": "^1.0.0",
+        "named-placeholders": "^1.1.3",
+        "seq-queue": "^0.0.5",
+        "sqlstring": "^2.3.2"
+      },
+      "engines": {
+        "node": ">= 8.0"
+      }
+    },
+    "node_modules/named-placeholders": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
+      "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
+      "dependencies": {
+        "lru-cache": "^7.14.1"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
     },
     "node_modules/nanoid": {
       "version": "3.3.11",
@@ -5414,6 +5763,14 @@
       "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
       "dev": true
     },
+    "node_modules/negotiator": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+      "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/next": {
       "version": "15.3.0",
       "resolved": "https://registry.npmjs.org/next/-/next-15.3.0.tgz",
@@ -5498,7 +5855,6 @@
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
       "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
-      "dev": true,
       "engines": {
         "node": ">=0.10.0"
       }
@@ -5507,7 +5863,6 @@
       "version": "1.13.4",
       "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
       "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
-      "dev": true,
       "engines": {
         "node": ">= 0.4"
       },
@@ -5609,6 +5964,25 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/on-finished": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
     "node_modules/optionator": {
       "version": "0.9.4",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -5690,6 +6064,14 @@
         "node": ">=6"
       }
     },
+    "node_modules/parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/path-exists": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -5714,6 +6096,14 @@
       "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
       "dev": true
     },
+    "node_modules/path-to-regexp": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
+      "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
+      "engines": {
+        "node": ">=16"
+      }
+    },
     "node_modules/picocolors": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -5788,6 +6178,18 @@
         "react-is": "^16.13.1"
       }
     },
+    "node_modules/proxy-addr": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+      "dependencies": {
+        "forwarded": "0.2.0",
+        "ipaddr.js": "1.9.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/punycode": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -5797,6 +6199,20 @@
         "node": ">=6"
       }
     },
+    "node_modules/qs": {
+      "version": "6.14.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+      "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+      "dependencies": {
+        "side-channel": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -5817,6 +6233,28 @@
         }
       ]
     },
+    "node_modules/range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/raw-body": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
+      "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
+      "dependencies": {
+        "bytes": "3.1.2",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.6.3",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/react": {
       "version": "19.1.0",
       "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
@@ -6013,6 +6451,21 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/router": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+      "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+      "dependencies": {
+        "debug": "^4.4.0",
+        "depd": "^2.0.0",
+        "is-promise": "^4.0.0",
+        "parseurl": "^1.3.3",
+        "path-to-regexp": "^8.0.0"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
     "node_modules/run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -6055,6 +6508,25 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
     "node_modules/safe-push-apply": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
@@ -6088,6 +6560,11 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
     "node_modules/scheduler": {
       "version": "0.26.0",
       "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
@@ -6105,6 +6582,46 @@
         "node": ">=10"
       }
     },
+    "node_modules/send": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+      "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+      "dependencies": {
+        "debug": "^4.3.5",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "etag": "^1.8.1",
+        "fresh": "^2.0.0",
+        "http-errors": "^2.0.0",
+        "mime-types": "^3.0.1",
+        "ms": "^2.1.3",
+        "on-finished": "^2.4.1",
+        "range-parser": "^1.2.1",
+        "statuses": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/seq-queue": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
+      "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
+    },
+    "node_modules/serve-static": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+      "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+      "dependencies": {
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "parseurl": "^1.3.3",
+        "send": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
     "node_modules/set-function-length": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -6151,6 +6668,11 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+    },
     "node_modules/sharp": {
       "version": "0.34.1",
       "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.1.tgz",
@@ -6216,7 +6738,6 @@
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
       "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
-      "dev": true,
       "dependencies": {
         "es-errors": "^1.3.0",
         "object-inspect": "^1.13.3",
@@ -6235,7 +6756,6 @@
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
       "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
-      "dev": true,
       "dependencies": {
         "es-errors": "^1.3.0",
         "object-inspect": "^1.13.3"
@@ -6251,7 +6771,6 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
       "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
-      "dev": true,
       "dependencies": {
         "call-bound": "^1.0.2",
         "es-errors": "^1.3.0",
@@ -6269,7 +6788,6 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
       "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
-      "dev": true,
       "dependencies": {
         "call-bound": "^1.0.2",
         "es-errors": "^1.3.0",
@@ -6301,6 +6819,14 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/sqlstring": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
+      "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/ssf": {
       "version": "0.11.2",
       "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
@@ -6318,6 +6844,14 @@
       "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==",
       "dev": true
     },
+    "node_modules/statuses": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/streamsearch": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
@@ -6578,6 +7112,14 @@
         "node": ">=8.0"
       }
     },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
     "node_modules/tr46": {
       "version": "0.0.3",
       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@@ -6632,6 +7174,19 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/type-is": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+      "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+      "dependencies": {
+        "content-type": "^1.0.5",
+        "media-typer": "^1.1.0",
+        "mime-types": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
     "node_modules/typed-array-buffer": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
@@ -6743,6 +7298,14 @@
       "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
       "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="
     },
+    "node_modules/unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/unrs-resolver": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.5.0.tgz",
@@ -6820,6 +7383,14 @@
         }
       }
     },
+    "node_modules/vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/webidl-conversions": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
@@ -6959,6 +7530,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    },
     "node_modules/ws": {
       "version": "8.18.1",
       "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
diff --git a/diplomas/package.json b/diplomas/package.json
index f19bb18..c78ae7a 100644
--- a/diplomas/package.json
+++ b/diplomas/package.json
@@ -21,8 +21,11 @@
     "@supabase/supabase-js": "^2.49.4",
     "class-variance-authority": "^0.7.1",
     "clsx": "^2.1.1",
+    "cors": "^2.8.5",
     "diplomas": "file:",
+    "express": "^5.1.0",
     "lucide-react": "^0.488.0",
+    "mysql2": "^3.14.1",
     "next": "15.3.0",
     "papaparse": "^5.5.2",
     "react": "^19.0.0",
diff --git a/diplomas/src/components/app-sidebar.jsx b/diplomas/src/components/app-sidebar.jsx
index eef192b..d290e46 100644
--- a/diplomas/src/components/app-sidebar.jsx
+++ b/diplomas/src/components/app-sidebar.jsx
@@ -52,6 +52,15 @@ const data = {
         },
       ],
     },
+    {
+      title: "Diplomas",
+      items: [
+        {
+          title: "Creación de diplomas",
+          url: "/diplomasVista",
+        },
+      ],
+    },
   ],
 };
 
diff --git a/diplomas/src/pages/alumnosArchivo.jsx b/diplomas/src/pages/alumnosArchivo.jsx
index 83cd140..91026ee 100644
--- a/diplomas/src/pages/alumnosArchivo.jsx
+++ b/diplomas/src/pages/alumnosArchivo.jsx
@@ -1,34 +1,75 @@
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
 import Papa from "papaparse";
 import * as XLSX from "xlsx";
 import Layout from "@/components/layout/Layout";
 import { Button } from "@/components/ui/button";
+import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
 
 export default function AlumnosArchivo() {
   const [archivo, setArchivo] = useState(null);
   const [datos, setDatos] = useState([]);
+  const [dialogoAbierto, setDialogoAbierto] = useState(false);
+  const [mensajeDialogo, setMensajeDialogo] = useState("");
+
+  useEffect(() => {
+    if (archivo) extraerContenido();
+  }, [archivo]);
+
+  const registrarAlumnos = async () => {
+    if (datos.length === 0) return;
+
+    const errores = [];
+
+    for (const alumno of datos) {
+      const res = await fetch("/api/alumno", {
+        method: "POST",
+        headers: { "Content-Type": "application/json" },
+        body: JSON.stringify({
+          nombre: alumno.nombre,
+          correo: alumno.correo,
+          nombreCurso: alumno.nombreCurso,
+        }),
+      });
+
+      const resultado = await res.json();
+      if (!res.ok) {
+        errores.push({ alumno, error: resultado.error || "Error desconocido" });
+      }
+    }
+
+    if (errores.length > 0) {
+      setMensajeDialogo(`Se registraron algunos errores:\n${JSON.stringify(errores, null, 2)}`);
+    } else {
+      setMensajeDialogo("Todos los alumnos fueron registrados correctamente.");
+      setArchivo(null);
+      setDatos([]);
+    }
+    setDialogoAbierto(true);
+  };
 
   const manejarArchivo = (e) => {
     const file = e.target.files[0];
-    if (file && (file.name.endsWith(".csv") || file.name.endsWith(".xlsx"))) {
-      setArchivo(file);
-    } else {
-      alert("Solo se permiten archivos .csv o .xlsx");
-    }
+    if (validarArchivo(file)) setArchivo(file);
   };
 
   const manejarSoltar = (e) => {
     e.preventDefault();
     const file = e.dataTransfer.files[0];
-    if (file && (file.name.endsWith(".csv") || file.name.endsWith(".xlsx"))) {
-      setArchivo(file);
-    } else {
-      alert("Solo se permiten archivos .csv o .xlsx");
-    }
+    if (validarArchivo(file)) setArchivo(file);
   };
 
   const manejarArrastrar = (e) => e.preventDefault();
 
+  const validarArchivo = (file) => {
+    if (file && (file.name.endsWith(".csv") || file.name.endsWith(".xlsx"))) {
+      return true;
+    } else {
+      setMensajeDialogo("Solo se permiten archivos .csv o .xlsx");
+      setDialogoAbierto(true);
+      return false;
+    }
+  };
+
   const extraerContenido = () => {
     if (!archivo) return;
 
@@ -39,7 +80,6 @@ export default function AlumnosArchivo() {
         header: true,
         skipEmptyLines: true,
         complete: (result) => {
-          console.log("Contenido CSV:", result.data);
           setDatos(result.data);
         },
         error: (error) => {
@@ -55,7 +95,6 @@ export default function AlumnosArchivo() {
         const contenido = XLSX.utils.sheet_to_json(workbook.Sheets[hoja], {
           defval: "",
         });
-        console.log("Contenido XLSX:", contenido);
         setDatos(contenido);
       };
       reader.readAsArrayBuffer(archivo);
@@ -64,7 +103,7 @@ export default function AlumnosArchivo() {
 
   return (
     <Layout>
-      <div className="w-[60vw] pt-10 flex flex-col items-end justify-center">
+      <div className="w-[60vw] pt-10 flex flex-col items-end justify-center text-black">
         <div className="bg-white p-8 font-sans text-center w-[70%] flex flex-col items-center">
           <h1 className="text-xl font-semibold mb-4 text-black">
             Nuevo alumno
@@ -90,22 +129,47 @@ export default function AlumnosArchivo() {
           </label>
 
           <Button
-            onClick={extraerContenido}
-            className="bg-green-400 hover:bg-green-500 text-white font-bold py-2 px-4 rounded-md"
+            onClick={registrarAlumnos}
+            className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-md mt-4"
           >
-            Extraer contenido
+            Registrar alumnos
           </Button>
 
           {datos.length > 0 && (
-            <div className="mt-6 text-left w-full max-w-md">
-              <h3 className="font-bold mb-2">Contenido extraído:</h3>
-              <pre className="bg-gray-100 p-2 rounded overflow-x-auto text-sm">
-                {JSON.stringify(datos, null, 2)}
-              </pre>
+            <div className="mt-6 text-left w-full overflow-auto">
+              <h3 className="font-bold mb-2">Vista previa del archivo:</h3>
+              <table className="min-w-full bg-white border border-gray-300 text-sm">
+                <thead className="bg-gray-100 text-gray-700">
+                  <tr>
+                    {Object.keys(datos[0]).map((columna, index) => (
+                      <th key={index} className="border px-4 py-2">{columna}</th>
+                    ))}
+                  </tr>
+                </thead>
+                <tbody>
+                  {datos.map((fila, index) => (
+                    <tr key={index}>
+                      {Object.values(fila).map((valor, i) => (
+                        <td key={i} className="border px-4 py-1">{valor}</td>
+                      ))}
+                    </tr>
+                  ))}
+                </tbody>
+              </table>
             </div>
           )}
         </div>
       </div>
+
+      {/* Dialog Component */}
+      <Dialog open={dialogoAbierto} onOpenChange={setDialogoAbierto}>
+        <DialogContent>
+          <DialogHeader>
+            <DialogTitle className="text-black">Información</DialogTitle>
+            <DialogDescription>{mensajeDialogo}</DialogDescription>
+          </DialogHeader>
+        </DialogContent>
+      </Dialog>
     </Layout>
   );
-}
+}
\ No newline at end of file
diff --git a/diplomas/src/pages/alumnosVista.jsx b/diplomas/src/pages/alumnosVista.jsx
index aa38f3a..f1dad9f 100644
--- a/diplomas/src/pages/alumnosVista.jsx
+++ b/diplomas/src/pages/alumnosVista.jsx
@@ -20,7 +20,6 @@ import {
   SelectValue,
 } from "@/components/ui/select";
 
-
 export default function AlumnosVista() {
   const [alumnos, setAlumnos] = useState([]);
   const [alumnoEditando, setAlumnoEditando] = useState(null);
@@ -28,10 +27,13 @@ export default function AlumnosVista() {
   const [nuevoCorreo, setNuevoCorreo] = useState("");
   const [mostrarModal, setMostrarModal] = useState(false);
   const [modalMensaje, setModalMensaje] = useState("");
-  const [nuevoCurso, setNuevoCurso] = useState(""); 
-
+  const [nuevoCurso, setNuevoCurso] = useState("");
   const [cursos, setCursos] = useState([]);
 
+  // Estado para confirmación de eliminación
+  const [confirmarEliminar, setConfirmarEliminar] = useState(false);
+  const [alumnoAEliminar, setAlumnoAEliminar] = useState(null);
+
   useEffect(() => {
     cargarAlumnos();
     cargarCursos();
@@ -60,7 +62,7 @@ export default function AlumnosVista() {
     setAlumnoEditando(alumno.id);
     setNuevoNombre(alumno.nombre);
     setNuevoCorreo(alumno.correo);
-    setNuevoCurso(alumno.nombreCurso); // Asumiendo que tienes un campo cursoId en el alumno
+    setNuevoCurso(alumno.nombreCurso);
   };
 
   // Cancelar edición
@@ -78,7 +80,7 @@ export default function AlumnosVista() {
       .update({
         nombre: nuevoNombre,
         correo: nuevoCorreo,
-        nombreCurso: nuevoCurso, // Asumiendo que tienes un campo cursoId en el alumno
+        nombreCurso: nuevoCurso,
       })
       .eq("id", id);
 
@@ -93,9 +95,15 @@ export default function AlumnosVista() {
     setMostrarModal(true);
   };
 
+  // Confirmar eliminación
+  const confirmarEliminacion = (id) => {
+    setAlumnoAEliminar(id);
+    setConfirmarEliminar(true);
+  };
+
   // Eliminar alumno
-  const eliminarAlumno = async (id) => {
-    const { error } = await supabaseClient.from("alumno").delete().eq("id", id);
+  const eliminarAlumno = async () => {
+    const { error } = await supabaseClient.from("alumno").delete().eq("id", alumnoAEliminar);
     if (error) {
       console.error("Error eliminando alumno:", error.message);
       setModalMensaje("Error al eliminar el alumno");
@@ -103,6 +111,7 @@ export default function AlumnosVista() {
       setModalMensaje("Alumno eliminado exitosamente");
       await cargarAlumnos();
     }
+    setConfirmarEliminar(false);
     setMostrarModal(true);
   };
 
@@ -191,7 +200,7 @@ export default function AlumnosVista() {
 
                     <Button
                       className="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-3 rounded"
-                      onClick={() => eliminarAlumno(alumno.id)}
+                      onClick={() => confirmarEliminacion(alumno.id)}
                     >
                       Eliminar
                     </Button>
@@ -203,7 +212,33 @@ export default function AlumnosVista() {
         </table>
       </div>
 
-      {/* Modal */}
+      {/* Modal de confirmación */}
+      <Dialog open={confirmarEliminar} onOpenChange={setConfirmarEliminar}>
+        <DialogContent>
+          <DialogHeader>
+            <DialogTitle className="text-black">Confirmar eliminación</DialogTitle>
+            <DialogDescription>
+              ¿Estás seguro de que deseas eliminar este alumno? Esta acción no se puede deshacer.
+            </DialogDescription>
+          </DialogHeader>
+          <DialogFooter>
+            <Button
+              className="bg-red-500 hover:bg-red-700 text-white"
+              onClick={eliminarAlumno}
+            >
+              Eliminar
+            </Button>
+            <Button
+              className="bg-gray-400 hover:bg-gray-600 text-white"
+              onClick={() => setConfirmarEliminar(false)}
+            >
+              Cancelar
+            </Button>
+          </DialogFooter>
+        </DialogContent>
+      </Dialog>
+
+      {/* Modal de resultado */}
       <Dialog open={mostrarModal} onOpenChange={setMostrarModal}>
         <DialogContent>
           <DialogHeader>
@@ -219,4 +254,4 @@ export default function AlumnosVista() {
       </Dialog>
     </Layout>
   );
-}
+}
\ No newline at end of file
diff --git a/diplomas/src/pages/api/alumno.js b/diplomas/src/pages/api/alumno.js
new file mode 100644
index 0000000..6278fe9
--- /dev/null
+++ b/diplomas/src/pages/api/alumno.js
@@ -0,0 +1,29 @@
+// pages/api/alumno.js
+import { createClient } from "@/utils/supabase";
+
+export default async function handler(req, res) {
+  if (req.method !== "POST") {
+    return res.status(405).json({ error: "Método no permitido" });
+  }
+
+  try {
+    const supabase = createClient({ req, res });
+    const { nombre, correo, nombreCurso } = req.body;
+
+    if (!nombre || !correo || !nombreCurso) {
+      return res.status(400).json({ error: "Faltan datos del alumno" });
+    }
+
+    const { data, error } = await supabase.from("alumno").insert([
+      { nombre, correo, nombreCurso },
+    ]);
+
+    if (error) {
+      return res.status(500).json({ error: "Error al insertar en Supabase", detalles: error.message });
+    }
+
+    return res.status(200).json({ mensaje: "Alumno registrado", data });
+  } catch (err) {
+    return res.status(500).json({ error: "Error interno del servidor", detalles: err.message });
+  }
+}
diff --git a/diplomas/src/pages/api/curso.js b/diplomas/src/pages/api/curso.js
new file mode 100644
index 0000000..81d3c00
--- /dev/null
+++ b/diplomas/src/pages/api/curso.js
@@ -0,0 +1,29 @@
+// pages/api/curso.js
+import { createClient } from "@/utils/supabase";
+
+export default async function handler(req, res) {
+  if (req.method !== "POST") {
+    return res.status(405).json({ error: "Método no permitido" });
+  }
+
+  try {
+    const supabase = createClient({ req, res });
+    const { nombre, horas, descripcion, competencias } = req.body;
+
+    if (!nombre || !horas || !descripcion || !competencias) {
+      return res.status(400).json({ error: "Faltan datos del curso" });
+    }
+
+    const { data, error } = await supabase
+      .from("curso")
+      .insert([{ nombre, horas, descripcion, competencias }]);
+
+    if (error) {
+      return res.status(500).json({ error: "Error al insertar en Supabase", detalles: error.message });
+    }
+
+    return res.status(200).json({ mensaje: "Curso registrado", data });
+  } catch (err) {
+    return res.status(500).json({ error: "Error interno del servidor", detalles: err.message });
+  }
+}
diff --git a/diplomas/src/pages/cursosArchivo.jsx b/diplomas/src/pages/cursosArchivo.jsx
index d9401c4..49b6067 100644
--- a/diplomas/src/pages/cursosArchivo.jsx
+++ b/diplomas/src/pages/cursosArchivo.jsx
@@ -1,80 +1,178 @@
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
 import Papa from "papaparse";
+import * as XLSX from "xlsx";
 import Layout from "@/components/layout/Layout";
 import { Button } from "@/components/ui/button";
+import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
 
-export default function CursosArchivo() {
+export default function cursosArchivo() {
   const [archivo, setArchivo] = useState(null);
-  const [datosCSV, setDatosCSV] = useState([]);
+  const [datos, setDatos] = useState([]);
+  const [dialogoAbierto, setDialogoAbierto] = useState(false);
+  const [mensajeDialogo, setMensajeDialogo] = useState("");
+
+  useEffect(() => {
+    if (archivo) extraerContenido();
+  }, [archivo]);
+
+  const registrarCursos = async () => {
+    if (datos.length === 0) return;
+
+    const errores = [];
+
+    for (const curso of datos) {
+      const res = await fetch("/api/curso", {
+        method: "POST",
+        headers: { "Content-Type": "application/json" },
+        body: JSON.stringify({
+          nombre: curso.nombre,
+          horas: curso.horas,
+          descripcion: curso.descripcion,
+          competencias: curso.competencias
+          ? curso.competencias.split(",").map(c => c.trim())
+          : [],
+        }),
+      });
+
+      const resultado = await res.json();
+      if (!res.ok) {
+        errores.push({ curso, error: resultado.error || "Error desconocido" });
+      }
+    }
+
+    if (errores.length > 0) {
+      setMensajeDialogo(`Se registraron algunos errores:\n${JSON.stringify(errores, null, 2)}`);
+    } else {
+      setMensajeDialogo("Todos los cursos fueron registrados correctamente.");
+      setArchivo(null);
+      setDatos([]);
+    }
+    setDialogoAbierto(true);
+  };
 
   const manejarArchivo = (e) => {
     const file = e.target.files[0];
-    setArchivo(file);
+    if (validarArchivo(file)) setArchivo(file);
   };
 
   const manejarSoltar = (e) => {
     e.preventDefault();
     const file = e.dataTransfer.files[0];
-    setArchivo(file);
+    if (validarArchivo(file)) setArchivo(file);
   };
 
-  const manejarArrastrar = (e) => {
-    e.preventDefault();
+  const manejarArrastrar = (e) => e.preventDefault();
+
+  const validarArchivo = (file) => {
+    if (file && (file.name.endsWith(".csv") || file.name.endsWith(".xlsx"))) {
+      return true;
+    } else {
+      setMensajeDialogo("Solo se permiten archivos .csv o .xlsx");
+      setDialogoAbierto(true);
+      return false;
+    }
   };
 
   const extraerContenido = () => {
     if (!archivo) return;
 
-    Papa.parse(archivo, {
-      header: true,
-      skipEmptyLines: true,
-      complete: (result) => {
-        console.log("Contenido CSV:", result.data);
-        setDatosCSV(result.data);
-      },
-      error: (error) => {
-        console.error("Error al leer el CSV:", error.message);
-      },
-    });
+    const extension = archivo.name.split(".").pop().toLowerCase();
+
+    if (extension === "csv") {
+      Papa.parse(archivo, {
+        header: true,
+        skipEmptyLines: true,
+        complete: (result) => {
+          setDatos(result.data);
+        },
+        error: (error) => {
+          console.error("Error al leer el CSV:", error.message);
+        },
+      });
+    } else if (extension === "xlsx") {
+      const reader = new FileReader();
+      reader.onload = (e) => {
+        const data = new Uint8Array(e.target.result);
+        const workbook = XLSX.read(data, { type: "array" });
+        const hoja = workbook.SheetNames[0];
+        const contenido = XLSX.utils.sheet_to_json(workbook.Sheets[hoja], {
+          defval: "",
+        });
+        setDatos(contenido);
+      };
+      reader.readAsArrayBuffer(archivo);
+    }
   };
 
   return (
     <Layout>
-      <div className="w-[60vw] pt-10 flex flex-col items-end justify-center">
+      <div className="w-[60vw] pt-10 flex flex-col items-end justify-center text-black">
         <div className="bg-white p-8 font-sans text-center w-[70%] flex flex-col items-center">
-          <h1 className="text-xl font-semibold mb-4 text-black">Nuevo curso</h1>
-          <h1
+          <h1 className="text-xl font-semibold mb-4 text-black">
+            Nuevo curso
+          </h1>
+          <label
             htmlFor="archivo"
             onDrop={manejarSoltar}
             onDragOver={manejarArrastrar}
             className="border-2 border-gray-300 rounded-md p-8 text-gray-600 cursor-pointer w-80 text-center mb-4"
           >
-            Arrastra y suelta un archivo o busca un archivo
+            {archivo ? (
+              <span className="text-black font-medium">{archivo.name}</span>
+            ) : (
+              <span>Arrastra y suelta un archivo o haz clic para seleccionarlo</span>
+            )}
             <input
               type="file"
               id="archivo"
-              accept=".csv"
+              accept=".csv, .xlsx"
               onChange={manejarArchivo}
               className="hidden"
             />
-          </h1>
+          </label>
+
           <Button
-            onClick={extraerContenido}
-            className="bg-green-400 hover:bg-green-500 text-white font-bold py-2 px-4 rounded-md"
+            onClick={registrarCursos}
+            className="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-md mt-4"
           >
-            Extraer contenido
+            Registrar cursos
           </Button>
 
-          {datosCSV.length > 0 && (
-            <div className="mt-6 text-left w-full max-w-md">
-              <h3 className="font-bold mb-2">Contenido extraído:</h3>
-              <pre className="bg-gray-100 p-2 rounded overflow-x-auto text-sm">
-                {JSON.stringify(datosCSV, null, 2)}
-              </pre>
+          {datos.length > 0 && (
+            <div className="mt-6 text-left w-full overflow-auto">
+              <h3 className="font-bold mb-2">Vista previa del archivo:</h3>
+              <table className="min-w-full bg-white border border-gray-300 text-sm">
+                <thead className="bg-gray-100 text-gray-700">
+                  <tr>
+                    {Object.keys(datos[0]).map((columna, index) => (
+                      <th key={index} className="border px-4 py-2">{columna}</th>
+                    ))}
+                  </tr>
+                </thead>
+                <tbody>
+                  {datos.map((fila, index) => (
+                    <tr key={index}>
+                      {Object.values(fila).map((valor, i) => (
+                        <td key={i} className="border px-4 py-1">{valor}</td>
+                      ))}
+                    </tr>
+                  ))}
+                </tbody>
+              </table>
             </div>
           )}
         </div>
       </div>
+
+      {/* Dialog Component */}
+      <Dialog open={dialogoAbierto} onOpenChange={setDialogoAbierto}>
+        <DialogContent>
+          <DialogHeader>
+            <DialogTitle className="text-black">Información</DialogTitle>
+            <DialogDescription>{mensajeDialogo}</DialogDescription>
+          </DialogHeader>
+        </DialogContent>
+      </Dialog>
     </Layout>
   );
-}
+}
\ No newline at end of file
diff --git a/diplomas/src/pages/cursosVista.jsx b/diplomas/src/pages/cursosVista.jsx
index 8da0065..fa01d47 100644
--- a/diplomas/src/pages/cursosVista.jsx
+++ b/diplomas/src/pages/cursosVista.jsx
@@ -21,6 +21,10 @@ export default function CursosVista() {
   const [mostrarModal, setMostrarModal] = useState(false);
   const [modalMensaje, setModalMensaje] = useState("");
 
+  // Estado para confirmación de eliminación
+  const [confirmarEliminar, setConfirmarEliminar] = useState(false);
+  const [cursoAEliminar, setCursoAEliminar] = useState(null);
+
   useEffect(() => {
     cargarCursos();
   }, []);
@@ -69,8 +73,13 @@ export default function CursosVista() {
     setMostrarModal(true);
   };
 
-  const eliminarCurso = async (id) => {
-    const { error } = await supabaseClient.from("curso").delete().eq("id", id);
+  const confirmarEliminacion = (id) => {
+    setCursoAEliminar(id);
+    setConfirmarEliminar(true);
+  };
+
+  const eliminarCurso = async () => {
+    const { error } = await supabaseClient.from("curso").delete().eq("id", cursoAEliminar);
     if (error) {
       console.error("Error eliminando curso:", error.message);
       setModalMensaje("Error al eliminar el curso");
@@ -78,6 +87,7 @@ export default function CursosVista() {
       setModalMensaje("Curso eliminado exitosamente");
       await cargarCursos();
     }
+    setConfirmarEliminar(false);
     setMostrarModal(true);
   };
 
@@ -149,7 +159,7 @@ export default function CursosVista() {
                     </Button>
                     <Button
                       className="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-3 rounded"
-                      onClick={() => eliminarCurso(curso.id)}
+                      onClick={() => confirmarEliminacion(curso.id)}
                     >
                       Eliminar
                     </Button>
@@ -161,7 +171,33 @@ export default function CursosVista() {
         </table>
       </div>
 
-      {/* Modal */}
+      {/* Modal de confirmación */}
+      <Dialog open={confirmarEliminar} onOpenChange={setConfirmarEliminar}>
+        <DialogContent>
+          <DialogHeader>
+            <DialogTitle className="text-black">Confirmar eliminación</DialogTitle>
+            <DialogDescription>
+              ¿Estás seguro de que deseas eliminar este curso? Esta acción no se puede deshacer.
+            </DialogDescription>
+          </DialogHeader>
+          <DialogFooter>
+            <Button
+              className="bg-red-500 hover:bg-red-700 text-white"
+              onClick={eliminarCurso}
+            >
+              Eliminar
+            </Button>
+            <Button
+              className="bg-gray-400 hover:bg-gray-600 text-white"
+              onClick={() => setConfirmarEliminar(false)}
+            >
+              Cancelar
+            </Button>
+          </DialogFooter>
+        </DialogContent>
+      </Dialog>
+
+      {/* Modal de resultado */}
       <Dialog open={mostrarModal} onOpenChange={setMostrarModal}>
         <DialogContent>
           <DialogHeader>
@@ -177,4 +213,4 @@ export default function CursosVista() {
       </Dialog>
     </Layout>
   );
-}
+}
\ No newline at end of file