diff --git a/.gitignore b/.gitignore
index 4e253e3ac57529bf3294b411dff3d768d2a756d6..8f1916aff7380e359b8beb4eae63b666ab94981e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,4 +34,5 @@ proptrackr-*.tar
 # In case you use Node.js/npm, you want to ignore these.
 npm-debug.log
 /assets/node_modules/
-/assets/package-lock.json
\ No newline at end of file
+/assets/package-lock.json
+/priv/static/uploads
\ No newline at end of file
diff --git a/config/dev.exs b/config/dev.exs
index 89b49fd53b900a3bd6d2f7ff77db7272d4911898..c86f683dff58c87b2b8da2a9fb608a811fbf8cfc 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -83,3 +83,5 @@ config :phoenix_live_view,
 
 # Disable swoosh api client as it is only required for production adapters.
 config :swoosh, :api_client, false
+
+config :proptrackr, upload_path: Path.expand("./priv/static/uploads")
diff --git a/features/advertisement_creation.feature b/features/advertisement_creation.feature
index e507413d30eb2de3076e4344df8d014d72598005..fc0a78ad5f8c5c6b9309e20d44e6d959f32b046a 100644
--- a/features/advertisement_creation.feature
+++ b/features/advertisement_creation.feature
@@ -1,35 +1,54 @@
 Feature: FR-08 Property Advertisement Creation
 
-    Scenario: Authenticated user should be able to create a property advertisement
+    Scenario: Authenticated user should be able to create a property advertisement with photos
         Given there exists following accounts
-              | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
-              | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
+            | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
+            | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
         Given I want to insert the following data
-            | title     | description     | type      | property_type | location       | room_count | area | floor | floor_count | price |
-            | Apartment | Small apartment | rent      | apartment     | Tartu, Estonia | 1          | 13   | 2     | 4           | 430   |
+            | title     | description     | type | property_type | location       | room_count | area | floor | floor_count | price |
+            | Apartment | Small apartment | rent | apartment     | Tartu, Estonia | 1          | 13   | 2     | 4           | 430   |
         And I am logged in
         And I want to create a new property advertisement
         And I fill in the property advertisement form with valid data
+        And I upload 3 valid photos
         When I click submit
         Then I should see a success message
         And I should be redirected to the property advertisement page
+        And I should see all uploaded photos on the details page
+        And I should see the first photo on the homepage
 
-    Scenario: Authenticated user should be shown an error if the property advertisement form is filled incorrectly
+    Scenario: Authenticated user cannot create property advertisement without photos
         Given there exists following accounts
-              | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
-              | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
+            | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
+            | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
         Given I want to insert the following data
-            | title     | description     | type      | property_type | location       | room_count | area | floor | floor_count | price |
-            | Apartment | Small apartment | rent      | apartment     | Tartu, Estonia | 1          | 13   | 2     | 4           | 430   |
+            | title     | description     | type | property_type | location       | room_count | area | floor | floor_count | price |
+            | Apartment | Small apartment | rent | apartment     | Tartu, Estonia | 1          | 13   | 2     | 4           | 430   |
         And I am logged in
         And I want to create a new property advertisement
-        And I fill in the property advertisement form with invalid data
+        And I fill in the property advertisement form with valid data
+        And I don't upload any photos
         When I click submit
-        Then I should see error messages
+        Then I should see "Please upload between 1 and 5 photos" message
         And I should still see the new property advertisement form
 
-    Scenario: Unauthenticated user should not be able to create an advertisement
-        Given I am not logged in
-        And I would like to create a new property advertisement
-        Then I should not see a link to create a new property advertisement
-        And I should be redirected back to home page when I try to access the link
+Scenario: Authenticated user cannot create property advertisement with too many photos
+    Given there exists following accounts
+        | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
+        | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
+    Given I want to insert the following data
+        | title     | description     | type | property_type | location       | room_count | area | floor | floor_count | price |
+        | Apartment | Small apartment | rent | apartment     | Tartu, Estonia | 1          | 13   | 2     | 4           | 430   |
+    And I am logged in
+    And I want to create a new property advertisement
+    And I fill in the property advertisement form with valid data
+    And I upload 6 photos
+    When I click submit
+    Then I should see "Please upload between 1 and 5 photos" message
+    And I should still see the new property advertisement form
+
+Scenario: Unauthenticated user should not be able to create an advertisement
+    Given I am not logged in
+    And I would like to create a new property advertisement
+    Then I should not see a link to create a new property advertisement
+    And I should be redirected back to home page when I try to access the link
\ No newline at end of file
diff --git a/features/contexts/advertisement_creation_context.exs b/features/contexts/advertisement_creation_context.exs
index 82f0fff06b8a3993c99e0f91cb3d82a49e1441df..aac77ab14bbdb5132c7d4fc98f94c22ed7e5d418 100644
--- a/features/contexts/advertisement_creation_context.exs
+++ b/features/contexts/advertisement_creation_context.exs
@@ -4,6 +4,7 @@ defmodule AdvertisementCreationContext do
   alias PropTrackr.Accounts
   alias PropTrackr.Repo
   alias PropTrackr.Accounts.User
+  alias Properties.Photo
 
   scenario_starting_state fn _state ->
     Ecto.Adapters.SQL.Sandbox.checkout(PropTrackr.Repo)
@@ -18,8 +19,8 @@ defmodule AdvertisementCreationContext do
   end
 
   given_ ~r/^there exists following accounts$/, fn state, %{table_data: table} ->
-    table                                                                                
-    |> Enum.map(fn user_details -> User.changeset(%User{}, user_details) end)                            
+    table
+    |> Enum.map(fn user_details -> User.changeset(%User{}, user_details) end)
     |> Enum.each(fn changeset -> Repo.insert!(changeset) end)
 
     existing_user = List.first(table)
@@ -66,6 +67,31 @@ defmodule AdvertisementCreationContext do
     {:ok, state}
   end
 
+  and_ ~r/^I upload 3 valid photos$/, fn state ->
+    # Find the file input element
+    file_input = find_element(:id, "property_photos")
+
+    execute_script("""
+      (function() {
+        const input = document.getElementById('property_photos');
+        const files = [
+          new File(['test content'], 'test_photo_1.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_2.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_3.jpg', { type: 'image/jpeg' })
+        ];
+        const dataTransfer = new DataTransfer();
+        files.forEach(file => dataTransfer.items.add(file));
+        input.files = dataTransfer.files;
+        input.dispatchEvent(new Event('change', { bubbles: true }));
+      })();
+    """)
+
+    # Give the browser a moment to process the file upload
+    :timer.sleep(100)
+
+    {:ok, state}
+  end
+
   when_ ~r/^I click submit$/, fn state ->
     click({:id, "submit_button"})
     {:ok, state}
@@ -84,6 +110,161 @@ defmodule AdvertisementCreationContext do
     {:ok, state}
   end
 
+  and_ ~r/^I should see all uploaded photos on the details page$/, fn state ->
+    # Wait for images to load
+    :timer.sleep(500)
+
+    # Find the photo slides container and count the photos
+    photo_slides = find_all_elements(:css, ".photo-slide")
+
+    # Verify navigation elements if there are multiple photos
+    if length(photo_slides) > 1 do
+      prev_button = find_element(:css, "button.prev-photo")
+      next_button = find_element(:css, "button.next-photo")
+      thumbnails = find_all_elements(:css, "button.thumbnail")
+
+      # Check that we have the correct number of thumbnails
+      assert length(thumbnails) == length(photo_slides),
+        "Expected #{length(photo_slides)} thumbnails but found #{length(thumbnails)}"
+    end
+
+    # Verify each photo is loaded and visible
+    Enum.each(photo_slides, fn slide ->
+      img = find_within_element(slide, :css, "img")
+      src = attribute_value(img, "src")
+
+      assert String.contains?(src, "/uploads/"),
+        "Image source should contain /uploads/ but was #{src}"
+    end)
+
+    # Check counter display
+    counter = find_element(:css, ".current-photo")
+    counter_text = visible_text(counter)
+    assert counter_text == "1", "Counter should start at 1"
+
+    # Verify total number of photos
+    assert length(photo_slides) == 3,
+      "Expected 3 photos but found #{length(photo_slides)}"
+
+    {:ok, state}
+  end
+
+  and_ ~r/^I should see the first photo on the homepage$/, fn state ->
+
+    # Navigate to homepage
+    navigate_to("/")
+    :timer.sleep(500)  # Wait for page to load
+
+    # Find the property container
+    property_div = find_element(:css, "#properties > div:first-child")
+
+    # Find the photo container within the property
+    photo_container = find_within_element(property_div, :css, ".w-48.h-48")
+
+    # Check if there's an image
+    case find_all_within_element(photo_container, :css, "img") do
+      [img | _] ->
+        src = attribute_value(img, "src")
+
+        # Verify image source contains uploads path
+        assert String.contains?(src, "/uploads/"),
+          "Image source should contain /uploads/ but was #{src}"
+
+        # Verify image has proper styling
+        classes = attribute_value(img, "class")
+
+        assert String.contains?(classes, "object-cover"),
+          "Image should have object-cover class"
+        assert String.contains?(classes, "rounded"),
+          "Image should have rounded class"
+
+        # Verify container dimensions
+        container_classes = attribute_value(photo_container, "class")
+
+        assert String.contains?(container_classes, "w-48"),
+          "Container should have w-48 class"
+        assert String.contains?(container_classes, "h-48"),
+          "Container should have h-48 class"
+
+      [] ->
+        flunk("No image found in the photo container")
+    end
+
+    IO.puts("Homepage photo verification completed")
+
+    {:ok, state}
+  end
+
+  and_ ~r/^I don't upload any photos$/, fn state ->
+    file_input = find_element(:id, "property_photos")
+
+    execute_script("""
+      const input = document.getElementById('property_photos');
+      return input.files.length;
+    """)
+    |> case do
+      0 -> IO.puts("Confirmed: No files selected")
+      count -> IO.puts("Warning: Found #{count} files when expecting none")
+    end
+
+    {:ok, state}
+  end
+
+  then_ ~r/^I should see "(?<argument_one>[^"]+)" message$/,
+  fn state, %{argument_one: argument_one} ->
+
+    assert visible_in_page?(~r/#{argument_one}/),
+      "Expected to see message '#{argument_one}' but it was not found on the page"
+
+    {:ok, state}
+  end
+
+  and_ ~r/^I upload 6 photos$/, fn state ->
+    file_input = find_element(:id, "property_photos")
+
+    execute_script("""
+      (function() {
+        const input = document.getElementById('property_photos');
+        const files = [
+          new File(['test content'], 'test_photo_1.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_2.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_3.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_4.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_5.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_6.jpg', { type: 'image/jpeg' })
+        ];
+        const dataTransfer = new DataTransfer();
+        files.forEach(file => dataTransfer.items.add(file));
+        input.files = dataTransfer.files;
+        input.dispatchEvent(new Event('change', { bubbles: true }));
+      })();
+    """)
+
+    :timer.sleep(100)
+    {:ok, state}
+  end
+
+  and_ ~r/^I upload 2 valid photos$/, fn state ->
+    file_input = find_element(:id, "property_photos")
+
+    execute_script("""
+      (function() {
+        const input = document.getElementById('property_photos');
+        const files = [
+          new File(['test content'], 'test_photo_1.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_2.jpg', { type: 'image/jpeg' }),
+        ];
+        const dataTransfer = new DataTransfer();
+        files.forEach(file => dataTransfer.items.add(file));
+        input.files = dataTransfer.files;
+        input.dispatchEvent(new Event('change', { bubbles: true }));
+      })();
+    """)
+
+    :timer.sleep(100)
+    {:ok, state}
+  end
+
   and_ ~r/^I fill in the property advertisement form with invalid data$/, fn state ->
     fill_field({:id, "title"}, "wrong")
     fill_field({:id, "description"}, "invalid_obvs")
@@ -144,4 +325,14 @@ defmodule AdvertisementCreationContext do
   defp select_dropdown(drop_down_id, option) do
     find_element(:css, "##{drop_down_id} option[value='#{option}']") |> click()
   end
+
+  defp create_test_photo(index) do
+    Path.join([
+      File.cwd!(),
+      "test",
+      "support",
+      "fixtures",
+      "photo_#{index}.jpg"
+    ])
+  end
 end
diff --git a/features/contexts/advertisement_list_context.exs b/features/contexts/advertisement_list_context.exs
index 3099ff47253ff7340eb92bddbd41bd5f77aa71a1..1e4ef680a6db71669ec711dbb0b0bb2afa200a3d 100644
--- a/features/contexts/advertisement_list_context.exs
+++ b/features/contexts/advertisement_list_context.exs
@@ -111,6 +111,26 @@ defmodule AdvertisementListContext do
     fill_field({:id, "floor"}, state[:data][:floor])
     fill_field({:id, "floor_count"}, state[:data][:floor_count])
     fill_field({:id, "price"}, state[:data][:price])
+
+    file_input = find_element(:id, "property_photos")
+
+    execute_script("""
+      (function() {
+        const input = document.getElementById('property_photos');
+        const files = [
+          new File(['test content'], 'test_photo_1.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_2.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_3.jpg', { type: 'image/jpeg' })
+        ];
+        const dataTransfer = new DataTransfer();
+        files.forEach(file => dataTransfer.items.add(file));
+        input.files = dataTransfer.files;
+        input.dispatchEvent(new Event('change', { bubbles: true }));
+      })();
+    """)
+
+    :timer.sleep(100)
+
     {:ok, state}
   end
 
diff --git a/features/contexts/my_advertisements_context.exs b/features/contexts/my_advertisements_context.exs
index a1cdbf8bfd4c4bc481b4f0b54d0073dbb5c828a9..bbee6664d68beb5e40c7e87cfed1341b95e3f45d 100644
--- a/features/contexts/my_advertisements_context.exs
+++ b/features/contexts/my_advertisements_context.exs
@@ -47,7 +47,7 @@ defmodule MyAdvertisementsContext do
     }
   end
 
-  given_ ~r/^I created given properties$/, fn state ->
+  given_ ~r/^I created given properties with photos$/, fn state ->
     navigate_to("/")
     click({:id, "add_advertisement"})
     fill_field({:id, "title"}, state[:data][:title])
@@ -60,6 +60,24 @@ defmodule MyAdvertisementsContext do
     fill_field({:id, "floor"}, state[:data][:floor])
     fill_field({:id, "floor_count"}, state[:data][:floor_count])
     fill_field({:id, "price"}, state[:data][:price])
+
+    file_input = find_element(:id, "property_photos")
+
+    execute_script("""
+      (function() {
+        const input = document.getElementById('property_photos');
+        const files = [
+          new File(['test content'], 'test_photo_1.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_2.jpg', { type: 'image/jpeg' }),
+          new File(['test content'], 'test_photo_3.jpg', { type: 'image/jpeg' })
+        ];
+        const dataTransfer = new DataTransfer();
+        files.forEach(file => dataTransfer.items.add(file));
+        input.files = dataTransfer.files;
+        input.dispatchEvent(new Event('change', { bubbles: true }));
+      })();
+    """)
+
     click({:id, "submit_button"})
     property = Repo.get_by(Property, title: state[:data][:title])
     {:ok, state |> Map.put(:property, property)}
diff --git a/features/my_advertisements.feature b/features/my_advertisements.feature
index 5edd5edbbb16ee4ca2665699355bcc3eabd6368d..0cd7af237c3c9c4146edb54623d5580a64642a5f 100644
--- a/features/my_advertisements.feature
+++ b/features/my_advertisements.feature
@@ -1,14 +1,14 @@
 Feature: FR-12 View Own Advertisements
   
-  Scenario: Authenticated user should view all its property listings from profile
+  Scenario: Authenticated user should view all its property listings with photos from profile
     Given there exists following accounts
-              | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
-              | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
+      | name     | surname | birth_date  | phone_number | email                      | password | confirm_password |
+      | Existing | Account | 2000-01-01  | 000         | existing.account@gmail.com | password | password         |
     Given I am logged in
     Given I want to insert the following data
-            | title      | description                        | type      | property_type | location         | room_count | area | floor | floor_count | price    |
-            | Apartment  | Small apartment in Tartu for rent  | rent      | apartment     | Tartu, Estonia   | 1          | 13   | 2     | 4           | 430      |
-    Given I created given properties
+      | title     | description                       | type | property_type | location       | room_count | area | floor | floor_count | price |
+      | Apartment | Small apartment in Tartu for rent | rent | apartment    | Tartu, Estonia | 1          | 13   | 2     | 4          | 430   |
+    Given I created given properties with photos
     When I navigate to my profile page
     And I click on My properties link
     Then I should be redirected to my properties page
@@ -24,14 +24,14 @@ Feature: FR-12 View Own Advertisements
     Given I want to insert the following data
             | title      | description                        | type      | property_type | location         | room_count | area | floor | floor_count | price    |
             | Apartment  | Small apartment in Tartu for rent  | rent      | apartment     | Tartu, Estonia   | 1          | 13   | 2     | 4           | 430      |
-    Given I created given properties
+    Given I created given properties with photos
     Given I log out
     Given I am logged in as "second.user@gmail.com"
     When I navigate to my profile page
     And I click on My properties link
     Then I should be redirected to my properties page
     And I should not see other user's properties
-      And I log out
+    And I log out
 
   Scenario: Authenticated user should view details of own advertisement
     Given there exists following accounts
@@ -41,7 +41,7 @@ Feature: FR-12 View Own Advertisements
     Given I want to insert the following data
             | title      | description                        | type      | property_type | location         | room_count | area | floor | floor_count | price    |
             | Apartment  | Small apartment in Tartu for rent  | rent      | apartment     | Tartu, Estonia   | 1          | 13   | 2     | 4           | 430      |
-    Given I created given properties
+    Given I created given properties with photos
     When I navigate to my profile page
     And I click on My properties link
     And I click to View more button
diff --git a/lib/proptrackr/properties/photo.ex b/lib/proptrackr/properties/photo.ex
new file mode 100644
index 0000000000000000000000000000000000000000..1a9d54b7d2239fa43b47cd31242219b63f07ad17
--- /dev/null
+++ b/lib/proptrackr/properties/photo.ex
@@ -0,0 +1,17 @@
+defmodule PropTrackr.Properties.Photo do
+  use Ecto.Schema
+  import Ecto.Changeset
+
+  schema "photos" do
+    field :filename, :string
+    field :order, :integer
+    belongs_to :property, PropTrackr.Properties.Property
+    timestamps()
+  end
+  
+  def changeset(photo, attrs) do
+    photo
+    |> cast(attrs, [:filename, :order, :property_id])
+    |> validate_required([:filename, :property_id])
+  end
+end
diff --git a/lib/proptrackr/properties/property.ex b/lib/proptrackr/properties/property.ex
index 942873f9dff09e8fc227e0add5d67df4bd6e22aa..e00404478265c861b4b7d08ee09cb62fc03c8ade 100644
--- a/lib/proptrackr/properties/property.ex
+++ b/lib/proptrackr/properties/property.ex
@@ -1,7 +1,6 @@
 defmodule PropTrackr.Properties.Property do
   use Ecto.Schema
   import Ecto.Changeset
-
   alias PropTrackr.Repo
 
   schema "properties" do
@@ -14,7 +13,7 @@ defmodule PropTrackr.Properties.Property do
     field :property_type, Ecto.Enum, values: [:apartment, :house, :other]
     field :state, Ecto.Enum, values: [:available, :reserved, :unavailable], default: :available
 
-    # TODO: Image references and upload
+    has_many :photos, PropTrackr.Properties.Photo
 
     field :location, :string
 
diff --git a/lib/proptrackr/uploads.ex b/lib/proptrackr/uploads.ex
new file mode 100644
index 0000000000000000000000000000000000000000..c2e74d07e38176f48644d19bcf7081e588f8d7fc
--- /dev/null
+++ b/lib/proptrackr/uploads.ex
@@ -0,0 +1,22 @@
+defmodule PropTrackr.Uploads do
+  def upload_file(%{filename: filename, path: temp_path}) do
+    extension = Path.extname(filename)
+    file_uuid = Ecto.UUID.generate()
+    new_filename = "#{file_uuid}#{extension}"
+
+    # Define uploads directory
+    uploads_dir = Application.app_dir(:proptrackr, "priv/static/uploads")
+
+    # Ensure directory exists
+    File.mkdir_p!(uploads_dir)
+
+    # Build final path
+    final_path = Path.join(uploads_dir, new_filename)
+
+    # Copy file from temp path to final destination
+    File.cp!(temp_path, final_path)
+
+    # Return the filename that was saved
+    new_filename
+  end
+end
diff --git a/lib/proptrackr_web/controllers/my_favorites_controller.ex b/lib/proptrackr_web/controllers/my_favorites_controller.ex
index 5b0bdae714d2dfcd87a4c2ed0196785a71293e4e..9464bfc86247cba44a68dae3097bb0b397b28f39 100644
--- a/lib/proptrackr_web/controllers/my_favorites_controller.ex
+++ b/lib/proptrackr_web/controllers/my_favorites_controller.ex
@@ -20,7 +20,7 @@ defmodule PropTrackrWeb.MyFavoritesController do
           join: u in User,
           on: p.user_id == u.id,
           where: f.user_id == ^user_id,
-          preload: [property: {p, user: u}]
+          preload: [property: {p, [:user, :photos]}] 
         )
         |> Repo.all()
 
diff --git a/lib/proptrackr_web/controllers/my_favorites_html/index.html.heex b/lib/proptrackr_web/controllers/my_favorites_html/index.html.heex
index fbc97de4d632066c848fdb199fa952180458cc9d..2a26060ec1303201328b7912b1281691dacba9e9 100644
--- a/lib/proptrackr_web/controllers/my_favorites_html/index.html.heex
+++ b/lib/proptrackr_web/controllers/my_favorites_html/index.html.heex
@@ -1,45 +1,58 @@
 <.header>
   My Favorite Properties
 </.header>
-
 <div id="favorites" class="flex flex-col gap-y-4 mt-8">
   <%= if @favorites == [] do %>
     <p>You haven't favorited any properties yet.</p>
   <% end %>
-
   <%= for favorite <- @favorites do %>
     <div class="bg-white border-black border rounded px-4 py-2">
-      <div class="flex justify-between items-start">
-        <h2 class="font-bold"><%= favorite.property.title %></h2>
-        <button
-          type="button"
-          class="favorite-button text-2xl"
-          data-property-reference={favorite.property.reference}
-          data-favorited="true"
-        >
-          âک…
-        </button>
-      </div>
-
-      <p><%= favorite.property.description %></p>
-      <p class="italic"><%= favorite.property.location %></p>
-
-      <div class="flex flex-row gap-x-2">
-        <span><%= favorite.property.price %> €</span>
-        <span><%= favorite.property.room_count %> rooms</span>
-        <span><%= favorite.property.area %> m<sup>2</sup></span>
-      </div>
+      <div class="flex gap-4">
+        <div class="w-48 h-48 flex-shrink-0">
+          <%= if first_photo = Enum.at(favorite.property.photos, 0) do %>
+            <img
+              src={~p"/uploads/#{first_photo.filename}"}
+              alt={"Photo of #{favorite.property.title}"}
+              class="w-full h-full object-cover rounded"
+            />
+          <% else %>
+            <div class="w-full h-full bg-gray-200 flex items-center justify-center rounded">
+              <span class="text-gray-400">No photo</span>
+            </div>
+          <% end %>
+        </div>
 
-      <div class="flex flex-row justify-end">
-        <.link href={~p"/properties/#{favorite.property.reference}"}>
-          <.button
-            type="button"
-            class="text-white rounded px-4 py-2"
-            id={"view-#{favorite.property.reference}"}
-          >
-            View more
-          </.button>
-        </.link>
+        <div class="flex-grow">
+          <div class="flex justify-between items-start">
+            <h2 class="font-bold"><%= favorite.property.title %></h2>
+            <button
+              type="button"
+              class="favorite-button text-2xl"
+              data-property-reference={favorite.property.reference}
+              data-favorited="true"
+            >
+              âک…
+            </button>
+          </div>
+          <p><%= favorite.property.description %></p>
+          <p class="italic"><%= favorite.property.location %></p>
+          <div class="flex flex-row gap-x-2">
+            <span><%= favorite.property.price %> €</span>
+            <span><%= favorite.property.room_count %> rooms</span>
+            <span><%= favorite.property.area %> m<sup>2</sup></span>
+          </div>
+          <div class="flex flex-row justify-end">
+            <.link href={~p"/properties/#{favorite.property.reference}"}>
+              <.button
+                type="button"
+                class="text-white rounded px-4 py-2"
+                id={"view-#{favorite.property.reference}"}
+              >
+                View more
+              </.button>
+            </.link>
+          </div>
+        </div>
       </div>
     </div>
   <% end %>
diff --git a/lib/proptrackr_web/controllers/my_properties_controller.ex b/lib/proptrackr_web/controllers/my_properties_controller.ex
index 2b209fd0d3ed49efdc412a7b7c92c976d032ea58..2c0f1957671633dbe1b895bdc75617a10574f471 100644
--- a/lib/proptrackr_web/controllers/my_properties_controller.ex
+++ b/lib/proptrackr_web/controllers/my_properties_controller.ex
@@ -11,6 +11,7 @@ defmodule PropTrackrWeb.MyPropertiesController do
                      from p in Property,
                      where: p.user_id == ^user_id,
                      order_by: [asc: p.inserted_at],
+                     preload: [:photos],
                      select: p)
     render conn, "index.html", properties: properties
   end
diff --git a/lib/proptrackr_web/controllers/my_properties_html/index.html.heex b/lib/proptrackr_web/controllers/my_properties_html/index.html.heex
index fb79e067b722b25d917be96561f35e85681831b5..60ada05ad49640bc4ec779f61e41217e99ebdc9b 100644
--- a/lib/proptrackr_web/controllers/my_properties_html/index.html.heex
+++ b/lib/proptrackr_web/controllers/my_properties_html/index.html.heex
@@ -1,25 +1,45 @@
 <.header>
   My Properties
 </.header>
-
 <div id="properties" class="flex flex-col gap-y-4 mt-20">
   <%= for property <- @properties do %>
     <div class="bg-white border-black border rounded px-4 py-2">
-      <h2 class="font-bold"><%= property.title %></h2>
-      <p><%= property.description %></p>
-
-      <p class="italic"><%= property.location %></p>
-
-      <div class="flex flex-row gap-x-2">
-        <span><%= property.price %> €</span>
-        <span><%= property.room_count %> rooms</span>
-        <span><%= property.area %> m<sup>2</sup></span>
-      </div>
+      <div class="flex gap-4">
+        <div class="w-48 h-48 flex-shrink-0">
+          <%= if first_photo = Enum.at(property.photos, 0) do %>
+            <img
+              src={~p"/uploads/#{first_photo.filename}"}
+              alt={"Photo of #{property.title}"}
+              class="w-full h-full object-cover rounded"
+            />
+          <% else %>
+            <div class="w-full h-full bg-gray-200 flex items-center justify-center rounded">
+              <span class="text-gray-400">No photo</span>
+            </div>
+          <% end %>
+        </div>
 
-      <div class="flex flex-row justify-end">
-        <.link href={~p"/properties/#{property.reference}"}>
-          <.button type="button" class="text-white rounded px-4 py-2" id={ "edit-#{property.reference}" }>View more</.button>
-        </.link>
+        <div class="flex-grow">
+          <h2 class="font-bold"><%= property.title %></h2>
+          <p><%= property.description %></p>
+          <p class="italic"><%= property.location %></p>
+          <div class="flex flex-row gap-x-2">
+            <span><%= property.price %> €</span>
+            <span><%= property.room_count %> rooms</span>
+            <span><%= property.area %> m<sup>2</sup></span>
+          </div>
+          <div class="flex flex-row justify-end">
+            <.link href={~p"/properties/#{property.reference}"}>
+              <.button
+                type="button"
+                class="text-white rounded px-4 py-2"
+                id={"edit-#{property.reference}"}
+              >
+                View more
+              </.button>
+            </.link>
+          </div>
+        </div>
       </div>
     </div>
   <% end %>
diff --git a/lib/proptrackr_web/controllers/properties_controller.ex b/lib/proptrackr_web/controllers/properties_controller.ex
index 8ae3be252a420d2bec8ff89a42a0a8e4263c79c4..33c03a6fb8414fe9c34746ac73421d9d8ea6f239 100644
--- a/lib/proptrackr_web/controllers/properties_controller.ex
+++ b/lib/proptrackr_web/controllers/properties_controller.ex
@@ -3,8 +3,9 @@ defmodule PropTrackrWeb.PropertiesController do
 
   import Ecto.Query, only: [from: 2]
   alias PropTrackr.Repo
-  alias PropTrackr.Properties.Property
+  alias PropTrackr.Properties.{Property,  Photo}
   alias PropTrackr.Favorites.Favorite
+  alias PropTrackr.Uploads
 
   def index(conn, _params) do
 
@@ -12,6 +13,8 @@ defmodule PropTrackrWeb.PropertiesController do
                      from p in Property,
                      where: p.state == :available,
                      order_by: [asc: p.inserted_at],
+                     preload: [:photos],
+                    # preload: [photos: ^from(ph in Photo, order_by: [asc: ph.order])],
                      select: p)
 
     favorites = case conn.assigns.current_user do
@@ -34,7 +37,7 @@ defmodule PropTrackrWeb.PropertiesController do
     property = Repo.one(
       from p in Property,
       where: p.reference == ^reference,
-      preload: [:user],
+      preload: [:user, :photos],
       select: p
     )
 
@@ -74,32 +77,94 @@ defmodule PropTrackrWeb.PropertiesController do
     render conn, "new.html", changeset: changeset
   end
 
-  def create(conn, %{"property" => property}) do
-    current_user = conn.assigns.current_user
 
-    if current_user == nil do
+def create(conn, %{"property" => property_params}) do
+  current_user = conn.assigns.current_user
+
+  if current_user == nil do
+    conn
+    |> put_flash(:error, "You are not logged in!")
+    |> redirect(to: "/")
+  else
+    uploaded_files = Map.get(property_params, "photos", [])
+
+    # Add reference to property params
+    property_params = property_params |> Map.put("reference", Ecto.UUID.generate())
+
+    # Clean and convert property params
+    property_params_with_atoms =
+      property_params
+      |> Map.delete("photos")
+      |> Enum.map(fn {key, value} -> {String.to_atom(key), value} end)
+      |> Enum.into(%{})
+
+    # Build property association with user
+    property_assoc = Ecto.build_assoc(current_user, :properties, property_params_with_atoms)
+    property_changeset = Property.changeset(property_assoc, property_params_with_atoms)
+
+    if length(uploaded_files) < 1 or length(uploaded_files) > 5 do
       conn
-      |> put_flash(:error, "You are not logged in!")
-      |> redirect(to: "/")
+      |> put_flash(:error, "Please upload between 1 and 5 photos")
+      |> render("new.html", changeset: property_changeset)
     else
-      property = property |> Map.put("reference", Ecto.UUID.generate())
-      property_assoc = Ecto.build_assoc(current_user, :properties, Enum.map(property, fn {key, value} -> {String.to_atom(key), value} end))
-      property_changeset = Property.changeset(property_assoc, property)
-
-      # Note: IDK this does not work properly
-      # |> Ecto.Changeset.put_change(:reference, Ecto.UUID.generate())
+      Ecto.Multi.new()
+      |> Ecto.Multi.insert(:property, property_changeset)
+      |> Ecto.Multi.run(:photos, fn repo, %{property: property} ->
+
+        results =
+          uploaded_files
+          |> Enum.with_index(1)
+          |> Enum.map(fn {upload, index} ->
+            case upload do
+              %Plug.Upload{} = file ->
+                # Save file and create photo record
+                filename = Uploads.upload_file(file)
+
+                photo_changeset = Photo.changeset(%Photo{}, %{
+                  filename: filename,
+                  order: index,
+                  property_id: property.id
+                })
+
+                case repo.insert(photo_changeset) do
+                  {:ok, photo} ->
+                    IO.puts("Successfully created photo with ID: #{photo.id}")
+                    {:ok, photo}
+                  {:error, reason} = error ->
+                    IO.puts("Failed to create photo: #{inspect(reason)}")
+                    error
+                end
+              _ -> {:error, "Invalid file upload"}
+            end
+          end)
 
-      case Repo.insert(property_changeset) do
-        {:ok, property} ->
+        case Enum.split_with(results, &(elem(&1, 0) == :ok)) do
+          {successful, []} ->
+            {:ok, Enum.map(successful, &elem(&1, 1))}
+          {_, failed} ->
+            {:error, "Failed to create some photos: #{inspect(failed)}"}
+        end
+      end)
+      |> Repo.transaction()
+      |> case do
+        {:ok, %{property: property, photos: photos}} ->
           conn
           |> put_flash(:info, "Property created successfully!")
           |> redirect(to: ~p"/properties/#{property.reference}")
 
-        {:error, changeset} ->
-          render conn, "new.html", changeset: changeset
+        {:error, :property, changeset, _} ->
+          conn
+          |> put_flash(:error, "Failed to create property")
+          |> render("new.html", changeset: changeset)
+
+        {:error, :photos, error, _} ->
+          conn
+          |> put_flash(:error, "Failed to upload photos: #{inspect(error)}")
+          |> render("new.html", changeset: property_changeset)
       end
     end
   end
+end
 
   def edit(conn, %{"reference" => reference}) do
     property = Repo.get_by(Property, reference: reference)
@@ -121,6 +186,7 @@ defmodule PropTrackrWeb.PropertiesController do
     end
   end
 
+  @spec update(Plug.Conn.t(), map()) :: Plug.Conn.t()
   def update(conn, %{"reference" => reference, "property" => property_params}) do
     property = Repo.get_by(Property, reference: reference)
 
@@ -155,7 +221,8 @@ defmodule PropTrackrWeb.PropertiesController do
       |> put_flash(:error, "You are not logged in!")
       |> redirect(to: "/")
     else
-      property = Repo.get_by(Property, reference: reference)
+      # property = Repo.get_by(Property, reference: reference)
+      property = Repo.get_by(Property, reference: reference) |> Repo.preload(:photos)
 
       case property do
         nil ->
@@ -165,6 +232,12 @@ defmodule PropTrackrWeb.PropertiesController do
 
         property ->
           if conn.assigns.current_user.id == property.user_id do
+            Enum.each(property.photos, fn photo ->
+              uploads_dir = Application.app_dir(:proptrackr, "priv/static/uploads")
+              file_path = Path.join(uploads_dir, photo.filename)
+              File.rm(file_path)
+            end)
+
             case Repo.delete(property) do
               {:ok, _deleted_property} ->
                 conn
diff --git a/lib/proptrackr_web/controllers/properties_html/index.html.heex b/lib/proptrackr_web/controllers/properties_html/index.html.heex
index ea5f9d655034ff397c7e13627c7b321fbac895a7..43f687abaa7c1e30aac5e5dda12143f4c902b305 100644
--- a/lib/proptrackr_web/controllers/properties_html/index.html.heex
+++ b/lib/proptrackr_web/controllers/properties_html/index.html.heex
@@ -15,36 +15,59 @@
 <%= if @properties == [] do %>
   <p>No advertisements at the moment</p>
 <% end %>
-
 <div id="properties" class="flex flex-col gap-y-4 mt-20">
   <%= for property <- @properties do %>
     <div class="bg-white border-black border rounded px-4 py-2">
-      <div class="flex justify-between items-start">
-        <h2 class="font-bold"><%= property.title %></h2>
-        <%= if @conn.assigns[:current_user] && @conn.assigns.current_user.id != property.user_id do %>
-          <button
-            type="button"
-            class="favorite-button text-2xl"
-            data-property-reference={property.reference}
-            data-favorited={if property.id in @favorites, do: "true", else: "false"}
-          >
-            <%= if property.id in @favorites, do: "âک…", else: "âک†" %>
-          </button>
-        <% end %>
-      </div>
-      <p><%= property.description %></p>
-      <p class="italic"><%= property.location %></p>
-      <div class="flex flex-row gap-x-2">
-        <span><%= property.price %> €</span>
-        <span><%= property.room_count %> rooms</span>
-        <span><%= property.area %> m<sup>2</sup></span>
-      </div>
-      <div class="flex flex-row justify-end">
-        <.link href={~p"/properties/#{property.reference}"}>
-          <.button type="button" class="text-white rounded px-4 py-2" id={ "edit-#{property.reference}" } data-title={property.title}>View more</.button>
-        </.link>
+      <div class="flex gap-4">
+        <div class="w-48 h-48 flex-shrink-0">
+          <%= if first_photo = Enum.at(property.photos, 0) do %>
+            <img
+              src={~p"/uploads/#{first_photo.filename}"}
+              alt={"Photo of #{property.title}"}
+              class="w-full h-full object-cover rounded"
+            />
+          <% else %>
+            <div class="w-full h-full bg-gray-200 flex items-center justify-center rounded">
+              <span class="text-gray-400">No photo</span>
+            </div>
+          <% end %>
+        </div>
+
+        <div class="flex-grow">
+          <div class="flex justify-between items-start">
+            <h2 class="font-bold"><%= property.title %></h2>
+            <%= if @conn.assigns[:current_user] && @conn.assigns.current_user.id != property.user_id do %>
+              <button
+                type="button"
+                class="favorite-button text-2xl"
+                data-property-reference={property.reference}
+                data-favorited={if property.id in @favorites, do: "true", else: "false"}
+              >
+                <%= if property.id in @favorites, do: "âک…", else: "âک†" %>
+              </button>
+            <% end %>
+          </div>
+          <p><%= property.description %></p>
+          <p class="italic"><%= property.location %></p>
+          <div class="flex flex-row gap-x-2">
+            <span><%= property.price %> €</span>
+            <span><%= property.room_count %> rooms</span>
+            <span><%= property.area %> m<sup>2</sup></span>
+          </div>
+          <div class="flex flex-row justify-end">
+            <.link href={~p"/properties/#{property.reference}"}>
+              <.button
+                type="button"
+                class="text-white rounded px-4 py-2"
+                id={"edit-#{property.reference}"}
+                data-title={property.title}
+              >
+                View more
+              </.button>
+            </.link>
+          </div>
+        </div>
       </div>
     </div>
   <% end %>
 </div>
-
diff --git a/lib/proptrackr_web/controllers/properties_html/new.html.heex b/lib/proptrackr_web/controllers/properties_html/new.html.heex
index f6f95555bbdfe5dacba543b4101a6b2eafd254af..ee6003a5e4dcca3a47cdb640e460ee69e0ffdab3 100644
--- a/lib/proptrackr_web/controllers/properties_html/new.html.heex
+++ b/lib/proptrackr_web/controllers/properties_html/new.html.heex
@@ -2,24 +2,71 @@
   Add a new property listing
 </.header>
 
-<.simple_form :let={f} for={@changeset} method="POST" action="/properties">
+<.simple_form :let={f} for={@changeset} method="POST" action="/properties" multipart>
   <.input field={f[:title]} id="title" type="text" label="Title" required />
   <.input field={f[:description]} id="description" type="textarea" label="Description" required />
-  <.input field={f[:type]} id="type" type="select" label="Advertisement type" options={[{"Rent", :rent}, {"Sell", :sell}]} requried />
-  <.input field={f[:property_type]} id="property_type" type="select" label="Property type" options={[{"Apartment", :apartment}, {"House", :house}, {"Other", :other}]} required />
+  <.input
+    field={f[:type]}
+    id="type"
+    type="select"
+    label="Advertisement type"
+    options={[{"Rent", :rent}, {"Sell", :sell}]}
+    requried
+  />
+  <.input
+    field={f[:property_type]}
+    id="property_type"
+    type="select"
+    label="Property type"
+    options={[{"Apartment", :apartment}, {"House", :house}, {"Other", :other}]}
+    required
+  />
 
-  <.input field={f[:location]} id="location" type="text" label="Location" placeholder="Tartu, Estonia" required />
+  <.input
+    field={f[:location]}
+    id="location"
+    type="text"
+    label="Location"
+    placeholder="Tartu, Estonia"
+    required
+  />
 
   <.input field={f[:area]} id="area" type="text" label="Area (m^2)" required />
-  <.input field={f[:room_count]} id="room_count" type="number" label="Room count" min={1} required />
+  <.input
+    field={f[:room_count]}
+    id="room_count"
+    type="number"
+    label="Room count"
+    min={1}
+    required
+  />
   <.input field={f[:floor]} id="floor" type="number" label="Floor" min={1} required />
-  <.input field={f[:floor_count]} id="floor_count" type="number" label="Floor count" min={0} required />
+  <.input
+    field={f[:floor_count]}
+    id="floor_count"
+    type="number"
+    label="Floor count"
+    min={0}
+    required
+  />
 
   <.input field={f[:price]} id="price" type="text" label="Price" required />
 
+  <div phx-feedback-for="property[photos]">
+    <label for="property_photos" class="block text-sm font-medium text-gray-700">
+      Photos (Upload 1-5 images)
+    </label>
+    <input
+      type="file"
+      name="property[photos][]"
+      id="property_photos"
+      multiple
+      accept="image/*"
+      class="mt-2 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-gray-700 focus:border-zinc-400 focus:outline-none focus:ring-4 focus:ring-zinc-400/10 sm:text-sm sm:leading-6"
+    />
+  </div>
+
   <:actions>
-    <.button id="submit_button">Create advertisement</.button>
+    <.button id="submit_button">Save Product</.button>
   </:actions>
 </.simple_form>
-
-
diff --git a/lib/proptrackr_web/controllers/properties_html/show.html.heex b/lib/proptrackr_web/controllers/properties_html/show.html.heex
index df0e48602088abfc5872f88bc0db65279b598385..2e2fd10fdeec55eb86c51fd625a1eeace894c396 100644
--- a/lib/proptrackr_web/controllers/properties_html/show.html.heex
+++ b/lib/proptrackr_web/controllers/properties_html/show.html.heex
@@ -40,6 +40,73 @@
   </:actions>
 </.header>
 
+<div class="mt-8 bg-white shadow rounded-lg p-6">
+  <h3 class="text-lg font-medium text-gray-900 mb-4">Property Photos</h3>
+
+  <div class="relative">
+    
+    <div class="w-full h-[500px] relative overflow-hidden rounded-lg">
+      <%= if length(@property.photos) > 0 do %>
+        <%= for {photo, index} <- Enum.with_index(@property.photos) do %>
+          <div
+            class="photo-slide absolute w-full h-full transition-transform duration-300"
+            data-index={index}
+            style="transform: translateX(#{index * 100}%)"
+          >
+            <img
+              src={~p"/uploads/#{photo.filename}"}
+              alt={"Photo #{index + 1} of #{@property.title}"}
+              class="w-full h-full object-cover"
+            />
+          </div>
+        <% end %>
+      <% else %>
+        <div class="w-full h-full bg-gray-200 flex items-center justify-center">
+          <span class="text-gray-400">No photos available</span>
+        </div>
+      <% end %>
+    </div>
+
+    <%= if length(@property.photos) > 1 do %>
+      <button
+        class="prev-photo absolute left-4 top-1/2 -translate-y-1/2 bg-black/50 hover:bg-black/75 text-white w-10 h-10 rounded-full flex items-center justify-center opacity-0 transition-opacity group-hover:opacity-100"
+        aria-label="Previous photo"
+      >
+        â†گ
+      </button>
+      <button
+        class="next-photo absolute right-4 top-1/2 -translate-y-1/2 bg-black/50 hover:bg-black/75 text-white w-10 h-10 rounded-full flex items-center justify-center opacity-0 transition-opacity group-hover:opacity-100"
+        aria-label="Next photo"
+      >
+        →
+      </button>
+    <% end %>
+
+    <%= if length(@property.photos) > 0 do %>
+      <div class="absolute bottom-4 right-4 bg-black/50 text-white px-3 py-1 rounded-full text-sm">
+        <span class="current-photo">1</span>/<span><%= length(@property.photos) %></span>
+      </div>
+    <% end %>
+  </div>
+
+  <%= if length(@property.photos) > 1 do %>
+    <div class="mt-4 flex gap-2 overflow-x-auto pb-2">
+      <%= for {photo, index} <- Enum.with_index(@property.photos) do %>
+        <button
+          class="thumbnail w-20 h-20 flex-shrink-0 rounded-lg overflow-hidden focus:ring-2 focus:ring-blue-500"
+          data-index={index}
+        >
+          <img
+            src={~p"/uploads/#{photo.filename}"}
+            alt={"Thumbnail #{index + 1}"}
+            class="w-full h-full object-cover"
+          />
+        </button>
+      <% end %>
+    </div>
+  <% end %>
+</div>
+
 <div class="mt-8 space-y-8">
   <div class="bg-white shadow rounded-lg p-6">
     <dl class="grid grid-cols-1 md:grid-cols-2 gap-4">
@@ -81,19 +148,47 @@
                   data-property-type={@property.type}
                 >
                   Update Status
-                  <svg class="-mr-3 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
-                    <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
+                  <svg
+                    class="-mr-3 ml-2 h-5 w-5"
+                    xmlns="http://www.w3.org/2000/svg"
+                    viewBox="0 0 20 20"
+                    fill="currentColor"
+                  >
+                    <path
+                      fill-rule="evenodd"
+                      d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
+                      clip-rule="evenodd"
+                    />
                   </svg>
                 </button>
               </div>
               <div
                 class="status-dropdown-menu hidden origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 divide-y divide-gray-100 focus:outline-none"
-                role="menu" aria-orientation="vertical" aria-labelledby="status-menu-button" tabindex="-1"
+                role="menu"
+                aria-orientation="vertical"
+                aria-labelledby="status-menu-button"
+                tabindex="-1"
               >
                 <div class="py-1" role="none">
-                  <button class="status-option text-gray-700 block px-4 py-2 text-sm w-full text-left hover:bg-gray-100" role="menuitem" data-status="available">Available</button>
-                  <button class="status-option text-gray-700 block px-4 py-2 text-sm w-full text-left hover:bg-gray-100" role="menuitem" data-status="reserved">Reserved</button>
-                  <button class="status-option text-gray-700 block px-4 py-2 text-sm w-full text-left hover:bg-gray-100" role="menuitem" data-status="unavailable">
+                  <button
+                    class="status-option text-gray-700 block px-4 py-2 text-sm w-full text-left hover:bg-gray-100"
+                    role="menuitem"
+                    data-status="available"
+                  >
+                    Available
+                  </button>
+                  <button
+                    class="status-option text-gray-700 block px-4 py-2 text-sm w-full text-left hover:bg-gray-100"
+                    role="menuitem"
+                    data-status="reserved"
+                  >
+                    Reserved
+                  </button>
+                  <button
+                    class="status-option text-gray-700 block px-4 py-2 text-sm w-full text-left hover:bg-gray-100"
+                    role="menuitem"
+                    data-status="unavailable"
+                  >
                     <%= if @property.type == :rent, do: "Rented", else: "Sold" %>
                   </button>
                 </div>
@@ -155,11 +250,13 @@
           <div
             class="flex items-center justify-between mt-4 similar-property"
             data-what="similar-property"
-            data-price={property.price}>
-
+            data-price={property.price}
+          >
             <div>
               <p class="text-sm text-gray-600"><%= property.title %></p>
-              <p class="text-sm text-gray-600"><%= :erlang.float_to_binary(property.price, decimals: 2) %>€</p>
+              <p class="text-sm text-gray-600">
+                <%= :erlang.float_to_binary(property.price, decimals: 2) %>€
+              </p>
               <p class="text-sm text-gray-600"><%= property.location %></p>
             </div>
             <a
@@ -175,3 +272,42 @@
     </div>
   </div>
 </div>
+
+<script>
+  document.addEventListener('DOMContentLoaded', function() {
+    const slides = document.querySelectorAll('.photo-slide');
+    const prevButton = document.querySelector('.prev-photo');
+    const nextButton = document.querySelector('.next-photo');
+    const thumbnails = document.querySelectorAll('.thumbnail');
+    const currentPhotoSpan = document.querySelector('.current-photo');
+    let currentIndex = 0;
+
+    function updateSlides(newIndex) {
+      slides.forEach((slide, index) => {
+        slide.style.transform = `translateX(${(index - newIndex) * 100}%)`;
+      });
+      currentIndex = newIndex;
+      currentPhotoSpan.textContent = (currentIndex + 1).toString();
+    }
+
+    if (prevButton) {
+      prevButton.addEventListener('click', () => {
+        const newIndex = currentIndex === 0 ? slides.length - 1 : currentIndex - 1;
+        updateSlides(newIndex);
+      });
+    }
+
+    if (nextButton) {
+      nextButton.addEventListener('click', () => {
+        const newIndex = currentIndex === slides.length - 1 ? 0 : currentIndex + 1;
+        updateSlides(newIndex);
+      });
+    }
+
+    thumbnails.forEach((thumbnail, index) => {
+      thumbnail.addEventListener('click', () => {
+        updateSlides(index);
+      });
+    });
+  });
+</script>
diff --git a/lib/proptrackr_web/endpoint.ex b/lib/proptrackr_web/endpoint.ex
index cf91fc7362e62067857f60484ab802dd57a1beb4..284c270bef78d6a567c0f677a14ef5ed6a0df027 100644
--- a/lib/proptrackr_web/endpoint.ex
+++ b/lib/proptrackr_web/endpoint.ex
@@ -25,6 +25,11 @@ defmodule PropTrackrWeb.Endpoint do
     gzip: false,
     only: PropTrackrWeb.static_paths()
 
+  plug Plug.Static,
+    at: "/uploads",
+    from: Path.expand("./priv/static/uploads"),
+    gzip: false
+
   # Code reloading can be explicitly enabled under the
   # :code_reloader configuration of your endpoint.
   if code_reloading? do
@@ -45,6 +50,7 @@ defmodule PropTrackrWeb.Endpoint do
     parsers: [:urlencoded, :multipart, :json],
     pass: ["*/*"],
     json_decoder: Phoenix.json_library()
+    # length: 100_000_000 TO BE CLARIFIED
 
   plug Plug.MethodOverride
   plug Plug.Head
diff --git a/priv/repo/migrations/20241128154230_photos.exs b/priv/repo/migrations/20241128154230_photos.exs
new file mode 100644
index 0000000000000000000000000000000000000000..fa91a147617300e39f7a79f00d9a6e404b86549f
--- /dev/null
+++ b/priv/repo/migrations/20241128154230_photos.exs
@@ -0,0 +1,14 @@
+defmodule PropTrackr.Repo.Migrations.Photos do
+  use Ecto.Migration
+
+  def change do
+    create table(:photos) do
+      add :filename, :string, null: false
+      add :order, :integer
+      add :property_id, references(:properties, on_delete: :delete_all)
+      timestamps()
+    end
+
+    create index(:photos, [:property_id])
+  end
+end
diff --git a/test/proptrackr_web/controllers/properties_controller_test.exs b/test/proptrackr_web/controllers/properties_controller_test.exs
index 71a1456cdbe1caffdc961fb14e5fc8f63d36953b..0184f18c1adeeec79fa312bed6ffdeac5643dfa3 100644
--- a/test/proptrackr_web/controllers/properties_controller_test.exs
+++ b/test/proptrackr_web/controllers/properties_controller_test.exs
@@ -44,6 +44,18 @@ defmodule PropTrackrWeb.PropertiesControllerTest do
   }
 
   setup do
+    uploads_dir = Application.app_dir(:proptrackr, "priv/static/uploads")
+    File.mkdir_p!(uploads_dir)
+
+    test_image_path = Path.join(uploads_dir, "test_image.jpg")
+    File.write!(test_image_path, "fake image content")
+
+    test_photo = %Plug.Upload{
+      path: test_image_path,
+      filename: "test_image.jpg",
+      content_type: "image/jpeg"
+    }
+
     user = %User{
       name: "Test",
       surname: "User",
@@ -68,13 +80,19 @@ defmodule PropTrackrWeb.PropertiesControllerTest do
     }
     other_user = Repo.insert!(other_user)
 
-    {:ok, %{user: user, other_user: other_user}}
+    on_exit(fn ->
+      File.rm_rf!(uploads_dir)
+    end)
+
+    {:ok, %{user: user, other_user: other_user, test_photo: test_photo}}
 
   end
 
-  test "Authenticated user should be able to create a new property advertisement with valid data", %{ conn: conn, user: user } do
+  test "Authenticated user should be able to create a new property advertisement with valid data", %{ conn: conn, user: user, test_photo: test_photo } do
     conn = conn |> setup_session(user)
-    conn = conn |> post("/properties", property: @valid_data)
+
+    property_data = Map.put(@valid_data, "photos", [test_photo])
+    conn = conn |> post("/properties", property: property_data)
 
     uuidv4_regex =  ~r/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
     path = String.split(redirected_to(conn), "/")
@@ -86,7 +104,7 @@ defmodule PropTrackrWeb.PropertiesControllerTest do
     conn = get conn, redirected_to(conn)
     assert html_response(conn, 200) =~ "Property created successfully!"
 
-    advertisement = Repo.get_by!(Property, reference: advertisement_reference)
+    advertisement = Repo.get_by!(Property, reference: advertisement_reference) |> Repo.preload(:photos)
     assert advertisement.title == @valid_data[:title]
     assert advertisement.description == @valid_data[:description]
     assert advertisement.type == String.to_atom(@valid_data[:type])
@@ -98,59 +116,122 @@ defmodule PropTrackrWeb.PropertiesControllerTest do
     assert advertisement.floor_count == @valid_data[:floor_count]
     assert advertisement.price == @valid_data[:price]
     assert advertisement.user_id == user.id # check if right user is connected to advertisement
+
+    assert length(advertisement.photos) == 1
+    photo = List.first(advertisement.photos)
+    assert photo.order == 1
+    assert String.ends_with?(photo.filename, ".jpg")
   end
 
-  test "Authenticated user should not be able to create an advertisement with invalid data",  %{ conn: conn, user: user } do
+  test "Authenticated user should not be able to create an advertisement with invalid data", %{
+    conn: conn,
+    user: user,
+    test_photo: test_photo
+  } do
     conn = conn |> setup_session(user)
-    conn = conn |> post("/properties", property: @invalid_data)
 
-    assert html_response(conn, 200) =~ "must be greater than 0"
+    invalid_data_with_photo = Map.put(@invalid_data, "photos", [test_photo])
+
+    conn = conn |> post("/properties", property: invalid_data_with_photo)
+
+    response = html_response(conn, 200)
+
+    assert response =~ "must be greater than 0"
   end
 
-  test "Authenticated user should not be able to create an advertisement with invalid floor values", %{ conn: conn, user: user } do
+
+  test "Authenticated user should not be able to create an advertisement with invalid floor values", %{
+    conn: conn,
+    user: user,
+    test_photo: test_photo
+  } do
     conn = conn |> setup_session(user)
 
-    data = %{ @invalid_data | floor: 2, floor_count: 1 }
-    conn = conn |> post("/properties", property: data)
+    valid_base_data = %{
+      title: "Valid Title Here",
+      description: "This is a valid description that is definitely long enough",
+      type: "rent",
+      property_type: "apartment",
+      location: "Tartu, Estonia",
+      room_count: 2,
+      area: 50.0,
+      price: 500.0,
+      floor: 2,
+      floor_count: 1
+    }
+
+    data_with_photo = Map.put(valid_base_data, "photos", [test_photo])
+
+    conn = conn |> post("/properties", property: data_with_photo)
 
     assert html_response(conn, 200) =~ "Floor count must be greater than floor"
   end
 
-  test "Authenticated user should not be able to create an advertisement with invalid floor count data on a house listing", %{ conn: conn, user: user } do
+
+  test "Authenticated user should not be able to create an advertisement with invalid floor count data on a house listing", %{ conn: conn, user: user, test_photo: test_photo } do
     conn = conn |> setup_session(user)
 
     data = %{ @invalid_data | property_type: :house, floor: 2, floor_count: 1 }
-    conn = conn |> post("/properties", property: data)
+
+    data_with_photo = Map.put(data, "photos", [test_photo])
+    conn = conn |> post("/properties", property: data_with_photo)
 
     # Just assert that a redirect happened, don't care about data since it does not matter here
     assert redirected_to(conn) != "/properties"
   end
 
-  test "Unauthenticated user should be redirected to the homepage", %{ conn: conn, user: user } do
-    conn = post(conn, "/properties", property: @valid_data)
+  test "Unauthenticated user should be redirected to the homepage", %{
+    conn: conn,
+    test_photo: test_photo
+  } do
+    property_data = Map.put(@valid_data, "photos", [test_photo])
+    conn = post(conn, "/properties", property: property_data)
+
     assert redirected_to(conn) == "/"
+
+    conn = get(conn, "/")
+    assert html_response(conn, 200) =~ "You are not logged in!"
   end
 
-  test "Unauthenticated user should see a message when there are no advertisements", %{ conn: conn } do
-    conn = get conn, "/"
 
+  test "Unauthenticated user should see a message when there are no advertisements", %{
+    conn: conn
+  } do
+    conn = get(conn, "/")
     assert html_response(conn, 200) =~ "No advertisements at the moment"
   end
 
-  test "Unauthenticated user should see a list of all properties", %{ conn: conn, user: user } do
+  test "Unauthenticated user should see a list of all properties", %{
+    conn: conn,
+    user: user,
+    test_photo: test_photo
+  } do
     conn = conn |> setup_session(user)
-    conn = conn |> post("/properties", property: @valid_data)
-
-    conn = get conn, "/"
-    assert html_response(conn, 200) =~ @valid_data[:title]
-    assert html_response(conn, 200) =~ @valid_data[:description]
-    assert html_response(conn, 200) =~ @valid_data[:location]
-    assert html_response(conn, 200) =~ Float.to_string(@valid_data[:price])
-    assert html_response(conn, 200) =~ Integer.to_string(@valid_data[:room_count])
-    assert html_response(conn, 200) =~ Float.to_string(@valid_data[:area])
+    property_data = Map.put(@valid_data, "photos", [test_photo])
+    conn = conn |> post("/properties", property: property_data)
+
+    property_path = redirected_to(conn)
+    conn = get(conn, property_path)
+    assert html_response(conn, 200) =~ "Property created successfully!"
+
+    conn = build_conn()
+    conn = get(conn, "/")
+
+    response = html_response(conn, 200)
+    assert response =~ @valid_data[:title]
+    assert response =~ @valid_data[:description]
+    assert response =~ @valid_data[:location]
+    assert response =~ Float.to_string(@valid_data[:price])
+    assert response =~ Integer.to_string(@valid_data[:room_count])
+    assert response =~ Float.to_string(@valid_data[:area])
+
+    property = Repo.one(Property) |> Repo.preload(:photos)
+    photo = List.first(property.photos)
+    assert response =~ photo.filename
   end
 
-  #UPDATE TESTS
+
+  # #UPDATE TESTS
   test "owner can update their property with valid data", %{conn: conn, user: user} do
     property = %Property{
       reference: Ecto.UUID.generate(),