diff --git a/financial-tracker/api-gateway/app/app.py b/financial-tracker/api-gateway/app/app.py
index 9d86bcea4c2c51aa2d36c82e155543dd11a1265e..a98550772383027c587b9eb45c45d37e75212103 100644
--- a/financial-tracker/api-gateway/app/app.py
+++ b/financial-tracker/api-gateway/app/app.py
@@ -1,14 +1,29 @@
+from datetime import timedelta
 from flask import Flask, jsonify, request
 from flask_cors import CORS
+from flask_jwt_extended import (
+    jwt_required, get_jwt_identity, JWTManager
+)
 import os
 import requests
 
 # Initialize Flask app
 app = Flask(__name__)
-CORS(app)
+CORS(app, resources={r"/*": {"origins": "http://localhost:3000"}})
 
-# Configure user service URL
+# Configuration
 USER_SERVICE_URL = os.getenv('USER_SERVICE_URL', 'http://user-service:5001')
+TRANSACTION_SERVICE_URL = os.getenv("TRANSACTION_SERVICE_URL", "http://transaction-service:5002")
+app.config["JWT_SECRET_KEY"] = os.getenv(
+    "JWT_SECRET_KEY", "3b5e41af18179f530c5881a5191e15f0ab35eed2fefdc068fda254eed3fb1ecb"
+)
+app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=1)
+app.config["JWT_TOKEN_LOCATION"] = ["headers"]
+app.config["JWT_HEADER_NAME"] = "Authorization"  # Default header for JWT
+app.config["JWT_HEADER_TYPE"] = "Bearer" 
+
+# Initialise Flask-JWT-Extended
+jwt = JWTManager(app)
 
 # HEALTH CHECK ROUTE
 @app.route('/health', methods=['GET'])
@@ -80,5 +95,124 @@ def me():
         return jsonify({"error": "User service unavailable"}), 503
 
 
+@app.route('/expenses', methods=['POST'])
+def add_expense():
+    """Forward request to transaction-service to add an expense."""
+    token = request.headers.get("Authorization")  # Get token from headers
+
+    if not token:
+        app.logger.error("Authorization token is missing.")
+        return jsonify({"error": "Authorization token is missing"}), 400
+
+    try:
+        headers = {"Authorization": token, "Content-Type": "application/json"}
+        data = request.get_json()
+        app.logger.info(f"Forwarding expense addition request: {data}")
+
+        response = requests.post(f"{TRANSACTION_SERVICE_URL}/expenses", headers=headers, json=data)
+        return jsonify(response.json()), response.status_code
+
+    except requests.exceptions.RequestException as e:
+        app.logger.error(f"Error contacting transaction-service: {e}")
+        return jsonify({"error": "Transaction service unavailable"}), 503
+    
+
+@app.route('/expenses', methods=['GET'])
+def fetch_expenses():
+    """Fetch expenses for the logged-in user."""
+    token = request.headers.get("Authorization")  # Get token from headers
+
+    if not token:
+        return jsonify({"error": "Authorization token is missing"}), 400
+
+    try:
+        headers = {"Authorization": token}  # Forward token
+        response = requests.get(f"{TRANSACTION_SERVICE_URL}/expenses", headers=headers)
+        app.logger.info(f"Response from transaction-service (expenses): {response.status_code} - {response.json()}")
+        return jsonify(response.json()), response.status_code
+    except requests.exceptions.RequestException as e:
+        return jsonify({"error": "Transaction service unavailable"}), 503
+
+
+@app.route('/expenses/<expense_id>', methods=['PUT'])
+@jwt_required()
+def edit_expense(expense_id):
+    """Forward request to transaction-service to edit an expense (excluding currency)."""
+    token = request.headers.get("Authorization")  # Get token from headers
+
+    if not token:
+        app.logger.error("Authorization token is missing.")
+        return jsonify({"error": "Authorization token is missing"}), 400
+
+    try:
+        headers = {"Authorization": token, "Content-Type": "application/json"}
+        data = request.get_json()
+
+        # Ensure currency field is not included in the update request
+        if "currency" in data:
+            app.logger.warning(f"Attempt to modify currency field in expense {expense_id}")
+            return jsonify({"error": "Currency field cannot be updated"}), 400
+
+        app.logger.info(f"Forwarding expense update request for ID {expense_id}: {data}")
+
+        response = requests.put(f"{TRANSACTION_SERVICE_URL}/expenses/{expense_id}", headers=headers, json=data)
+        return jsonify(response.json()), response.status_code
+
+    except requests.exceptions.RequestException as e:
+        app.logger.error(f"Error contacting transaction-service: {e}")
+        return jsonify({"error": "Transaction service unavailable"}), 503
+
+
+@app.route('/expenses/<expense_id>', methods=['DELETE'])
+@jwt_required()
+def delete_expense(expense_id):
+    """Forward request to transaction-service to delete an expense."""
+    token = request.headers.get("Authorization")  # Get token from headers
+
+    if not token:
+        app.logger.error("Authorization token is missing.")
+        return jsonify({"error": "Authorization token is missing"}), 400
+
+    try:
+        headers = {"Authorization": token}  # Forward token
+        response = requests.delete(f"{TRANSACTION_SERVICE_URL}/expenses/{expense_id}", headers=headers)
+
+        if response.status_code == 200:
+            app.logger.info(f"Expense with ID {expense_id} deleted successfully.")
+            return jsonify({"message": "Expense deleted successfully."}), 200
+        else:
+            app.logger.error(f"Failed to delete expense with ID {expense_id}.")
+            return jsonify({"error": "Failed to delete expense"}), response.status_code
+
+    except requests.exceptions.RequestException as e:
+        app.logger.error(f"Error contacting transaction-service: {e}")
+        return jsonify({"error": "Transaction service unavailable"}), 503
+
+
+@app.route('/categories', methods=['GET'])
+@jwt_required()
+def fetch_categories():
+    """Fetch available expense categories from transaction-service."""
+    token = request.headers.get("Authorization")  # Get token from headers
+
+    if not token:
+        return jsonify({"error": "Authorization token is missing"}), 400
+
+    try:
+        user_id = get_jwt_identity()  # Extract user_id from JWT token
+        headers = {"Authorization": token}
+        response = requests.get(f"{TRANSACTION_SERVICE_URL}/categories", headers=headers)
+
+        # Add CORS headers to the response
+        response_data = jsonify(response.json())
+        response_data.headers.add("Access-Control-Allow-Origin", "http://localhost:3000")
+        response_data.headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization")
+        response_data.headers.add("Access-Control-Allow-Methods", "GET, OPTIONS")
+
+        return response_data, response.status_code
+    except requests.exceptions.RequestException as e:
+        return jsonify({"error": "Transaction service unavailable"}), 503
+
+
 if __name__ == '__main__':
     app.run(host='0.0.0.0', port=8000, debug=True)
diff --git a/financial-tracker/docker-compose.yml b/financial-tracker/docker-compose.yml
index 6a7a78d547e1ad596363390a266130171f65918a..130d285ac21641f15e5d5bb625cbec6b3a850247 100644
--- a/financial-tracker/docker-compose.yml
+++ b/financial-tracker/docker-compose.yml
@@ -48,6 +48,10 @@ services:
       - transaction-db
     networks:
       - app-network
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:5002/health"]
+      interval: 30s
+      retries: 3
 
   budget-service:
     build:
diff --git a/financial-tracker/frontend/package-lock.json b/financial-tracker/frontend/package-lock.json
index aaf12de8f91640f2d677702213f2b903b1604e81..d109621253c524b888e4c90e15211c45de14c131 100644
--- a/financial-tracker/frontend/package-lock.json
+++ b/financial-tracker/frontend/package-lock.json
@@ -13,9 +13,13 @@
         "@testing-library/react": "^16.2.0",
         "@testing-library/user-event": "^13.5.0",
         "axios": "^1.8.4",
+        "chart.js": "^4.4.8",
         "formik": "^2.4.6",
+        "jwt-decode": "^4.0.0",
         "react": "^19.0.0",
+        "react-chartjs-2": "^5.3.0",
         "react-dom": "^19.0.0",
+        "react-paginate": "^8.3.0",
         "react-router-dom": "^7.4.0",
         "react-scripts": "5.0.1",
         "web-vitals": "^2.1.4",
@@ -2964,6 +2968,12 @@
         "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
+    "node_modules/@kurkle/color": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
+      "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
+      "license": "MIT"
+    },
     "node_modules/@leichtgewicht/ip-codec": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
@@ -5584,6 +5594,18 @@
         "node": ">=10"
       }
     },
+    "node_modules/chart.js": {
+      "version": "4.4.8",
+      "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.8.tgz",
+      "integrity": "sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==",
+      "license": "MIT",
+      "dependencies": {
+        "@kurkle/color": "^0.3.0"
+      },
+      "engines": {
+        "pnpm": ">=8"
+      }
+    },
     "node_modules/check-types": {
       "version": "11.2.3",
       "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz",
@@ -11126,6 +11148,15 @@
         "node": ">=4.0"
       }
     },
+    "node_modules/jwt-decode": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
+      "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/keyv": {
       "version": "4.5.4",
       "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -13913,6 +13944,16 @@
       "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
       "license": "MIT"
     },
+    "node_modules/react-chartjs-2": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz",
+      "integrity": "sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "chart.js": "^4.1.1",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+      }
+    },
     "node_modules/react-dev-utils": {
       "version": "12.0.1",
       "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@@ -14048,6 +14089,18 @@
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
       "license": "MIT"
     },
+    "node_modules/react-paginate": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/react-paginate/-/react-paginate-8.3.0.tgz",
+      "integrity": "sha512-TptZE37HPkT3R+7AszWA++LOTIsIHXcCSWMP9WW/abeF8sLpJzExFB/dVs7xbtqteJ5njF6kk+udTDC0AR3y5w==",
+      "license": "MIT",
+      "dependencies": {
+        "prop-types": "^15"
+      },
+      "peerDependencies": {
+        "react": "^16 || ^17 || ^18 || ^19"
+      }
+    },
     "node_modules/react-refresh": {
       "version": "0.11.0",
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
diff --git a/financial-tracker/frontend/package.json b/financial-tracker/frontend/package.json
index 8bfa2e5d5c862fba9f11d3ec5163d7361bcb07b1..bf17e4b0261820c73a6d4e022a3e06dffcd2bcdc 100644
--- a/financial-tracker/frontend/package.json
+++ b/financial-tracker/frontend/package.json
@@ -8,9 +8,13 @@
     "@testing-library/react": "^16.2.0",
     "@testing-library/user-event": "^13.5.0",
     "axios": "^1.8.4",
+    "chart.js": "^4.4.8",
     "formik": "^2.4.6",
+    "jwt-decode": "^4.0.0",
     "react": "^19.0.0",
+    "react-chartjs-2": "^5.3.0",
     "react-dom": "^19.0.0",
+    "react-paginate": "^8.3.0",
     "react-router-dom": "^7.4.0",
     "react-scripts": "5.0.1",
     "web-vitals": "^2.1.4",
diff --git a/financial-tracker/frontend/src/App.js b/financial-tracker/frontend/src/App.js
index 8ceaacc42b7cb8236fd52aa38621a6d7d0c81b19..15b508747874982d406ddce4337af6b06f4de5cd 100644
--- a/financial-tracker/frontend/src/App.js
+++ b/financial-tracker/frontend/src/App.js
@@ -5,17 +5,17 @@ import Home from "./pages/Home";
 import Register from "./pages/Register";
 import Login from "./pages/Login";
 import Dashboard from "./pages/Dashboard";
+import Expenses from "./pages/Expenses";
 
 function App() {
   const [token, setToken] = useState(localStorage.getItem("token"));
 
   useEffect(() => {
     const handleStorageChange = () => {
-      setToken(localStorage.getItem("token")); // Update token when it changes
+      setToken(localStorage.getItem("token"));
     };
 
     window.addEventListener("storage", handleStorageChange);
-
     return () => {
       window.removeEventListener("storage", handleStorageChange);
     };
@@ -33,6 +33,7 @@ function App() {
             {token ? (
               <>
                 <li><Link to="/dashboard">Dashboard</Link></li>
+                <li><Link to="/expenses">Expenses</Link></li>
                 <li>
                   <Link to="/" onClick={() => { localStorage.removeItem("token"); setToken(null); }}>
                     Logout
@@ -53,6 +54,7 @@ function App() {
           <Route path="/register" element={<Register />} />
           <Route path="/login" element={<Login setToken={setToken} />} />
           <Route path="/dashboard" element={<Dashboard setToken={setToken} />} />
+          <Route path="/expenses" element={<Expenses />} />
         </Routes>
       </div>
     </Router>
diff --git a/financial-tracker/frontend/src/pages/ExpenseChart.js b/financial-tracker/frontend/src/pages/ExpenseChart.js
new file mode 100644
index 0000000000000000000000000000000000000000..3b5a66336d4deed410fdcf7d15562d8c4ca5dd92
--- /dev/null
+++ b/financial-tracker/frontend/src/pages/ExpenseChart.js
@@ -0,0 +1,232 @@
+import React, { useEffect, useState } from "react";
+import { Pie, Bar, Line } from "react-chartjs-2";
+import {
+  Chart,
+  ArcElement,
+  Tooltip,
+  Legend,
+  CategoryScale,
+  LinearScale,
+  BarElement,
+  PointElement,
+  LineElement,
+  LineController,
+} from "chart.js";
+import "../styles/ExpenseChart.css";
+
+// Register chart components
+Chart.register(
+  ArcElement,
+  Tooltip,
+  Legend,
+  CategoryScale,
+  LinearScale,
+  BarElement,
+  PointElement,
+  LineElement,
+  LineController
+);
+
+const ExpenseChart = ({ expenses, type, timeRange }) => {
+  const [categoryTotals, setCategoryTotals] = useState({});
+  const [timeSeriesData, setTimeSeriesData] = useState({});
+
+  // Predefined color palette
+  const colorPalette = [
+    "#FF6384", "#36A2EB", "#FFCE56", "#4CAF50", "#FF9800", "#9C27B0",
+    "#FF5733", "#33FF57", "#3357FF", "#FF33A2", "#A233FF", "#57FF33",
+    "#FFD700", "#800080", "#00BFFF", "#00FF00", "#FF1493", "#8A2BE2",
+    "#FF6347", "#7CFC00", "#FF4500", "#32CD32", "#ADFF2F", "#FF8C00",
+  ];
+
+  // Function to group expenses by time range
+  const groupExpensesByTime = (expenses, range) => {
+    const grouped = {};
+
+    expenses.forEach((expense) => {
+      const date = new Date(expense.date);
+      let timeKey;
+
+      if (range === "daily") {
+        timeKey = date.toISOString().split("T")[0]; // YYYY-MM-DD
+      } else if (range === "weekly") {
+        const weekNumber = getWeekNumber(date);
+        timeKey = `${date.getFullYear()}-W${weekNumber}`;
+      } else if (range === "monthly") {
+        timeKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
+      } else if (range === "yearly") {
+        timeKey = `${date.getFullYear()}`;
+      }
+
+      if (!grouped[expense.category]) {
+        grouped[expense.category] = {};
+      }
+      grouped[expense.category][timeKey] =
+        (grouped[expense.category][timeKey] || 0) + expense.amount;
+    });
+
+    return grouped;
+  };
+
+  // Function to get the week number of a date
+  const getWeekNumber = (date) => {
+    const startOfYear = new Date(date.getFullYear(), 0, 1);
+    const pastDays = Math.floor((date - startOfYear) / (24 * 60 * 60 * 1000));
+    return Math.ceil((pastDays + startOfYear.getDay() + 1) / 7);
+  };
+
+  useEffect(() => {
+    if (expenses.length > 0) {
+      // Calculate total spending by category
+      const totals = expenses.reduce((acc, expense) => {
+        acc[expense.category] = (acc[expense.category] || 0) + expense.amount;
+        return acc;
+      }, {});
+      setCategoryTotals(totals);
+
+      // Group expenses by selected time range (daily, weekly, monthly, yearly)
+      const groupedData = groupExpensesByTime(expenses, timeRange);
+      setTimeSeriesData(groupedData);
+    }
+  }, [expenses, timeRange]);
+
+  // Generate colors for the categories
+  const dataColors = Object.keys(categoryTotals).map((_, index) => {
+    return colorPalette[index % colorPalette.length];
+  });
+
+  // Data for Pie Chart
+  const pieData = {
+    labels: Object.keys(categoryTotals),
+    datasets: [
+      {
+        label: "Spending by Category",
+        data: Object.values(categoryTotals),
+        backgroundColor: dataColors,
+      },
+    ],
+  };
+
+  // Data for Bar Chart
+  const barData = {
+    labels: Object.keys(categoryTotals),
+    datasets: [
+      {
+        data: Object.values(categoryTotals),
+        backgroundColor: dataColors,
+      },
+    ],
+  };
+
+  // Prepare data for the line chart
+  const timeLabels = [
+    ...new Set(
+      Object.values(timeSeriesData).flatMap((data) => Object.keys(data))
+    ),
+  ].sort();
+
+  const lineDatasets = Object.keys(timeSeriesData).map((category, index) => ({
+    label: category,
+    data: timeLabels.map((label) => timeSeriesData[category]?.[label] || 0),
+    borderColor: colorPalette[index % colorPalette.length],
+    backgroundColor: colorPalette[index % colorPalette.length],
+    fill: false,
+    tension: 0.1,
+  }));
+
+  const lineData = {
+    labels: timeLabels,
+    datasets: lineDatasets,
+  };
+
+  // Chart options
+  const options = {
+    responsive: true,
+    maintainAspectRatio: false,
+    scales: {
+      y: {
+        beginAtZero: true,
+        title: {
+          display: true,
+          text: "Amount Spent",
+        },
+      },
+      x: {
+        title: {
+          display: true,
+          text:
+            type === "line"
+              ? `Time (${timeRange.charAt(0).toUpperCase() + timeRange.slice(1)})`
+              : "Categories",
+        },
+      },
+    },
+    plugins: {
+      legend: {
+        display: false, // Set to false to hide the legend entirely
+      },
+      tooltip: {
+        mode: "index",
+        intersect: false,
+      },
+    },
+  };
+
+
+  return (
+    <div className="expense-chart-container">
+      {/* Pie Chart Section */}
+      {type === "pie" && (
+        <div className="chart-section">
+          <div className="text-container">
+            <h4>Pie Chart: Spending Breakdown</h4>
+            <p>
+              The pie chart shows the proportion of spending for each category.
+              Each slice of the pie represents a category, and the size of each
+              slice is proportional to the amount spent in that category.
+            </p>
+          </div>
+          <div className="chart">
+            <Pie data={pieData} />
+          </div>
+        </div>
+      )}
+
+      {/* Bar Chart Section */}
+      {type === "bar" && (
+        <div className="chart-section">
+          <div className="text-container">
+            <h4>Bar Chart: Spending by Category</h4>
+            <p>
+              The bar chart provides a clear comparison of spending across
+              categories. Each bar represents the total amount spent in each
+              category, making it easy to compare amounts visually.
+            </p>
+          </div>
+          <div className="chart">
+            <Bar data={barData} options={options} />
+          </div>
+        </div>
+      )}
+
+      {/* Line Chart Section */}
+      {type === "line" && (
+        <div className="chart-section">
+          <div className="text-container">
+            <h4>Line Chart: Spending Trends Over Time</h4>
+            <p>
+              The line chart shows how your spending has changed over time for
+              each category. This helps identify trends and patterns in your
+              expenses.
+            </p>
+          </div>
+          <div className="chart">
+            <Line data={lineData} options={options} />
+          </div>
+        </div>
+      )}
+    </div>
+  );
+};
+
+export default ExpenseChart;
diff --git a/financial-tracker/frontend/src/pages/Expenses.js b/financial-tracker/frontend/src/pages/Expenses.js
new file mode 100644
index 0000000000000000000000000000000000000000..f53a3106489566a3dc8239793e366c780cd567d1
--- /dev/null
+++ b/financial-tracker/frontend/src/pages/Expenses.js
@@ -0,0 +1,915 @@
+import React, { useState, useEffect } from "react";
+import axios from "axios";
+import { jwtDecode } from 'jwt-decode';
+import ReactPaginate from 'react-paginate';
+import ExpenseChart from "./ExpenseChart";
+import "../styles/Expenses.css";
+
+const Expenses = () => {
+  const [expenses, setExpenses] = useState([]);
+  const expensesPerPage = 5;
+  const [currentPage, setCurrentPage] = useState(0);
+  const offset = currentPage * expensesPerPage;
+  const [filteredExpenses, setFilteredExpenses] = useState([]);
+  const currentExpenses = filteredExpenses.slice(offset, offset + expensesPerPage);
+  const [isSessionValid, setIsSessionValid] = useState(true);
+  const [isRecurring, setIsRecurring] = useState(false);
+  const [recurring_type, setRecurringType] = useState(""); 
+  const [frequency, setFrequency] = useState("");    
+  const [interval, setInterval] = useState("");      
+  const [end_repeat, setEndRepeat] = useState("never");    
+  const [end_date, setEndDate] = useState("");             
+  const [sortConfig, setSortConfig] = useState({ key: "", direction: "asc" });
+  const [showFilters, setShowFilters] = useState(false);
+  const [categories, setCategories] = useState([]);
+  const [chartType, setChartType] = useState("bar");
+  const [timeRange, setTimeRange] = useState("monthly");
+  const [newExpense, setNewExpense] = useState({
+    category: "",
+    amount: "",
+    date: "",
+    description: "",
+    currency: "GBP",
+    recurring: false,
+    recurring_type: "",  
+    frequency: "",       
+    interval: "",        
+    end_repeat: "never", 
+    end_date: "",        
+  });
+  const [editExpense, setEditExpense] = useState({
+    id: null,
+    category: "",
+    amount: "",
+    date: "",
+    description: "",
+    currency: "GBP",
+    recurring: false,
+    recurring_type: "",  
+    frequency: "",       
+    interval: "",        
+    end_repeat: "never", 
+    end_date: "",        
+  });
+  const [filters, setFilters] = useState({
+    category: "",
+    minAmount: "",
+    maxAmount: "",
+    startDate: "",
+    end_date: "",
+  });
+  const [deleteMessage, setDeleteMessage] = useState("");
+  const [successMessage, setSuccessMessage] = useState("");
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  
+  const openModal = () => {
+    setIsModalOpen(true);
+  };
+  
+  const closeModal = () => {
+    setIsModalOpen(false);
+  };
+
+
+  // Check if token exists in localStorage to determine if session is valid
+  useEffect(() => {
+    const token = localStorage.getItem("token");
+
+    if (token) {
+      setIsSessionValid(true); // Token exists, session is valid
+    } else {
+      setIsSessionValid(false); // No token, session invalid
+      alert("Your session has expired. Please log in again.");
+      window.location.href = "/login"; // Redirect to login page
+    }
+  }, []);
+
+
+  // Only fetch data if session is valid
+  useEffect(() => {
+    if (isSessionValid) {
+      fetchCategories();
+      fetchExpenses();
+    }
+  }, [isSessionValid]);
+
+
+  const fetchExpenses = async () => {
+    try {
+      const token = localStorage.getItem("token");
+
+      if (!token) {
+        console.error("No token found, user might not be logged in.");
+        return;
+      }
+
+      const decoded = jwtDecode(token);
+      console.log("Decoded JWT:", decoded);
+  
+      // Use 'sub' as user_id
+      const user_id = decoded.sub;
+      if (!user_id) {
+        console.error("User ID is undefined. Check JWT structure.");
+        return;
+      }
+
+      const response = await axios.get("http://localhost:8000/expenses", {
+        headers: { Authorization: `Bearer ${token}` },
+      });
+
+      console.log("Fetched expenses:", response.data);
+
+      if (Array.isArray(response.data.expenses)) {
+        setExpenses(response.data.expenses);
+        setFilteredExpenses(response.data.expenses);
+      } else {
+        console.error("Expected an array but got:", response.data);
+        setExpenses([]);
+        setFilteredExpenses([]);
+      }
+    } catch (error) {
+      console.error("Error fetching expenses:", error);
+      setExpenses([]);
+      setFilteredExpenses([]);
+    }
+  };
+
+
+  const fetchCategories = async () => {
+    try {
+      const token = localStorage.getItem("token");
+      console.log("Token from localStorage:", token);
+  
+      if (!token) {
+        console.error("No token found, user might not be logged in.");
+        return;
+      }
+  
+      const decoded = jwtDecode(token);
+      console.log("Decoded JWT:", decoded);
+  
+      // Use 'sub' as user_id
+      const user_id = decoded.sub;
+      if (!user_id) {
+        console.error("User ID is undefined. Check JWT structure.");
+        return;
+      }
+  
+      const response = await axios.get(`http://localhost:8000/categories`, {
+        headers: { Authorization: `Bearer ${token}` },
+      });
+      
+      console.log("Categories Response:", response.data);
+  
+      if (Array.isArray(response.data.categories)) {
+        setCategories(response.data.categories);
+      } else {
+        console.error("Categories data is not in expected format", response.data);
+      }
+    } catch (error) {
+      console.error("Error fetching categories:", error);
+    }
+  };
+  
+
+  const handleChange = (e) => {
+    const { name, type, value, checked } = e.target;
+    setNewExpense({
+      ...newExpense,
+      [name]: type === "checkbox" ? checked : value,
+    });
+  };
+
+
+  const handleEdit = (expense) => {
+    if (!expense || !expense.id) {
+      console.error("Invalid expense to edit", expense);
+      return;
+    }
+    console.log("Editing expense:", expense);
+    setEditExpense({
+      id: expense.id,
+      category: expense.category,
+      amount: expense.amount,
+      date: expense.date,
+      description: expense.description,
+      recurring: expense.recurring,
+      recurring_type: expense.recurring_type || "",
+      frequency: expense.frequency || "",
+      interval: expense.interval || "",
+      end_repeat: expense.end_repeat || "never",
+      end_date: expense.end_date || "", 
+    });
+    openModal();
+  };
+
+
+  const handleSaveEdit = async (e, id) => {
+    e.preventDefault();
+  
+    try {
+      const updatedExpense = { 
+        ...editExpense,
+        recurring_type: editExpense.recurring ? editExpense.recurring_type : null,
+        frequency: editExpense.recurring_type === "custom" ? editExpense.frequency : null,
+        interval: editExpense.recurring_type === "custom" ? editExpense.interval : null,
+        end_repeat: editExpense.recurring ? editExpense.end_repeat : null,
+        end_date: editExpense.end_repeat === "on_date" ? editExpense.end_date : null,
+      };
+
+      // Ensure end_date is sent only if 'end_repeat' is 'on_date'
+      if (updatedExpense.end_repeat === "on_date" && !updatedExpense.end_date) {
+        alert("Please specify an end date.");
+        return;
+      }
+
+      if (updatedExpense.currency) {
+        delete updatedExpense.currency;
+      }
+      if (!updatedExpense.end_date) {
+        delete updatedExpense.end_date;
+      }
+      
+      console.log("Updated Expense Payload:", updatedExpense);
+  
+      const token = localStorage.getItem("token");
+  
+      const response = await axios.put(
+        `http://localhost:8000/expenses/${id}`,
+        updatedExpense,
+        {
+          headers: {
+            "Content-Type": "application/json",
+            Authorization: `Bearer ${token}`,
+          },
+        }
+      );
+  
+      if (response.status === 200) {
+        setExpenses((prevExpenses) =>
+          prevExpenses.map((expense) =>
+            expense.id === id ? { ...expense, ...updatedExpense } : expense
+          )
+        );
+        
+        setFilteredExpenses((prevFiltered) =>
+          prevFiltered.map((expense) =>
+            expense.id === id ? { ...expense, ...updatedExpense } : expense
+          )
+        );
+
+        closeModal();
+        setSuccessMessage("Expense updated successfully. Refreshing expense page...");
+        // Wait 1.5 seconds before refreshing
+        setTimeout(() => {
+            window.location.reload();
+        }, 1500);
+      } else {
+        console.error("Error updating expense:", response.data);
+      }
+    } catch (error) {
+      console.error("Error updating expense:", error);
+      alert(
+        `Error updating expense: ${
+          error.response ? error.response.data.error || error.response.data.message : error.message
+        }`
+      );
+    }
+  };  
+  
+
+  const handleDelete = async (id) => {
+    const confirmDelete = window.confirm("Are you sure you want to delete this expense?");
+    
+    if (confirmDelete) {
+      try {
+        const token = localStorage.getItem("token");
+          const response = await axios.delete(`http://localhost:8000/expenses/${id}`, {
+            headers: { Authorization: `Bearer ${token}` },
+          });
+
+          if (response.status === 200) {
+            setDeleteMessage("Expense deleted successfully. Refreshing expense page...");
+
+            // Wait 1.5 seconds before refreshing
+            setTimeout(() => {
+                window.location.reload();
+            }, 1500);
+          }
+        } catch (error) {
+          console.error("Error deleting expense:", error);
+          setDeleteMessage("Error deleting expense. Please try again.");
+      }
+    }
+  };
+
+
+  const handleAddExpense = async (e) => {
+    e.preventDefault();
+  
+    // Ensure correct key names for backend
+    const expenseWithCurrency = {
+      ...newExpense,
+      currency: newExpense.currency || 'GBP', // Default to GBP
+      recurring: isRecurring, // Ensure recurring is passed as boolean
+      recurring_type: recurring_type || null, // Match backend field
+      frequency: frequency || null, // Match backend field
+      interval: interval || null, // Match backend field
+      end_repeat: end_repeat || null, // Match backend field
+      end_date: end_date || null, // Match backend field
+    };
+  
+    try {
+      const token = localStorage.getItem("token");
+      const response = await axios.post(
+        "http://localhost:8000/expenses",
+        expenseWithCurrency,
+        {
+          headers: {
+            "Content-Type": "application/json",
+            Authorization: `Bearer ${token}`,
+          },
+        }
+      );
+  
+      if (response.status === 201) {
+        const addedExpense = response.data;
+        setExpenses([...expenses, addedExpense]);
+        setFilteredExpenses([...filteredExpenses, addedExpense]);
+  
+        // Re-fetch the expenses from the backend
+        fetchExpenses(); 
+  
+        setNewExpense({
+          category: "",
+          amount: "",
+          date: "",
+          description: "",
+          recurring: false,
+          recurring_type: "",
+          frequency: "",
+          interval: "",
+          end_repeat: "never",
+          end_date: "",
+          currency: "",
+        });
+  
+        setSuccessMessage("Expense added successfully. Refreshing expense page...");
+        // Wait 1.5 seconds before refreshing
+        setTimeout(() => {
+            window.location.reload();
+        }, 1500);
+      } else {
+        console.error("Error adding expense:", response.data);
+      }
+    } catch (error) {
+      console.error("Error adding expense:", error);
+      alert(
+        `Error adding expense: ${
+          error.response ? error.response.data.error : error.message
+        }`
+      );
+    }
+  };
+  
+
+  const applyFilters = () => {
+    let filtered = expenses.filter((expense) => {
+      return (
+        (!filters.category || expense.category.toLowerCase() === filters.category.toLowerCase()) &&
+        (!filters.minAmount || parseFloat(expense.amount) >= parseFloat(filters.minAmount)) &&
+        (!filters.maxAmount || parseFloat(expense.amount) <= parseFloat(filters.maxAmount)) &&
+        (!filters.startDate || expense.date >= filters.startDate) &&
+        (!filters.end_date || expense.date <= filters.end_date)
+      );
+    });
+    setFilteredExpenses(filtered);
+  };
+
+
+  const sortData = (key) => {
+    let direction = "asc";
+    if (sortConfig.key === key && sortConfig.direction === "asc") {
+      direction = "desc";
+    }
+    const sortedExpenses = [...filteredExpenses].sort((a, b) => {
+      if (key === "date") {
+        return direction === "asc" 
+          ? new Date(a[key]) - new Date(b[key])
+          : new Date(b[key]) - new Date(a[key]);
+      } else if (key === "amount") {
+        return direction === "asc"
+          ? parseFloat(a[key]) - parseFloat(b[key])
+          : parseFloat(b[key]) - parseFloat(a[key]);
+      }
+      return 0;
+    });
+    setFilteredExpenses(sortedExpenses);
+    setSortConfig({ key, direction });
+  };
+
+
+  const handlePageClick = (event) => {
+    const selectedPage = event.selected;
+    setCurrentPage(selectedPage);
+  };
+
+  const handleChartChange = (event) => {
+    setChartType(event.target.value);
+  };
+
+  const handleTimeRangeChange = (event) => {
+    setTimeRange(event.target.value);
+  };
+
+  return (
+    <div className="expenses-container">
+      <h1>Expenses</h1>
+
+      {/* Delete Message */}
+      {deleteMessage && <div className="delete-message">{deleteMessage}</div>}
+
+      {/* Success Message */}
+      {successMessage && <div className="success-message">{successMessage}</div>}
+
+      {/* Add Expense Form */}
+      <form onSubmit={handleAddExpense} className="expense-form">
+      <div class="expense-inputs">
+        <div class="expense-row">
+          <div class="input-group">
+            <label htmlFor="category">Category</label>
+            <input
+              type="text"
+              name="category"
+              placeholder="Category"
+              value={newExpense.category}
+              onChange={handleChange}
+              required
+            />
+          </div>
+          <div class="input-group">
+            <label htmlFor="amount">Amount</label>
+            <input
+              type="number"
+              name="amount"
+              placeholder="Amount"
+              value={newExpense.amount}
+              onChange={handleChange}
+              step="0.01"
+              required
+            />
+          </div>
+        </div>
+        <div class="expense-row">
+          <div class="input-group">
+            <label htmlFor="date">Date</label>
+            <input
+              type="date"
+              name="date"
+              value={newExpense.date}
+              onChange={handleChange}
+              required
+            />
+          </div>
+          <div class="input-group">
+            <label htmlFor="description">Description (optional)</label>
+            <input
+              type="text"
+              name="description"
+              placeholder="Description (optional)"
+              value={newExpense.description}
+              onChange={handleChange}
+            />
+          </div>
+        </div>
+        <div className="checkbox-container">
+          <div className="checkbox-label">
+            <input
+              type="checkbox"
+              id="recurring"
+              checked={isRecurring}
+              onChange={() => setIsRecurring((prev) => !prev)}
+            />
+            <label htmlFor="recurring">Recurring Expense</label>
+          </div>
+        </div>
+      </div>
+
+        {/* Recurring Options (Only shown if checkbox is checked) */}
+        {isRecurring && (
+          <div className="recurring-options">
+            {/* Left Column: Recurrence Type */}
+            <div className="recurring-left">
+              <label htmlFor="recurring_type">Recurrence Type</label>
+              <select
+                id="recurring_type"
+                value={recurring_type}
+                onChange={(e) => setRecurringType(e.target.value)}
+              >
+                <option value="">Select...</option>
+                <option value="daily">Daily</option>
+                <option value="weekly">Weekly</option>
+                <option value="every_two_weeks">Every Two Weeks</option>
+                <option value="monthly">Every Month</option>
+                <option value="yearly">Every Year</option>
+                <option value="custom">Custom</option>
+              </select>
+
+              {/* Custom Recurrence Options */}
+              {recurring_type === "custom" && (
+                <div className="custom-recurring">
+                  <label htmlFor="frequency">Frequency</label>
+                  <select
+                    id="frequency"
+                    value={frequency}
+                    onChange={(e) => setFrequency(e.target.value)}
+                  >
+                    <option value="">Select...</option>
+                    <option value="daily">Daily</option>
+                    <option value="weekly">Weekly</option>
+                    <option value="monthly">Monthly</option>
+                    <option value="yearly">Yearly</option>
+                  </select>
+
+                  <label htmlFor="interval">Interval (e.g., every X weeks)</label>
+                  <input
+                    id="interval"
+                    type="number"
+                    min="1"
+                    value={interval}
+                    onChange={(e) => setInterval(e.target.value)}
+                    placeholder="Enter interval (e.g., every 3 weeks)"
+                  />
+                </div>
+              )}
+            </div>
+
+            {/* Right Column: End Repeat */}
+            <div className="recurring-right">
+              <label htmlFor="end_repeat">End Repeat</label>
+              <select
+                id="end_repeat"
+                value={end_repeat}
+                onChange={(e) => setEndRepeat(e.target.value)}
+              >
+                <option value="never">Never</option>
+                <option value="on_date">On Date</option>
+              </select>
+
+              {end_repeat === "on_date" && (
+                <div className="input-group">
+                  <label htmlFor="end_date">End Date:</label>
+                  <input
+                    id="end_date"
+                    type="date"
+                    value={end_date}
+                    onChange={(e) => setEndDate(e.target.value)}
+                  />
+                </div>
+              )}
+            </div>
+          </div>
+        )}
+        <button type="submit" className="add-expense-btn">
+          Add Expense
+        </button>
+      </form>
+
+
+      {/* Filters Section */}
+      <div className="filter-toggle">
+        <button onClick={() => setShowFilters((prev) => !prev)}>
+          {showFilters ? "Hide Filters" : "Show Filters"}
+        </button>
+      </div>
+
+      {showFilters && (
+        <div className="filter-dropdown">
+          {/* First Column: Category */}
+          <div className="filter-column">
+            <label htmlFor="category">Category</label>
+            <select
+              id="category"
+              value={filters.category}
+              onChange={(e) => setFilters({ ...filters, category: e.target.value })}
+            >
+              <option value="">All Categories</option>
+              {categories.map((cat) => (
+                <option key={cat} value={cat}>
+                  {cat}
+                </option>
+              ))}
+            </select>
+          </div>
+
+          {/* Second Column: Min/Max Amount */}
+          <div className="filter-column">
+            <label htmlFor="minAmount">Min Amount</label>
+            <input
+              id="minAmount"
+              type="number"
+              placeholder="Min Amount"
+              value={filters.minAmount}
+              onChange={(e) => setFilters({ ...filters, minAmount: e.target.value })}
+              step="0.01"
+            />
+
+            <label htmlFor="maxAmount">Max Amount</label>
+            <input
+              id="maxAmount"
+              type="number"
+              placeholder="Max Amount"
+              value={filters.maxAmount}
+              onChange={(e) => setFilters({ ...filters, maxAmount: e.target.value })}
+              step="0.01"
+            />
+          </div>
+
+          {/* Third Column: Start/End Date */}
+          <div className="filter-column">
+            <label htmlFor="startDate">Start Date (dd/mm/yyyy)</label>
+            <input
+              id="startDate"
+              type="date"
+              value={filters.startDate}
+              onChange={(e) => setFilters({ ...filters, startDate: e.target.value })}
+            />
+
+            <label htmlFor="end_date">End Date (dd/mm/yyyy)</label>
+            <input
+              id="end_date"
+              type="date"
+              value={filters.end_date}
+              onChange={(e) => setFilters({ ...filters, end_date: e.target.value })}
+            />
+          </div>
+          {/* Apply Filters Button (Centered) */}
+          <div className="apply-filters-container">
+            <button className="apply-filters-btn" onClick={applyFilters}>
+              Apply Filters
+            </button>
+          </div>
+        </div>
+      )}
+
+
+      {/* Modal Content */}
+      <div className={`modal-overlay ${isModalOpen ? "show" : ""}`}>
+        <div className="modal-content">
+          <h3>Edit Expense</h3>
+          <form onSubmit={(e) => handleSaveEdit(e, editExpense.id)} className="expense-form">
+            <div className="expense-row">
+              <div className="input-group">
+                <label htmlFor="category">Category</label>
+                <input
+                  type="text"
+                  id="category"
+                  value={editExpense.category}
+                  onChange={(e) => setEditExpense({ ...editExpense, category: e.target.value })}
+                  required
+                />
+              </div>
+              <div className="input-group">
+                <label htmlFor="amount">Amount</label>
+                <input
+                  type="number"
+                  id="amount"
+                  value={editExpense.amount}
+                  onChange={(e) => setEditExpense({ ...editExpense, amount: e.target.value })}
+                  step="0.01"
+                  required
+                />
+              </div>
+            </div>
+            <div className="expense-row">
+              <div className="input-group">
+                <label htmlFor="date">Date</label>
+                <input
+                  type="date"
+                  id="date"
+                  value={editExpense.date}
+                  onChange={(e) => setEditExpense({ ...editExpense, date: e.target.value })}
+                  required
+                />
+              </div>
+              <div className="input-group">
+                <label htmlFor="description">Description</label>
+                <input
+                  type="text"
+                  id="description"
+                  value={editExpense.description}
+                  onChange={(e) => setEditExpense({ ...editExpense, description: e.target.value })}
+                />
+              </div>
+            </div>
+            <div className="checkbox-container">
+              <label className="checkbox-label">
+                <input
+                  type="checkbox"
+                  checked={editExpense.recurring}
+                  onChange={(e) => setEditExpense({ ...editExpense, recurring: e.target.checked })}
+                />
+                Recurring Expense
+              </label>
+            </div>
+            {editExpense.recurring && (
+              <div className="recurring-options">
+                <div className="recurring-left">
+                  <label htmlFor="recurring_type">Recurring Type</label>
+                  <select
+                    id="recurring_type"
+                    value={editExpense.recurring_type || ""}
+                    onChange={(e) => setEditExpense({ ...editExpense, recurring_type: e.target.value })}
+                    required
+                  >
+                    <option value="">Select...</option>
+                    <option value="daily">Daily</option>
+                    <option value="weekly">Weekly</option>
+                    <option value="every_two_weeks">Every Two Weeks</option>
+                    <option value="monthly">Every Month</option>
+                    <option value="yearly">Every Year</option>
+                    <option value="custom">Custom</option>
+                  </select>
+                  {editExpense.recurring_type === "custom" && (
+                    <div className="custom-recurring">
+                      <label htmlFor="frequency">Frequency</label>
+                      <select
+                        id="frequency"
+                        value={editExpense.frequency || ""}
+                        onChange={(e) => setEditExpense({ ...editExpense, frequency: e.target.value })}
+                      >
+                        <option value="">Select...</option>
+                        <option value="daily">Daily</option>
+                        <option value="weekly">Weekly</option>
+                        <option value="monthly">Monthly</option>
+                        <option value="yearly">Yearly</option>
+                      </select>
+                      <label htmlFor="interval">Interval (e.g., every X weeks)</label>
+                      <input
+                        id="interval"
+                        type="number"
+                        min="1"
+                        value={editExpense.interval || ""}
+                        onChange={(e) => setEditExpense({ ...editExpense, interval: e.target.value })}
+                        placeholder="Enter interval (e.g., every 3 weeks)"
+                      />
+                    </div>
+                  )}
+                </div>
+                <div className="recurring-right">
+                  <label htmlFor="end_repeat">End Repeat</label>
+                  <select
+                    id="end_repeat"
+                    value={editExpense.end_repeat || ""}
+                    onChange={(e) => setEditExpense({ ...editExpense, end_repeat: e.target.value })}
+                  >
+                    <option value="never">Never</option>
+                    <option value="on_date">On Date</option>
+                  </select>
+                  {editExpense.end_repeat === "on_date" && (
+                    <div className="recurring-right">
+                      <label htmlFor="end_date">End Date</label>
+                      <input
+                        type="date"
+                        id="end_date"
+                        value={editExpense.end_date || ""}
+                        onChange={(e) => setEditExpense({ ...editExpense, end_date: e.target.value })}
+                        required
+                      />
+                    </div>
+                  )}
+                </div>
+              </div>
+            )}
+            <button type="submit" className="add-expense-btn">Save Changes</button>
+            <button type="button" className="close-modal-btn" onClick={closeModal}>Cancel</button>
+          </form>
+        </div>
+      </div>
+
+
+      {/* Expenses Table */}
+      <table className="expenses-table">
+        <thead>
+          <tr>
+            <th onClick={() => sortData("date")} className="sortable">
+              Date {sortConfig.key === "date" && (sortConfig.direction === "asc" ? "↑" : "↓")}
+            </th>
+            <th>Category</th>
+            <th onClick={() => sortData("amount")} className="sortable">
+              Amount (£) {sortConfig.key === "amount" && (sortConfig.direction === "asc" ? "↑" : "↓")}
+            </th>
+            <th>Description</th>
+            <th>Recurring</th>
+            <th>Actions</th>
+          </tr>
+        </thead>
+        <tbody>
+          {filteredExpenses && filteredExpenses.length > 0 ? (
+            currentExpenses.map((expense) => (
+              <tr key={expense.id}>
+                <td>{expense.date}</td>
+                <td>{expense.category}</td>
+                <td>£{parseFloat(expense.amount).toFixed(2)}</td>
+                <td>{expense.description}</td>
+                <td>{expense.recurring ? "Yes" : "No"}</td>
+                <td>
+                  <button onClick={() => handleEdit(expense)} className="edit-expense-btn">Edit</button>
+                  <button onClick={() => handleDelete(expense.id)}>Delete</button>
+                </td>
+              </tr>
+            ))
+          ) : (
+            <tr>
+              <td colSpan="6" style={{ textAlign: "center" }}>
+                No expenses found.
+              </td>
+            </tr>
+          )}
+        </tbody>
+      </table>
+
+
+      {/* Pagination Component */}
+      {filteredExpenses.length > 0 && (
+        <ReactPaginate
+          previousLabel={"<< Previous"}
+          nextLabel={"Next >>"}
+          breakLabel={"..."}
+          pageCount={Math.max(1, Math.ceil(filteredExpenses.length / expensesPerPage))}
+          marginPagesDisplayed={2}
+          pageRangeDisplayed={5}
+          onPageChange={handlePageClick}
+          containerClassName={"pagination"}
+          activeClassName={"active"}
+        />
+      )}
+
+      {/* Expenses Summary Section */}
+      <div className="expenses-summary">
+        <h2>Expenses Summary</h2>
+        <p>
+          Here’s a breakdown of your spending by category. The charts below visualise how your expenses are distributed
+          across different categories. This summary helps you get a quick overview of where your money is going.
+        </p>
+        <p>
+          Take note of categories where you spend the most, and consider adjusting your budget or habits to ensure
+          you're staying on track with your financial goals.
+        </p>
+      </div>
+
+      {/* Spending Distribution Section */}
+      <div className="spending-distribution">
+        <h3>Spending Distribution</h3>
+        <p>
+          This chart displays the distribution of your spending across various categories. Depending on the selected
+          chart type, you can view this data in different ways.
+        </p>
+
+        {/* Chart Type Selector for Bar/Pie Chart */}
+        <div className="chart-type-selector">
+          <label htmlFor="chartType">Select Chart Type: </label>
+          <select id="chartType" value={chartType} onChange={handleChartChange}>
+            <option value="bar">Bar Chart</option>
+            <option value="pie">Pie Chart</option>
+          </select>
+        </div>
+
+        {/* Render the selected Bar or Pie chart */}
+        <div className="chart-item">
+          <ExpenseChart type={chartType} expenses={expenses} />
+        </div>
+      </div>
+
+      {/* Monthly Spending Trend Section */}
+      <div className="spending-trend">
+        <h3>Spending Trend</h3>
+          <p>
+            This section provides a detailed view of your spending trends over different time periods—daily, weekly,
+            monthly, or yearly. By visualizing your expenses across various categories over these time ranges, you 
+            can easily identify patterns, fluctuations, and long-term trends in your spending habits. This insight 
+            allows you to make informed financial decisions, helping you better manage your budget and track changes
+            in your spending behavior over time.
+          </p>
+
+        {/* Time Range Selector for the Line Chart */}
+        <div className="time-range-selector">
+          <label htmlFor="timeRange">Select Time Range: </label>
+          <select id="timeRange" value={timeRange} onChange={handleTimeRangeChange}>
+            <option value="daily">Days</option>
+            <option value="weekly">Weeks</option>
+            <option value="monthly">Months</option>
+            <option value="yearly">Years</option>
+          </select>
+        </div>
+
+        {/* Render the Line Chart with the selected Time Range */}
+        <div className="chart-item">
+          <ExpenseChart expenses={expenses} type="line" timeRange={timeRange} />
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default Expenses;
diff --git a/financial-tracker/frontend/src/styles/ExpenseChart.css b/financial-tracker/frontend/src/styles/ExpenseChart.css
new file mode 100644
index 0000000000000000000000000000000000000000..a9934e8aa14a695981b35120ba9da1a0216d8e92
--- /dev/null
+++ b/financial-tracker/frontend/src/styles/ExpenseChart.css
@@ -0,0 +1,73 @@
+.charts-container {
+  display: flex;
+  gap: 20px;
+  justify-content: center;
+  margin-top: 20px;
+}
+
+.chart-item {
+  flex: 1;
+  max-width: 100%;
+}
+
+.chart canvas {
+  width: 100% !important;
+  height: 100% !important;
+  min-height: 350px !important;
+}
+
+.expense-chart-container {
+  margin: 20px;
+}
+
+.chart-section {
+  margin-bottom: 30px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  height: auto;
+  min-height: 450px;
+}
+
+.chart-section .text-container {
+  width: 100%; 
+  max-width: 800px; 
+  text-align: left;
+}
+
+.chart-section h4 {
+  margin-top: 15px;
+  font-size: 1.2em;
+  font-weight: bold;
+  text-align: center;
+}
+
+.chart-section p {
+  font-size: 1em;
+  margin-top: 10px;
+  line-height: 1.5;
+  text-align: center !important;
+}
+
+.chart {
+  margin-top: 20px;
+  height: 400px !important;
+  min-height: 400px;
+  max-height: 500px;
+  position: relative; 
+}
+
+.line-chart-container {
+  margin-top: 30px;
+  padding: 15px;
+  background-color: #f1f1f1;
+  border-radius: 10px;
+  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+}
+
+.line-chart-container h3 {
+  font-size: 1.5rem;
+  margin-bottom: 15px;
+  color: #333;
+}
diff --git a/financial-tracker/frontend/src/styles/Expenses.css b/financial-tracker/frontend/src/styles/Expenses.css
new file mode 100644
index 0000000000000000000000000000000000000000..38c3192b01a4b2da9f8ea1bbd2a733284cf7f5e3
--- /dev/null
+++ b/financial-tracker/frontend/src/styles/Expenses.css
@@ -0,0 +1,612 @@
+/* Main Container */
+.expenses-container {
+  width: 80%;
+  margin: auto;
+}
+
+
+/* Expense font */
+h1 {
+  font-size: 2.5em;
+  text-align: center;
+}
+
+.expenses-summary h2 {
+  font-size: 2em;
+  margin-top: 15px;
+  font-weight: bold;
+  text-align: center;
+}
+
+.spending-distribution h3,
+.spending-trend h3 {
+  font-size: 1.5em;
+  margin-top: 15px;
+  font-weight: bold;
+  text-align: left;
+}
+
+.expenses-summary p {
+  font-size: 1.3em;
+  margin-top: 10px;
+  line-height: 1.5;
+  text-align: justify;
+}
+
+.spending-distribution p,
+.spending-trend p {
+  font-size: 1.1em;
+  margin-top: 10px;
+  line-height: 1.5;
+  text-align: justify;
+}
+
+/* Modal Overlay */
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 999;
+  opacity: 0;
+  pointer-events: none; 
+  transition: opacity 0.3s ease;
+}
+
+.modal-overlay.show {
+  opacity: 1;
+  pointer-events: auto; 
+}
+
+
+/* Modal Content */
+.modal-content {
+  background-color: #fff;
+  padding: 20px;
+  border-radius: 10px;
+  width: 500px;
+  max-width: 90%;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  text-align: center;
+}
+
+.modal-content .input-group label {
+  font-weight: bold;
+}
+
+.modal-content .expense-row {
+  align-items: flex-start;
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  gap: 15px;
+  width: 100%;
+}
+
+.modal-content .expense-row .input-group {
+  box-sizing: border-box;
+  flex: 1 1 calc(50% - 15px);
+  min-width: 200px;
+  max-width: 250px;
+  box-sizing: border-box;
+}
+
+.modal-content .input-group input,
+.modal-content .input-group select {
+  width: 80%; 
+  padding: 8px;
+  border: 1px solid #ccc;
+  border-radius: 5px;
+  max-width: 250px;
+}
+
+.modal-content .custom-recurring label,
+.modal-content .recurring-left label,
+.modal-content .recurring-right label {
+  margin-top: 10px;
+  font-weight: bold;
+}
+
+.modal-content .recurring-options {
+  display: flex;
+  justify-content: space-between;
+  gap: 20px;
+  margin-top: 20px;
+  width: 100%
+}
+  
+
+.modal-content .recurring-left,
+.modal-content .recurring-right {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  flex: 1;
+}
+
+.modal-content .input-group {
+  margin-bottom: 15px;
+}
+
+.modal-content .custom-recurring {
+  margin-top: 10px;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.modal-content .custom-recurring input,
+.modal-content .custom-recurring select {
+  width: 100%;
+}
+
+
+/* Expense Form */
+.expense-form {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 20px;
+  padding: 20px;
+  border-radius: 10px;
+  background-color: #f9f9f9;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+.expense-inputs {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  gap: 10px;
+}
+
+.input-group {
+  flex: 1; 
+  min-width: calc(50% - 5px);
+}
+
+.expense-inputs input,
+.expense-inputs select {
+  padding: 8px;
+  font-size: 14px;
+  border: 1px solid #ccc;
+  border-radius: 5px;
+  width: calc(50% - 5px);
+  box-sizing: border-box;
+}
+
+.expense-inputs input[type="checkbox"] {
+  width: auto;
+}
+
+.expense-row {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+  width: 100%;
+}
+
+.expense-row .input-group {
+  flex: 1;
+  min-width: calc(50% - 5px);
+}
+
+.expense-inputs label {
+  font-weight: bold;
+}
+
+.checkbox-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+}
+
+.checkbox-label {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 14px;
+  font-weight: bold;
+  gap: 5px;
+}
+/* Recurring Options */
+.recurring-options {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 20px;
+  width: 100%;
+  max-width: 600px;
+  background-color: #f8f8f8;
+  padding: 15px;
+  border-radius: 5px;
+  border: 1px solid #ccc;
+}
+
+.recurring-options label {
+  display: block;
+  font-size: 14px;
+  font-weight: bold;
+  margin-bottom: 5px;
+}
+
+.recurring-left,
+.recurring-right {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.recurring-options select,
+.recurring-options input {
+  width: 100%;
+  padding: 8px;
+  font-size: 14px;
+  border: 1px solid #ccc;
+  border-radius: 5px;
+  background-color: #fff;
+  box-sizing: border-box;
+}
+
+.recurring-options input[type="date"],
+.recurring-options input[type="number"] {
+  appearance: none;
+  width: 100%; 
+}
+
+
+/* Custom Recurrence */
+.custom-recurring {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+/* End Repeat Section */
+.end-repeat {
+  margin-top: 10px;
+}
+
+/* Add / Submit Button */
+.add-expense-btn {
+  padding: 10px 15px;
+  font-size: 14px;
+  background-color: #007bff;
+  color: white;
+  border: none;
+  border-radius: 5px;
+  cursor: pointer;
+  margin-top: 20px;
+}
+
+.add-expense-btn:hover {
+  background-color: #0056b3;
+}
+
+/* Close Button */
+.close-modal-btn {
+  padding: 10px 15px;
+  font-size: 14px;
+  background-color: #dc3545;
+  color: white;
+  border: none;
+  border-radius: 5px;
+  cursor: pointer;
+  margin-top: 10px;
+}
+
+.close-modal-btn:hover {
+  background-color: #c82333;
+}
+
+/* Expenses Table */
+.expenses-table {
+  width: 100%;
+  max-width: 800px;
+  margin: auto;
+  border-collapse: collapse;
+  margin-top: 20px;
+}
+
+th.sortable {
+  cursor: pointer;
+}
+
+.expenses-table th,
+.expenses-table td {
+  border: 1px solid #ddd;
+  padding: 10px;
+  text-align: center;
+}
+
+.expenses-table th {
+  background-color: #f4f4f4;
+}
+
+.expenses-table tr:nth-child(even) {
+  background-color: #f9f9f9;
+}
+
+.expenses-table tr:hover {
+  background-color: #f1f1f1;
+}
+
+/* Action Buttons */
+.expenses-table button {
+  padding: 5px 10px;
+  font-size: 12px;
+  border: none;
+  cursor: pointer;
+  margin: 2px;
+  border-radius: 3px;
+}
+
+.expenses-table button:first-child {
+  background-color: #ffc107;
+  color: black;
+}
+
+.expenses-table button:last-child {
+  background-color: #dc3545;
+  color: white;
+}
+
+/* Filter Dropdown */
+.filter-dropdown {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  gap: 20px;
+  align-items: flex-start;
+  margin-top: 20px;
+  max-width: 600px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+/* Each column */
+.filter-column {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  flex: 1;
+  min-width: 180px; 
+}
+
+/* Input and select styling */
+.filter-column label {
+  font-size: 14px;
+  font-weight: bold;
+  margin-bottom: 5px;
+}
+
+.filter-column select,
+.filter-column input {
+  width: 100%;
+  padding: 8px;
+  font-size: 14px;
+  border: 1px solid #ccc;
+  border-radius: 5px;
+  box-sizing: border-box;
+  background-color: #f8f8f8;
+}
+
+.filter-column select {
+  cursor: pointer;
+}
+
+/* Apply Filters Button */
+.apply-filters-container {
+  width: 100%;
+  display: flex;
+  justify-content: center;
+}
+
+/* Apply Filters Button */
+.apply-filters-btn {
+  width: 100%;
+  max-width: 600px; 
+  padding: 12px 20px;
+  background-color: #28a745;
+  color: white;
+  border: none;
+  border-radius: 5px;
+  cursor: pointer;
+  font-size: 14px;
+  margin-top: 15px;
+  transition: background-color 0.3s;
+}
+
+.apply-filters-btn:hover {
+  background-color: #218838;
+}
+
+/* Responsive: Stack on small screens */
+@media (max-width: 600px) {
+  .expense-inputs {
+    flex-direction: column;
+    width: 100%;
+  }
+
+  .expense-inputs input,
+  .expense-inputs select {
+    width: 100%;
+  }
+
+  .expenses-table {
+    font-size: 12px;
+  }
+
+  .expenses-table th,
+  .expenses-table td {
+    padding: 8px;
+  }
+
+  .filter-dropdown {
+    flex-direction: column;
+    align-items: center;
+  }
+
+  .filter-column {
+    width: 100%;
+  }
+
+  .expense-inputs {
+    grid-template-columns: 1fr;
+  }
+
+  .recurring-options {
+    grid-template-columns: 1fr;
+  }
+
+  .chart-type-selector,
+  .time-range-selector {
+    flex-direction: column;
+    align-items: flex-start;
+  }
+
+  .chart-type-selector select,
+  .time-range-selector select {
+    width: 100%;
+  }
+}
+
+.delete-message {
+  padding: 10px;
+  margin-top: 10px;
+  background-color: #f44336;
+  color: white;
+  border-radius: 5px;
+  text-align: center;
+}
+
+.success-message {
+  padding: 10px;
+  margin-top: 10px;
+  background-color: #4CAF50;
+  color: white;
+  border-radius: 5px;
+  text-align: center;
+}
+
+/* Pagination */
+.pagination {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  list-style-type: none;
+  padding: 10px 0;
+  margin-top: 20px;
+}
+
+.pagination li {
+  margin: 0 10px;
+  cursor: pointer;
+  font-size: 14px;
+  padding: 8px 12px;
+  border-radius: 5px;
+  transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+.pagination li:hover {
+  background-color: #007bff;
+  color: white;
+}
+
+.pagination .active {
+  background-color: #007bff;
+  color: white;
+  font-weight: bold;
+  border-radius: 5px;
+  padding: 8px 12px;
+}
+
+.pagination li.disabled {
+  cursor: not-allowed;
+  opacity: 0.5;
+}
+
+.pagination .previous, .pagination .next {
+  font-weight: bold;
+}
+
+/* Adding styles for Previous and Next buttons */
+.pagination .previous,
+.pagination .next {
+  padding: 8px 12px;
+  background-color: #007bff;
+  color: white;
+  border-radius: 5px;
+  font-size: 14px;
+  cursor: pointer;
+  transition: background-color 0.3s ease;
+}
+
+.pagination .previous:hover,
+.pagination .next:hover {
+  background-color: #0056b3;
+}
+
+
+/* Chart Type Selector */
+.chart-type-selector {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-top: 20px;
+  margin-bottom: 20px;
+  font-size: 16px;
+}
+
+.chart-type-selector label {
+  font-weight: bold;
+}
+
+.chart-type-selector select {
+  padding: 8px;
+  font-size: 14px;
+  border: 1px solid #ccc;
+  border-radius: 5px;
+  background-color: #f8f8f8;
+  cursor: pointer;
+  transition: border-color 0.3s;
+}
+
+.chart-type-selector select:focus {
+  border-color: #007bff;
+  outline: none;
+}
+
+/* Time Range Selector */
+.time-range-selector {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 20px;
+  font-size: 16px;
+}
+
+.time-range-selector label {
+  font-weight: bold;
+}
+
+.time-range-selector select {
+  padding: 8px;
+  font-size: 14px;
+  border: 1px solid #ccc;
+  border-radius: 5px;
+  background-color: #f8f8f8;
+  cursor: pointer;
+  transition: border-color 0.3s;
+}
+
+.time-range-selector select:focus {
+  border-color: #007bff;
+  outline: none;
+}
diff --git a/financial-tracker/transaction-service/app/app.py b/financial-tracker/transaction-service/app/app.py
index 8b37a7fc7a61b0eae0d7d86f3572e3091df78653..bb654fe16c940a660e8f77b057f9d882596fa774 100644
--- a/financial-tracker/transaction-service/app/app.py
+++ b/financial-tracker/transaction-service/app/app.py
@@ -1,10 +1,502 @@
-from flask import Flask, jsonify, request
+from datetime import datetime, timedelta
+from flask import Flask, request, jsonify
+from flask_cors import CORS
+from flask_jwt_extended import (
+    jwt_required, get_jwt_identity, JWTManager
+)
+from flask_sqlalchemy import SQLAlchemy
+from sqlalchemy import Enum
+import enum
+import logging
+import os
 
+# Initialise Flask app
 app = Flask(__name__)
+app.debug = True
+CORS(app)
+
+# Configure logging
+logging.basicConfig(level=logging.INFO)
+app.logger.setLevel(logging.INFO)
+
+# Configuration
+app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv(
+    "DATABASE_URL", "postgresql://user:password@transaction-db:5432/transaction_db"
+)
+app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
+app.config["JWT_SECRET_KEY"] = os.getenv(
+    "JWT_SECRET_KEY", "3b5e41af18179f530c5881a5191e15f0ab35eed2fefdc068fda254eed3fb1ecb"
+)
+app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=1)
+app.config["JWT_TOKEN_LOCATION"] = ["headers"]
+app.config["JWT_HEADER_NAME"] = "Authorization"  # Default header for JWT
+app.config["JWT_HEADER_TYPE"] = "Bearer" 
+
+# Initialise Flask-JWT-Extended & SQLAlchemy
+jwt = JWTManager(app)
+db = SQLAlchemy(app)
+
+
+# Define Enums for Expense model
+class CurrencyEnum(enum.Enum):
+    USD = "USD"
+    EUR = "EUR"
+    GBP = "GBP"
+    JPY = "JPY"
+    AUD = "AUD"
+    CAD = "CAD"
+    CHF = "CHF"
+    CNY = "CNY"
+    INR = "INR"
+    NZD = "NZD"
+    MXN = "MXN"
+    SGD = "SGD"
+    HKD = "HKD"
+    SEK = "SEK"
+    NOK = "NOK"
+    DKK = "DKK"
+    KRW = "KRW"
+    BRL = "BRL"
+    BWP = "BWP"
+    BDT = "BDT"
+    BGN = "BGN"
+    BHD = "BHD"
+    BIF = "BIF"
+    BOB = "BOB"
+    CVE = "CVE"
+    CZK = "CZK"
+    DOP = "DOP"
+    EGP = "EGP"
+    ETB = "ETB"
+    FJD = "FJD"
+    GHS = "GHS"
+    GIP = "GIP"
+    GMD = "GMD"
+    GNF = "GNF"
+    GTQ = "GTQ"
+    HUF = "HUF"
+    IDR = "IDR"
+    ISK = "ISK"
+    JOD = "JOD"
+    KES = "KES"
+    KWD = "KWD"
+    LAK = "LAK"
+    LKR = "LKR"
+    MAD = "MAD"
+    MGA = "MGA"
+    MWK = "MWK"
+    MYR = "MYR"
+    MZN = "MZN"
+    NGN = "NGN"
+    NPR = "NPR"
+    OMR = "OMR"
+    PEN = "PEN"
+    PHP = "PHP"
+    PKR = "PKR"
+    PLN = "PLN"
+    PYG = "PYG"
+    QAR = "QAR"
+    RON = "RON"
+    RWF = "RWF"
+    SAR = "SAR"
+    SLE = "SLE"
+    SRD = "SRD"
+    THB = "THB"
+    TND = "TND"
+    TRY = "TRY"
+    TWD = "TWD"
+    TZS = "TZS"
+    UGX = "UGX"
+    VND = "VND"
+    XAF = "XAF"
+    XCD = "XCD"
+    XOF = "XOF"
+    ZAR = "ZAR"
+    ZMW = "ZMW"
+
+class RecurringTypeEnum(enum.Enum):
+    DAILY = "daily"
+    WEEKLY = "weekly"
+    FORTNIGHTLY = "every_two_weeks"
+    MONTHLY = "monthly"
+    YEARLY = "yearly"
+    CUSTOM = "custom"
+
+class FrequencyEnum(enum.Enum):
+    DAILY = "daily"
+    WEEKLY = "weekly"
+    MONTHLY = "monthly"
+    YEARLY = "yearly"
+
+class EndRepeatEnum(enum.Enum):
+    NEVER = "never"
+    ON_DATE = "on_date"
+
+
+# DATABASE MODELS
+class Expense(db.Model):
+    id = db.Column(db.Integer, primary_key=True)
+    user_id = db.Column(db.Integer, nullable=False)  
+    amount = db.Column(db.Float, nullable=False)
+    currency = db.Column(db.Enum(CurrencyEnum), nullable=False)
+    category = db.Column(db.String(50), nullable=False)
+    date = db.Column(db.Date, nullable=False)
+    description = db.Column(db.String(255))
+
+    # Recurring fields
+    recurring = db.Column(db.Boolean, nullable=False, default=False)
+    recurring_type = db.Column(db.Enum(RecurringTypeEnum), nullable=True)  
+    frequency = db.Column(db.Enum(FrequencyEnum), nullable=True) 
+    interval = db.Column(db.Integer, nullable=True)
+    end_repeat = db.Column(db.Enum(EndRepeatEnum), nullable=True)
+    end_date = db.Column(db.Date, nullable=True) 
+
+    def to_dict(self):
+        """Convert object to dictionary for JSON response"""
+        return {
+            "id": self.id,
+            "user_id": self.user_id,
+            "amount": self.amount,
+            "currency": self.currency.value,  # Convert Enum to its string value
+            "category": self.category,
+            "date": self.date.strftime('%Y-%m-%d'),
+            "description": self.description,
+            "recurring": self.recurring,
+            "recurring_type": self.recurring_type.value if self.recurring_type else None,
+            "interval": self.interval,
+            "end_repeat": self.end_repeat.value if self.end_repeat else None,
+            "end_date": self.end_date.strftime('%Y-%m-%d') if self.end_date else None
+        }
+
 
 @app.route('/transactions', methods=['GET'])
 def get_transactions():
     return jsonify({"message": "Transaction service active"}), 200
 
-if __name__ == '__main__':
-    app.run(host='0.0.0.0', port=5002)
+
+# EXPENSES ROUTES
+@app.route('/expenses', methods=['POST'])
+@jwt_required()
+def add_expense():
+    """Add a new expense for the logged-in user"""
+    data = request.get_json()
+    app.logger.info(f"Received data: {data}")  
+
+    # Default currency to GBP if not provided
+    currency = data.get('currency', 'GBP')
+
+    # Required fields check
+    required_fields = ["amount", "currency", "category", "date", "description", "recurring"]
+    missing_fields = [field for field in required_fields if field not in data]
+
+    if missing_fields:
+        app.logger.error(f"Missing required fields: {missing_fields}")
+        return jsonify({"error": f"Missing required fields: {', '.join(missing_fields)}"}), 400
+
+    # Validate currency code (must be a 3-letter code)
+    if len(currency) != 3:
+        app.logger.error(f"Invalid currency code: {currency}")
+        return jsonify({"error": "Invalid currency code"}), 400
+
+    try:
+        user_id = get_jwt_identity()
+        user_id = int(user_id)
+        app.logger.info(f"User ID: {user_id}")
+
+        if not user_id:
+            app.logger.error("User ID is missing or invalid.")
+            return jsonify({"error": "User authentication failed"}), 401
+
+        # Validate date format and ensure it is not in the future
+        try:
+            expense_date = datetime.strptime(data["date"], '%Y-%m-%d').date()
+            if expense_date > datetime.today().date():
+                app.logger.error(f"Invalid date: {expense_date}. Future expenses are not allowed.")
+                return jsonify({"error": "Expense date cannot be in the future"}), 400
+        except ValueError:
+            app.logger.error(f"Invalid date format: {data['date']}")
+            return jsonify({"error": "Invalid date format. Use YYYY-MM-DD"}), 400
+
+        # Parse recurring fields if applicable
+        recurring = data["recurring"]
+        recurring_type = data.get("recurring_type")
+        frequency = data.get("frequency") if recurring_type == "custom" else None
+        interval = data.get("interval") if recurring_type == "custom" else None
+        end_repeat = data.get("end_repeat")
+        end_date = data.get("end_date")
+
+        # Convert end_date to a Date object if provided
+        if end_date:
+            try:
+                end_date = datetime.strptime(end_date, '%Y-%m-%d').date()
+                if end_date < expense_date:
+                    app.logger.error("End date cannot be before the expense date.")
+                    return jsonify({"error": "End date must be after the expense date"}), 400
+            except ValueError:
+                app.logger.error(f"Invalid end_date format: {end_date}")
+                return jsonify({"error": "Invalid end_date format. Use YYYY-MM-DD"}), 400
+
+        # Custom recurrence validation
+        if recurring and recurring_type == "custom":
+            if not frequency or not interval:
+                app.logger.error("Custom recurrence requires frequency and interval.")
+                return jsonify({"error": "Custom recurrence requires frequency and interval"}), 400
+            if interval <= 0:
+                app.logger.error("Interval must be greater than 0.")
+                return jsonify({"error": "Interval must be a positive number"}), 400
+
+        # Create a new expense object
+        new_expense = Expense(
+            user_id=user_id,
+            amount=data["amount"],
+            currency=currency,
+            category=data["category"],
+            date=expense_date,
+            description=data["description"],
+            recurring=recurring,
+            recurring_type=RecurringTypeEnum(recurring_type) if recurring_type else None,
+            frequency=FrequencyEnum(frequency) if frequency else None,
+            interval=interval,
+            end_repeat=EndRepeatEnum(end_repeat) if end_repeat else None,
+            end_date=end_date
+        )
+
+        # Add expense to the database
+        db.session.add(new_expense)
+        db.session.commit()
+
+        app.logger.info(f"Expense added: {new_expense.to_dict()}")
+        return jsonify({"message": "Expense added", "expense": new_expense.to_dict()}), 201
+
+    except ValueError as ve:
+        app.logger.error(f"Value error: {str(ve)}")
+        return jsonify({"error": "Invalid value provided"}), 400
+
+    except Exception as e:
+        app.logger.error(f"Error while adding expense: {str(e)}", exc_info=True)
+        return jsonify({"error": "An error occurred while adding the expense"}), 500
+
+
+
+@app.route('/expenses', methods=['GET'])
+@jwt_required()
+def get_expenses():
+    """Retrieve all expenses for the logged-in user"""
+    try:
+        user_id = get_jwt_identity()  # Extract user_id from JWT token
+        user_id = int(user_id)
+        app.logger.info(f"Retrieved user_id from JWT: {user_id}")  # Log user_id
+
+        if not user_id:
+            app.logger.error("User ID is None or invalid.")
+            return jsonify({"error": "Invalid user authentication"}), 401
+
+        expenses = Expense.query.filter_by(user_id=user_id).all()
+        app.logger.info(f"Found {len(expenses)} expenses for user_id {user_id}")
+
+        expenses_list = [expense.to_dict() for expense in expenses]
+        return jsonify({"expenses": expenses_list}), 200
+    except Exception as e:
+        app.logger.error(f"Error retrieving expenses: {e}", exc_info=True)
+        return jsonify({"error": "An error occurred while fetching expenses"}), 500
+    
+
+@app.route('/expenses/<int:expense_id>', methods=['PUT'])
+@jwt_required()
+def edit_expense(expense_id):
+    """Edit an expense by ID for the logged-in user"""
+    try:
+        user_id = get_jwt_identity()
+        user_id = int(user_id)
+        app.logger.info(f"User ID: {user_id}")
+
+        if not user_id:
+            app.logger.error("User ID is missing or invalid.")
+            return jsonify({"error": "User authentication failed"}), 401
+
+        expense = Expense.query.filter_by(id=expense_id, user_id=user_id).first()
+
+        if not expense:
+            app.logger.error(f"Expense not found for ID {expense_id} and User ID {user_id}")
+            return jsonify({"error": "Expense not found"}), 404
+
+        data = request.json
+
+        app.logger.info(f"Received data: {data}") 
+        # Validate date if it is being updated
+        if "date" in data:
+            try:
+                new_date = datetime.strptime(data["date"], '%Y-%m-%d').date()
+                if new_date > datetime.today().date():
+                    app.logger.error(f"Invalid date: {new_date}. Future expenses are not allowed.")
+                    return jsonify({"error": "Expense date cannot be in the future"}), 400
+                expense.date = new_date
+            except ValueError:
+                app.logger.error(f"Invalid date format: {data['date']}")
+                return jsonify({"error": "Invalid date format. Use YYYY-MM-DD"}), 400
+
+        # Validate end_date if updated
+        if "end_date" in data:
+            try:
+                new_end_date = datetime.strptime(data["end_date"], '%Y-%m-%d').date()
+                if new_end_date < expense.date:
+                    app.logger.error("End date cannot be before the expense date.")
+                    return jsonify({"error": "End date must be after the expense date"}), 400
+                expense.end_date = new_end_date
+            except ValueError:
+                app.logger.error(f"Invalid end_date format: {data['end_date']}")
+                return jsonify({"error": "Invalid end_date format. Use YYYY-MM-DD"}), 400
+
+        # Validate custom recurrence fields
+        if expense.recurring and expense.recurring_type == RecurringTypeEnum.CUSTOM:
+            if "interval" in data:
+                try:
+                    interval_value = int(data["interval"])  # Convert to integer
+                    if interval_value <= 0:
+                        app.logger.error("Interval must be greater than 0.")
+                        return jsonify({"error": "Interval must be a positive number"}), 400
+                    expense.interval = interval_value  # Assign as an integer
+                except ValueError:
+                    app.logger.error("Interval must be a valid integer.")
+                    return jsonify({"error": "Interval must be a valid integer"}), 400
+
+         # Setting the recurring type enum
+        if expense.recurring:
+            recurring_type = data.get("recurring_type", None)
+            if recurring_type:
+                if recurring_type.lower() == 'daily':
+                    expense.recurring_type = RecurringTypeEnum.DAILY
+                elif recurring_type.lower() == 'weekly':
+                    expense.recurring_type = RecurringTypeEnum.WEEKLY
+                elif recurring_type.lower() == "every_two_weeks":
+                    expense.recurring_type = RecurringTypeEnum.FORTNIGHTLY
+                elif recurring_type.lower() == 'monthly':
+                    expense.recurring_type = RecurringTypeEnum.MONTHLY
+                elif recurring_type.lower() == 'yearly':
+                    expense.recurring_type = RecurringTypeEnum.YEARLY
+                elif recurring_type.lower() == 'custom':
+                    expense.recurring_type = RecurringTypeEnum.CUSTOM
+            else:
+                app.logger.error(f"Invalid recurring type: {recurring_type}")
+                return jsonify({"error": "Invalid recurring type"}), 400
+
+        # Setting the frequency enum
+        if expense.recurring and expense.recurring_type == RecurringTypeEnum.CUSTOM:
+            frequency = data.get("frequency", None)
+            if frequency:
+                if frequency.lower() == 'daily':
+                    expense.frequency = FrequencyEnum.DAILY
+                elif frequency.lower() == 'weekly':
+                    expense.frequency = FrequencyEnum.WEEKLY
+                elif frequency.lower() == 'monthly':
+                    expense.frequency = FrequencyEnum.MONTHLY
+                elif frequency.lower() == 'yearly':
+                    expense.frequency = FrequencyEnum.YEARLY
+            else:
+                app.logger.error(f"Invalid frequency: {frequency}")
+                return jsonify({"error": "Invalid frequency"}), 400
+        
+        # Setting the end_repeat enum
+        if expense.recurring:
+            end_repeat = data.get("end_repeat", None)
+            if end_repeat:
+                if end_repeat.lower() == 'never':
+                    expense.end_repeat = EndRepeatEnum.NEVER
+                    expense.end_date = None
+                elif end_repeat.lower() == 'on_date':
+                    expense.end_repeat = EndRepeatEnum.ON_DATE
+                else:
+                    app.logger.error(f"Invalid end_repeat value: {end_repeat}")
+                    return jsonify({"error": "Invalid end_repeat value"}), 400
+            else:
+                app.logger.error("end_repeat is missing")
+                return jsonify({"error": "end_repeat is required"}), 400
+
+        # Update other fields
+        expense.category = data.get("category", expense.category)
+        expense.amount = data.get("amount", expense.amount)
+        expense.description = data.get("description", expense.description)
+
+        db.session.commit()
+
+        app.logger.info(f"Expense updated: {expense.to_dict()}")
+        return jsonify({"message": "Expense updated successfully", "expense": expense.to_dict()}), 200
+
+    except Exception as e:
+        app.logger.error(f"Error updating expense: {str(e)}", exc_info=True)
+        return jsonify({"error": "An error occurred while updating the expense"}), 500
+
+
+
+@app.route('/expenses/<int:expense_id>', methods=['DELETE'])
+@jwt_required()
+def delete_expense(expense_id):
+    """Delete an expense by ID for the logged-in user"""
+    try:
+        # Get user_id from JWT token
+        user_id = get_jwt_identity()
+        user_id = int(user_id)
+        app.logger.info(f"User ID: {user_id}")
+
+        if not user_id:
+            app.logger.error("User ID is missing or invalid.")
+            return jsonify({"error": "User authentication failed"}), 401
+
+        # Fetch the expense from the database
+        expense = Expense.query.filter_by(id=expense_id, user_id=user_id).first()
+
+        if not expense:
+            app.logger.error(f"Expense not found for ID {expense_id} and User ID {user_id}")
+            return jsonify({"error": "Expense not found"}), 404
+
+        # Delete the expense from the database
+        db.session.delete(expense)
+        db.session.commit()
+
+        app.logger.info(f"Expense deleted: {expense.to_dict()}")
+        return jsonify({"message": "Expense deleted successfully"}), 200
+
+    except Exception as e:
+        app.logger.error(f"Error deleting expense: {str(e)}", exc_info=True)
+        return jsonify({"error": "An error occurred while deleting the expense"}), 500
+
+
+@app.route('/categories', methods=['GET'])
+@jwt_required()
+def get_categories():
+    """Retrieve distinct categories for the logged-in user"""
+    try:
+        user_id = get_jwt_identity()  # Extract user_id from JWT token
+        user_id = int(user_id)
+        app.logger.info(f"Retrieved user_id from JWT: {user_id}")  # Log user_id
+
+        if not user_id:
+            app.logger.error("User ID is None or invalid.")
+            return jsonify({"error": "Invalid user authentication"}), 401
+
+        categories = db.session.query(Expense.category).filter_by(user_id=user_id).distinct().all()
+        category_list = [category[0] for category in categories]
+        app.logger.info(f"Category list: {category_list}")
+
+        return jsonify({"categories": category_list}), 200
+    except Exception as e:
+        app.logger.error(f"Error retrieving categories: {e}", exc_info=True)
+        return jsonify({"error": "An error occurred while fetching categories"}), 500
+
+
+# HEALTH CHECK ROUTE
+@app.route('/health')
+def health():
+    """Health check endpoint to verify service is running."""
+    app.logger.info("Health check requested")
+    return jsonify({"status": "User service is running"}), 200
+
+
+# INITIALIZATION & RUNNING APP
+if __name__ == "__main__":
+    # Create all tables in the database (if they don't exist)
+    with app.app_context():
+        db.create_all()  # Creates the tables for all models
+
+    app.logger.info("Starting Transaction Service...")
+    app.run(host='0.0.0.0', port=5002, debug=True)