diff --git a/.DS_Store b/.DS_Store
index 7fa1be84..8697ea9b 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/Development.xcconfig b/Development.xcconfig
new file mode 100644
index 00000000..5e42bbba
--- /dev/null
+++ b/Development.xcconfig
@@ -0,0 +1,9 @@
+//
+//  Development.xcconfig
+//  MobileAcebook
+//
+//  Created by Sam Quincey on 03/09/2024.
+//
+
+// Configuration settings file format documentation can be found at:
+// https://help.apple.com/xcode/#/dev745c5c974
diff --git a/MobileAcebook.xcodeproj/project.pbxproj b/MobileAcebook.xcodeproj/project.pbxproj
index 5506db3b..121a5d2c 100644
--- a/MobileAcebook.xcodeproj/project.pbxproj
+++ b/MobileAcebook.xcodeproj/project.pbxproj
@@ -7,6 +7,8 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		25F17D2D2C870C9F001CEF06 /* SignUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F17D2C2C870C9F001CEF06 /* SignUpView.swift */; };
+		25F17D2F2C870CAD001CEF06 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F17D2E2C870CAD001CEF06 /* LoginView.swift */; };
 		AE5D85B02AC8A221009680C6 /* MobileAcebookApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85AF2AC8A221009680C6 /* MobileAcebookApp.swift */; };
 		AE5D85B42AC8A224009680C6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE5D85B32AC8A224009680C6 /* Assets.xcassets */; };
 		AE5D85B72AC8A224009680C6 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE5D85B62AC8A224009680C6 /* Preview Assets.xcassets */; };
@@ -19,6 +21,20 @@
 		AE5D85E32AC9AFD2009680C6 /* MockAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E22AC9AFD2009680C6 /* MockAuthenticationService.swift */; };
 		AE5D85E62AC9B077009680C6 /* AuthenticationServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E52AC9B077009680C6 /* AuthenticationServiceProtocol.swift */; };
 		AE5D85E82AC9B29A009680C6 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E72AC9B29A009680C6 /* User.swift */; };
+		F82DA57C2C89BC6800CA8A56 /* PhotoPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = F82DA57B2C89BC6800CA8A56 /* PhotoPicker.swift */; };
+		F8304C5D2C888BF000B4BBC9 /* FeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8304C5C2C888BF000B4BBC9 /* FeedView.swift */; };
+		F8304C5F2C888C0500B4BBC9 /* PostCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8304C5E2C888C0500B4BBC9 /* PostCardView.swift */; };
+		F83545452C875D9300AB9C9E /* FullPostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F83545442C875D9300AB9C9E /* FullPostViewModel.swift */; };
+		F83545472C875DAC00AB9C9E /* FullPostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F83545462C875DAC00AB9C9E /* FullPostView.swift */; };
+		F844A8AC2C874802007EA48A /* PostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F844A8A92C874802007EA48A /* PostService.swift */; };
+		F844A8AD2C874802007EA48A /* CommentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F844A8AA2C874802007EA48A /* CommentService.swift */; };
+		F844A8AE2C874802007EA48A /* UserService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F844A8AB2C874802007EA48A /* UserService.swift */; };
+		F844A8B12C87480F007EA48A /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = F844A8AF2C87480F007EA48A /* Post.swift */; };
+		F844A8B22C87480F007EA48A /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = F844A8B02C87480F007EA48A /* Comment.swift */; };
+		F844A8B62C874D56007EA48A /* CreatePostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F844A8B52C874D56007EA48A /* CreatePostView.swift */; };
+		F844A8B82C875538007EA48A /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F844A8B72C875538007EA48A /* DateExtension.swift */; };
+		F87BD8272C88AF5E0071F4D3 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87BD8262C88AF5E0071F4D3 /* MainView.swift */; };
+		F8A25B612C884FF6009AE361 /* LogoutConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8A25B602C884FF6009AE361 /* LogoutConfirmationView.swift */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -39,6 +55,8 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+		25F17D2C2C870C9F001CEF06 /* SignUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpView.swift; sourceTree = "<group>"; };
+		25F17D2E2C870CAD001CEF06 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
 		AE5D85AC2AC8A221009680C6 /* MobileAcebook.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MobileAcebook.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		AE5D85AF2AC8A221009680C6 /* MobileAcebookApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobileAcebookApp.swift; sourceTree = "<group>"; };
 		AE5D85B32AC8A224009680C6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -54,6 +72,20 @@
 		AE5D85E22AC9AFD2009680C6 /* MockAuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAuthenticationService.swift; sourceTree = "<group>"; };
 		AE5D85E52AC9B077009680C6 /* AuthenticationServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProtocol.swift; sourceTree = "<group>"; };
 		AE5D85E72AC9B29A009680C6 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
+		F82DA57B2C89BC6800CA8A56 /* PhotoPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPicker.swift; sourceTree = "<group>"; };
+		F8304C5C2C888BF000B4BBC9 /* FeedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedView.swift; sourceTree = "<group>"; };
+		F8304C5E2C888C0500B4BBC9 /* PostCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostCardView.swift; sourceTree = "<group>"; };
+		F83545442C875D9300AB9C9E /* FullPostViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullPostViewModel.swift; sourceTree = "<group>"; };
+		F83545462C875DAC00AB9C9E /* FullPostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullPostView.swift; sourceTree = "<group>"; };
+		F844A8A92C874802007EA48A /* PostService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostService.swift; sourceTree = "<group>"; };
+		F844A8AA2C874802007EA48A /* CommentService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommentService.swift; sourceTree = "<group>"; };
+		F844A8AB2C874802007EA48A /* UserService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserService.swift; sourceTree = "<group>"; };
+		F844A8AF2C87480F007EA48A /* Post.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
+		F844A8B02C87480F007EA48A /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = "<group>"; };
+		F844A8B52C874D56007EA48A /* CreatePostView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreatePostView.swift; sourceTree = "<group>"; };
+		F844A8B72C875538007EA48A /* DateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtension.swift; sourceTree = "<group>"; };
+		F87BD8262C88AF5E0071F4D3 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
+		F8A25B602C884FF6009AE361 /* LogoutConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutConfirmationView.swift; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -111,6 +143,16 @@
 				AE5D85B32AC8A224009680C6 /* Assets.xcassets */,
 				AE5D85B52AC8A224009680C6 /* Preview Content */,
 				AE5D85D92AC8A337009680C6 /* WelcomePageView.swift */,
+				25F17D2C2C870C9F001CEF06 /* SignUpView.swift */,
+				25F17D2E2C870CAD001CEF06 /* LoginView.swift */,
+				F844A8B52C874D56007EA48A /* CreatePostView.swift */,
+				F844A8B72C875538007EA48A /* DateExtension.swift */,
+				F83545462C875DAC00AB9C9E /* FullPostView.swift */,
+				F8A25B602C884FF6009AE361 /* LogoutConfirmationView.swift */,
+				F8304C5C2C888BF000B4BBC9 /* FeedView.swift */,
+				F8304C5E2C888C0500B4BBC9 /* PostCardView.swift */,
+				F87BD8262C88AF5E0071F4D3 /* MainView.swift */,
+				F82DA57B2C89BC6800CA8A56 /* PhotoPicker.swift */,
 			);
 			path = MobileAcebook;
 			sourceTree = "<group>";
@@ -145,6 +187,9 @@
 		AE5D85DD2AC9AF72009680C6 /* Services */ = {
 			isa = PBXGroup;
 			children = (
+				F844A8AA2C874802007EA48A /* CommentService.swift */,
+				F844A8A92C874802007EA48A /* PostService.swift */,
+				F844A8AB2C874802007EA48A /* UserService.swift */,
 				AE5D85E02AC9AFA9009680C6 /* AuthenticationService.swift */,
 			);
 			path = Services;
@@ -161,7 +206,10 @@
 		AE5D85DF2AC9AF83009680C6 /* Models */ = {
 			isa = PBXGroup;
 			children = (
+				F844A8B02C87480F007EA48A /* Comment.swift */,
+				F844A8AF2C87480F007EA48A /* Post.swift */,
 				AE5D85E72AC9B29A009680C6 /* User.swift */,
+				F83545442C875D9300AB9C9E /* FullPostViewModel.swift */,
 			);
 			path = Models;
 			sourceTree = "<group>";
@@ -238,7 +286,7 @@
 			attributes = {
 				BuildIndependentTargetsInParallel = 1;
 				LastSwiftUpdateCheck = 1420;
-				LastUpgradeCheck = 1420;
+				LastUpgradeCheck = 1540;
 				TargetAttributes = {
 					AE5D85AB2AC8A221009680C6 = {
 						CreatedOnToolsVersion = 14.2;
@@ -305,9 +353,25 @@
 			buildActionMask = 2147483647;
 			files = (
 				AE5D85E12AC9AFA9009680C6 /* AuthenticationService.swift in Sources */,
+				F83545472C875DAC00AB9C9E /* FullPostView.swift in Sources */,
+				F844A8B82C875538007EA48A /* DateExtension.swift in Sources */,
+				F844A8B12C87480F007EA48A /* Post.swift in Sources */,
+				F844A8B62C874D56007EA48A /* CreatePostView.swift in Sources */,
+				F8304C5F2C888C0500B4BBC9 /* PostCardView.swift in Sources */,
+				25F17D2F2C870CAD001CEF06 /* LoginView.swift in Sources */,
+				F8A25B612C884FF6009AE361 /* LogoutConfirmationView.swift in Sources */,
 				AE5D85E62AC9B077009680C6 /* AuthenticationServiceProtocol.swift in Sources */,
+				F844A8AC2C874802007EA48A /* PostService.swift in Sources */,
+				F844A8AD2C874802007EA48A /* CommentService.swift in Sources */,
+				F8304C5D2C888BF000B4BBC9 /* FeedView.swift in Sources */,
 				AE5D85B02AC8A221009680C6 /* MobileAcebookApp.swift in Sources */,
+				F87BD8272C88AF5E0071F4D3 /* MainView.swift in Sources */,
+				F82DA57C2C89BC6800CA8A56 /* PhotoPicker.swift in Sources */,
+				F83545452C875D9300AB9C9E /* FullPostViewModel.swift in Sources */,
+				F844A8B22C87480F007EA48A /* Comment.swift in Sources */,
+				F844A8AE2C874802007EA48A /* UserService.swift in Sources */,
 				AE5D85E82AC9B29A009680C6 /* User.swift in Sources */,
+				25F17D2D2C870C9F001CEF06 /* SignUpView.swift in Sources */,
 				AE5D85DA2AC8A337009680C6 /* WelcomePageView.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -383,6 +447,7 @@
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
+				ENABLE_USER_SCRIPT_SANDBOXING = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_NO_COMMON_BLOCKS = YES;
@@ -443,6 +508,7 @@
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				ENABLE_NS_ASSERTIONS = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_USER_SCRIPT_SANDBOXING = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
diff --git a/MobileAcebook/.DS_Store b/MobileAcebook/.DS_Store
new file mode 100644
index 00000000..c9824d14
Binary files /dev/null and b/MobileAcebook/.DS_Store differ
diff --git a/MobileAcebook/Assets.xcassets/.DS_Store b/MobileAcebook/Assets.xcassets/.DS_Store
new file mode 100644
index 00000000..66338794
Binary files /dev/null and b/MobileAcebook/Assets.xcassets/.DS_Store differ
diff --git a/MobileAcebook/CreatePostView.swift b/MobileAcebook/CreatePostView.swift
new file mode 100644
index 00000000..a7d76965
--- /dev/null
+++ b/MobileAcebook/CreatePostView.swift
@@ -0,0 +1,128 @@
+import SwiftUI
+import PhotosUI
+
+struct CreatePostView: View {
+    @State private var userInput: String = ""
+    @State private var showAlert: Bool = false
+    @State private var alertTitle: String = ""
+    @State private var alertMessage: String = ""
+    @State private var selectedImage: UIImage? = nil
+    @State private var showPhotoPicker = false
+    @State private var isUploadingImage = false
+    @Environment(\.presentationMode) var presentationMode  // Handle modal dismissal
+
+    var body: some View {
+        VStack(alignment: .center) {
+            HStack {
+                // Cancel Button to dismiss CreatePostView
+                Button(action: {
+                    self.presentationMode.wrappedValue.dismiss()  // Dismiss the view
+                }) {
+                    Text("Cancel")
+                        .foregroundColor(.blue)
+                }
+                .padding(.leading, 20)
+                Spacer()
+            }
+            .padding(.top, 20)
+
+            Spacer()
+
+            Text("Make a Post")
+                .font(.largeTitle)
+                .bold()
+                .padding(.bottom, 20)
+
+            // Post Text Field - Centered
+            TextField(
+                "Post text, lorem ipsum day...",
+                text: $userInput,
+                axis: .vertical
+            )
+            .textFieldStyle(.roundedBorder)
+            .lineLimit(10, reservesSpace: true)
+            .multilineTextAlignment(.leading)
+            .frame(minWidth: 100, maxWidth: 400, minHeight: 100, maxHeight: 250)
+            .padding(.horizontal, 20)
+
+            // Show selected image preview
+            if let image = selectedImage {
+                Image(uiImage: image)
+                    .resizable()
+                    .scaledToFit()
+                    .frame(width: 200, height: 200)
+                    .cornerRadius(10)
+            }
+
+            // Action Buttons - Centered
+            HStack(alignment: .center, spacing: 20) {
+                Button("Add Image") {
+                    showPhotoPicker = true  // Show the photo picker
+                }
+                .frame(width: 120, height: 44)
+                .background(Color.blue)
+                .cornerRadius(40)
+                .foregroundColor(.white)
+
+                Button("Create Post") {
+                    Task {
+                        do {
+                            var imageUrl: String? = nil
+                            if let selectedImage = selectedImage {
+                                isUploadingImage = true
+                                // Upload the image to Cloudinary and get the image URL
+                                imageUrl = try await PostService.uploadImageToCloudinary(image: selectedImage)
+                            }
+
+                            // Create the post with or without an image URL
+                            _ = try await PostService.createPost(message: userInput, image: selectedImage)
+                            
+                            // Show success alert
+                            alertTitle = "Post Created"
+                            alertMessage = "Your post has been created successfully."
+                            showAlert = true
+                            
+                        } catch {
+                            // Show error alert
+                            alertTitle = "Error"
+                            alertMessage = "Failed to create the post. Please try again."
+                            showAlert = true
+                        }
+                    }
+                }
+                .frame(width: 120, height: 44)
+                .background(Color.blue)
+                .cornerRadius(40)
+                .foregroundColor(.white)
+                .disabled(isUploadingImage)  // Disable if image is uploading
+            }
+            .padding(.top, 30)
+
+            Spacer()
+
+            // Alert for showing success or error message
+            .alert(isPresented: $showAlert) {
+                Alert(
+                    title: Text(alertTitle),
+                    message: Text(alertMessage),
+                    dismissButton: .default(Text("OK"), action: {
+                        if alertTitle == "Post Created" {
+                            // Dismiss the CreatePostView modal and return to MainView
+                            self.presentationMode.wrappedValue.dismiss()
+                        }
+                    })
+                )
+            }
+        }
+        .background(Color(red: 0, green: 0.96, blue: 1).ignoresSafeArea())  // Cover entire screen with background color
+        .navigationBarHidden(true)  // Hide default navigation bar
+        .sheet(isPresented: $showPhotoPicker) {
+            // Use SwiftUI's photo picker
+            PhotoPicker(selectedImage: $selectedImage)
+        }
+    }
+}
+
+#Preview {
+    CreatePostView()
+}
diff --git a/MobileAcebook/DateExtension.swift b/MobileAcebook/DateExtension.swift
new file mode 100644
index 00000000..d06ac05e
--- /dev/null
+++ b/MobileAcebook/DateExtension.swift
@@ -0,0 +1,16 @@
+//
+//  DateExtension.swift
+//  MobileAcebook
+//
+//  Created by Sam Quincey on 03/09/2024.
+//
+
+import Foundation
+
+extension Date {
+    func iso8601String() -> String {
+        let formatter = ISO8601DateFormatter()
+        formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
+        return formatter.string(from: self)
+    }
+}
diff --git a/MobileAcebook/FeedView.swift b/MobileAcebook/FeedView.swift
new file mode 100644
index 00000000..6b319a78
--- /dev/null
+++ b/MobileAcebook/FeedView.swift
@@ -0,0 +1,140 @@
+import SwiftUI
+
+struct FeedView: View {
+    @Binding var shouldRefresh: Bool  // Use binding to trigger refresh
+    @State private var posts: [Post] = []  // To store the fetched posts
+    @State private var isLoading: Bool = true  // To show loading state
+    @State private var errorMessage: String?  // To handle and show errors
+
+    var body: some View {
+        VStack {
+            if isLoading {
+                ProgressView("Loading posts...")  // Show loading indicator
+            } else if let errorMessage = errorMessage {
+                Text("Error: \(errorMessage)")
+                    .foregroundColor(.red)
+                    .padding()
+            } else if posts.isEmpty {
+                Text("No posts available.")
+                    .padding()
+            } else {
+                ScrollView {
+                    VStack(spacing: 10) {  // Add some spacing between posts
+                        // Display the posts in reversed order (newest first)
+                        ForEach(posts.reversed()) { post in
+                            PostView(post: post)
+                                .padding(.bottom, 10)
+                        }
+                    }
+                    .padding(.horizontal)
+                    .padding(.bottom, 100)  // Extra padding to avoid overlap with the navigation bar
+                }
+            }
+        }
+        .onAppear {
+            fetchPosts()  // Fetch posts when the view appears
+        }
+        .onChange(of: shouldRefresh) { newValue in
+            if newValue {
+                fetchPosts()  // Refetch posts when shouldRefresh is true
+                shouldRefresh = false  // Reset the refresh flag
+            }
+        }
+        .background(Color(red: 0, green: 0.48, blue: 1).opacity(0.28))
+        .frame(maxWidth: .infinity, maxHeight: .infinity)
+    }
+
+    private func fetchPosts() {
+        Task {
+            do {
+                let fetchedPosts = try await PostService.fetchPosts()
+                DispatchQueue.main.async {
+                    print(fetchedPosts)  // Check if posts are being received
+                    self.posts = fetchedPosts
+                    self.isLoading = false
+                }
+            } catch {
+                DispatchQueue.main.async {
+                    self.errorMessage = "Failed to load posts."
+                    self.isLoading = false
+                    print("Error fetching posts: \(error.localizedDescription)")
+                }
+            }
+        }
+    }
+}
+
+struct PostView: View {
+    let post: Post
+    @State private var showFullPostView = false  // State to control showing FullPostView
+
+    var body: some View {
+        ZStack {
+            // The grey background placeholder or image
+            if let imgUrl = post.imgUrl, let url = URL(string: imgUrl) {
+                AsyncImage(url: url) { image in
+                    image
+                        .resizable()
+                        .frame(width: 192, height: 217)  // Same size as before
+                        .cornerRadius(48)
+                        .padding(.trailing, 140)  // Image aligned to left with padding
+                        .onTapGesture {
+                            showFullPostView.toggle()  // Show FullPostView when tapped
+                        }
+                } placeholder: {
+                    Rectangle()
+                        .foregroundColor(Color.gray.opacity(0.3))
+                        .frame(width: 192, height: 217)
+                        .cornerRadius(48)
+                        .padding(.trailing, 140)
+                        .onTapGesture {
+                            showFullPostView.toggle()  // Show FullPostView even if no image is present
+                        }
+                }
+            } else {
+                Rectangle()
+                    .foregroundColor(Color.gray.opacity(0.3))
+                    .frame(width: 192, height: 217)
+                    .cornerRadius(48)
+                    .padding(.trailing, 140)
+                    .onTapGesture {
+                        showFullPostView.toggle()  // Show FullPostView if no image is present
+                    }
+            }
+
+            // Post message on the right side
+            Text("\(post.message)")
+                .font(Font.custom("SF Pro", size: 17))
+                .foregroundColor(.black)
+                .frame(width: 135, height: 137, alignment: .topLeading)
+                .padding(.leading, 200)
+
+            // Heart icon to show like status
+            Image(systemName: checkIfLiked(userId: post.id, post: post) ? "heart.fill" : "heart")
+                .resizable()
+                .frame(width: 35, height: 35)
+                .foregroundColor(checkIfLiked(userId: post.id, post: post) ? .red : .black)
+                .padding(.top, 200)
+                .padding(.leading, 200)
+        }
+        .frame(width: 393, height: 259)
+        .background(.white)
+        .cornerRadius(48)
+        .fullScreenCover(isPresented: $showFullPostView) {
+            // Show FullPostView in full screen when triggered
+            FullPostView(postId: post.id, token: AuthenticationService.shared.getToken() ?? "")
+        }
+    }
+}
+
+
+// Helper function to check if a post is liked
+func checkIfLiked(userId: String, post: Post) -> Bool {
+    return post.likes.contains(userId)
+}
+
+struct FeedView_Previews: PreviewProvider {
+    static var previews: some View {
+        FeedView(shouldRefresh: .constant(false))
+    }
+}
diff --git a/MobileAcebook/FullPostView.swift b/MobileAcebook/FullPostView.swift
new file mode 100644
index 00000000..fe861822
--- /dev/null
+++ b/MobileAcebook/FullPostView.swift
@@ -0,0 +1,225 @@
+import SwiftUI
+
+struct FullPostView: View {
+    @StateObject private var viewModel = FullPostViewModel()
+    let postId: String
+    let token: String
+    
+    @State private var commentText: String = ""  // To store the new comment text
+    @State private var isAddingComment = false  // To track comment submission
+    @State private var submissionError: Bool = false  // Handle errors during comment submission
+    
+    @Environment(\.dismiss) private var dismiss  // For dismissing the view
+    
+    var body: some View {
+        VStack {
+            // Dismiss button
+            HStack {
+                Button(action: {
+                    dismiss()  // Close the view when tapped
+                }) {
+                    Image(systemName: "xmark.circle.fill")
+                        .resizable()
+                        .frame(width: 30, height: 30)
+                        .foregroundColor(.black)
+                        .padding(.leading, 20)
+                        .padding(.top, 10)
+                }
+                Spacer()
+            }
+
+            ScrollView {
+                VStack(alignment: .leading, spacing: 16) {
+                    if viewModel.hasError {
+                        mockPostView  // If there's an error, show the mock post
+                    } else if let post = viewModel.post {
+                        // Display the image and message...
+                        if let imageUrl = post.imgUrl {
+                            AsyncImage(url: URL(string: imageUrl)) { image in
+                                image
+                                    .resizable()
+                                    .aspectRatio(contentMode: .fit)
+                                    .cornerRadius(10)
+                            } placeholder: {
+                                Rectangle()
+                                    .fill(Color.gray.opacity(0.3))
+                                    .frame(height: 200)
+                                    .cornerRadius(10)
+                            }
+                        } else {
+                            Rectangle()
+                                .fill(Color.gray.opacity(0.3))
+                                .frame(height: 200)
+                                .cornerRadius(10)
+                        }
+                        
+                        Text(post.message)
+                            .font(.body)
+                            .padding(.horizontal)
+                        
+                        // Like Button for a real post
+                        likeButton(isMock: false)
+                        
+                        Divider()
+                        
+                        // Comments Section
+                        Text("Comments")
+                            .font(.headline)
+                            .padding(.horizontal)
+                        
+                        if let comments = viewModel.comments {
+                            ForEach(comments) { comment in
+                                VStack(alignment: .leading, spacing: 8) {
+                                    Text(comment.createdBy.username)
+                                        .font(.caption)
+                                        .foregroundColor(.gray)
+                                    Text(comment.message)
+                                        .font(.body)
+                                    Divider()
+                                }
+                                .padding(.horizontal)
+                            }
+                        } else {
+                            Text("No comments yet.")
+                                .padding(.horizontal)
+                        }
+                    } else {
+                        // Loading state (Optional)
+                        Text("Loading...")
+                            .padding(.horizontal)
+                    }
+                }
+            }
+            
+            // Add Comment Section
+            VStack {
+                HStack {
+                    TextField("Add a comment...", text: $commentText)
+                        .textFieldStyle(RoundedBorderTextFieldStyle())
+                        .frame(height: 44)
+                        .padding(.horizontal)
+                    
+                    Button(action: {
+                        if !commentText.isEmpty {
+                            isAddingComment = true
+                            submissionError = false  // Reset any previous submission error
+                            CommentService.shared.createComment(message: commentText, forPostId: postId) { success, error in
+                                if success {
+                                    // Comment added successfully, now refresh the comments
+                                    viewModel.fetchComments(postId: postId, token: token)
+                                    commentText = ""  // Clear the text field
+                                } else {
+                                    // Handle error during comment submission
+                                    submissionError = true
+                                }
+                                isAddingComment = false
+                            }
+                        }
+                    }) {
+                        Image(systemName: "paperplane.fill")
+                            .resizable()
+                            .frame(width: 44, height: 44)
+                            .foregroundColor(.blue)
+                    }
+                    .disabled(isAddingComment)  // Disable button when adding comment
+                    .padding(.trailing)
+                }
+                .padding(.horizontal)
+                
+                // Show error message if comment submission fails
+                if submissionError {
+                    Text("Failed to submit comment. Please try again.")
+                        .foregroundColor(.red)
+                        .font(.caption)
+                        .padding(.horizontal)
+                }
+            }
+            .padding()
+        }
+        .navigationBarTitleDisplayMode(.inline)
+        .onAppear {
+            // Fetch the post and comments when the view appears
+            viewModel.fetchPost(postId: postId, token: token)
+            viewModel.fetchComments(postId: postId, token: token)
+        }
+    }
+    
+    // Mock Post View
+    private var mockPostView: some View {
+        VStack(alignment: .leading, spacing: 8) {
+            Rectangle()
+                .fill(Color.gray.opacity(0.3))
+                .frame(height: 200)
+                .cornerRadius(10)
+                .padding(.horizontal)
+                .padding(.top, 16)
+            
+            Text("This is a mock post. The original post could not be loaded.")
+                .font(.body)
+                .padding(.horizontal)
+            
+            // Like Button for the mock post
+            likeButton(isMock: true)
+            
+            Divider()
+                .padding(.horizontal)
+            
+            // Mock Comments Section
+            Text("Comments")
+                .font(.headline)
+                .padding(.horizontal)
+            
+            VStack(alignment: .leading, spacing: 8) {
+                Text("This is a mock comment.")
+                    .font(.body)
+                Divider()
+                Text("This is another mock comment.")
+                    .font(.body)
+            }
+            .padding(.horizontal)
+            
+            Spacer()
+        }
+    }
+    
+    // Like Button logic based on whether it's a mock post or real post
+    @ViewBuilder
+    private func likeButton(isMock: Bool) -> some View {
+        HStack {
+            Spacer()
+            Button(action: {
+                if isMock {
+                    // Toggle like for mock, no server update
+                    viewModel.isLiked.toggle()
+                } else {
+                    // Toggle like for real post, send server update
+                    viewModel.toggleLike(postId: postId, token: token)
+                }
+            }) {
+                HStack(alignment: .center, spacing: 3) {
+                    Image(systemName: viewModel.isLiked ? "heart.fill" : "heart")
+                        .resizable()
+                        .frame(width: 24, height: 24)
+                        .foregroundColor(viewModel.isLiked ? .red : .black)
+                    
+                    // Show the number of likes
+                    Text("\(viewModel.post?.likes.count ?? 0)")
+                        .font(.body)
+                        .foregroundColor(viewModel.isLiked ? .red : .black)
+                }
+                .padding(.horizontal, 10)
+                .padding(.vertical, 4)
+                .frame(height: 44, alignment: .center)  // Fixed height to prevent resizing
+                .background(Color.clear) // Transparent background
+                .cornerRadius(40)
+                .overlay(
+                    RoundedRectangle(cornerRadius: 40)
+                        .stroke(viewModel.isLiked ? Color.red : Color.black, lineWidth: 2) // Add border to maintain button shape
+                )
+            }
+            Spacer().frame(width: 20)
+        }
+        .padding(.horizontal)
+    }
+}
+
diff --git a/MobileAcebook/LoginView.swift b/MobileAcebook/LoginView.swift
new file mode 100644
index 00000000..881fcdab
--- /dev/null
+++ b/MobileAcebook/LoginView.swift
@@ -0,0 +1,111 @@
+import SwiftUI
+
+struct LoginView: View {
+    @State private var email: String = ""
+    @State private var password: String = ""
+    @State private var errorMessage: String?
+    @State private var isLoggedIn: Bool = false
+    @State private var isSignUpViewPresented: Bool = false  // State to trigger SignUpView presentation
+
+    func submit() {
+        AuthenticationService.shared.login(email: email.lowercased(), password: password) { success, error in
+            if success {
+                DispatchQueue.main.async {
+                    print("User logged in successfully")
+                    isLoggedIn = true
+                }
+            } else {
+                DispatchQueue.main.async {
+                    errorMessage = error
+                }
+            }
+        }
+    }
+
+    var body: some View {
+        VStack {
+            Text("Login!")
+                .font(.system(size: 40, weight: .bold))
+                .multilineTextAlignment(.center)
+                .foregroundColor(.black)
+                .frame(width: 288, height: 79, alignment: .center)
+
+            VStack {
+                VStack {
+                    // Email input field
+                    TextField("Enter Email", text: $email)
+                        .onChange(of: email) { newValue in
+                            email = newValue.lowercased()
+                        }
+                        .padding(.leading, 16)
+                        .padding(.vertical, 15)
+                        .frame(maxWidth: .infinity, alignment: .topLeading)
+                        .background(Color.white.opacity(0.95))
+                        .font(.system(size: 17))
+
+                    // Password input field
+                    SecureField("Enter Password", text: $password)
+                        .padding(.leading, 16)
+                        .padding(.vertical, 15)
+                        .frame(maxWidth: .infinity, alignment: .topLeading)
+                        .background(Color.white.opacity(0.95))
+                }
+                .frame(width: 302, height: 180)
+                .cornerRadius(10)
+
+                // Show error message if any
+                if let errorMessage = errorMessage {
+                    Text(errorMessage)
+                        .foregroundColor(.red)
+                        .multilineTextAlignment(.center)
+                        .padding()
+                }
+
+                // Login button
+                Button(action: submit) {
+                    Text("Login!")
+                        .font(.system(size: 20))
+                        .foregroundColor(.white)
+                }
+                .padding(.horizontal, 10)
+                .padding(.vertical, 4)
+                .frame(width: 113, height: 48)
+                .background(Color.blue)
+                .cornerRadius(40)
+
+                // Sign-up prompt
+                Button(action: {
+                    isSignUpViewPresented = true
+                }) {
+                    Text("Don't have an account? Sign up!")
+                        .font(.system(size: 18))
+                        .multilineTextAlignment(.center)
+                        .foregroundColor(Color.blue)
+                }
+                .padding(.top, 10)
+
+                // Navigation to MainView after login
+                NavigationLink(destination: MainView(), isActive: $isLoggedIn) {
+                    EmptyView()
+                }
+
+                // Navigation to SignUpView
+                NavigationLink(destination: SignUpView(), isActive: $isSignUpViewPresented) {
+                    EmptyView()
+                }
+            }
+            .frame(width: 335, height: 432)
+            .background(Color.white.opacity(0.75))
+            .cornerRadius(48)
+        }
+        .frame(maxWidth: .infinity, maxHeight: .infinity)
+        .background(Color(red: 0, green: 0.96, blue: 1))
+        .navigationBarBackButtonHidden(true)
+    }
+}
+
+struct LoginView_Previews: PreviewProvider {
+    static var previews: some View {
+        LoginView()
+    }
+}
diff --git a/MobileAcebook/LogoutConfirmationView.swift b/MobileAcebook/LogoutConfirmationView.swift
new file mode 100644
index 00000000..ed5562e4
--- /dev/null
+++ b/MobileAcebook/LogoutConfirmationView.swift
@@ -0,0 +1,52 @@
+import SwiftUI
+
+struct LogoutConfirmationView: View {
+    @Binding var isShowing: Bool
+    let onLogout: () -> Void
+    
+    var body: some View {
+        VStack {
+            Text("Are you sure about logging out?")
+                .font(.headline)
+                .padding(.top, 20)
+            
+            Spacer()
+            
+            HStack {
+                Button(action: {
+                    // Dismiss the pop-up
+                    isShowing = false
+                }) {
+                    Text("No")
+                        .foregroundColor(.blue)
+                        .padding()
+                }
+                
+                Spacer()
+                
+                Button(action: {
+                    // Perform the logout action
+                    onLogout()  // Log out the user and navigate back
+                }) {
+                    Text("Log me out")
+                        .foregroundColor(.blue)
+                        .padding()
+                }
+            }
+            .padding([.leading, .trailing, .bottom], 20)
+        }
+        .frame(width: 300, height: 150)
+        .background(Color.white.opacity(0.85))
+        .cornerRadius(10)
+        .shadow(radius: 10)
+    }
+}
+
+struct LogoutConfirmationView_Previews: PreviewProvider {
+    @State static var isShowing = true
+    static var previews: some View {
+        LogoutConfirmationView(isShowing: $isShowing, onLogout: {
+            print("Logged out")
+        })
+    }
+}
diff --git a/MobileAcebook/MainView.swift b/MobileAcebook/MainView.swift
new file mode 100644
index 00000000..2f5e6184
--- /dev/null
+++ b/MobileAcebook/MainView.swift
@@ -0,0 +1,92 @@
+import SwiftUI
+
+struct MainView: View {
+    @State private var isLogoutPopupShowing = false  // Control logout pop-up visibility
+    @State private var showCreatePostView = false  // Control showing the Create Post view
+    @State private var navigateToWelcome = false   // Handle navigation to WelcomePageView after logout
+    @State private var shouldRefreshFeed = false   // Trigger feed refresh
+
+    init() {
+        // Configure tab bar appearance
+        let tabBarAppearance = UITabBarAppearance()
+        tabBarAppearance.backgroundColor = UIColor.white
+        tabBarAppearance.stackedLayoutAppearance.normal.iconColor = UIColor.systemBlue
+        tabBarAppearance.stackedLayoutAppearance.selected.iconColor = UIColor.systemBlue
+        
+        UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance
+        UITabBar.appearance().standardAppearance = tabBarAppearance
+    }
+
+    var body: some View {
+        ZStack {
+            // Show Feed and pass in the refresh control
+            FeedView(shouldRefresh: $shouldRefreshFeed)
+
+            VStack {
+                Spacer() // Pushes the tab bar to the bottom
+
+                // TabView-style bar
+                HStack {
+                    Spacer()
+
+                    // Logout Button (Triggers logout popup)
+                    Button(action: {
+                        isLogoutPopupShowing = true
+                    }) {
+                        VStack {
+                            Image(systemName: "person.slash.fill")
+                            Text("Logout")
+                        }
+                    }
+                    Spacer()
+
+                    // Create Post Button (Navigates to Create Post view using fullScreenCover)
+                    Button(action: {
+                        showCreatePostView = true
+                    }) {
+                        VStack {
+                            Image(systemName: "plus.circle.fill")
+                            Text("Create Post")
+                        }
+                    }
+                    Spacer()
+
+                    // Refresh Button (Triggers feed refresh)
+                    Button(action: {
+                        print("Refreshing feed...")
+                        shouldRefreshFeed = true  // Set refresh flag to true
+                    }) {
+                        VStack {
+                            Image(systemName: "arrow.clockwise")
+                            Text("Refresh")
+                        }
+                    }
+                    Spacer()
+                }
+                .padding()
+                .background(Color.white)
+            }
+            
+            // Show logout confirmation popup
+            if isLogoutPopupShowing {
+                LogoutConfirmationView(isShowing: $isLogoutPopupShowing, onLogout: {
+                    AuthenticationService.shared.logout()  // Perform logout
+                    navigateToWelcome = true  // Navigate to WelcomePageView
+                })
+                .transition(.opacity)
+                .animation(.easeInOut, value: isLogoutPopupShowing)
+            }
+        }
+        // Present CreatePostView in a full screen mode without NavigationView
+        .fullScreenCover(isPresented: $showCreatePostView) {
+            CreatePostView()
+        }
+        // Navigate to the Welcome screen after logout
+        .fullScreenCover(isPresented: $navigateToWelcome) {
+            WelcomePageView()  // Assume WelcomePageView exists
+        }
+        // Ensure the navigation bar is hidden
+        .navigationBarBackButtonHidden(true)
+        .navigationBarHidden(true)
+    }
+}
diff --git a/MobileAcebook/Models/.DS_Store b/MobileAcebook/Models/.DS_Store
new file mode 100644
index 00000000..87967912
Binary files /dev/null and b/MobileAcebook/Models/.DS_Store differ
diff --git a/MobileAcebook/Models/Comment.swift b/MobileAcebook/Models/Comment.swift
new file mode 100644
index 00000000..d5c753c7
--- /dev/null
+++ b/MobileAcebook/Models/Comment.swift
@@ -0,0 +1,40 @@
+//
+//  Comment.swift
+//  MobileAcebook
+//
+//  Created by Sam Quincey on 03/09/2024.
+//
+
+import Foundation
+
+struct Comment: Codable, Identifiable {
+    let id: String
+    let message: String   // The text content of the comment
+    let createdAt: String   // The creation date of the comment
+    let createdBy: User   // The user who created the comment
+    
+    enum CodingKeys: String, CodingKey {
+        case id = "_id"  // Map MongoDB _id to id in Swift
+        case message
+        case createdAt
+        case createdBy
+    }
+    
+//    // Custom initializer to decode the `createdAt` field as a Date from a String
+//    init(from decoder: Decoder) throws {
+//        let container = try decoder.container(keyedBy: CodingKeys.self)
+//        
+//        id = try container.decode(String.self, forKey: .id)
+//        message = try container.decode(String.self, forKey: .message)
+//        createdBy = try container.decode(User.self, forKey: .createdBy)
+//        
+//        // Decode `createdAt` as a string and convert it to a `Date`
+//        let createdAtString = try container.decode(String.self, forKey: .createdAt)
+//        let formatter = ISO8601DateFormatter()
+//        if let date = formatter.date(from: createdAtString) {
+//            createdAt = date
+//        } else {
+//            throw DecodingError.dataCorruptedError(forKey: .createdAt, in: container, debugDescription: "Date string does not match format expected by formatter.")
+//        }
+//    }
+}
diff --git a/MobileAcebook/Models/FullPostViewModel.swift b/MobileAcebook/Models/FullPostViewModel.swift
new file mode 100644
index 00000000..66d4458c
--- /dev/null
+++ b/MobileAcebook/Models/FullPostViewModel.swift
@@ -0,0 +1,74 @@
+import Foundation
+import Combine
+
+class FullPostViewModel: ObservableObject {
+    @Published var post: Post?
+    @Published var comments: [Comment]?
+    @Published var isLiked: Bool = false
+    @Published var hasError: Bool = false  // Add this property to track errors
+    
+    func fetchPost(postId: String, token: String) {
+        Task {
+            do {
+                let posts = try await PostService.fetchPosts() // Static call
+                if let fetchedPost = posts.first(where: { $0.id == postId }) {
+                    DispatchQueue.main.async {
+                        self.post = fetchedPost
+                        self.isLiked = fetchedPost.likes.contains(token)  // Check if user has already liked the post
+                        self.hasError = false  // Reset the error state
+                    }
+                } else {
+                    DispatchQueue.main.async {
+                        self.hasError = true  // Set error state if no post found
+                    }
+                }
+            } catch {
+                print("Error fetching post: \(error)")
+                DispatchQueue.main.async {
+                    self.hasError = true  // Set error state if there's an error
+                }
+            }
+        }
+    }
+    
+    func fetchComments(postId: String, token: String) {
+        CommentService.shared.fetchComments(forPostId: postId) { [weak self] comments, error in
+            guard let self = self else { return }
+
+            if let error = error {
+                DispatchQueue.main.async {
+                    print("Error fetching comments: \(error)")
+                    self.hasError = true
+                }
+                return
+            }
+
+            DispatchQueue.main.async {
+                self.comments = comments ?? []
+                self.hasError = false
+            }
+        }
+    }
+    
+    func toggleLike(postId: String, token: String) {
+        guard post != nil else { return }
+
+        isLiked.toggle()  // Toggle the isLiked state locally
+
+        Task {
+            do {
+                let success = try await PostService.updateLikes(postId: postId) // Static call
+                if !success {
+                    DispatchQueue.main.async {
+                        self.isLiked.toggle()  // Revert the isLiked state on failure
+                    }
+                }
+            } catch {
+                print("Error updating likes: \(error)")
+                DispatchQueue.main.async {
+                    self.isLiked.toggle()  // Revert the isLiked state on error
+                }
+            }
+        }
+    }
+}
diff --git a/MobileAcebook/Models/Post.swift b/MobileAcebook/Models/Post.swift
new file mode 100644
index 00000000..0a213557
--- /dev/null
+++ b/MobileAcebook/Models/Post.swift
@@ -0,0 +1,27 @@
+//
+//  Post.swift
+//  MobileAcebook
+//
+//  Created by Sam Quincey on 03/09/2024.
+//
+
+import Foundation
+
+struct Post: Codable, Identifiable {
+    let id: String
+    let message: String
+    let createdAt: String
+    let createdBy: User // The user data associated with the post
+    let imgUrl: String?
+    let likes: [String]
+
+    enum CodingKeys: String, CodingKey {
+        case id = "_id"  // Map MongoDB _id to id in Swift
+        case message
+        case createdAt
+        case createdBy
+        case imgUrl
+        case likes
+    }
+}
+
diff --git a/MobileAcebook/Models/User.swift b/MobileAcebook/Models/User.swift
index ea748dd0..4c3343c5 100644
--- a/MobileAcebook/Models/User.swift
+++ b/MobileAcebook/Models/User.swift
@@ -4,8 +4,18 @@
 //
 //  Created by Josué Estévez Fernández on 01/10/2023.
 //
+import Foundation
 
-public struct User {
+struct User: Codable, Identifiable {
+    let id: String
+    let email: String
     let username: String
-    let password: String
+    let imgUrl: String?
+
+    enum CodingKeys: String, CodingKey {
+        case id = "_id" // Map the MongoDB _id to id in Swift
+        case email
+        case username
+        case imgUrl
+    }
 }
diff --git a/MobileAcebook/PhotoPicker.swift b/MobileAcebook/PhotoPicker.swift
new file mode 100644
index 00000000..4428b8bb
--- /dev/null
+++ b/MobileAcebook/PhotoPicker.swift
@@ -0,0 +1,48 @@
+//
+//  PhotoPicker.swift
+//  MobileAcebook
+//
+//  Created by Sam Quincey on 05/09/2024.
+//
+
+import SwiftUI
+import PhotosUI
+
+struct PhotoPicker: UIViewControllerRepresentable {
+    @Binding var selectedImage: UIImage?
+
+    class Coordinator: NSObject, PHPickerViewControllerDelegate {
+        var parent: PhotoPicker
+
+        init(parent: PhotoPicker) {
+            self.parent = parent
+        }
+
+        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
+            picker.dismiss(animated: true)
+
+            if let result = results.first {
+                result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
+                    guard let self = self, let uiImage = image as? UIImage, error == nil else { return }
+                    DispatchQueue.main.async {
+                        self.parent.selectedImage = uiImage
+                    }
+                }
+            }
+        }
+    }
+
+    func makeCoordinator() -> Coordinator {
+        return Coordinator(parent: self)
+    }
+
+    func makeUIViewController(context: Context) -> PHPickerViewController {
+        var config = PHPickerConfiguration()
+        config.filter = .images
+        let picker = PHPickerViewController(configuration: config)
+        picker.delegate = context.coordinator
+        return picker
+    }
+
+    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {}
+}
diff --git a/MobileAcebook/PostCardView.swift b/MobileAcebook/PostCardView.swift
new file mode 100644
index 00000000..f35e3267
--- /dev/null
+++ b/MobileAcebook/PostCardView.swift
@@ -0,0 +1,89 @@
+import SwiftUI
+
+struct PostCardView: View {
+    let post: Post
+    let userId: String // This is the logged-in user's ID
+    
+    @State private var isLiked: Bool
+    @State private var likesCount: Int
+    
+    init(post: Post, userId: String) {
+        self.post = post
+        self.userId = userId
+        _isLiked = State(initialValue: post.likes.contains(userId))
+        _likesCount = State(initialValue: post.likes.count)
+    }
+    
+    var body: some View {
+        VStack(alignment: .leading) {
+            // Display image (if any)
+            if let imgUrl = post.imgUrl, let url = URL(string: imgUrl) {
+                AsyncImage(url: url) { image in
+                    image
+                        .resizable()
+                        .aspectRatio(contentMode: .fit)
+                        .frame(maxWidth: .infinity)
+                        .cornerRadius(10)
+                } placeholder: {
+                    Rectangle()
+                        .fill(Color.gray.opacity(0.3))
+                        .frame(height: 150)
+                        .cornerRadius(10)
+                }
+            }
+            
+            // Display message
+            Text(post.message)
+                .lineLimit(3) // Limit the message to prevent the card from being too big
+                .truncationMode(.tail)
+                .padding(.vertical, 10)
+            
+            HStack {
+                // Like button and count
+                Button(action: toggleLike) {
+                    HStack {
+                        Image(systemName: isLiked ? "heart.fill" : "heart")
+                            .foregroundColor(isLiked ? .red : .black)
+                        Text("\(likesCount)") // Display the number of likes
+                    }
+                }
+                Spacer()
+                // Show when the post was created
+                Text(formatDate(post.createdAt))
+                    .font(.footnote)
+                    .foregroundColor(.gray)
+            }
+        }
+        .padding()
+        .background(Color.white)
+        .cornerRadius(12)
+        .shadow(radius: 3)
+    }
+    
+    // Handle like toggling
+    private func toggleLike() {
+        Task {
+            do {
+                let success = try await PostService.updateLikes(postId: post.id)
+                if success {
+                    isLiked.toggle()
+                    likesCount += isLiked ? 1 : -1
+                }
+            } catch {
+                print("Error updating likes: \(error)")
+            }
+        }
+    }
+    
+    // Helper function to format date string
+    private func formatDate(_ dateString: String) -> String {
+        let formatter = ISO8601DateFormatter()
+        if let date = formatter.date(from: dateString) {
+            let displayFormatter = DateFormatter()
+            displayFormatter.dateStyle = .medium
+            displayFormatter.timeStyle = .short
+            return displayFormatter.string(from: date)
+        }
+        return dateString
+    }
+}
diff --git a/MobileAcebook/Protocols/AuthenticationServiceProtocol.swift b/MobileAcebook/Protocols/AuthenticationServiceProtocol.swift
index ae012f49..dad84533 100644
--- a/MobileAcebook/Protocols/AuthenticationServiceProtocol.swift
+++ b/MobileAcebook/Protocols/AuthenticationServiceProtocol.swift
@@ -2,9 +2,9 @@
 //  AuthenticationServiceProtocol.swift
 //  MobileAcebook
 //
-//  Created by Josué Estévez Fernández on 01/10/2023.
+////  Created by Josué Estévez Fernández on 01/10/2023.
+////
 //
-
-public protocol AuthenticationServiceProtocol {
-    func signUp(user: User) -> Bool
-}
+//public protocol AuthenticationServiceProtocol {
+//    func signUp(user: User) -> Bool
+//}
diff --git a/MobileAcebook/Services/AuthenticationService.swift b/MobileAcebook/Services/AuthenticationService.swift
index 9f7181c3..4cf0bc0a 100644
--- a/MobileAcebook/Services/AuthenticationService.swift
+++ b/MobileAcebook/Services/AuthenticationService.swift
@@ -2,12 +2,199 @@
 //  AuthenticationService.swift
 //  MobileAcebook
 //
-//  Created by Josué Estévez Fernández on 01/10/2023.
+//  Created by Sam Quincey on 03/09/2024.
 //
 
-class AuthenticationService: AuthenticationServiceProtocol {
-    func signUp(user: User) -> Bool {
-        // Logic to call the backend API for signing up
-        return true // placeholder
+import Foundation
+
+class AuthenticationService {
+    static let shared = AuthenticationService()
+    
+    private let baseURL = "http://localhost:3000"
+    
+    private init() {}
+
+    // "Local Storage" and Authentication frontend
+    private let jwtTokenKey = "jwtToken"
+    
+    // Save token in UserDefaults
+    func saveToken(_ token: String) {
+        UserDefaults.standard.set(token, forKey: jwtTokenKey)
+    }
+    
+    // Retrieve token from UserDefaults
+    func getToken() -> String? {
+        return UserDefaults.standard.string(forKey: jwtTokenKey)
+    }
+    
+    // Check if the user is logged in based on the token
+    func isLoggedIn() -> Bool {
+        return getToken() != nil
+    }
+    
+    // Log out the user by removing the token
+    func logout() {
+        UserDefaults.standard.removeObject(forKey: jwtTokenKey)
+    }
+
+    // MARK: - JWT Decoding Helper
+
+    // Decode the JWT token to extract payload
+    func decodeJWT(_ token: String) -> [String: Any]? {
+        let segments = token.split(separator: ".")
+        guard segments.count == 3 else { return nil }
+
+        let base64String = String(segments[1])
+            .replacingOccurrences(of: "-", with: "+")
+            .replacingOccurrences(of: "_", with: "/")
+
+        guard let decodedData = Data(base64Encoded: base64String, options: .ignoreUnknownCharacters) else {
+            return nil
+        }
+
+        return try? JSONSerialization.jsonObject(with: decodedData, options: []) as? [String: Any]
+    }
+
+    // Retrieve the user ID from the JWT token payload
+    func getUserId() -> String? {
+        guard let token = getToken(), let payload = decodeJWT(token) else { return nil }
+        return payload["user_id"] as? String  // Adjust this key based on your JWT structure
+    }
+
+    // MARK: - Login
+
+    func login(email: String, password: String, completion: @escaping (Bool, String?) -> Void) {
+        guard let url = URL(string: "\(baseURL)/tokens") else {
+            completion(false, "Invalid URL")
+            return
+        }
+        
+        var request = URLRequest(url: url)
+        request.httpMethod = "POST"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        
+        let body: [String: Any] = [
+            "email": email,
+            "password": password
+        ]
+        
+        do {
+            let jsonData = try JSONSerialization.data(withJSONObject: body, options: [])
+            request.httpBody = jsonData
+        } catch {
+            completion(false, "Error encoding login details")
+            return
+        }
+        
+        URLSession.shared.dataTask(with: request) { data, response, error in
+            if let error = error {
+                DispatchQueue.main.async {
+                    completion(false, "Login error: \(error.localizedDescription)")
+                }
+                return
+            }
+            
+            guard let data = data, let httpResponse = response as? HTTPURLResponse else {
+                DispatchQueue.main.async {
+                    completion(false, "No data received")
+                }
+                return
+            }
+            
+            if (200...299).contains(httpResponse.statusCode) {
+                // Handle success response
+                do {
+                    if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
+                       let token = json["token"] as? String {
+                        self.saveToken(token)
+                        DispatchQueue.main.async {
+                            completion(true, nil)
+                        }
+                    } else {
+                        DispatchQueue.main.async {
+                            completion(false, "Invalid login response")
+                        }
+                    }
+                } catch {
+                    DispatchQueue.main.async {
+                        completion(false, "Error parsing response")
+                    }
+                }
+            } else {
+                // Handle HTTP error responses (e.g. 401 Unauthorized)
+                DispatchQueue.main.async {
+                    completion(false, "Login failed with status code: \(httpResponse.statusCode)")
+                }
+            }
+        }.resume()
+    }
+    
+    // MARK: - Sign Up
+    
+    func signUp(username: String, email: String, password: String, completion: @escaping (Bool, String?) -> Void) {
+        guard let url = URL(string: "\(baseURL)/users") else {
+            completion(false, "Invalid URL")
+            return
+        }
+        
+        var request = URLRequest(url: url)
+        request.httpMethod = "POST"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        
+        let body: [String: Any] = [
+            "username": username,
+            "email": email,
+            "password": password
+        ]
+        
+        do {
+            let jsonData = try JSONSerialization.data(withJSONObject: body, options: [])
+            request.httpBody = jsonData
+        } catch {
+            completion(false, "Error encoding sign-up details")
+            return
+        }
+        
+        URLSession.shared.dataTask(with: request) { data, response, error in
+            if let error = error {
+                DispatchQueue.main.async {
+                    completion(false, "Sign-up error: \(error.localizedDescription)")
+                }
+                return
+            }
+            
+            guard let data = data, let httpResponse = response as? HTTPURLResponse else {
+                DispatchQueue.main.async {
+                    completion(false, "No data received")
+                }
+                return
+            }
+            
+            if (200...299).contains(httpResponse.statusCode) {
+                // Handle success response
+                do {
+                    if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
+                       let message = json["message"] as? String, message.contains("created") {
+                        DispatchQueue.main.async {
+                            completion(true, nil)
+                        }
+                    } else {
+                        DispatchQueue.main.async {
+                            completion(false, "Invalid sign-up response")
+                        }
+                    }
+                } catch {
+                    DispatchQueue.main.async {
+                        completion(false, "Error parsing response")
+                    }
+                }
+            } else {
+                // Handle HTTP error responses (e.g. 400 Bad Request)
+                DispatchQueue.main.async {
+                    completion(false, "Sign-up failed with status code: \(httpResponse.statusCode)")
+                }
+            }
+        }.resume()
     }
 }
+
diff --git a/MobileAcebook/Services/CommentService.swift b/MobileAcebook/Services/CommentService.swift
new file mode 100644
index 00000000..2b5ac9a2
--- /dev/null
+++ b/MobileAcebook/Services/CommentService.swift
@@ -0,0 +1,98 @@
+import Foundation
+
+class CommentService {
+    static let shared = CommentService()
+    private let baseURL = "http://localhost:3000"
+    
+    private init() {}
+
+    // Fetch comments for a specific post
+    func fetchComments(forPostId postId: String, completion: @escaping ([Comment]?, Error?) -> Void) {
+        guard let url = URL(string: "\(baseURL)/comments/\(postId)") else { return }
+
+        var request = URLRequest(url: url)
+        request.httpMethod = "GET"
+        
+        // Add token if available
+        if let token = AuthenticationService.shared.getToken() {
+            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
+        }
+        
+        // Define the CommentResponse structure within the function
+        struct CommentResponse: Codable {
+            let message: String
+            let comments: [Comment]
+            let token: String
+        }
+        
+        let task = URLSession.shared.dataTask(with: request) { data, response, error in
+            // Handle network error
+            if let error = error {
+                completion(nil, error)
+                return
+            }
+
+            // Handle HTTP error
+            if let httpResponse = response as? HTTPURLResponse {
+                if httpResponse.statusCode != 200 {
+                    let statusError = NSError(domain: "HTTPError", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: "Server returned status code \(httpResponse.statusCode)"])
+                    completion(nil, statusError)
+                    return
+                }
+            }
+
+            // Ensure there's valid data
+            guard let data = data else {
+                completion(nil, NSError(domain: "DataError", code: 0, userInfo: [NSLocalizedDescriptionKey: "No data returned"]))
+                return
+            }
+
+            // Try decoding the response
+            do {
+                let commentResponse = try JSONDecoder().decode(CommentResponse.self, from: data)
+                completion(commentResponse.comments, nil) // Pass comments array to the completion handler
+            } catch let jsonError {
+                completion(nil, jsonError)
+            }
+        }
+
+        task.resume()
+    }
+
+    
+    // Create a new comment for a specific post
+    func createComment(message: String, forPostId postId: String, completion: @escaping (Bool, Error?) -> Void) {
+        guard let url = URL(string: "\(baseURL)/comments/\(postId)") else { return }
+        
+        var request = URLRequest(url: url)
+        request.httpMethod = "POST"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        if let token = AuthenticationService.shared.getToken() {
+            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
+        }
+        
+        let body: [String: Any] = [
+            "message": message,
+            "createdAt": Date().iso8601String()
+        ]
+        
+        do {
+            let jsonData = try JSONSerialization.data(withJSONObject: body, options: [])
+            request.httpBody = jsonData
+        } catch let encodingError {
+            completion(false, encodingError)
+            return
+        }
+        
+        let task = URLSession.shared.dataTask(with: request) { data, response, error in
+            if let error = error {
+                completion(false, error)
+                return
+            }
+            
+            completion(true, nil)
+        }
+        
+        task.resume()
+    }
+}
diff --git a/MobileAcebook/Services/PostService.swift b/MobileAcebook/Services/PostService.swift
new file mode 100644
index 00000000..21769663
--- /dev/null
+++ b/MobileAcebook/Services/PostService.swift
@@ -0,0 +1,178 @@
+import UIKit
+import Foundation
+
+// PostService to handle network requests related to posts
+class PostService {
+    static let shared = PostService()
+    private static let baseURL = "http://localhost:3000"
+    private static let CLOUDINARY_CLOUD_NAME = "dq51orqba"
+    private static let CLOUDINARY_UPLOAD_PRESET = "jr6ol490"
+    
+    private init() {}
+    
+    // Response struct to decode backend response that contains posts
+    struct PostResponse: Codable {
+        let posts: [Post]
+        let token: String?
+    }
+
+    // Fetch all posts
+    static func fetchPosts() async throws -> [Post] {
+        guard let url = URL(string: "\(baseURL)/posts") else {
+            throw URLError(.badURL)
+        }
+        
+        var request = URLRequest(url: url)
+        if let token = AuthenticationService.shared.getToken() {
+            print("Token: \(token)") // Debug: Token output
+            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
+        }
+        
+        do {
+            let (data, response) = try await URLSession.shared.data(for: request)
+            
+            if let httpResponse = response as? HTTPURLResponse {
+                if httpResponse.statusCode == 200 {
+                    if let jsonString = String(data: data, encoding: .utf8) {
+                        print("Response JSON: \(jsonString)") // Debug: Response JSON output
+                    }
+                    
+                    let decodedResponse = try JSONDecoder().decode(PostResponse.self, from: data)
+                    return decodedResponse.posts
+                } else {
+                    let errorMessage = "Failed to fetch posts: HTTP \(httpResponse.statusCode)"
+                    print(errorMessage)
+                    throw NSError(domain: "", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: errorMessage])
+                }
+            } else {
+                throw NSError(domain: "NetworkError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response from server"])
+            }
+        } catch {
+            print("Error fetching posts: \(error)") // Debug: Error fetching posts
+            throw error
+        }
+    }
+
+    // Create a new post with optional image
+    static func createPost(message: String, image: UIImage?) async throws -> Bool {
+        if let image = image {
+            print("Image selected for upload.") // Debug: Image selected
+            let url = try await uploadImageToCloudinary(image: image)
+            print("Image uploaded to Cloudinary: \(url)") // Debug: Cloudinary image URL
+            return try await createPostWithImage(message: message, imgUrl: url)
+        } else {
+            print("No image selected for upload.") // Debug: No image selected
+            return try await createPostWithImage(message: message, imgUrl: nil)
+        }
+    }
+    
+    // Helper function to create post with or without image URL
+    static private func createPostWithImage(message: String, imgUrl: String?) async throws -> Bool {
+        guard let url = URL(string: "\(baseURL)/posts") else {
+            throw URLError(.badURL)
+        }
+        
+        var request = URLRequest(url: url)
+        request.httpMethod = "POST"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        if let token = AuthenticationService.shared.getToken() {
+            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
+        }
+        
+        let body: [String: Any] = [
+            "message": message,
+            "imgUrl": imgUrl ?? NSNull()
+        ]
+        
+        let jsonData = try JSONSerialization.data(withJSONObject: body, options: [])
+        request.httpBody = jsonData
+        
+        do {
+            let (_, response) = try await URLSession.shared.data(for: request)
+            if let httpResponse = response as? HTTPURLResponse {
+                return httpResponse.statusCode == 200
+            } else {
+                throw NSError(domain: "NetworkError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response from server"])
+            }
+        } catch {
+            print("Error creating post: \(error)")
+            throw error
+        }
+    }
+    
+    // Upload image to Cloudinary
+    static internal func uploadImageToCloudinary(image: UIImage) async throws -> String {
+        // Directly use the constants since they are not optional
+        let cloudName = CLOUDINARY_CLOUD_NAME
+        let uploadPreset = CLOUDINARY_UPLOAD_PRESET
+        
+        let url = URL(string: "https://api.cloudinary.com/v1_1/\(cloudName)/image/upload")!
+        
+        var request = URLRequest(url: url)
+        request.httpMethod = "POST"
+        
+        let boundary = UUID().uuidString
+        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
+        
+        var data = Data()
+        
+        data.append("--\(boundary)\r\n".data(using: .utf8)!)
+        data.append("Content-Disposition: form-data; name=\"upload_preset\"\r\n\r\n".data(using: .utf8)!)
+        data.append("\(uploadPreset)\r\n".data(using: .utf8)!)
+        
+        if let imageData = image.jpegData(compressionQuality: 0.7) {
+            print("Image data size: \(imageData.count) bytes") // Debug: Image data size
+            data.append("--\(boundary)\r\n".data(using: .utf8)!)
+            data.append("Content-Disposition: form-data; name=\"file\"; filename=\"image.jpg\"\r\n".data(using: .utf8)!)
+            data.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)
+            data.append(imageData)
+            data.append("\r\n".data(using: .utf8)!)
+        } else {
+            throw NSError(domain: "ImageError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to convert UIImage to JPEG data"])
+        }
+        
+        data.append("--\(boundary)--\r\n".data(using: .utf8)!)
+        
+        request.httpBody = data
+        
+        do {
+            let (responseData, _) = try await URLSession.shared.data(for: request)
+            if let json = try JSONSerialization.jsonObject(with: responseData, options: []) as? [String: Any],
+               let url = json["secure_url"] as? String {
+                return url
+            } else {
+                throw NSError(domain: "CloudinaryError", code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to upload image."])
+            }
+        } catch {
+            print("Error uploading image to Cloudinary: \(error)") // Debug: Error uploading image
+            throw error
+        }
+    }
+    
+    // Update likes for a post
+    static func updateLikes(postId: String) async throws -> Bool {
+        guard let url = URL(string: "\(baseURL)/posts/\(postId)") else {
+            throw URLError(.badURL)
+        }
+        
+        var request = URLRequest(url: url)
+        request.httpMethod = "PUT"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        if let token = AuthenticationService.shared.getToken() {
+            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
+        }
+        
+        let body: [String: Any] = ["postId": postId]
+        
+        let jsonData = try JSONSerialization.data(withJSONObject: body, options: [])
+        request.httpBody = jsonData
+        
+        let (_, response) = try await URLSession.shared.data(for: request)
+        
+        if let httpResponse = response as? HTTPURLResponse {
+            return httpResponse.statusCode == 200
+        } else {
+            throw NSError(domain: "NetworkError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response from server"])
+        }
+    }
+}
diff --git a/MobileAcebook/Services/UserService.swift b/MobileAcebook/Services/UserService.swift
new file mode 100644
index 00000000..f461c050
--- /dev/null
+++ b/MobileAcebook/Services/UserService.swift
@@ -0,0 +1,109 @@
+//
+//  UserService.swift
+//  MobileAcebook
+//
+//  Created by Sam Quincey on 03/09/2024.
+//
+
+import Foundation
+
+class UserService {
+    static let shared = UserService()
+    private let baseURL = "http://localhost:3000"
+    
+    private init() {}
+    
+    func createUser(email: String, password: String, username: String, completion: @escaping (User?, Error?) -> Void) {
+        guard let url = URL(string: "\(baseURL)/users") else { return }
+        
+        var request = URLRequest(url: url)
+        request.httpMethod = "POST"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        
+        let body: [String: Any] = ["email": email, "password": password, "username": username]
+        
+        do {
+            let jsonData = try JSONSerialization.data(withJSONObject: body, options: [])
+            request.httpBody = jsonData
+        } catch let encodingError {
+            completion(nil, encodingError)
+            return
+        }
+        
+        let task = URLSession.shared.dataTask(with: request) { data, response, error in
+            if let error = error {
+                completion(nil, error)
+                return
+            }
+            
+            guard let data = data else { return }
+            
+            do {
+                let user = try JSONDecoder().decode(User.self, from: data)
+                completion(user, nil)
+            } catch let jsonError {
+                completion(nil, jsonError)
+            }
+        }
+        
+        task.resume()
+    }
+    
+    func getUserDetails(token: String, completion: @escaping (User?, Error?) -> Void) {
+        guard let url = URL(string: "\(baseURL)/users") else { return }
+        
+        var request = URLRequest(url: url)
+        request.httpMethod = "GET"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
+        
+        let task = URLSession.shared.dataTask(with: request) { data, response, error in
+            if let error = error {
+                completion(nil, error)
+                return
+            }
+            
+            guard let data = data else { return }
+            
+            do {
+                let user = try JSONDecoder().decode(User.self, from: data)
+                completion(user, nil)
+            } catch let jsonError {
+                completion(nil, jsonError)
+            }
+        }
+        
+        task.resume()
+    }
+    
+    func updateProfilePicture(token: String, imgUrl: String, completion: @escaping (Bool, Error?) -> Void) {
+        guard let url = URL(string: "\(baseURL)/users") else { return }
+        
+        var request = URLRequest(url: url)
+        request.httpMethod = "PUT"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
+        
+        let body: [String: Any] = ["imgUrl": imgUrl]
+        
+        do {
+            let jsonData = try JSONSerialization.data(withJSONObject: body, options: [])
+            request.httpBody = jsonData
+        } catch let encodingError {
+            completion(false, encodingError)
+            return
+        }
+        
+        let task = URLSession.shared.dataTask(with: request) { data, response, error in
+            if let error = error {
+                completion(false, error)
+                return
+            }
+            
+            completion(true, nil)
+        }
+        
+        task.resume()
+    }
+}
+
diff --git a/MobileAcebook/SignUpView.swift b/MobileAcebook/SignUpView.swift
new file mode 100644
index 00000000..bc6ebd5f
--- /dev/null
+++ b/MobileAcebook/SignUpView.swift
@@ -0,0 +1,138 @@
+import SwiftUI
+
+struct SignUpView: View {
+    @State private var username: String = ""  // Adding username field
+    @State private var email: String = ""
+    @State private var password: String = ""
+    @State private var errorMessage: String?
+    @State private var isSignUpSuccessful: Bool = false
+    @State private var isLoginViewPresented: Bool = false  // State to trigger LoginView presentation
+
+    // Function to handle sign-up
+    func submitSignUp() {
+        AuthenticationService.shared.signUp(username: username, email: email.lowercased(), password: password) { success, error in  // Ensure email is passed in lowercase
+            if success {
+                // Navigate to MainView after successful sign-up
+                DispatchQueue.main.async {
+                    print("User signed up successfully")
+                    isSignUpSuccessful = true  // This triggers the NavigationLink
+                }
+            } else {
+                // Show error message
+                DispatchQueue.main.async {
+                    errorMessage = error
+                }
+            }
+        }
+    }
+
+    var body: some View {
+        NavigationStack {
+            VStack {
+                Spacer()
+
+                Text("Sign Up!")
+                    .font(.system(size: 40, weight: .bold, design: .default))
+                    .multilineTextAlignment(.center)
+                    .foregroundColor(.black)
+                    .frame(width: 288, height: 79, alignment: .center)
+
+                VStack {
+                    VStack {
+                        // Username input field
+                        TextField("Enter Username", text: $username)
+                            .padding(.leading, 16)
+                            .padding(.vertical, 15)
+                            .frame(maxWidth: .infinity, alignment: .topLeading)
+                            .background(Color.white.opacity(0.95))
+                            .font(Font.custom("SF Pro", size: 17))
+
+                        // Email input field
+                        TextField("Enter Email", text: $email)
+                            .onChange(of: email) { newValue in
+                                // Force the email text to lowercase
+                                email = newValue.lowercased()
+                            }
+                            .padding(.leading, 16)
+                            .padding(.vertical, 15)
+                            .frame(maxWidth: .infinity, alignment: .topLeading)
+                            .background(Color.white.opacity(0.95))
+                            .font(Font.custom("SF Pro", size: 17))
+
+                        // Password input field
+                        SecureField("Enter Password", text: $password)
+                            .padding(.leading, 16)
+                            .padding(.vertical, 15)
+                            .frame(maxWidth: .infinity, alignment: .topLeading)
+                            .background(Color.white.opacity(0.95))
+                    }
+                    .padding(0)
+                    .padding(.bottom)
+                    .frame(width: 302, height: 240, alignment: .center)
+                    .cornerRadius(10)
+
+                    // Show error message if any
+                    if let errorMessage = errorMessage {
+                        Text(errorMessage)
+                            .foregroundColor(.red)
+                            .multilineTextAlignment(.center)
+                            .padding()
+                    }
+
+                    // Sign Up button
+                    HStack(alignment: .center, spacing: 3) {
+                        Button(action: submitSignUp) {
+                            Text("Sign Up!")
+                                .font(Font.custom("SF Pro", size: 20))
+                                .foregroundColor(.white)
+                        }
+                    }
+                    .padding(.horizontal, 10)
+                    .padding(.vertical, 4)
+                    .frame(width: 113, height: 48, alignment: .center)
+                    .background(Color.blue)
+                    .cornerRadius(40)
+
+                    // Already have an account? Log in prompt
+                    HStack(alignment: .center, spacing: 0) {
+                        Button(action: {
+                            isLoginViewPresented = true  // Trigger LoginView presentation
+                        }) {
+                            Text("Already have an account? Log in")
+                                .font(Font.custom("SF Pro", size: 18))
+                                .multilineTextAlignment(.center)
+                                .foregroundColor(Color(red: 0, green: 0.48, blue: 1))
+                                .frame(width: 272, height: 43, alignment: .top)
+                        }
+                    }
+                    .padding(0)
+                    .frame(width: 272, height: 43, alignment: .center)
+
+                    // NavigationLink to MainView, activated when signed up
+                    NavigationLink(destination: MainView(), isActive: $isSignUpSuccessful) {
+                        EmptyView()
+                    }
+
+                    // NavigationLink back to LoginView
+                    NavigationLink(destination: LoginView(), isActive: $isLoginViewPresented) {
+                        EmptyView()
+                    }
+                }
+                .frame(width: 335, height: 432)
+                .background(Color.white.opacity(0.75))
+                .cornerRadius(48)
+
+                Spacer()
+            }
+            .frame(maxWidth: .infinity, maxHeight: .infinity)
+            .background(Color(red: 0, green: 0.96, blue: 1))
+            .statusBar(hidden: false)
+        }
+    }
+}
+
+struct SignUpView_Previews: PreviewProvider {
+    static var previews: some View {
+        SignUpView()
+    }
+}
diff --git a/MobileAcebook/WelcomePageView.swift b/MobileAcebook/WelcomePageView.swift
index 96006af9..d75d9329 100644
--- a/MobileAcebook/WelcomePageView.swift
+++ b/MobileAcebook/WelcomePageView.swift
@@ -1,40 +1,65 @@
-//
-//  WelcomePageView.swift
-//  MobileAcebook
-//
-//  Created by Josué Estévez Fernández on 30/09/2023.
-//
-
 import SwiftUI
 
 struct WelcomePageView: View {
+    @State private var navigateToLogin = false
+    @State private var navigateToSignUp = false
+
     var body: some View {
-        ZStack {
+        NavigationStack {
             VStack {
                 Spacer()
 
-                Text("Welcome to Acebook!")
+                Text("Acebook")
                     .font(.largeTitle)
-                    .padding(.bottom, 20)
-                    .accessibilityIdentifier("welcomeText")
+                    .fontWeight(.bold)
+                    .foregroundColor(.black)
 
                 Spacer()
 
-                Image("makers-logo")
-                    .resizable()
-                    .scaledToFit()
-                    .frame(width: 200, height: 200)
-                    .accessibilityIdentifier("makers-logo")
-                
-                Spacer()
+                Text("You are not logged in.\nPlease login or sign up")
+                    .multilineTextAlignment(.center)
+                    .padding()
+                    .background(Color.white.opacity(0.8))
+                    .cornerRadius(10)
+                    .padding(.horizontal)
 
-                Button("Sign Up") {
-                    // TODO: sign up logic
+                HStack {
+                    // Sign Up Button with NavigationLink
+                    NavigationLink(destination: SignUpView(), isActive: $navigateToSignUp) {
+                        Button(action: {
+                            navigateToSignUp = true
+                        }) {
+                            Text("Sign Up")
+                                .foregroundColor(.blue)
+                                .padding()
+                                .frame(maxWidth: .infinity)
+                                .background(Color.white.opacity(0.8))
+                                .cornerRadius(10)
+                                .padding(.horizontal, 5)
+                        }
+                    }
+
+                    // Login Button with NavigationLink
+                    NavigationLink(destination: LoginView(), isActive: $navigateToLogin) {
+                        Button(action: {
+                            navigateToLogin = true
+                        }) {
+                            Text("Login")
+                                .foregroundColor(.blue)
+                                .padding()
+                                .frame(maxWidth: .infinity)
+                                .background(Color.white.opacity(0.8))
+                                .cornerRadius(10)
+                                .padding(.horizontal, 5)
+                        }
+                    }
                 }
-                .accessibilityIdentifier("signUpButton")
-                
+                .padding()
+
                 Spacer()
             }
+            .background(Color.cyan)
+            .navigationBarHidden(true)  // Hide navigation bar for welcome screen
         }
     }
 }
diff --git a/MobileAcebookTests/Services/MockAuthenticationService.swift b/MobileAcebookTests/Services/MockAuthenticationService.swift
index 29a608e0..8d75d02d 100644
--- a/MobileAcebookTests/Services/MockAuthenticationService.swift
+++ b/MobileAcebookTests/Services/MockAuthenticationService.swift
@@ -1,15 +1,15 @@
 //
 //  MockAuthenticationService.swift
 //  MobileAcebookTests
+////
+////  Created by Josué Estévez Fernández on 01/10/2023.
+////
 //
-//  Created by Josué Estévez Fernández on 01/10/2023.
+//@testable import MobileAcebook
 //
-
-@testable import MobileAcebook
-
-class MockAuthenticationService: AuthenticationServiceProtocol {
-    func signUp(user: User) -> Bool {
-        // Mocked logic for unit tests
-        return true // placeholder
-    }
-}
+//class MockAuthenticationService: AuthenticationServiceProtocol {
+//    func signUp(user: User) -> Bool {
+//        // Mocked logic for unit tests
+//        return true // placeholder
+//    }
+//}
diff --git a/README.md b/README.md
index 8fc42aff..f459ff99 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,41 @@
-# SwiftUI Project
-
-As part of this project, you will create a new SwiftUI app that integrates with
-[this Acebook backend](https://github.com/makersacademy/acebook-mobile-express-mongo-backend/tree/main).
+# Mobile Acebook SwiftUI
 
+Front-end application for Mobile Acebook project - by:
+Karina, Maz, Robert, Sam and Will
 
 ## This Repo
 
-This repo contains the seed project for your SwiftUI front-end application. 
+This repo contains the project for a Swift-UI frontend application consuming an Express backend that lives [here](https://github.com/QS-Coding/Mobile-Acebook)
+
+## Installation
+ 1. Clone the front-end and [back-end](https://github.com/QS-Coding/Mobile-Acebook) repos to your local machine
+ 2. Navigate to /api in the backend and run `npm install`
+ 3. Install MongoDB (ONLY IF YOU HAVEN'T ALREADY - skip this step if so, to avoid running into issues)
+   ```
+   brew tap mongodb/brew
+   brew install mongodb-community@6.0
+   ```
+   *Note:* If you see a message that says `If you need to have
+   mongodb-community@5.0 first in your PATH, run:`, follow the instruction.
+   Restart your terminal after this.
+   
+ 4. Start MongoDB
+   ```
+   brew services start mongodb-community@6.0
+   ```
+ 5. Create .env file in /api and add `MONGODB_URL` and `JWT_SECRET` environment variables
+ 6. Start backend server with command `npm run dev`
+ 7. Open frontend folder with XCode
+ 8. Build Swift app using XCode's top menu -> Product -> Build
+ 9. Run Swift app using XCode's top menu -> Product -> Run
+ 10. Simulator window will appear with app running
+
+## Usage
+1. App allows user to Signup / Login
+2. User navigated to Feed upon successful Login
+3. User can create new posts (with an optional image) by clicking "Create Post" on navbar
+4. User navigated to Feed upon successful Post creation
+5. User can click on a post in Feed and is navigated to Full Post View.
+6. User can read and add comments to post in Full Post View.
+7. User can refresh Feed by clicking "Refresh" on navbar
+8. User can logout by clicking "Logout" on navbar and confirming on alert/popup.