sideproject · 2026-08-28 · 조회수 34
탐색기 창이 너무 많아서 만든 FlowDesk
평소 파일은 Everything에서 찾고, 복사하거나 옮기는 작업은 Windows 파일 탐색기에서 한다. 나는 탐색기를 여러 개 띄워놓고 일하는 편이라 필요한 폴더를 하나씩 열다 보면 창이 금방 늘어난다. 검색 창은 따로 있고, 작업할 탐색기 창도 여러 개 떠 있는 식이다.
FlowDesk는 이 창들을 좀 줄여보려고 만들기 시작했다. 빠른 색인 검색으로 파일을 찾고, 같은 앱 안에서 탐색기를 분할해 여러 폴더를 함께 보고 싶었다. 작업별로 탭도 열어두면 여러 창을 오가던 일을 한곳에서 할 수 있겠다고 생각했다.
검색과 분할 탐색기로 시작했지만, 개발하면서 메일 확인과 설치·업데이트까지 붙이게 됐다. 처음에는 1.0.0 설치 파일을 NAS에 올렸고, 현재 배포 버전은 1.0.2다. 중간에 파일 정리와 AI 연동도 고민했는데, 그쪽은 일단 멈췄다.
2026년 9월 2일 업데이트
1.0.0 배포에 사용한 업데이트 서명 키를 잃어버려 1.0.0에서는 이후 버전으로 자동 업데이트할 수 없다. 기존 사용자는 1.0.2를 한 번 수동으로 설치해야 한다. 새 서명 키를 적용한 자동 업데이트는 1.0.2부터 다시 동작한다.

왼쪽에서 파일을 찾고 오른쪽에서 폴더를 함께 본다. 이 글의 화면은 모두 개인정보 대신 테스트용 파일과 메일로 구성해 실제 앱에서 촬영했다.
빠른 검색과 분할 탐색기를 한곳에
WinUI 3와 .NET 10으로 만든 Windows 11 x64용 앱이다. 앞서 만든 앱에서는 Tauri나 Electron을 썼는데, 이번 파일 탐색기는 WinUI로 만들었다.
작업할 폴더들을 탭으로 열고, 탭 안에서는 화면을 분할해 나란히 볼 수 있게 했다. 파일을 끌어서 다른 분할 영역으로 옮기는 동작도 넣었다. 여러 탐색기 창을 띄워놓고 하던 작업을 여기서도 이어가려는 구성이었다. 마지막에 열어둔 탭과 분할 상태는 다시 실행하면 복원된다.

작업 자료와 공유할 파일을 나란히 열어둔 화면. 폴더를 바꿀 때마다 탐색기 창을 하나 더 띄우지 않으려 했다.
검색 쪽에는 로컬 SQLite 색인을 뒀다. NTFS에서는 MFT로 파일 목록을 읽고 USN 변경 기록으로 이후 변경을 반영한다. 색인도 빠르게 만들고, 이미 읽은 목록을 매번 처음부터 훑는 일도 줄이려 했다. 별도의 백그라운드 서비스가 색인을 관리해서 앱 창을 닫아도 작업을 이어간다. 마지막 처리 위치를 저장하므로 앱을 다시 열었다고 처음부터 색인하지는 않는다.
파일을 찾은 다음에는 익숙한 방식으로 다룰 수 있어야 했다. 한 번 눌러 선택하고 두 번 눌러 열기, 뒤로 가기와 상위 폴더 이동, 복사·잘라내기·붙여넣기, 이름 변경과 휴지통 삭제 같은 기본 동작을 붙였다.
파일 아이콘과 우클릭 메뉴는 Windows 탐색기의 것을 사용했다. 익숙한 모양을 그대로 쓰면 편할 줄 알았는데, 가져오는 것만으로 끝나지는 않았다.
빈 공간에서 우클릭했더니 새 폴더가 두 개 나왔다. 처음에는 앱 쪽에서 명령을 두 번 넣었나 싶었지만 Windows Shell에서 받은 메뉴 안에 이미 중복이 있었다. 중복을 정리하고 다시 눌러보니 이번에는 현재 폴더가 아닌 상위 폴더에 새 폴더가 만들어지는 경우도 확인됐다. 메뉴에서 새 폴더를 만드는 경로를 기존 툴바 동작에 연결하고, 생성된 위치와 선택 상태까지 다시 확인했다.
화면에 메뉴 하나가 보인다고 그 기능이 끝난 건 아니었다.
자꾸 눈에 밟히는 것들
파일 보기 크기를 바꾸면 기본 아이콘이 잠깐 나왔다가 Windows 아이콘으로 바뀌었다. 탭을 옮기거나 목록을 다시 그릴 때도 비슷한 깜빡임이 보였다.
이 문제는 이미 받아둔 아이콘을 다시 쓰도록 고쳤다. 정확한 크기가 없으면 가까운 크기의 아이콘을 먼저 보여준다. 새 아이콘이 준비될 때까지 기존 아이콘은 그대로 두었다.
왼쪽 메뉴를 접을 때도 아이콘 크기가 달라 보이거나 위쪽 버튼과 아래쪽 메뉴의 중심선이 어긋났다. 메일 옆에 읽지 않은 수를 붙인 다음에는 글자와 숫자 높이가 살짝 달라 보였다. 체크박스를 줄였더니 이번에는 체크 표시가 깨져 보이기도 했다.
한 번 발견하면 계속 보인다.
로딩 중이라고 화면 전체가 흐려지거나 상태 문구 때문에 목록이 아래로 밀리는 건 없앴다. 진행 표시와 취소 버튼은 정해진 자리 안에서만 바뀐다. 설정을 저장했다는 안내도 잠깐 보여주고 사라지게 했다.
파일 탭을 처음 열 때 목록이 스르륵 나타나는 효과도 빼게 됐다. 파일을 다루는 화면에서는 눌렀을 때 바로 그 자리에 보이는 쪽이 편했다.
메일 연결이 끝이 아니었다
파일 검색과 탭·분할 탐색의 기본 흐름을 잡은 뒤에야 정리와 메일 중 무엇을 먼저 할지 고민했다. 메일은 개발하면서 추가한 기능이다. 정리는 기준부터 더 생각해보기로 하고 메일부터 붙였다.
실제 계정으로 연결해서 새 메일이 들어오는 것까지 확인했다. 그런데 처음에는 제목 목록과 텍스트 본문 정도만 있었다. 메일을 가져오기는 했지만 이 상태로 계속 쓰고 싶지는 않았다.
계정 연결, 동기화 주기, 알림, 외부 이미지 허용은 설정 탭으로 옮겼다. 메일 탭에서 먼저 보여야 할 건 메일함과 목록, 본문이었다. 본문을 읽었다는 안내가 엉뚱하게 설정 화면에 남아 있던 것도 치웠다.
화면은 Thunderbird를 참고했다. 왼쪽에 메일함, 가운데에 목록, 오른쪽 위에 발신자·제목 같은 정보와 그 아래에 본문을 두었다. 메일함을 접어도 아이콘은 남기고, 목록과 본문 사이의 너비도 직접 조절하게 했다. 창은 넓은데 정작 읽는 곳이 좁은 상태를 계속 두고 싶지 않았다.

메일함·목록·본문을 나누고 오른쪽 위에 발신자와 제목을 배치했다. 표시된 계정과 메일 내용은 촬영용 예시다.
HTML 메일은 WebView2로 표시한다. 표와 이미지가 있는 메일을 텍스트로만 보면 원래 내용을 읽기 불편했다. 그렇다고 검은 본문 영역에 텍스트가 먼저 떴다가 웹뷰로 갈아끼워지는 모습도 별로였다. 준비가 끝난 본문을 같은 배경에서 보여주도록 바꾸고 다크 테마도 맞췄다.
WebView2의 스크립트 실행을 끄고, 메일 HTML에서도 스크립트와 이벤트 속성을 제거한다. 외부 이미지는 기본 차단하고, 현재 메일에서 허용하거나 설정에서 항상 허용하도록 했다. 원래 메일의 복잡한 서식까지 전부 똑같이 보여주는 단계는 아니다.
클릭할 때마다 다시 가져오나?
Thunderbird와 비교하면서 신경 쓰였던 건 속도였다. 메일을 바꿀 때마다 목록이 다시 갱신되는 것처럼 보였고, 읽지 않은 메일 하나를 눌렀을 뿐인데 왼쪽 메뉴와 받은편지함까지 흐릿해졌다.
이쯤 되면 서버가 느린 건지, 앱이 굳이 다시 그리는 건지 구분해서 봐야 했다.
읽음 상태 하나 바뀌었다고 목록 전체를 비울 필요는 없었다. 기존 항목에서 필요한 상태만 바꾸면 된다. 그렇게 바꿔서 선택한 메일과 스크롤 위치를 유지하고, 웹메일에서 읽은 상태는 다음 동기화 때 반영하도록 했다.
한 번 가져온 데이터는 메모리에서 다시 쓴다. 본문에는 디스크 캐시도 붙였다. 메모리에서 찾고, 없으면 디스크를 보고, 거기에도 없을 때 서버에서 가져오는 순서다. 메일함을 옮길 때도 이미 가져온 목록부터 보여주고 오래된 목록은 뒤에서 갱신한다. 다시 내려받는 횟수를 줄이는 캐시이지, 모든 메일을 영구 보관하는 백업 기능은 아니다.
트레이에 있어도 설정한 주기로 받은편지함을 확인하고 새 메일을 알리도록 했다. 다만 메일 확인은 앱이 실행 중일 때만 동작한다. 파일 색인 서비스와는 별개라 트레이에서 앱을 완전히 종료하면 메일 확인도 멈춘다.
현재는 한 계정의 메일함 조회, 본문과 첨부파일 확인·저장, 읽음과 중요 표시, 이동과 휴지통 처리를 넣은 상태다. 작성·답장·전달·발송이나 여러 계정 동시 연결은 아직 없다. 가져오는 목록도 메일함별 최근 30일 중 최대 500개로 제한했다. 이 정도면 메일 쪽 첫 사용 흐름은 잡혔지만, Thunderbird를 대체한다고 말할 단계는 아니다.
설치 파일에서 다시 걸렸다
내 PC에서 실행하는 단계를 넘어서, 다른 PC에도 설치할 수 있는 형태로 묶고 싶었다. 여기서는 당연히 EXE 하나를 받아서 설치하는 흐름을 생각했다.
처음 시험한 MSIX 방식은 인증서 등록 얘기부터 나왔다. Tauri나 Electron으로 만든 앱에서는 설치 파일을 실행해서 쓰던 경험이 있는데, 이번 앱의 사용자가 인증서 설정까지 해야 하는 건 원하지 않았다.
그래서 NSIS 기반 EXE로 정리했다. 앱뿐 아니라 백그라운드 색인 서비스와 필요한 실행 환경도 함께 넣었다. 사용자가 .NET SDK나 개발자 모드를 따로 준비할 필요는 없다. 서비스 설치에는 Windows 관리자 승인이 필요하다.
설치 방식을 바꾸다 보니 다른 저장소를 쓰는 서비스가 이미 있다는 문제도 나왔다. 같은 프로그램인데 설치한 방식에 따라 색인 DB가 달라지면 다음 업데이트는 또 어떻게 해야 하나 싶었다. DB 경로는 공통으로 맞췄다. 기존 데이터가 있으면 백업을 남기고 옮기도록 했다.
재설치나 업데이트 때문에 쌓아둔 색인을 버리고 다시 만드는 일은 피하고 싶었다.
자동 업데이트도 붙였다. 자동 확인을 켜두면 앱을 켠 뒤와 이후 6시간마다 새 버전을 확인한다. 배포 정보의 서명을 먼저 확인하고, 사용자가 설치를 승인하면 EXE를 내려받아 크기와 SHA-256 해시를 그 정보에 기록된 값과 비교한다. 확인을 마친 뒤 앱을 종료하고 설치를 넘긴다. NAS에는 전용 배포 사이트를 따로 두고, 다른 앱도 각자 폴더를 나눠 올릴 수 있게 준비했다.
다만 1.0.0을 배포한 뒤 해당 버전의 업데이트 서명 키를 잃어버렸다. 1.0.0에 포함된 공개키로는 새 키로 서명한 배포 정보를 검증할 수 없기 때문에, 1.0.0에서 1.0.2로 넘어갈 때는 설치 파일을 직접 받아야 한다. 1.0.2에는 새 공개키를 넣었고, 이후 버전의 자동 업데이트는 이 키를 기준으로 이어간다.
설정 화면에는 배포 서버 주소도 적혀 있었는데 지웠다. 배포를 관리하는 나한테나 필요하지, 앱을 쓰는 사람한테까지 계속 보여줄 이유는 없었다.
현재 배포 중인 1.0.2 설치 파일은 NAS에 올려뒀다. Windows 11 x64 환경에서 아래 파일을 내려받아 설치하면 된다.
1.0.0을 쓰고 있다면 트레이에서 FlowDesk를 완전히 종료한 뒤 1.0.2를 수동 설치한다. 다른 PC에서의 실제 설치와 재설치는 더 확인해야 한다. EXE에 공인 코드 서명은 없어서 Windows 보안 경고가 표시될 수 있다. 사용자에게 인증서를 등록시키지 않는 것과 경고가 없는 것은 별개다.
정리는 일단 비워뒀다
처음 구상에는 파일 정리도 있었다. 바탕화면이나 다운로드 폴더에 쌓인 파일을 자동으로 분류하고 옮겨주는 기능이다. AI를 붙이는 것도 생각해봤다.
그런데 확장자별로 폴더를 나누는 정도와 실제로 내가 원하는 정리는 꽤 다를 것 같았다. 같은 PDF여도 같이 둬야 하는 파일이 있고, 오래됐다고 지워도 되는 파일인지 날짜만 보고 결정할 수도 없다. AI가 분류를 잘해도 어디까지 제안하고 어느 시점에 파일을 움직일지부터 정해야 했다.
아직 그 기준을 못 잡았다. 그래서 정리 화면은 걷어내고, 홈에는 ‘추후 개발 예정’이라는 안내만 남겼다. 파일 탐색과 메일을 쓰면서 필요한 쪽부터 더 생각해보려 한다.
Codex와 같이 만든 과정
이번에도 Codex와 같이 작업했다. 기능을 정해서 요청하고 앱을 켜봤다. 거슬리는 게 보이면 다시 얘기하고, 수정하면 또 눌러봤다. 처음에 요청한 기능보다 화면을 보고 덧붙인 얘기가 더 많았다.
소스를 고쳤고 빌드도 성공했는데 화면이 그대로인 적도 있었다. 확인해보니 새로 빌드한 파일과 실제 실행 중인 AppX 폴더의 파일이 달랐다. 이후에는 실행 경로와 DLL·리소스 해시가 맞는지부터 확인한 다음 화면을 보게 됐다.
1.0.0을 묶을 때는 자동 테스트 439개가 통과했다. 설치 파일에서 다시 꺼낸 801개 파일은 패키징에 사용한 원본 파일 목록의 SHA-256 해시와 비교했고, 모두 일치했다. 물론 이 숫자로 다른 PC의 설치나 장시간 사용까지 확인한 셈 칠 수는 없다. 실제로 눌러보고 발견한 문제들이 따로 있었으니까.
여기까지를 1.0.0으로 잡았다. 메일까지 붙었지만 처음 만들고 싶었던 건 그대로다. Everything에서 파일을 찾고 여러 탐색기 창을 오가던 일을, 빠른 검색과 분할 화면이 있는 한 앱에서 하고 싶었다. 이제 평소 하던 파일 작업에 써보면서 창을 덜 띄우고도 편하게 일할 수 있는지 더 확인해볼 생각이다.
댓글