기능

기능 목록이 아니라 한 번의 작업입니다

연결을 만들고, 쿼리를 돌리고, 결과를 고치고, 상태줄을 확인하는 데까지 여덟 장면으로 따라갑니다. 여덟 장 전부 실제 화면이고, 한 장도 늘이거나 줄이지 않았습니다.

01연결

먼저 연결을 만듭니다

DB 타입을 고르고 호스트 · 포트 · 계정을 적습니다. 여기서 이미 두 가지가 정해집니다 — 비밀번호가 어디에 저장되는지, 그리고 이 연결이 운영 서버인지.

새 연결 폼(General 탭). Name 칸에 “New Connection”, DB Type 드롭다운에 “MySQL / MariaDB”, 그 옆에 “Mark as a production server (red tab and status bar)” 체크박스. 아래로 Host localhost, Port 3306, User root, Password 빈 칸과 그 아래 설명 줄, Default Database scratch.
비밀번호 칸 아래에 저장 위치가 적혀 있습니다 — Stored only in the OS keychain (never written to the profile file). 「OS 키체인에만 저장되고 프로파일 파일에는 기록되지 않는다」는 뜻입니다. 위쪽 체크박스 Mark as a production server 는 이 연결을 운영 서버로 표시합니다.

비밀번호는 OS 키체인에만 들어갑니다

macOS 는 Keychain, Windows 는 Credential Manager 입니다. 평문으로 저장되는 경로가 없습니다. 프로파일 파일을 열어도 비밀번호는 없습니다.

운영 서버는 눈에 띄게 달라집니다

운영 서버로 표시해 둔 연결은 탭과 상태줄이 다르게 보입니다. 지금 어디에 붙어 있는지를 기억에 맡기지 않습니다.

붙은 다음, 가만히 둬도 끊기지 않습니다

서버의 wait_timeout · interactive_timeout 을 읽어 그 절반 주기로 ping 합니다(15~60초로 제한). 다만 자동 재연결은 일부러 하지 않습니다 — 끊긴 연결을 몰래 되살리면 열려 있던 트랜잭션이 조용히 사라지기 때문입니다. SSH 터널이 필요하면 같은 폼의 두 번째 탭에서 설정합니다.

SSH 터널은 같은 폼의 두 번째 탭입니다

중간 서버를 거쳐야 하는 연결도 별도 도구 없이 같은 자리에서 설정합니다. 이 탭의 안내문들이 무엇을 묻는지가 아니라 무엇이 어디에 저장되는지를 말한다는 점이 연결 폼과 같습니다.

연결 폼의 SSH Tunnel 탭. “Open this connection through a jump server” 체크박스, SSH Host bastion.example.com, SSH Port 22, SSH User deploy, Authentication “Key file”, Private Key File 선택 버튼, Key passphrase, Host Key Fingerprint 칸과 각각의 설명 줄.
키 파일 칸은 Only absolute paths are stored, 암호 칸은 Stored in the OS keychain as an entry separate from the DB password — DB 비밀번호와 다른 항목으로 키체인에 들어갑니다. 지문은 The fingerprint is checked and stored on the first connect 라, 처음 붙을 때 받아 두고 다음부터 대조합니다. 손으로 적어 넣는 칸이 아닙니다.

02capability

연결하고 나면 화면이 그 DB 답게 갈립니다

네 종류를 한 화면에 밀어 넣은 것이 아닙니다. 어댑터가 붙고 나면 이 DB 가 무엇을 할 수 있는지 물어보고, 그 대답에 따라 화면 요소가 켜지거나 꺼집니다. 그래서 Redis 에서는 쿼리 에디터가 아니라 키 브라우저가 뜹니다. Redis 는 SQL 이 아니라 KV 니까요.

DB 성격 화면이 달라지는 지점
MySQL · MariaDBSQL기준 화면
PostgreSQLSQLDDL 이 트랜잭션 안에서 롤백됩니다
SQLiteSQL컬럼 타입 변경이 테이블 재작성이고, 사용자·권한 화면이 없습니다
RedisKV키 브라우저 · TTL · 값 타입별 뷰. 쿼리 에디터가 아닙니다
Redis 에 붙은 DBerio 창. 쿼리 에디터가 없고, 왼쪽은 키 패턴 입력칸과 db0 아래 폴더 트리(bulk · tags · text · user · stream · leaderboard · queue · counter · big · session), user:3 아래에 name string 과 profile hash. 오른쪽은 “user:3:profile hash · TTL Permanent · Set expiry” 머리줄과 field/value 표. 맨 아래 상태줄에 Key ≈10,026 · hash TTL Permanent · Transaction Interactive transactions not supported.
같은 앱인데 쿼리 에디터가 없습니다. 키 트리에는 값 타입이 배지로 붙고(string · hash), 머리줄에 TTL Permanent 와 만료를 거는 버튼이 섭니다. 상태줄 오른쪽은 한 발 더 나갑니다 — Transaction: Interactive transactions not supported. 트랜잭션 UI 를 회색으로 눌러 둔 것이 아니라, 이 DB 에서는 성립하지 않는다고 적어 둔 것입니다.

창 전체입니다(1440×892). 맨 아래 상태줄까지 보여야 하는 그림이라 자르지 않았습니다. 이미지는 1:1 이고, 화면이 좁으면 그림 안에서 옆으로 밀어 보세요.

물어보는 것은 라벨이 아니라 화면 요소입니다

“SQL 이냐 KV 냐” 같은 큰 딱지를 붙이지 않습니다. UI 가 실제로 알아야 하는 것은 이 화면 요소가 성립하는가 하나뿐이라서, capability 도 그 단위로 되어 있습니다.

capability 무엇을 묻는가
transactional_ddlDDL 이 트랜잭션 안에서 롤백되는가
supports_interactive_transactionautocommit / commit / rollback 이 의미를 갖는가
supports_ttlTTL 개념이 있는가
supports_column_modify기존 컬럼 타입 변경이 되는가
supports_editable_resultsetF8(편집 가능한 결과)이 켜질 수 있는가
supports_multiple_result_sets다중 결과셋을 낼 수 있는가
supports_user_admin사용자·권한 화면이 성립하는가
supports_schema_sync스키마 동기화 도구가 성립하는가
value_typesKV 값 타입 — String · Hash · List · Set · ZSet · Stream

이 페이지에 실린 화면은 MySQL 과 Redis 둘뿐입니다. PostgreSQL · SQLite 화면은 아직 실제 캡처가 없어 싣지 않았습니다. 없는 화면을 그리거나 다른 화면에 그 이름을 붙이는 대신, 그 둘은 위 표의 글로만 말합니다.

03실행

실행 키가 셋이고, 셋의 뜻이 서로 다릅니다

키가 셋이라는 게 요점이 아닙니다. 같은 쿼리를 어떤 결과로 받을지가 셋으로 갈린다는 것이 요점입니다. 그리고 그 계약은 문서가 아니라 버튼 아래 작은 글씨에 적혀 있습니다.

실행 툴바의 세 버튼. 왼쪽부터 “Execute — One query at the cursor · read-only”, “Execute (Editable) — Same query · asks for an editable result”, “Execute Selection — Selection only · does nothing without one”.
세 버튼이 각자 자기 계약을 아래에 적고 있습니다. 눌러 보고 알게 되지 않습니다.
  • F9 ExecuteOne query at the cursor · read-only
  • F8 Execute (Editable)Same query · asks for an editable result
  • Ctrl+F9 Execute SelectionSelection only · does nothing without one

기본이 안전한 쪽입니다

F9 는 커서가 놓인 문장 하나만 돌리고, 결과는 읽기 전용입니다. 기본 LIMIT 1000 이 붙고, 한 행을 더 읽어 “더 있음”을 판별합니다 — 천만 행을 실수로 끌어오지 않습니다. 잘못 던졌으면 세션을 끊지 않고 멈출 수 있습니다. 쿼리 취소는 모든 어댑터의 계약 필수 항목입니다.

선택이 있으면 세 번째 버튼이 그 사실을 말합니다

선택 영역이 있는 상태의 실행 툴바와 에디터 세 줄. 세 번째 버튼의 설명이 “Selection only · 3 lines right now” 로 바뀌어 있고, 아래 에디터에는 SELECT … FROM scratch.orders ORDER BY placed_at DESC 세 줄이 선택된 채로 보인다. 오른쪽에는 autocommit ON 토글과 Commit · Rollback 버튼.
드래그해 두면 세 번째 버튼의 설명이 Selection only · 3 lines right now — 「지금 3줄」로 바뀝니다. 무엇이 돌지 누르기 전에 알 수 있고, 선택이 없으면 아예 실행하지 않습니다(does nothing without one) — 조용히 전체를 돌리는 일이 없습니다.

위 그림은 원본 크기 그대로입니다(1044×112). 화면이 좁으면 그림 안에서 옆으로 밀어 보세요.

탭이 늘어나지 않습니다

F9 와 F8 은 같은 결과 탭을 덮어씁니다. 실행할 때마다 탭이 쌓이지 않습니다.

04결과

결과가 자기 상태를 스스로 적습니다

F9 로 돌린 결과입니다. 머리줄에 Read-only (F9) · F8 to edit 이 이미 적혀 있습니다 — 「읽기 전용이고 고치려면 F8」. 편집 계열 동작도 같은 이유로 꺼져 있습니다. “왜 안 되지”를 눌러 보고 알게 되는 구조가 아닙니다.

읽기 전용 결과 그리드. 컬럼 머리에 id bigint unsigned · customer_id int unsigned · amount decimal(10,2) · status varchar · placed_at timestamp, 그 아래로 placed_at 내림차순 12행.
컬럼 머리가 이름과 타입을 같이 적습니다 — amount decimal(10,2) 처럼. 자릿수가 두 자리인지 네 자리인지 세어 보지 않아도 됩니다. 정렬도 id 가 아니라 placed_at 을 따라간다는 것이 그대로 보입니다 — F9 로 돌렸기 때문에 결과는 읽기 전용입니다.

위 그림은 원본 크기 그대로입니다(1030×246). 화면이 좁으면 그림 안에서 옆으로 밀어 보세요.

편집이 꺼지는 사유는 타입으로 정의돼 있습니다

화면이 얼버무리지 않는 근거입니다. 꺼져 있으면 아래 다섯 중 하나이고, 그 이유가 그대로 표시됩니다.

사유 무슨 상황인가
요청 안 함F9 로 돌렸습니다. 편집 가능한 결과를 요청하지 않았습니다
어댑터 미지원이 DB 의 어댑터가 편집 가능한 결과셋을 지원하지 않습니다
원본 테이블 없음표현식·집계뿐이라 되돌려 쓸 자리가 없습니다
여러 테이블JOIN 결과라 어느 테이블을 고칠지 결정할 수 없습니다
같은 원본 컬럼이 두 번셀프 조인입니다. 틀린 행이 조용히 갱신되는 것을 막습니다

내보내기는 화면에 뜬 행이 아니라 쿼리를 다시 돌립니다

이 구분이 중요합니다. 기본 실행에는 한도가 붙어 있으므로, 화면의 행을 그대로 저장하면 잘린 앞부분만 파일이 됩니다. 그래서 같은 문장을 한도 없이 다시 돌려 씁니다.

“Export Result Set — scratch-mysql” 대화상자. Target 은 “Query result (12 rows shown)” 이고 그 아래 설명 줄, Format 은 CSV · TSV · JSON 중 CSV 선택, Save file 은 파일 선택 버튼으로만 지정, Delimiter 쉼표, “Write column names on the first line” 체크됨, Encoding UTF-8 과 줄바꿈 CRLF. 맨 아래에 “Export is read-only — it does not change the source data.”
설명 줄이 그 이유를 그대로 적어 둡니다 — Writes the result of re-running the same statement with no row limit, not the rows on screen. 「화면의 행이 아니라 같은 문장을 한도 없이 다시 돌린 결과를 쓴다」는 뜻입니다. 맨 아래 줄은 Export is read-only — it does not change the source data. 내보내기가 원본을 건드리지 않는다는 약속입니다. (이 화면은 결과셋 내보내기라 형식이 셋입니다. 테이블 데이터 쪽은 SQL 과 Excel 까지 냅니다.)

그리드는 보이는 행만 그리고(가상화 렌더링), 큰 결과는 한 번에 넘기지 않고 청크로 흘려보냅니다. 저장 경로를 직접 타이핑할 수 없게 막아 둔 것도 같은 규율입니다 — 파일 대화상자가 돌려준 절대 경로만 들어갑니다.

05편집

고칠 생각이 있을 때만 F8 을 누릅니다

같은 문장을 F8 로 다시 돌리면 결과 모드가 바뀝니다. 머리줄도 같이 바뀝니다.

편집 가능한 결과 그리드. 머리줄에 “완료 3행 · 47ms · 첫 청크 36ms · 편집 가능 — 셀을 고치고 행을 떠나면 저장됩니다 (Esc 취소)”. 행 선택 체크박스가 켜져 있다.
머리줄의 배지가 Editable — edit a cell and leave the row to save (Esc to discard) 로 바뀝니다 — 「셀을 고치고 행을 떠나면 저장, Esc 면 취소」. 저장 시점을 배지가 직접 말해 줍니다. 언제 반영되는지 짐작하지 않아도 됩니다.

위 그림은 원본 크기 그대로입니다(1030×298). 화면이 좁으면 그림 안에서 옆으로 밀어 보세요.

이 한 단계가 이 제품의 존재 이유입니다

고치려면 키를 따로 눌러야 하므로, 실수로 운영 데이터를 건드릴 경로가 기본에 없습니다. 하루 종일 쓰는 사람이 체감하는 것은 기능의 개수가 아니라 이런 기본값입니다.

06상태줄

나머지는 상태줄이 적습니다

결과 머리줄이 “이 실행”에 대해 말한다면, 상태줄은 “지금 이 창”에 대해 말합니다. 연결 상태 · 선택 범위 · 커서 위치 · 인코딩이 그대로 적혀 있습니다.

상태줄 오른쪽 구간. “Connected to scratch-mysql · Selection 3 lines · 98 chars · Cursor Ln 3, Col 27 · UTF-8”.
연결 이름 · 선택 범위(3 lines · 98 chars) · 커서 위치 · 인코딩이 그대로 적혀 있습니다. 왼쪽 구간에는 서버 버전 · 부하 · 트랜잭션 모드가 있습니다 — 장면 08 에서 같이 보입니다.

테이블 옵션도 같은 규율을 따릅니다. 서버의 실제 값을 읽어 오기 때문에 AUTO_INCREMENT 는 실제 다음 번호이고, 엔진은 그 테이블의 실제 엔진입니다.

07단축키

여기까지 쓴 키는 전부 계약 파일 한 장에서 나옵니다

바인딩의 원본은 docs/keymap-contract.json(v0.7) 하나입니다. 컴포넌트에 단축키를 직접 적는 것이 금지돼 있고, 감사가 계약과 구현을 기계로 대조합니다. 손으로 맞춘 것이 아니라 대조된 것입니다.

사용자가 느끼는 결과는 셋입니다 — 세 OS 에서 같고, 전부 바꿔 쓸 수 있고(JSON 내보내기 포함), 버전이 올라도 안 바뀝니다.

항목 값
액션102개 (동작의 수)
단축키 조합Windows 114 · macOS 126
듣는 범위global 66 · editor 19 · grid 9 · browser 6 · dialog 2
분류editor 18 · schema 18 · result 12 · connection 9 · common 9 · browser 6 · powertool 5 · tools 5 · statement 4 · query 3 · format 3 · panel 3 · user 3 · app 3 · favorites 1

macOS 에서 달라지는 것은 이만큼이 전부입니다

원칙은 “Ctrl 조합을 macOS 에서도 그대로 둔다”입니다. OS 예약키와 부딪히는 자리는 Windows 키를 지우지 않고 대체 키를 하나 더 붙였습니다. 액션 102개 중 macOS 에서 키가 달라지는 것은 13개이고, 그중 12개는 Windows 키를 그대로 둔 채 Cmd 조합을 더한 것입니다. Windows 키가 사라진 항목은 종료 하나뿐입니다 — Alt+F4 는 macOS 에 없어서 Cmd+Q 로 갈렸습니다.

동작 Windows macOS 이유
자동완성 Ctrl+SpaceCtrl+Space · Option+EscCtrl+Space 가 입력 소스 전환 — 한글 사용자 다수가 실제로 씁니다
Insert/Update 다이얼로그 F11F11 · Cmd+F11F11 이 시스템 “데스크톱 보기”
탭 닫기 Alt+LAlt+L · Cmd+WmacOS 관례 — 연결 끊기와 구분합니다
복사 · 붙여넣기 · 저장 · 찾기 · 실행취소 Ctrl+…Ctrl+… · Cmd+…범용 편집 동작은 Cmd 조합을 함께 받습니다
종료 Alt+F4Cmd+Q유일하게 Windows 키를 대체한 항목입니다

미리 말해 둘 마찰 하나. macOS 는 F1~F12 가 기본으로 미디어 키입니다. F9 · F8 · F12 를 쓰려면 시스템 설정에서 “F1, F2 등의 키를 표준 기능 키로 사용”을 켜야 합니다.

첫 실행 안내가 이 설정을 짚어 주고, Fn 조합도 함께 인식합니다.

메뉴도 같은 계약에서 생성됩니다 — macOS 는 네이티브 메뉴바, Windows 는 인윈도우 메뉴바이고, 메뉴에 키를 손으로 적는 자리가 없습니다.

08한 창

지금까지 본 것은 조각이 아니라 한 창입니다

결과 머리줄(04) · 그리드(05) · 상태줄(06) 은 따로 있는 화면이 아닙니다. 아래는 메인 창의 아래쪽 절반을 원본에서 그대로 잘라낸 것입니다 — 셋이 이렇게 붙어 있습니다.

메인 창 아래쪽 절반. 왼쪽은 오브젝트 브라우저 패널의 빈 아래 영역, 오른쪽은 Result 1·Profiler·Messages·Table Data·Info·History 탭과 결과 머리줄 “Done 12 rows · 59ms First chunk 51ms · Read-only (F9) · F8 to edit”, 그 아래 결과 그리드, 그리고 창 맨 아래를 가로지르는 상태줄.
한 창의 아래쪽 절반입니다. 맨 아래 상태줄 왼쪽에 Load 0.6 q/s · 2 / 151 · 2 와 서버 버전 · 트랜잭션 모드가 있고, 오른쪽 끝에 장면 06 에서 본 커서 위치가 그대로 있습니다.

원본 1440×892 의 y=562 아래를 자른 것입니다. 자른 자리는 에디터와 결과 패널을 가르는 경계라 행 한가운데가 아니라 패널 경계에서 끊깁니다. 이미지는 1:1 이고, 화면이 좁으면 그림 안에서 옆으로 밀어 보세요.

왼쪽은 필터 한 칸으로 다 걸립니다

잘라 낸 위쪽 왼쪽에는 오브젝트 브라우저가 있습니다. 필터는 테이블만 거르지 않습니다 — 같은 글자로 뷰 · 프로시저 · 트리거까지 한꺼번에 걸립니다.

오브젝트 브라우저 패널. root@127.0.0.1:33107 아래 필터 칸에 “ord” 가 입력돼 있고, scratch utf8mb4 아래로 Tables(order_items · orders), Views(v_customer_orders), Stored Procedures(sp_count_orders), Triggers(trg_orders_ai AFTER INSERT · orders, trg_orders_bi BEFORE INSERT · orders) 가 걸려 있다.
ord 세 글자에 테이블 · 뷰 · 프로시저 · 트리거가 같이 걸렸습니다. 트리거는 AFTER INSERT · orders 처럼 언제 어디에 걸린 트리거인지까지 옆에 답니다. 어느 종류인지 먼저 고르고 찾는 것이 아니라, 이름을 알면 바로 나옵니다.

창의 나머지 구성

탭은 3중입니다 — 연결 탭 / 쿼리 탭 / 결과 탭. 이 밖에 연결 매니저, 테이블 구조 편집기(컬럼 · 인덱스 · 외래키 · 옵션 · SQL 미리보기), 사용자·권한 화면이 있습니다.

끝만듦새

오류 메시지까지 한국어입니다

앱 언어는 셋입니다 — 한국어 · English · 日本語. 앱 안에서 Alt+Shift+L 로 바꿉니다. 번역 대상 문구는 언어마다 1,499개로 같습니다.

많은 도구가 화면만 번역하고 서버·엔진 오류는 영어로 뱉습니다. 이쪽은 백엔드가 값이 박힌 문장 대신 틀과 자리값을 보내기 때문에, 오류 문장 자체가 사용자 언어로 조립됩니다. 다만 서버가 준 원문(MySQL · PostgreSQL 방언 메시지)은 그대로 보여줍니다 — 그건 저희가 옮길 문장이 아닙니다.

무엇으로 만들었나

층 내용
셸Tauri 2로 만들었고, Electron 대신 OS 웹뷰를 씁니다. Windows에서는 WebView2, macOS에서는 WKWebView입니다.
백엔드Rust — mysql_async · tokio-postgres · russh · keyring
프론트React 19 · TypeScript · Monaco 에디터 · Glide 데이터 그리드 · Zustand
IPC 타입Rust 정의에서 TypeScript 를 생성합니다. 손으로 맞추지 않습니다

에디터는 Monaco 입니다. 스키마를 읽어 자동완성에 연결하고, 에디터 내부 키도 같은 키맵 레지스트리와 동기화됩니다. 내보내기는 진입점마다 형식이 다릅니다 — 테이블 데이터는 CSV · TSV · JSON · SQL · Excel(xlsx), 결과셋은 CSV · TSV · JSON 입니다. DB 접속과 라이센스 검증은 컴파일된 Rust 바이너리 안에 있습니다 — 프론트엔드 JS 에 검증 로직을 두지 않았습니다.

“Export Table Data — scratch-mysql” 대화상자. Target 은 scratch.orders 이고, Format 줄에 CSV · TSV · JSON · SQL · Excel (xlsx) 다섯 개가 나란히 서 있다.
테이블 데이터 쪽에는 다섯 형식이 한 줄에 섭니다 — CSV · TSV · JSON · SQL · Excel (xlsx). 결과셋 내보내기와 형식이 다른 것은 실수가 아니라 진입점이 다르기 때문입니다.
에디터 두 줄. “SELECT id, customer_id, amount, status” 아래 “FROM scratch.or” 까지 친 상태에서 자동완성 목록이 떠 있고, order_items · orders · sp_count_orders · v_customer_orders 네 후보의 “or” 부분이 굵게 표시돼 있다. 후보마다 테이블 · 프로시저 · 뷰를 가리키는 아이콘이 다르다.
스키마에서 읽어 온 후보라 테이블뿐 아니라 뷰와 프로시저까지 같이 나오고, 아이콘이 어느 종류인지 가릅니다. 친 글자 or 이 후보 안에서 어디에 걸렸는지도 굵게 표시됩니다 — 이름 앞이 아니라 중간에 걸려도 보입니다.

여기에 “몇 배 빠름” 같은 숫자를 적지 않은 이유는 재본 적이 없기 때문입니다. 메모리 사용량도, 시작 시간도, 쿼리 속도도 측정하지 않았습니다. OS 웹뷰를 쓰는 네이티브 앱이라는 구조 사실까지가 지금 말할 수 있는 전부입니다.