diff --git a/package-lock.json b/package-lock.json
index f5edb998e4e..5c703af8fe1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -60,6 +60,7 @@
         "xlsx": "^0.18.5"
       },
       "devDependencies": {
+        "@julr/vite-plugin-validate-env": "^1.1.1",
         "@tailwindcss/container-queries": "^0.1.1",
         "@tailwindcss/forms": "^0.5.9",
         "@tailwindcss/typography": "^0.5.15",
@@ -106,7 +107,8 @@
         "vite": "^5.4.10",
         "vite-plugin-checker": "^0.8.0",
         "vite-plugin-pwa": "^0.20.5",
-        "vite-plugin-static-copy": "^2.0.0"
+        "vite-plugin-static-copy": "^2.0.0",
+        "zod": "^3.23.8"
       },
       "engines": {
         "node": ">=22.11.0"
@@ -196,6 +198,16 @@
         "node": ">=6.0.0"
       }
     },
+    "node_modules/@antfu/utils": {
+      "version": "0.7.10",
+      "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz",
+      "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
     "node_modules/@babel/code-frame": {
       "version": "7.25.7",
       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz",
@@ -2836,6 +2848,33 @@
         "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
+    "node_modules/@julr/vite-plugin-validate-env": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@julr/vite-plugin-validate-env/-/vite-plugin-validate-env-1.1.1.tgz",
+      "integrity": "sha512-MiAvuLrolS6xkzG/B4ofOCFUzmOEnC32pvD5fn9g6b3SK4nVruGZp5PU/WG+F+hw9fhsw0ES13L7GVzAeDJaYA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@poppinss/cliui": "^6.3.0",
+        "@poppinss/validator-lite": "^1.0.3",
+        "unconfig": "^0.3.11"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/Julien-R44"
+      },
+      "peerDependencies": {
+        "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0",
+        "zod": "^3.0.0"
+      },
+      "peerDependenciesMeta": {
+        "zod": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@mapbox/node-pre-gyp": {
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
@@ -3266,6 +3305,327 @@
         "@pnotify/core": "^5.2.0"
       }
     },
+    "node_modules/@poppinss/cliui": {
+      "version": "6.4.1",
+      "resolved": "https://registry.npmjs.org/@poppinss/cliui/-/cliui-6.4.1.tgz",
+      "integrity": "sha512-tdV3QpAfrPFRLPOh98F8QxWBvwYF3ziWGGtpVqfZtFNTFkC7nQnVQlUW55UtQ7rkeMmFohxfDI+2JNWScGJ1jQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@poppinss/colors": "^4.1.3",
+        "cli-boxes": "^3.0.0",
+        "cli-table3": "^0.6.4",
+        "cli-truncate": "^4.0.0",
+        "log-update": "^6.0.0",
+        "pretty-hrtime": "^1.0.3",
+        "string-width": "^7.1.0",
+        "supports-color": "^9.4.0",
+        "terminal-size": "^4.0.0",
+        "wordwrap": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=18.16.0"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/ansi-escapes": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
+      "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "environment": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/ansi-regex": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+      "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/ansi-styles": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+      "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/cli-cursor": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+      "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "restore-cursor": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/cli-truncate": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
+      "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "slice-ansi": "^5.0.0",
+        "string-width": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/emoji-regex": {
+      "version": "10.4.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
+      "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@poppinss/cliui/node_modules/is-fullwidth-code-point": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
+      "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/log-update": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
+      "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-escapes": "^7.0.0",
+        "cli-cursor": "^5.0.0",
+        "slice-ansi": "^7.1.0",
+        "strip-ansi": "^7.1.0",
+        "wrap-ansi": "^9.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/log-update/node_modules/is-fullwidth-code-point": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz",
+      "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "get-east-asian-width": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/log-update/node_modules/slice-ansi": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz",
+      "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.2.1",
+        "is-fullwidth-code-point": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/onetime": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+      "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mimic-function": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/restore-cursor": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+      "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "onetime": "^7.0.0",
+        "signal-exit": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/slice-ansi": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
+      "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.0.0",
+        "is-fullwidth-code-point": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/string-width": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+      "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^10.3.0",
+        "get-east-asian-width": "^1.0.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/strip-ansi": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/supports-color": {
+      "version": "9.4.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
+      "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/@poppinss/cliui/node_modules/wrap-ansi": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
+      "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.2.1",
+        "string-width": "^7.0.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@poppinss/colors": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.3.tgz",
+      "integrity": "sha512-A0FjJ6x14donWDN3bHAFFjJaPWTwM2PgWT834+bPKVK6Xukf25CscoRqCPYI939a8yuJFX9PYWWnVbUVI0E2Cg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "kleur": "^4.1.5"
+      },
+      "engines": {
+        "node": ">=18.16.0"
+      }
+    },
+    "node_modules/@poppinss/validator-lite": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@poppinss/validator-lite/-/validator-lite-1.0.3.tgz",
+      "integrity": "sha512-u4dmT7PDHwNtxY3q1jHVp/u+hMEEcBlkzd37QwwM4tVt/0mLlEDttSfPQ+TT7sqPG4VEtWKwVSlMInwPUYyJpA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "validator": "^13.9.0"
+      }
+    },
     "node_modules/@radix-ui/primitive": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz",
@@ -6957,6 +7317,19 @@
         "node": ">=6"
       }
     },
+    "node_modules/cli-boxes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz",
+      "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/cli-cursor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -7686,6 +8059,13 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/defu": {
+      "version": "6.1.4",
+      "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
+      "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/delayed-stream": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -15041,6 +15421,16 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/pretty-hrtime": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+      "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/proc-log": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz",
@@ -17411,6 +17801,19 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/terminal-size": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/terminal-size/-/terminal-size-4.0.0.tgz",
+      "integrity": "sha512-rcdty1xZ2/BkWa4ANjWRp4JGpda2quksXIHgn5TMjNBPZfwzJIgR68DKfSYiTL+CZWowDX/sbOo5ME/FRURvYQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/terser": {
       "version": "5.36.0",
       "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz",
@@ -17907,6 +18310,21 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/unconfig": {
+      "version": "0.3.13",
+      "resolved": "https://registry.npmjs.org/unconfig/-/unconfig-0.3.13.tgz",
+      "integrity": "sha512-N9Ph5NC4+sqtcOjPfHrRcHekBCadCXWTBzp2VYYbySOHW0PfD9XLCeXshTXjkPYwLrBr9AtSeU0CZmkYECJhng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@antfu/utils": "^0.7.7",
+        "defu": "^6.1.4",
+        "jiti": "^1.21.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
     "node_modules/undici": {
       "version": "5.28.4",
       "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
@@ -18462,6 +18880,16 @@
         "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
       }
     },
+    "node_modules/validator": {
+      "version": "13.12.0",
+      "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
+      "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/verror": {
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@@ -19742,6 +20170,13 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/workbox-background-sync": {
       "version": "7.1.0",
       "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.1.0.tgz",
@@ -20381,6 +20816,16 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/zod": {
+      "version": "3.23.8",
+      "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
+      "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/colinhacks"
+      }
+    },
     "node_modules/zrender": {
       "version": "5.6.0",
       "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.0.tgz",
diff --git a/package.json b/package.json
index 60250c2209e..020d73f5e65 100644
--- a/package.json
+++ b/package.json
@@ -99,6 +99,7 @@
     "xlsx": "^0.18.5"
   },
   "devDependencies": {
+    "@julr/vite-plugin-validate-env": "^1.1.1",
     "@tailwindcss/container-queries": "^0.1.1",
     "@tailwindcss/forms": "^0.5.9",
     "@tailwindcss/typography": "^0.5.15",
@@ -145,7 +146,8 @@
     "vite": "^5.4.10",
     "vite-plugin-checker": "^0.8.0",
     "vite-plugin-pwa": "^0.20.5",
-    "vite-plugin-static-copy": "^2.0.0"
+    "vite-plugin-static-copy": "^2.0.0",
+    "zod": "^3.23.8"
   },
   "browserslist": {
     "production": [
diff --git a/src/Integrations/Plausible.tsx b/src/Integrations/Plausible.tsx
index dfbb2942e5d..89d0572e9e4 100644
--- a/src/Integrations/Plausible.tsx
+++ b/src/Integrations/Plausible.tsx
@@ -10,6 +10,16 @@ export default function Plausible() {
   });
 
   useEffect(() => {
+    const missingConfig = [];
+    if (!careConfig.plausible.domain) missingConfig.push("domain");
+    if (!careConfig.plausible.server) missingConfig.push("server");
+    if (missingConfig.length > 0) {
+      console.error(
+        `Plausible analytics disabled. Missing configuration: ${missingConfig.join(", ")}`,
+      );
+      return;
+    }
+
     plausible("pageview");
   }, []);
 
diff --git a/src/Integrations/Sentry.tsx b/src/Integrations/Sentry.tsx
index 90a8e78f3a9..1fa3d7e6da1 100644
--- a/src/Integrations/Sentry.tsx
+++ b/src/Integrations/Sentry.tsx
@@ -7,7 +7,10 @@ interface Props {
 
 export default function Sentry({ disabled }: Props) {
   useEffect(() => {
-    if (disabled || !careConfig.sentry.dsn) {
+    if (disabled || !careConfig.sentry.dsn || !careConfig.sentry.environment) {
+      console.error(
+        "Sentry is not configured correctly. Please check your environment variables.",
+      );
       return;
     }
 
diff --git a/vite.config.mts b/vite.config.mts
index 3f6df95c290..ca92aa50954 100644
--- a/vite.config.mts
+++ b/vite.config.mts
@@ -1,14 +1,17 @@
+import { ValidateEnv } from "@julr/vite-plugin-validate-env";
+import react from "@vitejs/plugin-react-swc";
+import DOMPurify from "dompurify";
 import fs from "fs";
+import { JSDOM } from "jsdom";
+import { marked } from "marked";
+import { createRequire } from "node:module";
 import path from "path";
 import { defineConfig, loadEnv } from "vite";
-import { createRequire } from "node:module";
-import { VitePWA } from "vite-plugin-pwa";
-import react from "@vitejs/plugin-react-swc";
 import checker from "vite-plugin-checker";
+import { VitePWA } from "vite-plugin-pwa";
 import { viteStaticCopy } from "vite-plugin-static-copy";
-import DOMPurify from "dompurify";
-import { JSDOM } from "jsdom";
-import { marked } from "marked";
+import { z } from "zod";
+
 import { treeShakeCareIcons } from "./plugins/treeShakeCareIcons";
 
 const pdfWorkerPath = path.join(
@@ -100,6 +103,24 @@ export default defineConfig(({ mode }) => {
       ),
     },
     plugins: [
+      ValidateEnv({
+        validator: "zod",
+        schema: {
+          REACT_CARE_API_URL: z.string().url(),
+
+          REACT_SENTRY_DSN: z.string().url().optional(),
+          REACT_SENTRY_ENVIRONMENT: z.string().optional(),
+
+          REACT_PLAUSIBLE_SITE_DOMAIN: z.string().url().optional(),
+          REACT_PLAUSIBLE_SERVER_URL: z.string().url().optional(),
+          REACT_CDN_URLS: z
+            .string()
+            .optional()
+            .transform((val) => val?.split(" "))
+            .pipe(z.array(z.string().url()).optional())
+            .describe("Optional: Space-separated list of CDN URLs"),
+        },
+      }),
       viteStaticCopy({
         targets: [
           {