diff --git a/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh b/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh
old mode 100755
new mode 100644
index 60944e58..d128a9b8
--- a/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh
+++ b/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 # This software is a part of Isar.
-# Copyright (C) Siemens AG, 2024
+# Copyright (C) Siemens AG, 2026
 #
 # SPDX-License-Identifier: MIT
 
@@ -9,293 +9,202 @@ installdata=${INSTALL_DATA:-/install}
 SCRIPT_DIR=$( dirname -- "$( readlink -f -- "$0"; )"; )
 
 . "${SCRIPT_DIR}/../lib/deploy-image-wic/handle-config.sh"
+. "${SCRIPT_DIR}/sys_api.sh"
+. "${SCRIPT_DIR}/installer_ui.sh"
 
-if [ "$installer_unattended" = true ] && [ "$installer_unattended_abort_enable" = true ]; then
-    abort_file=/tmp/attended_mode_trigger
-    for ((i=$installer_unattended_abort_timeout; i>0; i--)); do
-        echo -ne "\rUnattended installation will start in $i seconds. Press any key to switch to attended mode..."
+#--------------------------------------------------------------------------
+# This module contains high-level installer flow logic
+# while keeping low-level backend APIs in sys_api.sh
+# and user-facing dialogs in installer_ui.sh.
+#--------------------------------------------------------------------------
 
-	# Switch to attended mode if the abort file exists or any key pressed during countdown
-	# Create abort file to notify all other console instances to abort
-        if [ -f "$abort_file" ] || read -n 1 -t 1; then
-            installer_unattended=false
-            touch "$abort_file"
-            break
-        fi
-    done
-fi
-
-if ! $installer_unattended; then
-    installer_image_uri=$(find "$installdata" -type f -iname "*.wic*" -a -not -iname "*.wic.bmap" -exec basename {} \;)
-    if [ -z "$installer_image_uri" ] || [ ! -f "$installdata/$installer_image_uri" ]; then
-        pushd "$installdata"
-        for f in $(find . -type f ! -iname "*.wic.bmap"); do
-            array+=("$f" "$f")
-        done
-        popd
-        if [ ${#array[@]} -gt 0 ]; then
-            if ! installer_image_uri=$(dialog --no-tags \
-                              --menu "Select image to be installed" 10 60 3 \
-                              "${array[@]}" --output-fd 1); then
-                exit 0
-            fi
-        fi
-    fi
-
-    if [ ! -f "$installdata/$installer_image_uri" ]; then
-        dialog --msgbox "Could not find an image to install. Installation aborted." 6 60
-        exit 1
-    fi
-
-    # inspired by poky/meta/recipes-core/initrdscripts/files/install-efi.sh
-    target_device_list=""
-    current_root_dev_type=$(findmnt / -o fstype -n)
-    exclude_list=()
-
-    if [ "$current_root_dev_type" = "nfs" ]; then
-        current_root_dev="nfs"
-        exclude_list+=("nfs")
-    else
-    # For normal or immutable systems, get the backing device of '/'
-        root_source=$(findmnt / -o source -n)
-        root_source_resolved=$(readlink -f "$root_source" 2>/dev/null || echo "$root_source")
-        current_root_dev=${root_source_resolved#/dev/}
-
-        # Always exclude the exact device mounted as /
-        exclude_list+=("$current_root_dev")
-
-        if [[ "$current_root_dev" =~ ^(mmcblk|nvme) ]]; then
-            base_no_part="${current_root_dev%p[0-9]*}"
-        else
-            base_no_part="${current_root_dev%%[0-9]*}"
-        fi
-        if [ -n "$base_no_part" ]; then
-            exclude_list+=("$base_no_part")
-        fi
-
-        # If root is coming through a dm-* device (e.g., dm-verity),
-        # the actual physical devices appear under /sys/block/<dm>/slaves/.
-        # We must exclude those slaves as well, otherwise the installer
-        # might show the live USB stick as a valid target.
-        if [ -d "/sys/block/$current_root_dev/slaves" ]; then
-            for slave in /sys/block/"$current_root_dev"/slaves/*; do
-                [ -e "$slave" ] || continue
-                slave_dev=$(basename "$slave")
-                exclude_list+=("$slave_dev")
-                slave_base=${slave_dev%%[0-9]*}
-                [ -n "$slave_base" ] && exclude_list+=("$slave_base")
-            done
-        fi
-    fi
-
-    echo "Searching for target device..."
-
-    devices=$(find /sys/block/ -type b,c,f,l -not -iname "mmcblk*" -printf "%f\n") || true
-    mmc_devices=$(find /sys/block/ -type b,c,f,l -iname "mmcblk[0-9]" -printf "%f\n") || true
-    devices="$devices $mmc_devices"
-
-    for device in $devices; do
-        is_raid_member=0
-
-        if [ -d "/sys/block/$device/holders" ] && [ ! -d "/sys/block/$device/md" ]; then
-            for holder_path in /sys/block/$device/holders/*; do
-                holder_name=$(basename "$holder_path")
-                case "$holder_name" in
-                    md[0-9]*)
-                        is_raid_member=1
-                        break
-                        ;;
-                esac
-            done
-        fi
-
-        if [ "$is_raid_member" -eq 1 ]; then
-            continue # Skip RAID member disks
-        fi
-
-        if [[ "$device" == md* ]]; then
-            if [ -f "/sys/block/$device/md/array_state" ]; then
-                state=$(cat /sys/block/$device/md/array_state)
-                if [ "$state" != "active" ] && [ "$state" != "clean" ]; then
-                    continue
-                fi
-            else
-                continue
-            fi
-        fi
-
-        case $device in
-            dm-*)
-                # skip device-mapper device
-                ;;
-            loop*)
-                # skip loop device
-                ;;
-            mtd*)
-                ;;
-            sr*)
-                # skip CDROM device
-                ;;
-            ram*)
-                # skip ram device
-                ;;
-            zram*)
-                # skip zram device
-                ;;
-            *)
-                #skip any excluded devices (root and its slaves)
-                skip_device=0
-                for ex in "${exclude_list[@]}"; do
-                    if [[ "$device" == "$ex"* ]]; then
-                        skip_device=1
-                        break
-                    fi
-                done
-
-                if [ "$skip_device" -eq 0 ]; then
-                    target_device_list="$target_device_list $device"
-                fi
-                ;;
-        esac
-    done
-
-    if [ -z "${target_device_list}" ]; then
-        dialog --msgbox "You need another device (besides the live device /dev/${current_root_dev}) to install the image. Installation aborted." 7 60
-        exit 1
-    fi
-
-    if [ "$(echo "$target_device_list" | wc -w)" -gt 1 ]; then
-        array=()
-        for target in $(echo "$target_device_list" | xargs -n1 | sort); do
-            target_size=$(lsblk --nodeps --noheadings -o SIZE /dev/"$target" | tr -d " ")
-            if cmp /dev/zero /dev/"$target" -n 1M; then
-                state="empty"
-            else
-                state="contains data"
-            fi
-            array+=("/dev/$target" "/dev/$target ($target_size, $state)")
-        done
-        if ! installer_target_dev=$(dialog --no-tags \
-                             --menu "Select device to install image to" 10 60 3 \
-                             "${array[@]}" --output-fd 1); then
-            exit 0
-        fi
-    else
-        installer_target_dev="/dev/$(echo "$target_device_list" | tr -d " ")"
-    fi
-    TARGET_DEVICE_SIZE=$(lsblk --nodeps --noheadings -o SIZE "$installer_target_dev" | tr -d " ")
-    if ! dialog --yes-label Ok --no-label Cancel \
-                --yesno "Start installing\n'$installer_image_uri'\nto $installer_target_dev (capacity: $TARGET_DEVICE_SIZE)" 7 60; then
-        exit 0
-    fi
-
-    # set absolute paths to be compatible with unattended mode
-    installer_image_uri="$installdata/$installer_image_uri"
-fi
-
-if ! cmp /dev/zero "$installer_target_dev" -n 1M; then
-    if ! $installer_unattended; then
-        if ! dialog --defaultno \
-                    --yesno "WARNING: Target device is not empty! Continue anyway?" 5 60; then
-            exit 0
-        fi
-    else
-        if [ "$installer_target_overwrite" != "OVERWRITE" ]; then
-            echo "Target device is not empty! -> Abort"
-            echo "If you want to override existing data set \"installer.target.overwrite=OVERWRITE\" on your kernel cmdline or edit your \"auto.install\" file accordingly."
-
-            exit 1
-        fi
-    fi
-fi
-
-bmap_options=""
-
-# bmap file is expected to be next to the installer image
-DISK_BMAP="${installer_image_uri%.wic*}.wic.bmap"
-
-if [ ! -f "$DISK_BMAP" ]; then
-    bmap_options="--nobmap"
-fi
-
-if ! $installer_unattended; then
-    clear
-fi
-
-# Function to compare version numbers
-version_ge() {
-    if [ "$(printf '%s\n' "$1"X "$2" | sort -V | head -n 1)" != "$1"X ]; then
-        return 0
-    else
-        return 1
-    fi
+#--------------------------------------------------------------------------
+# flow_run_attended
+#
+# Handles all attended-mode interactions and assigns:
+#   installer_image_uri
+#   installer_target_dev
+#
+# Returns:
+#   0 on success
+#   1 on hard error
+#   2 on user cancel
+#--------------------------------------------------------------------------
+flow_run_attended() {
+	local default_image
+	local selected_image
+	local selected_target
+	local target_device_size
+
+	default_image=$(sys_first_default_image_name "$installdata")
+	if [ -n "$default_image" ] && [ -f "$installdata/$default_image" ]; then
+		installer_image_uri="$default_image"
+	fi
+
+	if [ -z "$installer_image_uri" ] || [ ! -f "$installdata/$installer_image_uri" ]; then
+		selected_image=$(ui_select_image_menu "$installdata")
+		case $? in
+			0)
+				installer_image_uri="$selected_image"
+				;;
+			1)
+				ui_show_error "Could not find an image to install. Installation aborted."
+				return 1
+				;;
+			2)
+				return 2
+				;;
+			*)
+				return 1
+				;;
+		esac
+	fi
+
+	if [ ! -f "$installdata/$installer_image_uri" ]; then
+		ui_show_error "Could not find an image to install. Installation aborted."
+		return 1
+	fi
+
+	echo "Searching for target device..."
+	sys_discover_target_devices
+	if [ "${#SYS_TARGET_DEVICES[@]}" -eq 0 ]; then
+		ui_show_error "You need another device (besides the live device /dev/${SYS_CURRENT_ROOT_DEV}) to install the image. Installation aborted."
+		return 1
+	fi
+
+	if [ "${#SYS_TARGET_DEVICES[@]}" -gt 1 ]; then
+		selected_target=$(ui_select_target_device_menu "${SYS_TARGET_DEVICES[@]}")
+		case $? in
+			0)
+				installer_target_dev="$selected_target"
+				;;
+			1)
+				ui_show_error "No installable target devices available. Installation aborted."
+				return 1
+				;;
+			2)
+				return 2
+				;;
+			*)
+				return 1
+				;;
+		esac
+	else
+		installer_target_dev="${SYS_TARGET_DEVICES[0]}"
+	fi
+
+	target_device_size=$(sys_device_size "$installer_target_dev")
+	if ! ui_confirm_install "$installer_image_uri" "$installer_target_dev" "$target_device_size"; then
+		return 2
+	fi
+
+	installer_image_uri="$installdata/$installer_image_uri"
+	return 0
 }
 
-lockfile="/run/installer.lock"
-progress_pipe="/run/installer.fifo"
-
-exec 9>"$lockfile"
-if flock -n 9; then
-    # Get bmap-tools version
-    bmap_version=$(bmaptool --version | awk '{ print $NF }')
-
-    if version_ge "$bmap_version" "3.6"; then
-        if ! mkfifo "$progress_pipe"; then
-            echo "Error: Failed to create named pipe $progress_pipe"
-            exit 1
-        fi
-
-        # Add psplash pipe to bmap_options
-        bmap_options="$bmap_options --psplash-pipe=$progress_pipe"
-        quiet_flag="-q"
-
-        # Initialize the dialog gauge and update it dynamically
-        (
-            while true; do
-                if read -r line < "$progress_pipe"; then
-                    percentage=$(echo "$line" | awk '{ print $2 }')
-                    echo "$percentage"
-                fi
-            done
-        ) | dialog --gauge "Flashing image, please wait..." 10 70 0 &
-
-        gauge_pid=$!
-    fi
-
-    if ! bmaptool $quiet_flag copy $bmap_options "$installer_image_uri" "$installer_target_dev"; then
-        kill "$gauge_pid"
-        exit 1
-    fi
-
-    # Attempt to terminate the gauge process if still running.
-    # Errors are ignored since the process may already have exited.
-    kill "$gauge_pid" 2>/dev/null
-else
-    echo "Installation already running in another console."
+#--------------------------------------------------------------------------
+# flow_validate_target_overwrite_policy
+#
+# Enforces overwrite policy for non-empty targets in both attended and
+# unattended modes.
+#
+# Returns:
+#   0 when policy permits installation
+#   1 when policy rejects installation
+#   2 when user cancels in attended mode
+#--------------------------------------------------------------------------
+flow_validate_target_overwrite_policy() {
+	if sys_device_is_empty "$installer_target_dev"; then
+		return 0
+	fi
+
+	if ! $installer_unattended; then
+		if ! ui_confirm_overwrite; then
+			return 2
+		fi
+	else
+		if [ "$installer_target_overwrite" != "OVERWRITE" ]; then
+			echo "Target device is not empty! -> Abort"
+			echo "If you want to override existing data set \"installer.target.overwrite=OVERWRITE\" on your kernel cmdline or edit your \"auto.install\" file accordingly."
+			return 1
+		fi
+	fi
+
+	return 0
+}
 
-    # Wait for running console to create the progress pipe
-    sleep 5
+#--------------------------------------------------------------------------
+# flow_maybe_switch_to_attended
+#
+# If unattended abort-by-key is enabled, this function offers a timeout
+# window to switch to attended mode.
+#--------------------------------------------------------------------------
+flow_maybe_switch_to_attended() {
+	local abort_file
+
+	if [ "$installer_unattended" = true ] && [ "$installer_unattended_abort_enable" = true ]; then
+		abort_file=/tmp/attended_mode_trigger
+		if ui_countdown_allow_attended_switch "$installer_unattended_abort_timeout" "$abort_file"; then
+			installer_unattended=false
+		fi
+	fi
+}
 
-    # Check if progress pipe exists and has content
-    if [ -e "$progress_pipe" ]; then
-        echo "Installation progress..."
-        tail -f "$progress_pipe" | while read line; do
-            printf "\r%s%%" "$line"
-        done
-    else
-        # Periodically check if bmaptool is still running every 5 seconds
-        echo "Waiting for installation to finish..."
-        while pgrep -x "bmaptool" > /dev/null; do
-            sleep 5
-        done
-    fi
-fi
+#--------------------------------------------------------------------------
+# flow_run
+#
+# Main installer flow combining attended/unattended execution paths.
+#--------------------------------------------------------------------------
+flow_run() {
+	flow_maybe_switch_to_attended
+
+	if ! $installer_unattended; then
+		flow_run_attended
+		case $? in
+			0)
+				;;
+			2)
+				return 0
+				;;
+			*)
+				return 1
+				;;
+		esac
+	fi
+
+	flow_validate_target_overwrite_policy
+	case $? in
+		0)
+			;;
+		2)
+			return 0
+			;;
+		*)
+			return 1
+			;;
+	esac
+
+	if ! $installer_unattended; then
+		clear
+	fi
+
+	if ! sys_install_image_with_lock "$installer_image_uri" "$installer_target_dev"; then
+		if ! $installer_unattended; then
+			ui_show_error "Installation failed."
+		fi
+		return 1
+	fi
+
+	if ! $installer_unattended; then
+		ui_show_info "Installation was successful. System will be rebooted. Please remove the USB stick."
+	else
+		echo "Installation was successful."
+	fi
+
+	return 0
+}
 
-if ! $installer_unattended; then
-    dialog --title "Reboot" \
-           --msgbox "Installation was successful. System will be rebooted. Please remove the USB stick." 6 60
-else
-    echo "Installation was successful."
-fi
+# Entrypoint: run the installer flow and propagate status.
+flow_run
+exit $?
 
-exit 0
