diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
new file mode 100644
index 0000000..79f371b
--- /dev/null
+++ b/frontend/src/App.jsx
@@ -0,0 +1,101 @@
+import { Routes, Route, Link, useLocation } from "react-router-dom";
+import { useState, useEffect } from "react";
+import MySQLMySQLMigrator from "./components/MySQLMySQLMigrator";
+import PostgreSQLPostgreSQLMigrator from "./components/PostgreSQLPostgreSQLMigrator";
+import PostgreSQLS3Migrator from "./components/PostgreSQLS3Migrator";
+import S3S3Migrator from "./components/S3S3Migrator";
+
+export default function App() {
+ const [darkMode, setDarkMode] = useState(() => {
+ const saved = localStorage.getItem('darkMode');
+ return saved ? JSON.parse(saved) : true; // Default to dark mode
+ });
+
+ const location = useLocation();
+
+ useEffect(() => {
+ localStorage.setItem('darkMode', JSON.stringify(darkMode));
+ if (darkMode) {
+ document.body.classList.add('dark');
+ } else {
+ document.body.classList.remove('dark');
+ }
+ }, [darkMode]);
+
+ const navItems = [
+ { path: "/mysql-mysql", label: "MySQL β MySQL", icon: "ποΈ" },
+ { path: "/psql-psql", label: "PostgreSQL β PostgreSQL", icon: "π" },
+ { path: "/psql-s3", label: "PostgreSQL β S3", icon: "βοΈ" },
+ { path: "/s3-s3", label: "S3 β S3", icon: "π¦" },
+ ];
+
+ return (
+
+
+ {/* Header */}
+
+
+
+
+ Universal Database Migrator
+
+
+ Seamlessly migrate your databases across platforms
+
+
+
+
+
+
+ {/* Navigation */}
+
+
+ {/* Main Content */}
+
+
+ } />
+ } />
+ } />
+ } />
+
+ π
+ Welcome to Universal Migrator
+
+ Choose a migration type from the navigation above to get started.
+
+
+ }
+ />
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/api.js b/frontend/src/api.js
new file mode 100644
index 0000000..5d0946f
--- /dev/null
+++ b/frontend/src/api.js
@@ -0,0 +1,69 @@
+// API Base URL Ω
Ω Ω
ΨͺΨΊΩΨ±Ψ§Ψͺ Ψ§ΩΨ¨ΩΨ¦Ψ©
+const API_BASE = import.meta.env.VITE_API_BASE ?? "";
+
+// =========================
+// Schemas
+// =========================
+async function getSchemas(type, payload) {
+ const r = await fetch(`${API_BASE}/api/get_schemas`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ type,
+ ...payload
+ })
+ });
+ return r.json();
+}
+
+// =========================
+// Tables
+// =========================
+async function getTables(type, payload) {
+ const r = await fetch(`${API_BASE}/api/get_tables`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ type,
+ ...payload
+ })
+ });
+ return r.json();
+}
+
+// =========================
+// Start Migration
+// =========================
+async function startMigration(type, payload) {
+ const r = await fetch(`${API_BASE}/api/migrate`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ type,
+ ...payload
+ })
+ });
+ return r.json();
+}
+
+// =========================
+// Progress
+// =========================
+async function getProgress(type) {
+ const r = await fetch(`${API_BASE}/api/progress/${type}`);
+ return r.json();
+}
+
+// =========================
+// List Buckets
+// =========================
+async function listBuckets(payload) {
+ const r = await fetch(`${API_BASE}/api/list_buckets`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload)
+ });
+ return r.json();
+}
+
+export { getSchemas, getTables, startMigration, getProgress, listBuckets };
\ No newline at end of file
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
new file mode 100644
index 0000000..8cc8d25
--- /dev/null
+++ b/frontend/src/main.jsx
@@ -0,0 +1,13 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import { BrowserRouter } from "react-router-dom";
+import App from "./App.jsx";
+import "./styles.css";
+
+ReactDOM.createRoot(document.getElementById("root")).render(
+
+
+
+
+
+);
\ No newline at end of file
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
new file mode 100644
index 0000000..2ac97b6
--- /dev/null
+++ b/frontend/src/styles.css
@@ -0,0 +1,137 @@
+@reference "tailwindcss";
+
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* ===========================
+ LIGHT MODE STYLES
+ =========================== */
+:root {
+ --bg-color: #f4f6f8;
+ --container-bg: white;
+ --text-color: #333;
+ --input-border: #ccc;
+ --button-bg: #2563eb;
+ --button-color: white;
+ --link-color: #2563eb;
+ --pre-bg: #111;
+ --pre-color: #0f0;
+}
+
+/* ===========================
+ DARK MODE STYLES
+ =========================== */
+.dark {
+ --bg-color: #000000;
+ --container-bg: #0d0d0d;
+ --text-color: #ffffff;
+ --input-border: #ff0000;
+ --button-bg: #b91c1c;
+ --button-color: #ffffff;
+ --link-color: #ef4444;
+ --pre-bg: #000000;
+ --pre-color: #ff0000;
+}
+
+/* ===========================
+ BODY STYLES
+ =========================== */
+body {
+ margin: 0;
+ font-family: Arial, sans-serif;
+ background-color: var(--bg-color);
+ color: var(--text-color);
+ transition: background-color 0.3s, color 0.3s;
+}
+
+.container {
+ background: var(--container-bg);
+ padding: 20px;
+ max-width: 800px;
+ margin: auto;
+ border-radius: 8px;
+ transition: background-color 0.3s;
+}
+
+/* ===========================
+ CUSTOM COMPONENTS
+ =========================== */
+.glow-red {
+ box-shadow: 0 0 10px rgba(239, 68, 68, 0.5), 0 0 20px rgba(239, 68, 68, 0.3);
+}
+
+.custom-input {
+ @apply w-full px-4 py-3 border border-gray-300 dark:border-red-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-red-500 focus:border-red-500 transition-all duration-200 placeholder-gray-400 dark:placeholder-gray-500;
+}
+
+.custom-button {
+ @apply bg-red-600 hover:bg-red-700 disabled:bg-gray-400 text-white font-medium py-3 px-4 rounded-lg transition-all duration-200 shadow-lg hover:shadow-xl disabled:cursor-not-allowed;
+}
+
+.custom-select {
+ @apply w-full px-4 py-3 border border-gray-300 dark:border-red-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-red-500 focus:border-red-500 transition-all duration-200;
+}
+
+.custom-label {
+ @apply block text-sm font-medium mb-1 text-gray-700 dark:text-white;
+}
+
+body {
+ margin: 0;
+ font-family: Arial, sans-serif;
+ background-color: var(--bg-color);
+ color: var(--text-color);
+ transition: background-color 0.3s, color 0.3s;
+}
+
+.container {
+ background: var(--container-bg);
+ padding: 20px;
+ max-width: 800px;
+ margin: auto;
+ border-radius: 8px;
+ transition: background-color 0.3s;
+}
+
+select {
+ width: 100%;
+ padding: 10px;
+ margin-bottom: 10px;
+ border: 1px solid var(--input-border);
+ border-radius: 4px;
+ background-color: var(--container-bg);
+ color: var(--text-color);
+ transition: border-color 0.3s, background-color 0.3s, color 0.3s;
+}
+select.multi-select {
+ height: 120px;
+}
+button {
+ background: var(--button-bg);
+ color: var(--button-color);
+ border: none;
+ width: 100%;
+ padding: 10px;
+ cursor: pointer;
+ border-radius: 4px;
+ transition: background-color 0.3s;
+}
+
+button:hover {
+ opacity: 0.9;
+}
+
+a {
+ color: var(--link-color);
+ text-decoration: none;
+}
+
+pre {
+ background: var(--pre-bg);
+ color: var(--pre-color);
+ padding: 10px;
+ height: 140px;
+ overflow: auto;
+ border-radius: 4px;
+}
\ No newline at end of file