가이드 문서

FieldWeft로 필드 단위 매핑을 그리고 분석·저장·공유하는 방법을 정리했습니다.

소개

FieldWeft 필드 단위 데이터 흐름을 시각화하는 앱입니다. 여러 데이터 소스의 어떤 필드가 다른 엔터티의 어떤 필드로 연동되는지를 그래프(엣지)로 보여줍니다. 각 엔터티는 표 형태 노드로 그리고, 중첩이 깊은 필드는 들여쓰기로 표현합니다.

대표적으로 한 시스템(특히 Spring 웹 백엔드)의 DTO·데이터 처리 흐름을 그대로 그래프로 표현합니다 — Kafka 이벤트 수신 → API 조회 → DB 조회 → 각 정보를 조합해 외부 시스템으로 전송. 최종 엔터티는 소스들의 조합이지만 슈퍼셋은 아니며(필요한 필드만 골라 옴), 어떤 필드가 최종 필드를 채우는지·값이 그대로인지 가공됐는지를 엣지로 나타냅니다.

기본 개념

  • 필드 ↔ 필드 매핑 — 엣지는 엔터티A.필드x → 엔터티B.필드y 단위입니다. 리프(말단) 필드 행만 좌(도착)·우(출발) 핸들을 갖고, object·object[] 같은 컨테이너는 핸들이 없어 리프 단위로 매핑합니다. 핸들 id 는 이름·위치와 분리된 문서 전역 stable field ID이며, address.city 같은 경로는 표시할 때 현재 트리에서 파생합니다.
  • 필드 매핑 표시 실선(keep)은 값이 그대로 유지됨, 점선(transform)은 가공됨(trim·포맷 변경 등)을 뜻합니다.
  • 엔터티 = 표 노드 — 헤더(종류 아이콘 + 이름 + 종류 라벨)와 필드 행으로 구성됩니다. 종류는 event(Kafka 이벤트)·api(API 응답)·db·other(DTO 등)로 나뉩니다.
  • 프로세스 노드 — 입력을 받아 다른 출력을 내는 블랙박스입니다. 왼쪽 input(받기만)과 오른쪽 output(내보내기만) 으로 나뉘고, 내부 매핑은 그리지 않습니다.

화면 구성

  • 왼쪽 사이드바 — 페이지 목록. 그래프 하나가 페이지 하나이며 추가·이름 변경·삭제·전환할 수 있습니다.
  • 가운데 캔버스 — React Flow 기반 인터랙티브 캔버스. 노드를 끌어 배치하고 필드 핸들을 드래그해 매핑을 만듭니다.
  • 좌하단 화면 설정 화면 설정에서 입력 변형 패널, 표시 패널, 노드 사이 엣지를 보이거나 숨기고 격자 맞춤을 켜거나 끕니다. 브라우저는 이 선택을 페이지와 읽기 전용 샘플별로 나누어 저장합니다.
  • 노드 사이 엣지 — 기본은 숨김입니다. 켜면 명시적 노드 관계는 긴 점선과 선택적 label로, 필드 매핑에서 파생된 읽기 전용 흐름은 촘촘한 점선과 필드 매핑 ×N으로 표시하며 같은 노드 쌍에 함께 있을 수 있습니다. 명시적 관계만 선택·편집·JSON 저장 대상이며, 필드 매핑을 만들거나 필드 추적 범위를 넓히지 않습니다. 숨겨도 데이터와 분석은 유지되고 새 엣지노드 관계 선택지는 비활성화됩니다.
  • 격자 맞춤 — 기본은 켬입니다. 켜면 노드·경계의 드래그와 화살표 이동을 10px 격자에 맞추고 Shift 이동은 40px입니다. 편집 페이지에서 켜거나 켜진 상태로 페이지를 열면 현재 좌표를 정렬해 자동 저장할 수 있으며 이 정렬은 되돌릴 수 없습니다. 읽기 전용 샘플은 새로고침이나 처음 상태로 뒤에도 현재 화면만 정렬합니다. 끄면 노드를 따로 움직이지 않고 자유 드래그와 화살표 5px·Shift 20px 이동으로 돌아갑니다.
  • 화면 설정 기본값 — 왼쪽 사이드바 하단의 화면 설정 기본값(접힌 레일에서도 열 수 있음)에서 새 편집 페이지가 시작할 화면 설정을 정합니다. 새 페이지는 물론 샘플·공유 링크·백업으로 이 브라우저에 추가된 페이지도 만들어질 때 이 네 값을 복사합니다. 기존 페이지는 각자의 설정을 유지하며, 기존 페이지에도 적용을 고르면 한 번만 덮어쓰고 이후 기본값 변경은 따라가지 않습니다. 읽기 전용 샘플에는 영향을 주지 않습니다.
  • 우상단 표시 패널 — 노드별 눈 아이콘으로 개별 노드를 숨기거나 다시 보이게 합니다 (데이터·위치는 보존).
  • 우하단 버튼 + 엔터티 · + 프로세스 · + 경계로 새 노드와 그룹을 만들고, 새 엣지 토글로 그릴 엣지 종류(유지/가공/노드 관계)를 고릅니다.
  • 오른쪽 개요 — 기본은 접힌 상태이며 캔버스 폭을 바꾸지 않는 오버레이입니다. 펼치면 페이지 이름(인라인 변경)·마지막 저장 시각, 엔터티/프로세스·노드 관계·매핑·필드 수와 입력 변형을 요약해 보여줍니다. 아래 코드 도구로 그래프 전체를 JSON 으로 편집합니다.

매핑 만들기

리프 필드 행의 핸들을 끌어 다른 필드의 핸들에 놓으면 새 매핑이 생깁니다. 오른쪽(출발) 핸들에서 시작해 왼쪽(도착) 핸들로 잇습니다.

우하단 새 엣지 토글로 그릴 종류를 미리 고르고, 기존 엣지를 클릭하면 컨텍스트 메뉴가 열려 라벨과 설명·태그·metadata 수정, 타입 변경 (유지 ↔ 가공), 삭제를 할 수 있습니다.

엔터티 · 프로세스 편집

우하단 + 엔터티/+ 프로세스 버튼으로 새 노드를, 노드 헤더의 ✏️ 로 기존 노드를 모달에서 편집합니다.

  • 이름·종류와 함께 필드를 추가/수정/삭제합니다. object 타입은 FieldWeft 자원 한도인 최대 64단계 안에서 하위 필드를 추가하거나 접을 수 있습니다.
  • 모달의 설명 · 태그 · metadata 섹션은 기본적으로 접혀 있습니다. 필드별 annotation은 각 행의 annotation 버튼에서 편집합니다.
  • 행 왼쪽 손잡이(⠿)를 드래그해 순서를 바꿉니다. 재배치는 같은 부모(형제) 안에서만 됩니다.
  • 필드 이름을 바꾸면 이를 참조하던 매핑·조건이 따라오고, 필드를 삭제하거나 object 로 바꾸면 그 필드에 걸린 엣지는 함께 제거됩니다.
  • 모달 왼쪽 아래 삭제 버튼(실수 방지 2단계 확인)으로 노드를 지우면 연결된 엣지도 함께 삭제됩니다.

설명 · 태그 · metadata

엔터티·프로세스·경계·모든 필드·매핑에는 같은 공통 annotation을 선택적으로 기록할 수 있습니다. 이름과 label을 대체하는 값이 아니라, 의미와 분류·외부 식별자를 보충하는 영속 데이터입니다.

  • description은 plain text 설명, tags는 exact string 목록, meta string | number | boolean | null 값만 갖는 얕은 map입니다.
  • 엔터티·프로세스 수정 모달에서는 접힌 공통 섹션을 펼치고, 필드는 행의 annotation 버튼, 경계는 헤더의 ✏️, 매핑은 엣지 컨텍스트 메뉴에서 편집합니다.
  • 노드와 필드의 설명은 , 태그는 칩으로 확인합니다. 우상단 노드 표시 패널은 이름·설명·태그를 검색하지만 metadata 값은 검색하지 않습니다.
  • annotation은 semantic diff, 자동저장, 백업, 코드 JSON과 공유 URL에 포함됩니다. timestamp·request ID 같은 실행별 값이나 비밀번호·토큰· 실제 고객 정보는 기록하지 마세요.

경계로 그룹화

경계는 관련 엔터티·프로세스를 도메인, 시스템, 외부 연동, 보안 영역 같은 의미 단위로 묶습니다. 우하단 + 경계로 빈 경계를 만든 뒤 자유 노드를 안으로 끌어, 포함 준비 안내가 나타났을 때 놓습니다.

  • 편입 후보에서는 600ms 진행 안내가 표시됩니다. 준비 전에는 놓아도 편입되지 않아 경계를 지나가는 드래그와 구분할 수 있습니다.
  • 경계를 끌면 멤버가 함께 움직이고, 멤버를 이동·편집하면 경계 크기가 내용에 맞춰 자동으로 조정됩니다. 헤더의 · N은 현재 멤버 수이며 빈 경계에서는 표시하지 않습니다.
  • 격자 맞춤이 켜져 있으면 경계 자동 맞춤은 멤버를 침범하지 않도록 가장 가까운 바깥쪽 격자선까지 확장됩니다. 배경 점은 20px 간격으로 표시되어 스냅 위치를 하나 걸러 하나씩 표시합니다.
  • 멤버를 끌면 경계 하단에 내보내기 존이 나타납니다. 준비 상태에서 놓거나 멤버 헤더의 경계에서 빼기 버튼을 누르면 배출됩니다. 경계를 삭제해도 멤버와 엣지는 보존됩니다.
  • 경계 헤더의 ✏️ 속성 팝오버에서 이름, 고정 색상 토큰, 유형과 공통 설명·태그·metadata를 편집합니다. 유형은 이름 앞 아이콘으로, 설명은 툴팁으로 표시되며 색상과 유형은 서로 독립적입니다. 이름만 빠르게 바꾸려면 헤더 라벨을 더블클릭합니다.
  • 경계의 annotation·metadata·멤버십·위치·크기는 자동저장·백업·코드 JSON과 URL 공유에 모두 포함됩니다. 경계 중첩은 지원하지 않습니다.

입력 변형 (discriminated union)

엔터티 내부 개념입니다. 같은 엔터티의 특정 필드(discriminator) 값에 따라 그 엔터티의 다른 필드가 "있는지"가 갈립니다 — 예: 주문 이벤트가 type=CREATED 면 주문자 정보 포함, type=CANCELED 면 없음.

  • 분기 기준(🜨) field에는 선택할 값 목록을 두며, 한 엔터티에 여러 개 만들 수 있습니다. 코드에서는 discriminator: { values: [...] }로 표현합니다. 값 칩의 연필 버튼으로 이름을 바꾸면 그 값을 참조하는 모든 when 조건도 함께 갱신됩니다.
  • 다른 필드에 when 절을 달면 조건부로 존재합니다. 절 사이는 AND, 값 안은 OR이라 "status=CANCELED 이면서 channel=APP 일 때만" 같은 조합도 표현됩니다. 조건 key는 이름이나 경로가 아니라 같은 엔터티의 discriminator stable field ID입니다.
  • 좌상단 셀렉터에서 값을 고르거나 캔버스의 배지를 클릭하면 그 변형으로 전환되고, 변형에 없는 필드는 숨기지 않고 흐리게(dim) 처리됩니다.
  • 변형은 엔터티 모달 필드행의 분기 아이콘(⑂) 팝오버에서 설정합니다. 입력 변형은 엔터티 전용입니다.

접기 · 하이라이트

  • object 접기 object 필드를 클릭하면 하위를 접습니다. 접힌 컨테이너로 오가던 엣지는 컨테이너로 롤업되어 점선으로 표시되고, 펼치면 복원됩니다.
  • 호버 하이라이트 — 필드에 마우스를 올리면 그 필드와 연결된 엣지·프로세스 블랙박스 너머의 필드까지 강조됩니다. 클릭 추적과 같은 규칙을 사용하며, 숨긴 노드는 제외됩니다.

필드 추적 · 영향 분석

호버가 흐름을 잠깐 미리 보는 기능이라면, 필드 클릭은 분석 결과를 오른쪽 오버레이 패널에 유지합니다. 리프 필드를 클릭하거나 object 행의 하위 필드 묶음 추적 아이콘을 누르면 추적 패널이 열립니다.

  • Upstream은 값의 출처를, Downstream은 영향받는 필드와 요약을, Paths는 중간 단계를 포함한 전체 경로를 보여줍니다.
  • 노드명·필드 경로·최대 거리로 결과를 좁히고, Paths에서는 방향도 선택할 수 있습니다. 필터는 화면과 복사 대상만 바꾸며 전체 영향 요약과 Markdown 리포트는 원본 분석을 유지합니다.
  • 경로에는 유지/가공 여부, 변환 설명, 조건부 variant와 프로세스 블랙박스 통과가 표시됩니다. 프로세스 내부는 명시적 매핑 대신 모든 input이 모든 output에 영향을 줄 수 있는 구간으로 계산하고, 내부 통과는 매핑 거리에 더하지 않습니다.
  • 결과를 클릭하면 대상 노드로 이동하고 필드 행을 잠시 강조합니다. 영향 필드와 경로는 복사할 수 있고, Downstream 영향 분석은 MD 버튼으로 내려받을 수 있습니다.
  • 엔터티·프로세스 헤더의 영향 분석 아이콘은 노드 단위 분석을 엽니다. 명시적 노드 관계와 field mapping에서 파생된 흐름을 함께 계산하고 결과에 두 출처를 표시합니다. field trace는 명시적 노드 관계를 통과하지 않습니다. 숨긴 노드는 추적에서 제외되며, 패널 닫기·빈 캔버스 클릭·Esc·선택 필드 재클릭으로 분석을 닫습니다.

페이지 · 저장 · 공유

  • 자동 저장 — 그래프는 편집할 때마다 IndexedDB 에 디바운스 자동저장되고, 마지막으로 열었던 페이지를 기억해 다음 방문 때 이어서 봅니다. 오른쪽 개요에서 마지막 저장 시각을 확인할 수 있습니다.
  • URL 공유 — 오른쪽 개요를 펼치고 패널 헤더의 🔗 링크 복사 를 누르면 현재 페이지의 전체 그래프를 담은 #g=d1.… fragment URL이 복사됩니다(native DEFLATE + base64url). stable ID, 정확한 위치, 접힘, 모든 대상의 설명·태그·metadata, 경계 멤버십·크기와 node relation·field mapping까지 함께 복원됩니다. 링크는 /share 또는 한국어 UI의 /ko/share에서 읽기 전용으로 열리며, 열람만으로 페이지·문서·화면 설정을 저장하지 않습니다. 새 페이지로 가져오기가 같은 로케일의 /app/new를 거쳐 공유 원본의 사본을 저장하고 기존 페이지를 유지합니다. 기존 /app/new#g=… 링크는 바로 가져옵니다. fragment는 가져오기에 성공한 앱에서만 지우고 보기 화면에서는 새로고침·북마크를 위해 유지합니다. 페이지 이름·다른 페이지·화면의 pan/zoom·선택·필터·추적·저장 이력은 포함하지 않습니다. 링크가 너무 길면 전달 중 잘릴 수 있다는 경고가 표시되고, 발행 한도를 넘거나 브라우저가 압축 기능을 지원하지 않으면 JSON 백업을 사용합니다.
  • 백업 — 공유가 현재 페이지 하나를 전달하는 데 비해 백업은 페이지 이름을 포함한 전체 페이지 목록을 파일로 내보냅니다. 병합 또는 덮어쓰기로 다시 가져올 수 있으며, 각 document를 FieldWeft v1으로 다시 검증합니다. 손상된 페이지가 하나라도 있으면 일부만 건너뛰지 않고 전체 가져오기를 중단합니다. 긴 링크나 중요한 작업 전달에는 백업을 함께 권장합니다.

보기 화면의 노드·경계 이동, 노드 숨김, 필드 접기, 추적과 입력 변형 선택은 임시 상태입니다. 처음 상태로는 원본 배치·접힘을 복원하고 탐색 상태·오른쪽 패널을 초기화하며 화면 설정 네 값을 출고 기본값으로 돌립니다. 그래프는 현재 캔버스 크기에 맞춥니다. 샘플의 초기화는 기존처럼 저장된 화면 설정을 유지합니다.

복사한 링크를 위키 iframe에 삽입할 수 있습니다. sandbox에는 allow-same-origin allow-scripts allow-popups allow-popups-to-escape-sandbox가 필요합니다. 모듈을 받기 위해 원래 출처를 유지하고, 가져올 때는 저장 가능한 제한 없는 앱 탭을 열어야 합니다. 열람은 브라우저 저장소 없이 동작합니다. 위키가 이 권한과 새 창을 허용하고 iframe 정책·앞단 프록시의 frame 헤더도 삽입을 허용해야 합니다. iframe의 새 페이지로 가져오기는 새 탭에서 열립니다. URL에 표시 옵션을 추가하지 않습니다.

코드로 편집

오른쪽 패널을 펼친 뒤 개요 아래의 코드 도구를 열면 그래프 전체를 JSON 으로 편집할 수 있습니다. 적용 버튼을 눌러야 반영되며, 반영 전에 구조·종류·참조·공통 annotation·자원 한도를 검증합니다(실시간 아님). 검증에 걸리면 항목별 에러 메시지가 표시되므로, 고쳐서 다시 적용하면 됩니다.

노드를 하나하나 만드는 대신 AI 에게 JSON 을 통째로 생성시킬 수도 있습니다 — 코드 도구의 스펙 복사 버튼으로 전체 규칙 문서를 복사해 사용하는 AI 에 붙여넣고, 만들려는 데이터 흐름을 설명하면 됩니다. 영문 정본은 JSON 명세 로도 제공됩니다. 안전한 수정·외부 모델 변환·공유 계약의 영문 정본은 각각 작성·수정 가이드·adapter 가이드·공유 가이드에서 확인할 수 있습니다. 같은 내용을 다르게 설명하면 영문 정본이 우선합니다.

한국어 해설은 정본을 이해하기 위한 비규범 보조 자료입니다. JSON 명세 해설·작성·수정 가이드 해설·adapter 가이드 해설·공유 가이드 해설을 함께 제공합니다.

최상위 format: "fieldweft", version: 1과 다섯 배열은 비어 있어도 모두 필수입니다:

{
  "format": "fieldweft",
  "version": 1,
  "entities": [
    {
      "id": "orderEvent",
      "name": "OrderEvent",
      "kind": "event",
      "description": "주문이 접수됐을 때 발행되는 이벤트",
      "tags": ["critical", "pii"],
      "meta": { "com.example.owner": "orders", "reviewed": true },
      "fields": [
        {
          "id": "order_id_aB3kP9xQ2", "name": "orderId", "type": "string",
          "tags": ["identifier"], "pk": true
        },
        {
          "id": "items_D6fG1hJ4k", "name": "items", "type": "object", "array": true,
          "children": [
            { "id": "product_id_C4mN7rS1v", "name": "productId", "type": "string" }
          ]
        }
      ]
    }
  ],
  "processes": [
    {
      "id": "riskApi", "name": "RiskApi", "kind": "api",
      "inputs": [
        { "id": "risk_order_id_R8tY2uI5o", "name": "orderId", "type": "string" }
      ],
      "outputs": [
        { "id": "risk_score_L3pQ6wE9r", "name": "riskScore", "type": "number" }
      ]
    }
  ],
  "boundaries": [
    {
      "id": "riskZone", "name": "위험도 평가",
      "color": "purple", "kind": "system",
      "description": "위험도 평가 흐름", "members": ["riskApi"]
    }
  ],
  "nodeRelations": [
    {
      "id": "order_to_risk",
      "sourceNodeId": "orderEvent",
      "targetNodeId": "riskApi",
      "label": "위험도 조회",
      "meta": { "com.example.source": "catalog" }
    }
  ],
  "mappings": [
    {
      "id": "p1",
      "sourceFieldId": "order_id_aB3kP9xQ2",
      "targetFieldId": "risk_order_id_R8tY2uI5o"
    }
  ]
}

손으로 쓰거나 AI 산출물을 점검할 때 핵심 규칙:

  • 노드 id 는 영문·숫자·_·- 만 쓸 수 있고 전체 노드에서 유일해야 합니다. 노드 이름·종류·위치를 바꿔도 기존 ID를 유지하며, ID를 바꾸거나 노드를 삭제하면 boundary members와 node relation endpoint를 같은 변경에서 갱신해야 합니다.
  • 모든 엔터티 필드와 프로세스 입출력 필드에는 문서 전역에서 고유한 id가 필요합니다. 새 ID는 <이름 slug>_<9자 base64url suffix> 형식을 권장합니다. rename·reorder·move·속성 변경 때는 기존 ID를 보존하고, 새 필드와 clone에만 새 ID를 발급합니다.
  • 엔터티·프로세스·경계·모든 필드·node relation·mapping은 공통으로 description, tags, meta를 직접 가질 수 있습니다. annotations wrapper는 쓰지 않습니다. metadata 값은 중첩 object/array가 아닌 string | number | boolean | null이며, 명시적 null은 보존됩니다.
  • 문자열 길이는 Unicode code point로 셉니다. ID·name과 discriminator/when 값은 256자, node relation·mapping label은 512자, 모든 description과 metadata string은 4,096자까지 허용합니다. object별 tag와 meta entry는 각각 32개이며 tag는 1..64자, meta key는 1..128자입니다. discriminator.values와 각 when 값 배열은 최대 256개입니다.
  • 엔터티 필드는 object.children으로 중첩할 수 있지만, 프로세스의 inputs/outputs은 캔버스 핸들과 일대일로 대응하는 평탄한 목록이므로 children을 둘 수 없습니다.
  • 엔터티·프로세스의 kind event | api | db | other, type uuid | string | number | boolean | timestamp | object | json 중 하나입니다.
  • boundariescolor blue | green | purple | rose | slate, kind domain | system | external | security | other 중 하나입니다. members에는 존재하는 엔터티·프로세스 id만 넣을 수 있고 한 노드는 경계 하나에만 속합니다.
  • nodeRelations는 entity/process ID 사이의 명시적 node lineage입니다. boundary endpoint와 self-relation은 허용하지 않으며, node relation이 field mapping을 대신하거나 암시하지 않습니다.
  • sourceFieldId/targetFieldId 는 실제 리프 field의 stable ID여야 하고 object 컨테이너에는 매핑할 수 없습니다. 노드와 현재 경로는 ID 인덱스에서 파생되며, 프로세스 input은 target, output은 source로만 쓸 수 있습니다.
  • 입력 변형은 엔터티 전용입니다. 분기 필드는 discriminator: { values: [...] }, 조건부 필드는 when: { "<discriminatorFieldId>": [...] }로 씁니다. when key는 같은 엔터티의 discriminator stable ID여야 하며, 매핑과 프로세스 필드에는 when을 달 수 없습니다.
  • collapsed에는 해당 엔터티의 object field ID만 넣습니다. field ID를 변경·삭제·clone했다면 when, mappings, collapsed의 참조를 같은 변경에서 모두 갱신해야 합니다.
  • position 은 선택입니다 — 생략하면 자동 배치됩니다. 경계의 size도 선택이며, 멤버에 맞춰 자동 조정됩니다.
  • 공통 한도는 node·boundary 5,000개, field 100,000개, field tree 깊이 64와 node relation·mapping 합계 20,000개입니다. 제한을 넘거나 marker· enum·참조가 잘못된 문서는 일부를 고치지 않고 전체를 거부합니다. canonical document는 UTF-8 8 MiB, raw JSON 입력은 16 MiB, backup JSON은 64 MiB까지입니다.