diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..7148b367d2da835dedfe208b5aec5590b27bc048
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,66 @@
+FROM python:3.11.4
+
+#Copy requirements
+COPY requirements.txt /user_ms/
+
+COPY app /user_ms/
+
+#Set working direcroty
+WORKDIR /user_ms
+
+#Install dependencies
+RUN pip install --no-cache-dir -r requirements.txt
+
+
+#Install other libraries in container
+RUN apt-get update && apt-get install -y \
+    unixodbc \
+    unixodbc-dev \
+	iputils-ping\
+	apt-transport-https \
+	gcc\
+    curl \
+    gnupg \
+    freetds-dev \
+    tdsodbc \
+    && rm -rf /var/lib/apt/lists/*
+
+
+#Install ODBC Driver for Microsoft SQL Server Section...
+#Source: https://learn.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver16&tabs=debian18-install%2Calpine17-install%2Cdebian8-install%2Credhat7-13-install%2Crhel7-offline
+
+
+#Add Microsoft repository GPG key
+RUN curl https://packages.microsoft.com/keys/microsoft.asc | tee /etc/apt/trusted.gpg.d/microsoft.asc
+
+#Add the Microsoft SQL Server repository for Debian 12
+RUN curl https://packages.microsoft.com/config/debian/12/prod.list | tee /etc/apt/sources.list.d/mssql-release.list
+
+
+#Add Microsoft GPG key
+RUN curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft-archive-keyring.gpg
+
+#Add the Microsoft SQL Server repository for Debian 12
+RUN echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/debian/12/prod bookworm main" > /etc/apt/sources.list.d/mssql-release.list
+
+#Update package list
+RUN apt-get update
+
+#Install ODBC Driver 17 for SQL Server
+RUN ACCEPT_EULA=Y apt-get install -y msodbcsql17
+
+#Install mssql-tools
+RUN ACCEPT_EULA=Y apt-get install -y mssql-tools
+RUN bash -c "echo 'export PATH=\"$PATH:/opt/mssql-tools/bin\"' >> ~/.bashrc && source ~/.bashrc"
+
+
+#RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc && source ~/.bashrc
+
+#Install unixodbc-dev and kerberos library
+RUN apt-get install -y libgssapi-krb5-2
+
+#Set environment variables for ODBC configuration
+ENV ODBCINI=/etc/odbc.ini
+ENV ODBCSYSINI=/etc
+
+CMD ["python", "index.py"]
\ No newline at end of file
diff --git a/Dockerfile.userdb b/Dockerfile.userdb
new file mode 100644
index 0000000000000000000000000000000000000000..c7d3ab70d82a45909512cf4bc2a09936ade8c4ad
--- /dev/null
+++ b/Dockerfile.userdb
@@ -0,0 +1,27 @@
+FROM mcr.microsoft.com/mssql/server:2022-latest
+
+# Set environment variables
+ENV SA_PASSWORD WebTechGroup3
+ENV ACCEPT_EULA=Y
+
+COPY User_Management.bak /var/opt/mssql/data/
+
+
+
+
+# Change user permissions
+USER root
+
+RUN chown -R mssql:mssql /var/opt/mssql/data
+
+COPY entrypoint.sh /usr/local/bin/entrypoint.sh
+
+
+# Expose the default SQL Server port
+EXPOSE 1433
+
+ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
+
+
+# Define the default command to run when the container starts
+CMD ["/opt/mssql/bin/sqlservr"]
\ No newline at end of file
diff --git a/Dockerfile.userms b/Dockerfile.userms
new file mode 100644
index 0000000000000000000000000000000000000000..3e73e5fab859fa6eaf160356db11b952ca22c20a
--- /dev/null
+++ b/Dockerfile.userms
@@ -0,0 +1,62 @@
+FROM python:3.11.4
+
+#Copy requirements
+COPY requirements.txt /user_ms/
+
+COPY app /user_ms/
+
+#Set working direcroty
+WORKDIR /user_ms
+
+#Install dependencies
+RUN pip install --no-cache-dir -r requirements.txt
+
+
+#Install other libraries in container
+RUN apt-get update && apt-get install -y \
+    unixodbc \
+    unixodbc-dev \
+	iputils-ping\
+	apt-transport-https \
+	gcc\
+    curl \
+    gnupg \
+    freetds-dev \
+    tdsodbc \
+    && rm -rf /var/lib/apt/lists/*
+
+
+#Add Microsoft repository GPG key
+RUN curl https://packages.microsoft.com/keys/microsoft.asc | tee /etc/apt/trusted.gpg.d/microsoft.asc
+
+#Add the Microsoft SQL Server repository for Debian 12
+RUN curl https://packages.microsoft.com/config/debian/12/prod.list | tee /etc/apt/sources.list.d/mssql-release.list
+
+
+#Add Microsoft GPG key
+RUN curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft-archive-keyring.gpg
+
+#Add the Microsoft SQL Server repository for Debian 12
+RUN echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/debian/12/prod bookworm main" > /etc/apt/sources.list.d/mssql-release.list
+
+#Update package list
+RUN apt-get update
+
+#Install ODBC Driver 17 for SQL Server
+RUN ACCEPT_EULA=Y apt-get install -y msodbcsql17
+
+#Optional: Install mssql-tools and add to PATH
+RUN ACCEPT_EULA=Y apt-get install -y mssql-tools
+RUN bash -c "echo 'export PATH=\"$PATH:/opt/mssql-tools/bin\"' >> ~/.bashrc && source ~/.bashrc"
+
+
+#RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc && source ~/.bashrc
+
+#Optional: Install unixodbc-dev and kerberos library
+RUN apt-get install -y libgssapi-krb5-2
+
+#Set environment variables for ODBC configuration if needed
+ENV ODBCINI=/etc/odbc.ini
+ENV ODBCSYSINI=/etc
+
+CMD ["python", "index.py"]
\ No newline at end of file
diff --git a/User_Management.bak b/User_Management.bak
new file mode 100644
index 0000000000000000000000000000000000000000..8286826a43c0de28f2cdc67078940fdafcfd9f9a
Binary files /dev/null and b/User_Management.bak differ
diff --git a/app.yaml b/app.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ab488dfb9077cfca361f84c8511c86b3ed935dbb
--- /dev/null
+++ b/app.yaml
@@ -0,0 +1,2 @@
+runtime: python312
+entrypoint: gunicorn -b :$PORT index:app
\ No newline at end of file
diff --git a/app/__init__.py b/app/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e5da06c31592e6410ec992cae27f65004ade98d6
--- /dev/null
+++ b/app/__init__.py
@@ -0,0 +1,10 @@
+from flask import Flask
+
+from app.models import login
+
+app = Flask(__name__)
+
+from app import routes
+
+if __name__ == '__main__':
+    app.run(debug=True)
\ No newline at end of file
diff --git a/app/__pycache__/config.cpython-311.pyc b/app/__pycache__/config.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..091813a29718206a89d166b99bce03396b05d34c
Binary files /dev/null and b/app/__pycache__/config.cpython-311.pyc differ
diff --git a/app/config.py b/app/config.py
new file mode 100644
index 0000000000000000000000000000000000000000..0405b913851c12c81c205bd6e66277fba2a0278a
--- /dev/null
+++ b/app/config.py
@@ -0,0 +1,11 @@
+import os
+
+
+DEBUG = True
+SECRET_KEY = "Group3"
+
+PORT = 5000
+
+KAFKA_SERVER = "kafka:9092"
+
+HOST = "0.0.0.0"
\ No newline at end of file
diff --git a/app/controllers/__init__.py b/app/controllers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..83fe4b03fbf1ea1097fdec730685170c3a35cc8d
--- /dev/null
+++ b/app/controllers/__init__.py
@@ -0,0 +1,3 @@
+from flask import Flask
+from flask import Blueprint
+
diff --git a/app/controllers/__pycache__/__init__.cpython-311.pyc b/app/controllers/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5a4bfd8103bb4380305718ed59e96e027557a8a4
Binary files /dev/null and b/app/controllers/__pycache__/__init__.cpython-311.pyc differ
diff --git a/app/controllers/__pycache__/changePasswordController.cpython-311.pyc b/app/controllers/__pycache__/changePasswordController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..34cc426ee500d1191ecb52b66c1c4517c902dad9
Binary files /dev/null and b/app/controllers/__pycache__/changePasswordController.cpython-311.pyc differ
diff --git a/app/controllers/__pycache__/deleteProfileController.cpython-311.pyc b/app/controllers/__pycache__/deleteProfileController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6ce448acfcb8142341af9ce1dbd5583428925b08
Binary files /dev/null and b/app/controllers/__pycache__/deleteProfileController.cpython-311.pyc differ
diff --git a/app/controllers/__pycache__/fetchUsernameController.cpython-311.pyc b/app/controllers/__pycache__/fetchUsernameController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4cbe6aa45038b2bd7bda92392953d3e3b023f3a3
Binary files /dev/null and b/app/controllers/__pycache__/fetchUsernameController.cpython-311.pyc differ
diff --git a/app/controllers/__pycache__/login.cpython-311.pyc b/app/controllers/__pycache__/login.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ee02eac64b23cc7222f821324eb85aa9d76b8dc0
Binary files /dev/null and b/app/controllers/__pycache__/login.cpython-311.pyc differ
diff --git a/app/controllers/__pycache__/loginController.cpython-311.pyc b/app/controllers/__pycache__/loginController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c0b17d9c4604c96ba994a28b64fd1eebc7061a71
Binary files /dev/null and b/app/controllers/__pycache__/loginController.cpython-311.pyc differ
diff --git a/app/controllers/__pycache__/logoutController.cpython-311.pyc b/app/controllers/__pycache__/logoutController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..63d12e36ae470889c341e2c26608db4c1b994b39
Binary files /dev/null and b/app/controllers/__pycache__/logoutController.cpython-311.pyc differ
diff --git a/app/controllers/__pycache__/showReviewsController.cpython-311.pyc b/app/controllers/__pycache__/showReviewsController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..51d9ad122d7784716c744cb4a8122c6254d70f40
Binary files /dev/null and b/app/controllers/__pycache__/showReviewsController.cpython-311.pyc differ
diff --git a/app/controllers/__pycache__/signupController.cpython-311.pyc b/app/controllers/__pycache__/signupController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..55cd6b76556ac83d7c5d814dc2a64f828492b907
Binary files /dev/null and b/app/controllers/__pycache__/signupController.cpython-311.pyc differ
diff --git a/app/controllers/__pycache__/updateProfileController.cpython-311.pyc b/app/controllers/__pycache__/updateProfileController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8b7bc1569e5e102cdf2927d1001d7ef46f330135
Binary files /dev/null and b/app/controllers/__pycache__/updateProfileController.cpython-311.pyc differ
diff --git a/app/controllers/changePasswordController.py b/app/controllers/changePasswordController.py
new file mode 100644
index 0000000000000000000000000000000000000000..5fbb96dbca89b737017962cde091c6c2b72d7499
--- /dev/null
+++ b/app/controllers/changePasswordController.py
@@ -0,0 +1,122 @@
+#This page allows users to change their password
+#
+#
+from flask import Blueprint, jsonify, request, session
+from models.changePassword import check_old_password, set_new_password
+import hashlib
+import secrets
+import hmac
+
+change_password_bp = Blueprint("change_password",__name__)
+
+@change_password_bp.route("/user/change_password", methods=["POST"])
+def change_password():
+
+    user_id = session.get("user_id") #Get user ID from session
+
+    if user_id:#checks if user is logges in
+
+        if request.method == 'POST':
+
+            #User data from front end
+            data = request.get_json()
+            email = data.get("email")
+            old_password = data.get("old_password")
+            new_password = data.get("new_password")
+
+            new_encoded_password = generate_password_hash(new_password)
+            new_password_hash = new_encoded_password["hash"]
+            new_password_salt = new_encoded_password["salt"]
+            new_password_iterations = new_encoded_password["iterations"]
+
+            #collect old password, user id and email into json
+            old_auth = {
+                "user_id" : user_id,
+                "email" : email,
+                "password": old_password
+            }
+
+            #user_old_auth = check_old_password(old_auth) 
+            
+
+            #send old password to database            
+            old_auth_info, value = check_old_password(old_auth) #function returns certain columns collected from database
+
+            if value == 1: #if user exists in database
+
+                old_password_hash = old_auth_info.get("PasswordHash")
+                old_password_salt = old_auth_info.get("PasswordSalt")
+                old_password_iterations = old_auth_info.get("Iterations")
+
+
+                #password authentication. Calls password fucntions
+                old_password_info = generate_password_hash(old_password)
+                is_correct = verify_password(old_password_info, old_password, old_password_salt, old_password_iterations, old_password_hash)
+
+                if is_correct == True:#if password is correct
+
+                    #passes new password information to json
+                    new_auth = {
+                        "user_id" : user_id,
+                        "email" : email,
+                        "password": new_password,
+                        "hash": new_password_hash,
+                        "salt": new_password_salt,
+                        "iterations": new_password_iterations
+                    }
+
+                    #sends new password to database
+                    new_auth_info = set_new_password(new_auth)
+
+
+
+                    response_data = {"message":"Password is correct"}
+                    return jsonify(new_auth_info, user_id)
+                
+                else:
+                    response_data = {"error":"Old password is incorrect", "email": email}
+                    return jsonify(response_data)
+                
+            else:
+                return {"error" : "Email does not exist"}
+            
+        
+        return {"error" : "null"}
+    
+    else:
+        return {"error" : "User not logged in"}
+
+        
+
+    
+
+#password encoding
+def generate_password_hash(password):
+    # Generate a 16-byte salt
+    salt = secrets.token_bytes(16)
+    # Define the number of iterations
+    iterations = 100000
+    # Generate the hash using PBKDF2-HMAC-SHA-256
+    hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, iterations)
+    
+    # Return the salt, iterations, and hash, encoded in a way that can be stored in the database
+    return {
+        'salt': salt.hex(),
+        'iterations': iterations,
+        'hash': hash.hex()
+    }
+
+
+#password verification
+def verify_password(stored_password_info, submitted_password, salt, iterations, user_hash):
+    # Convert the stored salt back to bytes
+    salt = bytes.fromhex(salt)
+    # Use the same number of iterations as when the password was hashed
+    iterations = iterations
+    # Hash the submitted password with the stored salt and iterations
+    hash = hashlib.pbkdf2_hmac('sha256', submitted_password.encode(), salt, iterations)
+    
+    # Compare the newly generated hash with the stored hash
+    # Convert the generated hash to hex for comparison
+    
+    return hmac.compare_digest(hash.hex(), user_hash)
\ No newline at end of file
diff --git a/app/controllers/deleteProfileController.py b/app/controllers/deleteProfileController.py
new file mode 100644
index 0000000000000000000000000000000000000000..f29f3689923437d63695693ebaf81f1be31a2dcb
--- /dev/null
+++ b/app/controllers/deleteProfileController.py
@@ -0,0 +1,37 @@
+#This section allows a user to delete their profile
+#
+
+from flask import Blueprint, jsonify, request, session
+from models.deleteProfile import delete
+
+deleteProfile_bp = Blueprint("deleteProfile",__name__)
+
+@deleteProfile_bp.route("/user/deleteProfile", methods=["POST"])
+def deleteProfile():
+
+    #collects user id from session
+    user_id = session.get("user_id")
+
+    if user_id:#checks if user is logged in
+
+        if request.method == 'POST':
+
+            #User data from front end
+            data = request.get_json()
+            email = data.get("email")
+
+            user_info = {
+                "email" : email,
+                "user_id" : user_id
+            }
+
+            user = delete(user_info) #sends user data to database
+            
+
+            return jsonify(user, user_id)
+        
+        else:
+            return {"message" : "null"}
+    
+    else:
+        return {"error" : "User not logged in"}
\ No newline at end of file
diff --git a/app/controllers/fetchUsernameController.py b/app/controllers/fetchUsernameController.py
new file mode 100644
index 0000000000000000000000000000000000000000..00380458a388542e5aaa69a20561324d7f152a0c
--- /dev/null
+++ b/app/controllers/fetchUsernameController.py
@@ -0,0 +1,30 @@
+from flask import Blueprint, jsonify, request, json, session
+from models.fetchUsername import get_username
+
+fetch_username_bp = Blueprint("getUsername",__name__)
+
+#This function is for the product microservice. It makes a call to this
+#endpoint to fetch a user's username when they want to add a product review
+@fetch_username_bp.route("/user/getUsername", methods=["POST"])
+def username():
+
+    user_id = session.get("user_id") #gets session data
+
+    #if user_id: #if user is logged in
+
+    if request.method == 'POST':
+
+        #User data from front end
+        data = request.get_json()
+        userID = data.get("id")
+
+            
+
+        username= get_username(userID) #Send user info to database
+
+        return jsonify({"username" : username}), 200
+    
+    else:
+        return {"error" : "null"}
+    #else:
+     #   return {"error" : "User not logged in"}
\ No newline at end of file
diff --git a/app/controllers/getUsersController.py b/app/controllers/getUsersController.py
new file mode 100644
index 0000000000000000000000000000000000000000..e2a9bd4c09b48d0beb756dddd03e66562435a8ba
--- /dev/null
+++ b/app/controllers/getUsersController.py
@@ -0,0 +1,19 @@
+from flask import Blueprint, jsonify, request, json, session, redirect
+from config import KAFKA_SERVER
+
+from models.getUsers import fetch_user_info
+
+from kafka import KafkaConsumer
+
+consumer = KafkaConsumer("review_events", bootstrap_servers=KAFKA_SERVER)
+
+def getusers(user_id):
+
+    pass
+
+
+for message in consumer:
+
+    event_data = json.loads(message.value.decode())
+    user_id = event_data["user_id"]
+    username = getusers(user_id)
\ No newline at end of file
diff --git a/app/controllers/loginController.py b/app/controllers/loginController.py
new file mode 100644
index 0000000000000000000000000000000000000000..232350cda6d673061fd1a75a26a98ddcd07ab8de
--- /dev/null
+++ b/app/controllers/loginController.py
@@ -0,0 +1,93 @@
+#This section allows a user to log in
+
+from flask import Blueprint, jsonify, request, session
+from models.login import fetch_user
+from models.login import fetch_password
+import hashlib
+import secrets
+import hmac
+
+login_bp = Blueprint("login",__name__)
+
+@login_bp.route("/login", methods=["POST"])
+def login():
+
+    if request.method == 'POST':
+
+        #User data from front end
+        data = request.get_json()
+        email = data.get("email")
+        password = data.get("password")
+
+        
+
+        user = fetch_user(email) #Collect user data from database
+        
+        #User authentication
+        if user is not None: #If database found matching email the user entered
+
+            user_email = user.get("Email") #User email from database
+
+
+            if user_email == email: #Checks if email returned from database is the same as what user entered
+                
+                auth = fetch_password(user_email) #function returns certain columns collected from database
+
+                user_hash = auth.get("PasswordHash")
+                user_salt = auth.get("PasswordSalt")
+                user_iterations = auth.get("Iterations")
+
+
+                #password authentication
+                password_info = generate_password_hash(password)
+                is_correct = verify_password(password_info, password, user_salt, user_iterations, user_hash)
+
+                if is_correct == True: #if password is correct
+                    session["user_id"] = user.get("UserID")
+                    response_data = {"message":"Login Sucessful", "email": email, "session" : session["user_id"]}
+                    return jsonify(response_data)
+                
+                else:
+                    response_data = {"message":"Email or password incorrect", "email": email}
+                    return jsonify(response_data)
+
+                
+            else:
+                return ("Email does not exist")
+            
+        else:
+            response_data = {"message":"Email does not exist", "email": email}
+            return jsonify(response_data)
+    
+    return {"message" : "null"}
+    
+
+#password encryption
+def generate_password_hash(password):
+    # Generate a 16-byte salt
+    salt = secrets.token_bytes(16)
+    # Define the number of iterations
+    iterations = 100000
+    # Generate the hash using PBKDF2-HMAC-SHA-256
+    hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, iterations)
+    
+    # Return the salt, iterations, and hash, encoded in a way that can be stored in the database
+    return {
+        'salt': salt.hex(),
+        'iterations': iterations,
+        'hash': hash.hex()
+    }
+
+#password verification
+def verify_password(stored_password_info, submitted_password, salt, iterations, user_hash):
+    # Convert the stored salt back to bytes
+    salt = bytes.fromhex(salt)
+    # Use the same number of iterations as when the password was hashed
+    iterations = iterations
+    # Hash the submitted password with the stored salt and iterations
+    hash = hashlib.pbkdf2_hmac('sha256', submitted_password.encode(), salt, iterations)
+    
+    # Compare the newly generated hash with the stored hash
+    # Convert the generated hash to hex for comparison
+    
+    return hmac.compare_digest(hash.hex(), user_hash)
\ No newline at end of file
diff --git a/app/controllers/logoutController.py b/app/controllers/logoutController.py
new file mode 100644
index 0000000000000000000000000000000000000000..e296c4dae0172fed0af189b5005cfbef8d1a021c
--- /dev/null
+++ b/app/controllers/logoutController.py
@@ -0,0 +1,23 @@
+#This section allows a user to log out
+
+from flask import Blueprint, jsonify, request, json, session, redirect
+
+
+logout_bp = Blueprint("logout",__name__)
+
+@logout_bp.route("/logout", methods=["POST"])
+def logout():
+
+    user_id = session.get("user_id") #get session data
+
+    if user_id: #if user is logged in
+
+        if request.method == 'POST':
+
+            session.pop("user_id", None) #deletes session
+            return ({"message" : "Log out successful"})
+        
+        else:
+            return {"error" : "null"}
+    else:
+        return {"error" : "User not logged in"}
\ No newline at end of file
diff --git a/app/controllers/showReviewsController.py b/app/controllers/showReviewsController.py
new file mode 100644
index 0000000000000000000000000000000000000000..42d853475f2622e476bcb9ca5ed87e0c8d58e472
--- /dev/null
+++ b/app/controllers/showReviewsController.py
@@ -0,0 +1,56 @@
+from flask import Blueprint, jsonify, request, session
+from kafka import KafkaConsumer
+import json
+from config import KAFKA_SERVER
+
+show_reviews_bp = Blueprint("showReviews", __name__)
+
+
+consumer_conf = {
+    "bootstrap_servers": KAFKA_SERVER,
+    "group_id": "show_reviews_group", 
+    "auto_offset_reset": "earliest"   
+}
+
+#Function to consume reviews published by product microservice
+def consume_reviews(num_reviews=1):
+    consumer = KafkaConsumer("customer_reviews", **consumer_conf)
+    reviews = []
+    
+
+    for message in consumer:
+
+        review_data_str = message.value.decode("utf-8")
+        
+
+        review_data = json.loads(review_data_str)
+        
+
+        reviews.append(review_data)
+        
+
+        if len(reviews) >= num_reviews:
+            break
+
+
+    consumer.close()
+
+    return reviews
+
+
+#Route to show reviews for a user
+@show_reviews_bp.route("/user/showReviews", methods=["POST"])
+def show_reviews():
+    #Collect user id from session
+    user_id = session.get("user_id")
+
+    if user_id:  # Check if user is logged in
+        if request.method == 'POST':
+            #Call function to consume reviews
+            reviews = consume_reviews()
+
+            return jsonify(reviews)
+        else:
+            return {"message": "null"}
+    else:
+        return {"error": "User not logged in"}
diff --git a/app/controllers/signupController.py b/app/controllers/signupController.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ec066371a3283032f8f059a08a2e7eab3ea1d78
--- /dev/null
+++ b/app/controllers/signupController.py
@@ -0,0 +1,71 @@
+#This section allows a user to create a profile
+
+from flask import Blueprint, jsonify, request, json
+from models.signup import new_user
+import hashlib
+import secrets
+
+signup_bp = Blueprint("signup",__name__)
+
+@signup_bp.route("/signup", methods=["POST"])
+def signup():
+
+    if request.method == 'POST':
+
+        #User data from front end
+        data = request.get_json()
+        email = data.get("email")
+        first_name = data.get("first_name")
+        last_name = data.get("last_name")
+        location = data.get("location")
+        gender = data.get("gender")
+        password = data.get("password")
+        encoded_password = generate_password_hash(password)
+        hash = encoded_password["hash"]
+        salt = encoded_password["salt"]
+        iterations = encoded_password["iterations"]
+
+        if email.strip() != "": #checks if email is not empty (email cannot be null)
+            
+            # Create a dictionary from user data
+            user_data = {
+                "email": email,
+                "first_name": first_name,
+                "last_name": last_name,
+                "location": location,
+                "gender": gender,
+                "password": password,
+                "hash": hash,
+                "salt": salt,
+                "iterations": iterations
+            }
+
+            # Convert to JSON
+            json_user_data = json.dumps(user_data)
+
+
+            update = new_user(user_data) #Send user info to database
+
+            return jsonify(update)
+        
+        else:
+            return {"error" : "email cannot be empty"}
+    
+    return {"error" : "null"}
+    
+
+#This function encrypts the user's password
+def generate_password_hash(password):
+    # Generate a 16-byte salt
+    salt = secrets.token_bytes(16)
+    # Define the number of iterations
+    iterations = 100000
+    # Generate the hash using PBKDF2-HMAC-SHA-256
+    hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, iterations)
+    
+    # Return the salt, iterations, and hash, encoded in a way that can be stored in the database
+    return {
+        'salt': salt.hex(),
+        'iterations': iterations,
+        'hash': hash.hex()
+    }
diff --git a/app/controllers/updateProfileController.py b/app/controllers/updateProfileController.py
new file mode 100644
index 0000000000000000000000000000000000000000..bca3119885f245ad049dc58820fc7c92a1d5aceb
--- /dev/null
+++ b/app/controllers/updateProfileController.py
@@ -0,0 +1,56 @@
+#This section allows a user to update their profile
+
+from flask import Blueprint, jsonify, request, json, session
+from models.updateProfile import update_user
+from models.updateProfile import fetch_user_info
+
+from events.eventDefinitions import updated_username
+from publishers.kafkaPublishers import publish_username_updated_event
+
+update_profile_bp = Blueprint("update",__name__)
+
+@update_profile_bp.route("/user/update", methods=["POST"])
+def update_profile():
+
+    user_id = session.get("user_id") #gets session data
+
+    if user_id: #if user is logged in
+
+        user_info = fetch_user_info(user_id)
+        print(jsonify(user_info))
+
+        if request.method == 'POST':
+
+            #User data from front end
+            data = request.get_json()
+            email = data.get("email")
+            first_name = data.get("first_name")
+            last_name = data.get("last_name")
+            location = data.get("location")
+            gender = data.get("gender")
+
+                
+            # Create a json object from user data
+            user_data = {
+                "user_id" : user_id,
+                "email": email,
+                "first_name": first_name,
+                "last_name": last_name,
+                "location": location,
+                "gender": gender,
+            }
+
+            update = update_user(user_data) #Send user info to database
+
+            if "message" in update:
+
+                event_data = {"user_id" : user_id, "new_username" : user_data["first_name"]}
+                event_message = updated_username(user_id, user_data["first_name"])
+                publish_username_updated_event(event_data)
+
+                return jsonify({"Update Status": update, "Username" : user_data["first_name"], "User ID" : user_id, "Event message" : event_message})
+        
+        else:
+            return {"error" : "null"}
+    else:
+        return {"error" : "User not logged in"}
\ No newline at end of file
diff --git a/app/events/__init__.py b/app/events/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/app/events/__pycache__/__init__.cpython-311.pyc b/app/events/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..95be18671d60d24a8dd5c89660bea97b034080d2
Binary files /dev/null and b/app/events/__pycache__/__init__.cpython-311.pyc differ
diff --git a/app/events/__pycache__/eventDefinitions.cpython-311.pyc b/app/events/__pycache__/eventDefinitions.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..26189d001a07adbc3c51f25578fd46235d1830b5
Binary files /dev/null and b/app/events/__pycache__/eventDefinitions.cpython-311.pyc differ
diff --git a/app/events/eventDefinitions.py b/app/events/eventDefinitions.py
new file mode 100644
index 0000000000000000000000000000000000000000..bb88066408e7c588d1eeadaec115cac9b4c2f06a
--- /dev/null
+++ b/app/events/eventDefinitions.py
@@ -0,0 +1,5 @@
+def updated_username(user_id, new_username):
+
+    return {"event_type": "profile_updated",
+        "user_id": user_id,
+        "new_username": new_username}
\ No newline at end of file
diff --git a/app/index.py b/app/index.py
new file mode 100644
index 0000000000000000000000000000000000000000..2ee61fb8d8d7cd0d715eb4c479b74b65da147209
--- /dev/null
+++ b/app/index.py
@@ -0,0 +1,80 @@
+from flask import Flask, jsonify, redirect, json, url_for, request, render_template, make_response, session, abort
+from flask_cors import CORS
+from flask import jsonify
+from controllers.loginController import login_bp
+from controllers.signupController import signup_bp
+from controllers.updateProfileController import update_profile_bp
+from controllers.changePasswordController import change_password_bp
+from controllers.deleteProfileController import deleteProfile_bp
+from controllers.logoutController import logout_bp
+from controllers.fetchUsernameController import fetch_username_bp
+from controllers.showReviewsController import show_reviews_bp
+
+from config import DEBUG, SECRET_KEY, PORT, HOST
+import os
+import requests
+import publishers
+
+
+
+app = Flask(__name__)
+CORS(app)
+
+
+@app.route('/')
+def index():
+    return render_template("index.html")
+
+
+@app.route("/hello/<int:score>")
+def hello_user(score):
+    return render_template("hello.html", marks=score)
+
+
+app.register_blueprint(login_bp)
+
+app.register_blueprint(signup_bp)
+
+app.register_blueprint(update_profile_bp)
+
+app.register_blueprint(change_password_bp)
+
+app.register_blueprint(deleteProfile_bp)
+
+app.register_blueprint(logout_bp)
+
+app.register_blueprint(fetch_username_bp)
+
+app.register_blueprint(show_reviews_bp)
+
+publishers.create_profile_updated_topic()
+
+
+#Check if application is running in docker to collect or set secret key
+try:
+
+    #Check for the existence of the /proc/self/cgroup file
+    with open("/proc/self/cgroup", "r") as cgroup_file:
+        cgroup_info = cgroup_file.read()
+
+    #Check if the cgroup information contains 'docker' keyword
+    if 'docker' in cgroup_info:
+        print("Running inside Docker container")
+        app.secret_key = os.environ.get('SECRET_KEY')
+    
+except FileNotFoundError:
+    # If the file doesn't exist
+    print("Running on a local Windows machine")
+
+    app.secret_key = SECRET_KEY
+
+
+@app.route("/userIDs", methods=["POST"])
+def userIDs():
+
+    #ids = request.json
+    #print(ids)
+    return 'hi'
+
+if __name__ == '__main__':
+    app.run(host=HOST, debug=DEBUG, port=PORT)
\ No newline at end of file
diff --git a/app/models/__init__.py b/app/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d55ce4a0c8e0748e87cd3ecae1b6fe12294bdae3
--- /dev/null
+++ b/app/models/__init__.py
@@ -0,0 +1,15 @@
+from flask import Flask
+from flask_cors import CORS
+
+
+#from app.models import models
+
+app = Flask(__name__)
+CORS(app)
+
+#db = sqlAlchemy
+
+#from app import routes
+
+if __name__ == '__main__':
+    app.run(debug=True)
\ No newline at end of file
diff --git a/app/models/__pycache__/__init__.cpython-311.pyc b/app/models/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dfb0366dfbe4ee46a4cd5603bac50bd5dcb0efcf
Binary files /dev/null and b/app/models/__pycache__/__init__.cpython-311.pyc differ
diff --git a/app/models/__pycache__/changePassword.cpython-311.pyc b/app/models/__pycache__/changePassword.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..efbc1602a81cf43627230b17ff6be9b650f9cba8
Binary files /dev/null and b/app/models/__pycache__/changePassword.cpython-311.pyc differ
diff --git a/app/models/__pycache__/database_connection.cpython-311.pyc b/app/models/__pycache__/database_connection.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d54224fd06a5210d5b85dad1790380d510110bd7
Binary files /dev/null and b/app/models/__pycache__/database_connection.cpython-311.pyc differ
diff --git a/app/models/__pycache__/deleteProfile.cpython-311.pyc b/app/models/__pycache__/deleteProfile.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..11cd5e31a86ac49992cc243db920bc089e02298a
Binary files /dev/null and b/app/models/__pycache__/deleteProfile.cpython-311.pyc differ
diff --git a/app/models/__pycache__/fetchUsername.cpython-311.pyc b/app/models/__pycache__/fetchUsername.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ae95206848ec046c1557589c2b224c793de637e2
Binary files /dev/null and b/app/models/__pycache__/fetchUsername.cpython-311.pyc differ
diff --git a/app/models/__pycache__/getUsers.cpython-311.pyc b/app/models/__pycache__/getUsers.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dd54bdac2b3189ffb26e70c80dcb6d7a9d4b3f61
Binary files /dev/null and b/app/models/__pycache__/getUsers.cpython-311.pyc differ
diff --git a/app/models/__pycache__/login.cpython-311.pyc b/app/models/__pycache__/login.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b77602b227dc0fa7d1be7ce1a7e1b0b2398dca15
Binary files /dev/null and b/app/models/__pycache__/login.cpython-311.pyc differ
diff --git a/app/models/__pycache__/models.cpython-311.pyc b/app/models/__pycache__/models.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0c5497a917a5f33bfe0edde28b561ef47b6a7caf
Binary files /dev/null and b/app/models/__pycache__/models.cpython-311.pyc differ
diff --git a/app/models/__pycache__/signup.cpython-311.pyc b/app/models/__pycache__/signup.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..94a888ae05aa3787387431d65168edf553a0a2cf
Binary files /dev/null and b/app/models/__pycache__/signup.cpython-311.pyc differ
diff --git a/app/models/__pycache__/updateProfile.cpython-311.pyc b/app/models/__pycache__/updateProfile.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a3cc094c4a2bb3f0c99ed37c439242aab85aaf1a
Binary files /dev/null and b/app/models/__pycache__/updateProfile.cpython-311.pyc differ
diff --git a/app/models/changePassword.py b/app/models/changePassword.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e7403d667fa12de9e122853552fb14da27210a1
--- /dev/null
+++ b/app/models/changePassword.py
@@ -0,0 +1,107 @@
+from flask import jsonify
+import pyodbc
+from models.database_connection import connect_db
+
+
+
+def check_old_password(data):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        email = data["email"]
+        user_id = data["user_id"]
+
+        
+
+        #Check if the email already exists
+        email_check_query = "SELECT COUNT(*) FROM dbo.User_table WHERE UserID = ?"
+        cursor.execute(email_check_query, user_id) #executes the query
+        count = cursor.fetchone()[0]
+
+        if count == 0:
+            return ({"Error" : "Email does not exist"}, 0)
+        
+        else:
+            #selects password information from database
+            query = "SELECT t1.Email, t1.UserID, t2.Iterations, t2.PasswordHash, t2.PasswordSalt FROM dbo.User_table as t1 INNER JOIN dbo.AuthInfo as t2 ON t1.UserID = t2.UserID where t1.UserID= ?"
+            
+            cursor.execute(query, user_id) #executes query
+
+            row = cursor.fetchone()
+
+            columns = [column[0] for column in cursor.description]
+            user_data = dict(zip(columns, row))
+
+            #connection.close()
+
+            return (user_data, 1)
+    
+    except pyodbc.Error as e: #more error handling
+        print(f"Database error in check_old_password: {e}")
+        connection.rollback()
+        return {"Error" : "Database error"}
+    
+    except Exception as e: #more error handling
+        print(f"Unexpected error occured in check_old_password: {e}")
+        connection.rollback()
+        return {"Error" : "Unexpected error"}
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
+
+
+def set_new_password(data):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        email = data["email"]
+        user_id = data["user_id"]
+        
+
+        #selects user ID
+        select_userID_query = "SELECT UserID from dbo.User_table where UserID = ?"
+        cursor.execute(select_userID_query, user_id)
+        UserID = cursor.fetchone()[0]
+
+
+        #updates password
+        update_authinfo_query = '''UPDATE dbo.AuthInfo
+    SET PasswordHash = ?, PasswordSalt = ?, Iterations = ?, TempPlainText = ?
+    WHERE UserID = ?'''
+        
+
+        cursor.execute(update_authinfo_query, (data["hash"], data["salt"], data["iterations"], data["password"], UserID))
+
+        connection.commit()
+
+
+        #connection.close()
+
+        return {"Message" : "Password updated successfully"}
+    
+
+    
+    except pyodbc.Error as e: #more error handling
+        print(f"Database error in set_new_password: {e}")
+        connection.rollback()
+        return {"Error" : "Database error"}
+    
+    except Exception as e: #more error handling
+        print(f"Unexpected error occured in set_new_password: {e}")
+        connection.rollback()
+        return {"Error" : "Unexpected error"}
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
\ No newline at end of file
diff --git a/app/models/database_connection.py b/app/models/database_connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..945742875f3b666e8427edc3e662536a8e6ace70
--- /dev/null
+++ b/app/models/database_connection.py
@@ -0,0 +1,24 @@
+import pyodbc
+import os
+
+print("Outside db connection function")
+#Connect to database
+def connect_db():
+    print("In CONNECT DB")
+    try:
+
+        server = "35.197.217.212"
+        database = "userdatabase"
+        username = "sqlserver"
+        password = "WebTechGroup3"
+        driver = "ODBC Driver 17 for SQL Server"
+
+        connection_string = f"DRIVER={driver};SERVER={server};DATABASE={database};UID={username};PWD={password};Trusted_Connection=no;"
+      
+        return pyodbc.connect(connection_string)
+        
+    except Exception as e:
+        # If the file doesn't exist
+        print("Unexpected error occured {e}")
+
+        return False
diff --git a/app/models/deleteProfile.py b/app/models/deleteProfile.py
new file mode 100644
index 0000000000000000000000000000000000000000..7972b969a1ba2a46cee56c5a76c0310f2be1b219
--- /dev/null
+++ b/app/models/deleteProfile.py
@@ -0,0 +1,59 @@
+#from app import db
+from flask import jsonify
+import pyodbc
+from models.database_connection import connect_db
+
+
+
+def delete(data):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        email = data["email"]
+        user_id = data["user_id"]
+
+        # select user id from database
+        id_check_query = "SELECT UserID from dbo.User_table WHERE UserID= ?"
+        cursor.execute(id_check_query, user_id)
+        user_row = cursor.fetchone()
+
+        if user_row:
+            userID = user_row[0] 
+        else:
+            return {"Error": "User not found"}
+        
+        #delete from authinfo table first because of foreign key constraint
+        delete_authinfo_query = '''DELETE FROM dbo.AuthInfo WHERE UserID= ?'''
+        cursor.execute(delete_authinfo_query, userID)
+
+
+        #delete user info from user table 
+        delete_user_query = '''DELETE FROM dbo.User_table WHERE UserID = ?'''
+        cursor.execute(delete_user_query, userID)
+
+
+    
+
+        #commit changes to database if no errors
+        connection.commit()
+
+        return {"message" : "Account successfully deleted"}
+    
+    except pyodbc.Error as e: #more error handling
+        print(f"Database error in delete: {e}")
+        connection.rollback()
+        return {"Error" : "Database error"}
+    
+    except Exception as e: #more error handling
+        print(f"Unexpected error occured in delete: {e}")
+        connection.rollback()
+        return {"Error" : "Unexpected error"}
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
\ No newline at end of file
diff --git a/app/models/fetchUsername.py b/app/models/fetchUsername.py
new file mode 100644
index 0000000000000000000000000000000000000000..98c4cb135760391159dec56757fa7d2ddf267c88
--- /dev/null
+++ b/app/models/fetchUsername.py
@@ -0,0 +1,39 @@
+from flask import jsonify
+import pyodbc
+from models.database_connection import connect_db
+
+
+def get_username(id):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        query = "SELECT Username FROM dbo.User_table where UserID = ?"
+        cursor.execute(query, id)
+
+        row = cursor.fetchone() #fetch data
+
+        if row:
+            return row[0] 
+        else:
+            return None
+
+        #connection.close()
+
+        return username
+    
+    except pyodbc.Error as e: #error handling
+        print(f"Database error in fetch_user_info: {e}")
+        return None
+    
+    except Exception as e: #error handling
+        print(f"Unexpected error occured in get_username: {e}")
+        return None
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
diff --git a/app/models/getUsers.py b/app/models/getUsers.py
new file mode 100644
index 0000000000000000000000000000000000000000..f056e2dea7fe5579b85688e91003cd420b0dc591
--- /dev/null
+++ b/app/models/getUsers.py
@@ -0,0 +1,38 @@
+#from app import db
+from flask import jsonify
+import pyodbc
+from models.database_connection import connect_db
+
+
+def fetch_user_info(id):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        query = "SELECT First_name, Last_name FROM dbo.User_table where UserID = ?"
+        cursor.execute(query, id)
+
+        row = cursor.fetchone() #fetch data
+
+        columns = [column[0] for column in cursor.description]
+        user_data = dict(zip(columns, row))
+
+        #connection.close()
+
+        return user_data
+    
+    except pyodbc.Error as e: #error handling
+        print(f"Database error in fetch_user_info: {e}")
+        return None
+    
+    except Exception as e: #error handling
+        print(f"Unexpected error occured in fetch_user_info: {e}")
+        return None
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
\ No newline at end of file
diff --git a/app/models/login.py b/app/models/login.py
new file mode 100644
index 0000000000000000000000000000000000000000..f790b89365c7182f6c5345ca70a2a2436fa36c95
--- /dev/null
+++ b/app/models/login.py
@@ -0,0 +1,72 @@
+#from app import db
+import pyodbc
+from flask import jsonify
+from models.database_connection import connect_db
+
+#Function to get user info
+def fetch_user(email):
+
+    try: #error handling
+        print("In FETCH USER")
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        query = "SELECT * FROM dbo.User_table where Email = ?"
+        cursor.execute(query, email)
+
+        row = cursor.fetchone() #fetch data
+
+        columns = [column[0] for column in cursor.description]
+        user_data = dict(zip(columns, row))
+
+        #connection.close()
+
+        return user_data
+    
+    except pyodbc.Error as e: #error handling
+        print(f"Database error in fetch_user: {e}")
+        return None
+    
+    except Exception as e: #error handling
+        print(f"Unexpected error occured in fetch_user: {e}")
+        return None
+    
+
+    
+
+
+
+#Fetch user's password
+def fetch_password(email):
+
+    try:
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        query = "SELECT t1.Email, t1.UserID, t2.Iterations, t2.PasswordHash, t2.PasswordSalt FROM dbo.User_table as t1 INNER JOIN dbo.AuthInfo as t2 ON t1.UserID = t2.UserID where Email= ?"
+        
+        cursor.execute(query, email)
+
+        row = cursor.fetchone()
+
+        if row is None:
+            return {"message" : "Email does not exist"}
+
+        else:
+            columns = [column[0] for column in cursor.description]
+            user_data = dict(zip(columns, row))
+
+            #connection.close()
+
+            return user_data
+    
+    except pyodbc.Error as e:
+        print(f"Database error in fetch_user: {e}")
+        return None
+    
+    except Exception as e:
+        print(f"Unexpected error occured in fetch_user: {e}")
+        return None
+    
+ 
\ No newline at end of file
diff --git a/app/models/signup.py b/app/models/signup.py
new file mode 100644
index 0000000000000000000000000000000000000000..63031efd240aead253b9dfcab8b2ac556cd55b36
--- /dev/null
+++ b/app/models/signup.py
@@ -0,0 +1,63 @@
+#from app import db
+from flask import jsonify
+import pyodbc
+from models.database_connection import connect_db
+
+
+#Create a new user
+def new_user(data):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        email = data["email"]
+
+        # Check if the email already exists
+        email_check_query = "SELECT COUNT(*) FROM dbo.User_table WHERE Email = ?"
+        cursor.execute(email_check_query, email)
+        count = cursor.fetchone()[0]
+
+        if count > 0:
+            return {"Error": "Email already exists"}
+
+        
+        #insert data into user table
+        insert_user_query = '''INSERT INTO dbo.User_table (Username, Email, First_Name, Last_Name, Tenure_Months, Location, Gender)
+VALUES (?, ?, ?, ?, ?, ?, ?);'''
+        cursor.execute(insert_user_query, (data["first_name"], data["email"], data["first_name"], data["last_name"], " ", data["location"], data["gender"]))
+
+
+        UserID_query = "SELECT UserID FROM dbo.User_table WHERE Email= ?"
+        cursor.execute(UserID_query, email)
+        UserID = cursor.fetchone()[0]
+
+
+        #Insert password into authentication table
+        insert_authinfo_query = '''INSERT INTO dbo.AuthInfo (PasswordHash, PasswordSalt, Iterations, TempPlainText, UserID)
+VALUES (?, ?, ?, ?, ?);'''
+        cursor.execute(insert_authinfo_query, (data["hash"], data["salt"], data["iterations"], data["password"], UserID))
+        
+
+
+        #commit changes to database if no errors
+        connection.commit()
+
+        return {"message" : "New user info added successfully"}
+    
+    except pyodbc.Error as e: #more error handling
+        print(f"Database error in new_user: {e}")
+        connection.rollback()
+        return {"Error" : "Database error"}
+    
+    except Exception as e: #more error handling
+        print(f"Unexpected error occured in new_user: {e}")
+        connection.rollback()
+        return {"Error" : "Unexpected error"}
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
\ No newline at end of file
diff --git a/app/models/updateProfile.py b/app/models/updateProfile.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c70bedb121f72626f28135dc13b5d22fd962f08
--- /dev/null
+++ b/app/models/updateProfile.py
@@ -0,0 +1,86 @@
+#from app import db
+from flask import jsonify
+import pyodbc
+from models.database_connection import connect_db
+
+
+def fetch_user_info(id):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        query = "SELECT * FROM dbo.User_table where UserID = ?"
+        cursor.execute(query, id)
+
+        row = cursor.fetchone() #fetch data
+
+        columns = [column[0] for column in cursor.description]
+        user_data = dict(zip(columns, row))
+
+        #connection.close()
+
+        return user_data
+    
+    except pyodbc.Error as e: #error handling
+        print(f"Database error in fetch_user_info: {e}")
+        return None
+    
+    except Exception as e: #error handling
+        print(f"Unexpected error occured in fetch_user_info: {e}")
+        return None
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
+
+
+
+def update_user(data):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+        
+        user_id = data["user_id"]
+
+        #insert data into user table
+        update_user_query = '''UPDATE dbo.User_table
+    SET
+        Username= ?,
+        First_Name= ?,
+        Last_Name= ?,
+        Location= ?,
+        Gender= ?
+    WHERE
+        UserID= ?'''
+
+        cursor.execute(update_user_query, (data["first_name"], data["first_name"], data["last_name"], data["location"], data["gender"], user_id))
+
+
+        #commit changes to database if no errors
+        connection.commit()
+
+        return {"message" : "Profile updated successfully"}
+        
+
+
+    except pyodbc.Error as e: #more error handling
+        print(f"Database error in update_user: {e}")
+        connection.rollback()
+        return {"Error" : "Database error"}
+    
+    except Exception as e: #more error handling
+        print(f"Unexpected error occured in update_user: {e}")
+        connection.rollback()
+        return {"Error" : "Unexpected error"}
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
\ No newline at end of file
diff --git a/app/publishers/__init__.py b/app/publishers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..beb65e5ef1e4ca89b1eb1f7148c7aa845f8a7348
--- /dev/null
+++ b/app/publishers/__init__.py
@@ -0,0 +1 @@
+from publishers.kafkaPublishers import create_profile_updated_topic
\ No newline at end of file
diff --git a/app/publishers/__pycache__/__init__.cpython-311.pyc b/app/publishers/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3e5ad7960c3085c3269be00737e82ddc12a6c966
Binary files /dev/null and b/app/publishers/__pycache__/__init__.cpython-311.pyc differ
diff --git a/app/publishers/__pycache__/kafkaPublishers.cpython-311.pyc b/app/publishers/__pycache__/kafkaPublishers.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ab88574606876c33991d2d1f9cf5c27a3e73f26b
Binary files /dev/null and b/app/publishers/__pycache__/kafkaPublishers.cpython-311.pyc differ
diff --git a/app/publishers/kafkaPublishers.py b/app/publishers/kafkaPublishers.py
new file mode 100644
index 0000000000000000000000000000000000000000..279b149bd37ce8f3c30a1c38c406d8eb1bf06048
--- /dev/null
+++ b/app/publishers/kafkaPublishers.py
@@ -0,0 +1,47 @@
+from kafka import KafkaProducer
+from kafka.admin import KafkaAdminClient, NewTopic
+
+from config import KAFKA_SERVER
+
+import json
+
+producer = KafkaProducer(bootstrap_servers=KAFKA_SERVER)
+
+
+#Creates the topic
+def create_profile_updated_topic():
+
+    admin_client = KafkaAdminClient(bootstrap_servers=KAFKA_SERVER)
+
+    # Define the topic name
+    topic_name = "profile_updated_topic"
+    num_partitions = 1
+    replication_factor = 1
+
+    #Get topics
+    topic_metadata = admin_client.list_topics()
+
+    #Check if the topic exists
+    if topic_name not in topic_metadata:
+
+        new_topic = NewTopic(name=topic_name, num_partitions=num_partitions, replication_factor=replication_factor)
+
+        admin_client.create_topics(new_topics=[new_topic], validate_only=False)
+
+
+#Function is called in updateProfileControllers.py
+#Topic message is collected from ProductMicroservice/Subsribers/updateUsernameSubscriber.py
+def publish_username_updated_event(event_data):
+
+    event_json = json.dumps(event_data)
+    #Publish the event to the Kafka topic
+    data_to_send = producer.send("profile_updated_topic", value=event_json.encode("utf-8"))
+    try:
+        record_metadata = data_to_send.get(timeout=10)
+        print("Message sent successfully!")
+        print("Topic:", record_metadata.topic)
+        print("Partition:", record_metadata.partition)
+        print("Offset:", record_metadata.offset)
+    except Exception as e:
+        print("Failed to send message:", e)
+    producer.flush()
\ No newline at end of file
diff --git a/app/run.py b/app/run.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/app/templates/index.html b/app/templates/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..6207c5207b735653b32e6ad59ac7d969cdfab4eb
--- /dev/null
+++ b/app/templates/index.html
@@ -0,0 +1,6 @@
+<html>
+    <head></head>
+    <body>
+        <p>HELLO</p>
+    </body>
+</html>
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8ff3f2bcf3113452668a674fa0aea07c9c7f5cb7
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,24 @@
+version: "3.2"
+
+services:
+
+  user-microservice:
+    build: 
+      context: .
+      dockerfile: Dockerfile
+      no_cache: true
+    image: user-microservice:3.0
+    container_name: user-microservice
+    ports:
+      - "5000:5000"
+    environment:
+      #DATABASE_URL: "DRIVER={ODBC Driver 17 for SQL Server};SERVER=user-database,1433;DATABASE=User_Management;UID=sa;PWD=WebTechGroup3;"
+      KAFKA_SERVER: "kafka:9092"
+      SECRET_KEY: Group3
+    networks:
+      - kafka_network
+      
+networks:
+  kafka_network:
+    external: true
+    #driver: bridge
\ No newline at end of file
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100644
index 0000000000000000000000000000000000000000..268cd4a00310bd1e5a014d92a84e48a52a1cb1ad
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Start SQL Server in the background
+/opt/mssql/bin/sqlservr &
+
+# Wait for 5 minutes (300 seconds)
+sleep 300
+
+# Log in and restore database
+/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "$SA_PASSWORD" -Q "RESTORE DATABASE User_Management FROM DISK = '/var/opt/mssql/data/User_Management.bak' WITH MOVE 'User_Management.mdf' TO '/var/opt/mssql/data/User_Management.mdf', MOVE 'User_Management_log.ldf' TO '/var/opt/mssql/data/User_Management_log.ldf';"
+
+# Keep the script running indefinitely
+wait %1
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..aed8ace483f880061abeee73b97954403c1890b1
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,14 @@
+Flask==3.0.2
+Flask-Cors==4.0.0
+gunicorn==21.2.0
+kafka-python==2.0.2
+pyodbc==5.1.0
+blinker==1.7.0
+click==8.1.7
+itsdangerous==2.1.2
+Jinja2==3.1.2
+Werkzeug==3.0.1
+boto3==1.34.71
+colorama==0.4.6
+MarkupSafe==2.1.3
+requests==2.31.0
\ No newline at end of file