ee-database 동기화 클라이언트 - Entity Enricher 문서

ee-database 동기화 클라이언트

schema 데이터베이스를 위한 오픈소스 적용 클라이언트입니다. 자체 PostgreSQL에 접근할 수 있는 아무 머신에서나 실행하고 한 번 페어링하면, 해당 데이터베이스를 enrichment와 계속 동기화된 상태로 유지합니다. 스냅샷에서 부트스트랩한 뒤, 단일 아웃바운드 WebSocket으로 실시간 델타 피드를 적용합니다. 연결 문자열은 해당 머신을 벗어나지 않습니다.

Entity Enricherserver · outboxee-database여러분의 컴퓨터데이터베이스Postgres · MySQL · SQLitebatch · 리스 120초apply — 단일 트랜잭션커밋ack 다음 윈도우가 즉시 푸시됩니다

모든 구문은 리비전으로 보호되므로 재전송된 배치는 동일한 행으로 수렴합니다. SQL 오류가 발생하면 배치가 롤백되고 중단됩니다. 문제가 있는 델타가 조용히 건너뛰어지는 일은 없습니다.

클라이언트는 작업이 아니라 상태를 가져옵니다. 각 델타는 변경된 엔터티의 현재 행 전체를 멱등 INSERT … ON CONFLICT … DO UPDATE 형태로 담고 있으므로, 배치를 놓치더라도 대상이 수렴합니다.

동기화 클라이언트를 사용하는 이유는?

데이터베이스 동기화는 여러 방식으로 사용할 수 있습니다 — n8n, Make.com, MCP, 원시 웹훅, 또는 REST 델타 피드. 동기화 클라이언트는 완전 자동화된 방식으로, 구축할 것도 가장 적고 유출될 위험도 가장 적습니다.

구축할 워크플로가 전혀 없습니다

n8n 시나리오도, cron도, 글루 코드도 필요 없습니다. 한 번 페어링하면 스냅샷에서 부트스트랩한 후, 도착하는 모든 델타를 적용합니다.

DSN은 여러분의 컴퓨터를 벗어나지 않습니다

연결 문자열은 명령줄로 전달되거나 로컬에 mode-600으로 저장되며, Entity Enricher로는 절대 전송되지 않습니다. 클라이언트는 바깥쪽으로만 연결합니다.

설계상 재실행에 안전합니다

모든 델타는 멱등적이며 리비전으로 보호되는 upsert입니다. 배치 도중 클라이언트가 중단되면 리스가 만료된 후 배치가 재전송되며, 다시 적용해도 동일한 행으로 수렴합니다.

실패 시 격리하며, 조용히 넘어가지 않습니다

SQL 오류가 발생하면 배치가 롤백되고 실패한 델타가 보고됩니다. 서버는 해당 보강의 배치 전체를 격리하고 이를 제외한 채 큐를 다시 전송하므로, 클라이언트는 연결을 유지하며 계속 적용합니다. 잘못된 행 하나가 뒤따르는 모든 작업을 멈추게 할 수 없으며, 격리된 작업은 처리할 때까지 목록에 남아 있습니다.

빠른 시작

먼저 schema에 데이터베이스를 등록한 다음, 클라이언트를 페어링하고 데이터베이스에 접근할 수 있는 머신에서 실행합니다.

  1. 1

    데이터베이스 등록

    Database Sync 페이지에서 미러링하려는 스키마에 데이터베이스를 등록하고 데이터베이스 키를 확인하세요. 전체 모델은 Database Sync를 참조하세요. 이 단계에서 클라이언트가 적용할 대상 방언(dialect)을 선언합니다.

  2. 2

    클라이언트 설치

    터미널에 붙여넣으세요. 스크립트는 설치 전에 cosign 서명을 검증합니다.

    curl -fsSL https://entityenricher.ai/install-eedatabase.sh | sh

    Windows: iwr -useb https://entityenricher.ai/install-eedatabase.ps1 | iex. 또는 Releases에서 서명된 바이너리를 다운로드하거나 소스에서 빌드하세요(Go ≥ 1.23): go build -o ee-database .

    소스와 서명된 릴리스는 TOT-Concept/ee-database(MIT)에 있습니다.

  3. 3

    브라우저로 페어링하기

    ee-database pair를 실행하세요. /database/connect에서 짧은 코드와 함께 브라우저 탭이 열립니다. 코드를 확인하고, 이 클라이언트가 동기화할 데이터베이스를 선택하세요.

    ee-database pair --server https://entityenricher.ai
    
    Open this URL in your browser to confirm pairing:
       https://entityenricher.ai/database/connect?code=7QX-KP2
    
      Code: 7QX-KP2
    
    Waiting for confirmation...

    토큰을 사용하고 싶으신가요? Database Sync 페이지(Sync client → Pair a client)에서 발급한 뒤 직접 전달하세요: ee-database pair --server … <refresh-token>.

    이 흐름에서 결정할 것은 하나뿐입니다. 이 머신이 등록된 데이터베이스 중 어느 것을 동기화할지입니다. 페어링하면 해당 데이터베이스의 이전 자격 증명이 교체되므로 기존 클라이언트는 중지됩니다.
  4. 4

    데이터베이스에 접근할 수 있는 머신에서 실행합니다

    첫 실행 시 클라이언트는 .sql 스냅샷을 가져와 적용한 다음, 연결하여 델타를 스트리밍합니다. --save-dsn은 연결 문자열을 로컬에 저장하므로 이후 실행에는 인수가 필요 없습니다.

    각 실행은 로그인의 프로비저닝 권한(데이터베이스 생성, DDL, DML)도 자체 점검하여 그 결과를 Sync 클라이언트 카드에 보고하므로, 권한이 누락된 경우 delta 적용이 실패하기 전에 확인할 수 있습니다. 아직 게시된 연결 schema가 없으면 클라이언트는 연결된 상태로 대기합니다 — 첫 게시가 자동으로 피드를 시작하며, 재시작이 필요 없습니다.

    ee-database run --dsn "postgres://user:pass@localhost:5432/mydb" --save-dsn

    “Next to”는 데이터베이스 서버 위가 아니라 네트워크상 인접함을 의미합니다: DSN에 접근할 수 있는 모든 머신이나 컨테이너가 동작하며 — 보통 TLS를 강제하는 클라우드 관리형 PostgreSQL(Azure, OVHcloud, AWS RDS…)도 포함됩니다: …/mydb?sslmode=require.

    실행 중인 클라이언트가 보고하는 내용: 연결 여부와 프로비저닝 권한 자체 점검 결과입니다.

관리형 sync 호스트

여러 데이터베이스를 한 머신에서 운영하시나요? sync host는 페어링 절차를 한 단계 위로 올려 줍니다. 머신을 한 번만 페어링하면, 여기에 할당하는 모든 데이터베이스 동기화가 자동으로 확보·프로비저닝되고 동기화 상태로 유지됩니다 — 새 동기화를 등록할 때 터미널 세션이 다시 필요하지 않습니다. 클라이언트 1.5.0 이상이 필요하며, 이 버전은 머신당 한 번이 아니라 서버당 한 번 페어링하므로 호스트 하나가 여러 Entity Enricher 인스턴스를 동시에 지원할 수 있습니다.

  1. 1

    호스트 등록

    Database Sync 페이지에서 툴바의 Sync hosts 버튼을 클릭하고 해당 머신 이름으로 호스트를 추가하세요. 일회용 페어링 토큰이 단 한 번만 표시되며, 안내된 설정 단계와 함께 복사해 붙여 넣을 수 있는 host pair 명령에 포함되어 제공됩니다.

  2. 2

    머신을 한 번 페어링합니다

    데이터베이스 서버에 접근할 수 있는 머신에서 이 명령을 실행하세요. --dsn데이터베이스 이름 없이 서버만 지정하는 기본 연결 문자열입니다 — 할당된 각 동기화는 이 문자열로부터 자체 데이터베이스를 도출합니다. 모든 DSN과 마찬가지로 로컬에 mode-600으로 저장되며 Entity Enricher로 전송되지 않습니다.

    ee-database host pair --server https://entityenricher.ai \
      --dsn "postgres://user:pass@host:5432/" <token>

    페어링은 로그인의 프로비저닝 권한(데이터베이스 생성, DDL, DML)을 자체 점검하며, 권한이 누락되면 즉시 실패합니다. 최소 권한 로그인을 선호하시나요? --admin-dsn을 추가하면 프로비저닝이 대신 admin 연결을 통해 누락된 각 role과 데이터베이스를 생성합니다 — admin DSN은 프로비저닝 시점에만 사용되며 저장되지 않습니다.

    호스트는 머신당 한 번만 페어링합니다. 이후 해당 호스트에 할당하는 모든 등록은 그 머신을 다시 건드리지 않고 생성·동기화됩니다.
  3. 3

    실행한 다음 UI에서 동기화를 할당하세요

    ee-database host run

    호스트는 하나의 컨트롤 플레인 WebSocket을 유지하며 UI에서 이루어진 할당에 반응합니다: 데이터베이스를 등록할 때 호스트를 선택하거나, 나중에 데이터베이스의 Overview 탭에서 선택하세요. 할당된 각 동기화는 클레임되고, 데이터베이스가 없으면 생성되며(동기화 이름을 snake_case로 변환; 호스트의 config.json에 있는 database_names로 동기화별 재정의 가능), 아래의 일반 루프로 동기화됩니다.

    다른 클라이언트와 이미 페어링된 데이터베이스는 보고되고 건너뛰며, 절대 가로채지 않습니다. UI에서 호스트를 취소하면 해당 머신이 요청한 데이터베이스별 자격 증명을 포함해 머신이 즉시 차단됩니다. 할당과 이미 동기화된 데이터는 그대로 유지되므로, 다시 페어링된 호스트는 이전 호스트가 멈춘 지점부터 재개합니다.

전달 방식: 리스와 ack

델타는 데이터베이스별 엄격한 FIFO 아웃박스를 통해 Entity Enricher를 떠납니다. 서버는 보이는 윈도우를 120초 동안 리스하여 하나의 배치로 푸시하고, 클라이언트는 배치 전체를 단일 트랜잭션으로 적용한 뒤 ack 로 응답하며, 이는 커서를 진행시키고 다음 윈도우를 즉시 트리거합니다. 배치 도중 종료된 클라이언트는 리스 만료와 서버 측 재푸시로 보호되므로, 손실되거나 이중 커밋되는 것은 없습니다.

스냅샷 = 0에서 시작하는 델타

부트스트랩과 정상 상태(steady-state)는 하나의 코드 경로를 공유합니다. 데이터베이스에 이미 시드가 있다면 --skip-bootstrap으로 부트스트랩을 건너뛰세요.

리비전으로 보호됨

각 문(statement)에는 _sync_revision이 포함되어 있어, 순서가 어긋나더라도 오래된 행이 최신 행을 덮어쓰지 않습니다.

실패 시 격리

SQL 오류가 발생하면 배치가 롤백되고, 실패한 델타가 문제의 구문 전체와 함께 보고됩니다. 서버는 해당 보강의 배치를 격리한 뒤 이를 제외하고 큐를 다시 전송하며, 클라이언트는 나머지를 계속 적용합니다. 델타를 특정하지 못한 실패만 0이 아닌 코드로 종료됩니다.

각 윈도우가 기록하는 내용

적용된 모든 윈도우는 테이블별로 기록한 형태를 보고합니다. 따라서 야간 재보강 규모를 산정할 때 이미 확인 처리되어 사라진 델타를 로그에서 발굴할 필요가 없습니다.

applying 12 delta(s) (10831 .. 10842) in one transaction
applied 12 delta(s) in 84ms — 38 statement(s): mushroom 4 upserts,
  mushroom_common_names 12 upserts + 4 prunes, mushroom_human_uses 14 upserts + 4 prunes
acked up to delta 10842

upsert 하나가 행 하나이므로 집계 값은 행 수입니다. prune은 새 페이로드가 더 이상 참조하지 않는 자식 행이나 연결 행을 제거하는 단일 리비전 보호 DELETE입니다. 자식 행은 제자리에서 조정되며, 삭제 후 재삽입하지 않습니다. --verbose를 추가하면 델타마다 엔터티 유형, 실제 소요 시간, 자체 형태가 한 줄씩 출력됩니다.

데이터베이스와 방언(dialect)

대상 방언은 Entity Enricher의 스키마-데이터베이스 등록으로 결정되며, 클라이언트는 서버가 생성한 SQL을 그대로 적용합니다. 최초 지원 방언은 PostgreSQL이며, MySQL / MariaDB, SQL Server, Oracle 렌더러는 지원 예정입니다(MySQL 드라이버는 이미 포함되어 있습니다). 다중 구문 적용은 드라이버별로 처리됩니다(pgx simple protocol, MySQL multiStatements).

필요한 데이터베이스 권한 (PostgreSQL)

대상 데이터베이스가 이미 존재한다면, 로그인 계정에는 데이터베이스에 대한 CONNECT 권한과 대상 스키마에 대한 USAGE + CREATE 권한만 있으면 됩니다. (PostgreSQL 15부터는 public이 기본적으로 모든 사용자에게 CREATE 권한을 부여하지 않습니다.)

나머지는 모두 소유권에서 비롯됩니다. 클라이언트가 복제 테이블을 직접 생성하므로 그 테이블을 소유하게 되고, 소유권은 데이터 델타에 필요한 읽기와 쓰기 권한을 포함합니다. 소유권은 선택 사항이 아닙니다. 피드에는 PostgreSQL이 테이블 소유자에게만 허용하는 마이그레이션 구문(ALTER TABLE …, CREATE INDEX …)도 포함되며, 어떤 권한 조합으로도 이를 대체할 수 없습니다.

복제본 테이블이 이미 다른 소유자 아래에 존재하면 실행 전 권한 점검은 통과하지만 — 해당 로그인은 테이블을 만들 수 있기 때문입니다 — 첫 마이그레이션 델타가 실패합니다. 권한을 추가하는 대신 ALTER TABLE … OWNER TO <login>으로 소유권을 이전하세요(또는 소유 롤의 멤버십을 해당 로그인에 부여하세요).

델타가 격리되는 경우

데이터베이스가 거부하는 구문(대개 새 고유 인덱스에 걸리는 기존 중복이 원인입니다)이 있어도 피드는 멈추지 않습니다. 배치는 롤백되고, 클라이언트는 실패한 델타를 문제의 구문 전체와 함께(잘리지 않은 상태로) 보고하며, 서버는 해당 보강의 배치를 격리하고 이를 제외한 채 큐를 다시 전송합니다. 클라이언트는 그 뒤에 오는 모든 작업을 계속 적용합니다.

격리된 작업은 처리할 때까지 Database Sync 페이지의 Quarantine 탭에 그대로 남아 있습니다. 데이터베이스에서 원인을 해결한 뒤 재주입하거나 — 재주입은 오래된 구문을 다시 실행하는 대신 엔터티를 현재 상태에서 다시 투영합니다 — 해당 행이 더 이상 필요하지 않다면 삭제하세요.

bootstrap 실패는 경우가 다릅니다. 스냅샷은 하나의 트랜잭션이므로 일부만 적용되는 일이 없으며, 클라이언트가 이를 페어링의 프로필 디렉터리에 snapshot-failed.sql로 저장합니다(권한 0600, 시도할 때마다 교체, 다음 성공 시 삭제). 따라서 psql -f로 내용을 확인하거나 다시 실행할 수 있습니다.

보안

아웃바운드 전용

클라이언트가 :443/wss를 통해 WebSocket을 시작합니다. 데이터베이스 호스트는 인바운드 연결을 절대 수신하지 않으므로, 열어야 할 포트도 구성할 인그레스도 없습니다.

하나의 자격 증명, 하나의 데이터베이스, 하나의 클라이언트

자격 증명은 하나의 데이터베이스 동기화에만 연결됩니다. 다시 페어링하면 자격 증명이 교체되고 이전 라이브 연결이 즉시 해제됩니다.

수명이 짧은 액세스 토큰

365일 갱신 토큰(mode-600으로 저장됨)은 WebSocket을 인증하는 15분짜리 액세스 토큰으로 교환됩니다. UI에서 취소하면 실행 중인 클라이언트가 약 1초 이내에 연결 해제됩니다.

호스트 페어링 키는 불투명한 비밀 값입니다

관리형 호스트는 JWT가 아니라 짧은 eeh_… 키로 페어링합니다. 서버는 해시만 보관하고, 키는 만료되지 않으며, UI에서 호스트를 취소해야 사용이 종료됩니다.

페어링당 프로세스 하나

프로필별 잠금이 두 프로세스가 동일한 페어링을 동시에 실행하지 못하도록 막습니다. 그렇지 않으면 서로의 WebSocket 세션을 계속 밀어내게 됩니다.

범위는 한정되지만 자체 테이블을 소유합니다

클라이언트는 동기화 대상 스키마로 범위가 한정된 전용 역할로 실행하세요. 그러면 토큰이 유출되더라도 다른 것에는 손댈 수 없습니다 — 다만 복제 테이블은 그 역할이 직접 생성하게 해서 소유권을 갖도록 하세요. 마이그레이션 구문에 필요한 것은 권한 부여가 아니라 소유권입니다.

CLI 참조

명령기능
ee-database pair --server URL브라우저로 확인하는 디바이스 코드 페어링입니다. 동기화할 데이터베이스를 선택하세요.
ee-database pair --server URL <token>Database Sync 페이지에서 발급된 토큰으로 페어링합니다(헤드리스 환경에도 적합).
ee-database run --dsn DSN [--save-dsn] [--skip-bootstrap]스냅샷에서 부트스트랩한 후(건너뛰지 않는 한), 연결하여 델타를 적용합니다.
ee-database run … --create-missing대상 데이터베이스가 없으면 DSN 자체 자격 증명을 사용해 먼저 생성합니다(postgres는 CREATEDB, mysql은 CREATE 권한이 필요합니다).
ee-database run … --create-missing --admin-dsn DSN대상 DSN이 지정하는 모든 것을 관리자 연결을 통해 부트스트랩합니다. 즉, 누락된 역할/사용자(DSN의 비밀번호 포함)와 그 사용자가 소유한 데이터베이스를 생성합니다. 그러면 대상 DSN에는 생성 권한이 필요하지 않으며, 관리자 DSN은 저장되지 않습니다.
ee-database run --all하나의 프로세스에서 페어링된 모든 데이터베이스를 동시에 동기화합니다(각 데이터베이스에는 저장된 DSN이 필요합니다).
ee-database run … --verbose윈도우별 요약뿐 아니라 모든 델타의 기록 형태와 실제 소요 시간을 기록합니다. host run 명령에서도 사용할 수 있습니다.
ee-database host pair --server URL --dsn BASE_DSN [--admin-dsn DSN] <token>이 머신을 관리형 동기화 호스트로 한 번 페어링합니다 — 기본 DSN은 데이터베이스 서버를 가리키며(데이터베이스 이름은 포함하지 않음) 머신 밖으로 나가지 않습니다. 토큰은 Sync hosts 대화 상자(Database Sync 페이지의 Sync hosts 툴바 버튼)에서 발급됩니다. 서버당 페어링은 하나이며, 여러 Entity Enricher 서버에 나란히 페어링할 수 있습니다.
ee-database host run [--server URL]관리 모드: 이 호스트에 할당된 모든 데이터베이스 동기화를 자동으로 확보하고, 없으면 생성하며, 계속 동기화 상태로 유지합니다 — 데이터베이스별 페어링 없이 페어링된 모든 서버에 한 번에 적용됩니다(--server를 지정하면 하나로 제한됩니다). 이미 다른 클라이언트와 페어링된 데이터베이스는 보고만 하고 절대 가져오지 않습니다.
ee-database host status / host disconnect [--server URL]이 머신의 호스트 페어링을 표시하거나 삭제합니다. 서버 측 해지는 동기화 호스트 카드에서 진행합니다.
ee-database status페어링 상태, 서버 URL 및 페어링된 데이터베이스를 표시합니다.
ee-database disconnect한 페어링의 로컬 자격 증명을 삭제합니다. 서버 측에서는 UI에서 취소하세요.
ee-database version인쇄 버전.

자격 증명은 mode-600으로 저장되며, 페어링된 데이터베이스마다 프로필이 하나씩 ~/.config/ee-database/profiles/ 아래에 보관됩니다. 페어링은 데이터베이스당 한 번만 하면 되고, 여러 개를 페어링한 경우 --database NAME으로 하나를 선택합니다. 자동화를 전혀 원하지 않으신가요? 동일한 피드를 일반 REST로도 사용할 수 있습니다. GET /api/databases//changes 다음에 POST /api/databases//ack를 호출하세요. 자세한 내용은 Database Sync를 참고하세요.

오픈 소스

클라이언트는 MIT 라이선스로 공개 저장소에 있으므로, 누구나 자신의 데이터베이스에 대해 무엇이 실행되는지 정확히 감사할 수 있습니다.

소스: github.com/TOT-Concept/ee-database

릴리스: github.com/TOT-Concept/ee-database/releases — 각 바이너리는 배포 전에 cosign으로 서명됩니다.

설치 프로그램 감사: curl -fsSL https://entityenricher.ai/install-eedatabase.sh | less