본문으로 건너뛰기

정성 코딩을 위한 분석 메모

Potato 메모는 항목, 텍스트 구절, 그려진 도형에 붙으며 답글을 받을 수 있습니다. 이슈로 올린 메모는 누군가 이슈를 해결할 때까지 열려 있습니다.

Potato의 메모는 항목, 항목 안의 텍스트 선택, 이미지에 그린 도형에 붙이는 자유 텍스트 노트입니다. 메모를 읽을 수 있는 사용자라면 누구나 그 메모에 답글을 달 수 있으며, 이슈로 올린 메모는 작성자, 담당자, 판정자가 이슈를 해결할 때까지 열려 있습니다. 메모는 QDA 모드의 유무와 관계없이 모든 Potato 프로젝트에서 작동하며, Potato는 메모를 어노테이션 파일이 아니라 프로젝트 데이터베이스에 보관합니다. 메모는 Potato 2.6.0에, 답글과 이슈는 2.12.0에 도입되었습니다.

분석 메모는 연구자가 코딩 중에 데이터와 코드에 대해 쓰는 노트로, 예를 들어 코드가 구절에 맞는 이유나 코드북에 새 규칙이 필요한 곳을 적습니다. 메모 작성은 근거 이론의 일부로 가장 자주 설명되며, Birks, Chapman, and Francis (2008)는 여러 질적 방법에 걸쳐 메모 작성을 권장합니다. 저자들의 설명에서 메모는 분석가가 원자료에서 데이터를 설명하는 추상 개념으로 나아가는 것을 돕습니다. 코딩 팀에서 메모는 코드 뒤에 있는 결정도 기록하며, 아래의 내보내기는 그 노트를 감사 추적으로 바꿉니다.

각 메모는 다음을 기록합니다.

  • 앵커. 메모는 항목 전체, 항목 텍스트의 문자 범위(quote 배지로 표시), 또는 그려진 도형 하나(도형의 라벨과 유형으로 표시, 예: car box)에 놓입니다.
  • 공개 범위. 메모는 private(기본값) 또는 shared입니다.
  • 스레드. 답글은 첫 번째 노트 아래에 놓이며 첫 번째 노트의 공개 범위를 따릅니다.
  • 이슈 상태. 이슈는 open 또는 resolved이며, 담당자를 한 명 둘 수 있고, 누가 언제 이슈를 해결했는지 기록합니다.
  • 저장. 메모는 Add note를 클릭하는 즉시 <task_dir>/project.sqlite의 memos 및 memo_threads 테이블에 저장됩니다.

메모 켜기

메모는 표준 프로젝트에서는 꺼져 있고 QDA 모드와 솔로 모드에서는 기본으로 켜져 있습니다. 프로젝트는 annotation_ui 블록으로 메모를 켭니다. 아래 구성은 span 스킴과 비공개 메모로 인터뷰 발췌문을 코딩하는 팀을 설정합니다. adjudication 블록은 책임 분석가를 지정하며, 판정자는 프로젝트의 모든 메모를 읽을 수 있습니다.

yaml
annotation_task_name: Clinic access interviews
task_dir: .
output_annotation_dir: annotation_output/
data_files:
- data/excerpts.json
item_properties:
  id_key: id
  text_key: text
 
annotation_ui:
  memos: true
  visibility: private
 
adjudication:
  enabled: true
  adjudicator_users: [lead_analyst]
 
annotation_schemes:
- annotation_type: span
  name: codes
  description: Highlight a passage and apply a code
  labels: [transport barriers, cost concerns, provider trust]

인용 보고서에는 span 스킴이 필요하므로 span 스킴은 내보내기에서 중요합니다(메모 내보내기 참조). 네 개의 키가 메모를 제어합니다.

옵션기본값설명
annotation_ui.memos꺼짐, 또는 qda_mode.enabled나 solo_mode.enabled가 true이면 켜짐Notes 패널을 표시하고 /api/memos 엔드포인트를 켭니다. 명시적인 true 또는 false는 QDA 모드와 솔로 모드를 재정의합니다.
annotation_ui.visibilityprivatevisibility 필드 없이 API로 만든 메모의 공개 범위. private나 shared 이외의 값은 private로 대체됩니다.
qda_mode.memos.show_sidebar_by_defaulttrueQDA 모드에서 어노테이터가 패널을 닫기 전까지 각 항목에서 Notes 패널을 엽니다.
qda_mode.memos.enabledtrueQDA 모드에서 false이면 Notes 패널이 닫힌 채로 시작합니다. 메모는 계속 사용할 수 있으며, 메모를 끄는 키는 annotation_ui.memos: false입니다.

QDA 모드 밖에서는 Notes 패널이 닫힌 채로 시작하며, 어노테이터는 페이지 오른쪽 가장자리의 Notes 버튼으로 패널을 엽니다. 패널을 닫으면 브라우저 탭의 세션이 끝날 때까지 이후 항목에서도 닫힌 상태가 유지됩니다. 메모가 꺼져 있으면 Potato는 Notes 버튼을 렌더링하지 않고 /api/memos 엔드포인트는 503을 반환합니다. 컴포저의 공개 범위 메뉴는 모든 프로젝트에서 Private으로 시작하며, annotation_ui.visibility는 메뉴를 바꾸지 않습니다. 공유 메모를 원하는 팀은 코더에게 새 메모마다 Shared를 고르도록 요청합니다.

Potato는 각 메모를 프로젝트의 annotation_task_name 아래에 정리합니다. 구성에서 작업 이름을 바꾸면 옛 이름으로 쓴 메모가 숨겨집니다. 행은 project.sqlite에 남아 있으며, 옛 이름을 복원하면 메모가 돌아옵니다.

Notes 패널에서 메모 쓰기

Notes 패널은 현재 항목의 메모를 오래된 순으로 나열하며, 각 스레드의 답글은 첫 번째 노트 아래에 있습니다. 메모를 추가하려면 다음을 수행합니다.

  1. 어노테이션 페이지 오른쪽 가장자리의 Notes를 클릭합니다.
  2. 메모를 구절에 앵커로 붙이려면 먼저 항목에서 텍스트를 선택하고 Attach to selected text를 체크합니다. 메모를 그려진 도형에 앵커로 붙이려면 이미지 캔버스에서 도형을 선택하고 Attach to the selected shape를 체크합니다.
  3. 컴포저에 노트를 입력합니다.
  4. 노트를 이슈로 올리려면 Raise as an issue to resolve를 체크합니다. 선택적으로 Assign to 아래에 이슈를 해결할 사람의 사용자 이름을 입력합니다.
  5. Visibility에서 Private 또는 Shared를 고르고 Add note를 클릭합니다.

각 메모에는 현재 사용자가 쓸 수 있는 버튼이 표시됩니다. Reply는 모든 스레드에 나타나고, Resolve 또는 Reopen과 Assign은 사용자가 바꿀 수 있는 이슈에 나타나며, Edit와 Delete는 사용자 자신의 메모에 나타납니다. 판정자는 다른 사용자의 메모에서도 Delete를 봅니다. 첫 번째 노트를 편집하면 텍스트뿐 아니라 노트의 공개 범위도 바꿀 수 있습니다.

텍스트 앵커는 항목의 표시된 텍스트 안에서 선택의 시작 및 종료 문자 오프셋을 기록하며, 종료 오프셋은 포함되지 않습니다. 선택은 항목의 주 텍스트 표시 안에서만 계산됩니다. 그려진 도형에는 저장된 ID가 없으므로 도형 앵커는 도형의 스킴, 유형, 라벨, 정규화된 좌표를 기록합니다. 메모의 도형 배지를 클릭하면 저장된 좌표와 맞춰 도형이 다시 선택됩니다. 도형이 그 사이에 이동되었거나 삭제되었다면 패널은 도형이 더 이상 그려진 대로 이미지에 없다고 알립니다.

누가 메모를 읽을 수 있는가

비공개 메모는 작성자와 판정자가 읽을 수 있습니다. 공유 메모는 프로젝트의 모든 사용자가 읽을 수 있습니다. 이슈의 담당자는 이슈가 비공개여도 그 이슈의 스레드를 읽고 답글을 달 수 있습니다. 메모에 대한 나머지 규칙은 다음과 같습니다.

  • 메모의 텍스트나 공개 범위는 작성자만 편집합니다.
  • 메모는 작성자나 판정자가 삭제합니다. 스레드의 첫 번째 노트를 삭제하면 답글도 삭제됩니다.
  • 스레드를 읽을 수 있는 사람은 누구나 답글을 달 수 있습니다. 답글은 첫 번째 노트의 공개 범위를 따르며, 첫 번째 노트의 공개 범위를 나중에 바꾸면 답글에도 적용됩니다.
  • 사용자가 읽을 수 없는 메모에 대해 모든 동작은 404를 반환합니다. 존재하지 않는 메모에 대해서도 Potato는 같은 응답을 합니다.

메모에서 판정자는 adjudication.enabled가 true인 동안 adjudication.adjudicator_users에 나열된 사용자 이름입니다. 메모에 대해 Potato는 그 목록만 확인합니다. RBAC admin 역할을 가졌지만 목록에 없는 사용자는 일반 어노테이터와 같은 메모를 읽습니다.

비공개 메모는 어노테이션 인터페이스 안에서만 비공개입니다. 인용 보고서 내보내기를 실행하거나 project.sqlite를 여는 사람은 비공개 메모를 포함한 모든 메모를 읽습니다. 코딩이 시작되기 전에 코더에게 내보내기에 대해 알려 주세요.

공유 메모는 코더가 코딩하는 동안 서로의 추론을 읽을 수 있게 합니다. 두 코더가 코더 간 신뢰도 점검을 위해 같은 발췌문을 독립적으로 코딩할 때, 공유 메모는 두 번째 코더의 판단을 닻으로 고정해 코드북과 무관한 이유로 일치도를 높일 수 있습니다. 신뢰도 라운드 동안에는 메모를 비공개로 유지하세요. 라운드가 끝나면 코더는 각 비공개 메모를 Edit로 열어 조정 회의를 위해 Shared로 바꿀 수 있습니다.

답글과 이슈

모든 메모는 스레드를 시작합니다. 답글에는 첫 번째 노트와 별개의 공개 범위나 상태가 없습니다. Raise as an issue to resolve를 체크하면 첫 번째 노트가 open 상태가 됩니다. 이슈는 코드북이 정하지 않은 코드 경계처럼 코딩을 계속하기 전에 답이 필요한 질문에 적합합니다. 이슈에 대한 권한은 다음과 같습니다.

동작동작을 할 수 있는 사람
답글스레드를 읽을 수 있는 모든 사람
이슈 해결 또는 다시 열기이슈의 작성자, 담당자, 또는 판정자
이슈 배정 또는 담당자 지우기이슈의 작성자 또는 판정자

이슈를 해결하면 누가 언제 이슈를 해결했는지 기록되고, 이슈를 다시 열면 두 필드가 모두 지워집니다. 담당 지정을 지우면 비공개 이슈에 대한 담당자의 접근이 제거됩니다. 열린 이슈가 어노테이터에게 배정되면 Notes 버튼에 Notes · 2 assigned to you처럼 개수가 표시되고, 패널은 이슈를 맨 위에 나열합니다. 어노테이터 자신의 큐에 있는 항목의 이슈에는 Go to item 버튼이 붙고, 큐 밖 항목의 이슈에는 큐에 없다는 표시가 붙습니다. jumping_to_id_disabled: true를 설정하면 Go to item 버튼이 제거됩니다.

배정을 채팅 채널이나 트래커로 보내려면 웹훅을 memo.issue_assigned 이벤트에 구독시키세요. 이 이벤트는 이슈에 새 담당자가 생길 때마다 발생하며 메모 ID, 항목 ID, 담당자, 이슈를 배정한 사용자, 상태를 보냅니다. 이슈가 비공개일 수 있으므로 페이로드에는 메모의 텍스트가 빠져 있습니다.

관리자 대시보드의 이슈

메모가 켜져 있으면 관리자 대시보드의 Overview 탭에 열린 이슈 수와 해결된 이슈 수가 담긴 Open issues 타일이 표시됩니다. 관리자 API는 비공개 이슈를 포함해 이슈 자체를 나열합니다.

bash
curl -H "X-API-Key: $POTATO_ADMIN_KEY" \
  "http://localhost:8000/admin/api/memo_issues?status=open"

응답에는 이슈당 하나의 항목이 최신순으로 있으며, 메모의 텍스트, 작성자, 항목 ID, 앵커, 담당자, 상태, 해결한 사람이 들어 있습니다. 해결된 이슈에는 ?status=resolved를 사용하고, 둘 다 보려면 매개변수를 생략하세요. 이 엔드포인트는 이슈만 나열합니다. 일반 메모는 내보내기나 판정자 계정을 통해 프로젝트 책임자에게 도달합니다.

메모 내보내기

quotation_report 내보내기 도구는 코딩된 스팬당 하나의 CSV 행을 씁니다. include_memos=true이면 내보내기 도구는 메모와 답글마다 한 행을 추가합니다.

bash
python -m potato.export -c config.yaml -f quotation_report \
  --option include_memos=true -o ./export/

이 명령은 ./export/quotations.csv를 씁니다. 메모 행은 스팬 행과 같은 아홉 개의 열을 사용합니다.

열메모 행의 값
schema(memo), (memo reply), (issue: open), 또는 (issue: resolved)
code스레드의 공개 범위, private 또는 shared
text메모의 텍스트
start, end텍스트 앵커의 문자 오프셋, 그 외에는 비어 있음
field텍스트 앵커는 text, 그 외에는 비어 있음
instance_id메모가 붙은 항목
source_doc항목 텍스트의 처음 200자
coder메모의 작성자

내보내기 도구는 구성에 span 스킴이 하나 이상 있을 때만 실행됩니다. radio나 multiselect 질문으로만 코딩한 연구는 No span annotation schema found in config 오류를 받습니다. 메모 행에는 타임스탬프와 담당자도 없으며, 도형에 앵커된 메모는 빈 오프셋으로 내보내집니다.

날짜가 있는 감사 추적을 위해서는 두 메모 테이블을 직접 쿼리하세요. 아래의 sqlite3 명령은 프로젝트의 모든 메모를 UTC 생성 시각, 스레드 상태, 담당자, 해결한 사람과 함께 나열합니다.

bash
sqlite3 -header -csv project.sqlite "
  SELECT m.instance_id, m.created_by, datetime(m.created_at, 'unixepoch') AS created,
         m.visibility, t.parent_id, t.status, t.assignee, t.resolved_by, m.body
  FROM memos m LEFT JOIN memo_threads t ON t.memo_id = m.id
  WHERE m.project = 'Clinic access interviews'
  ORDER BY m.created_at" > memos.csv

비어 있지 않은 parent_id는 답글을 표시하며 스레드의 첫 번째 노트를 가리킵니다. Potato는 시각을 Unix 초로 저장하며, resolved_at과 updated_at도 created_at과 같은 방식으로 변환됩니다.

메모는 REFI-QDA .qdpx 내보내기에 들어가지 않습니다. 구성이 annotation_ui.memos: true를 설정하면 .qdpx 내보내기 도구는 메모가 제외되었다고 경고합니다. 그 키 없이 QDA 모드나 솔로 모드를 쓰면 내보내기는 경고 없이 메모를 제외합니다. 프로젝트를 다른 QDA 프로그램으로 옮길 때는 인용 보고서로 메모를 따로 내보내세요.

potato snapshot create가 만드는 아카이브에는 project.sqlite가 포함되며, potato deploy pull의 아카이브에도 그 파일이 포함됩니다. 따라서 두 아카이브 모두 비공개 메모를 포함한 모든 메모를 담고 있습니다. 스냅숏의 콘텐츠 해시는 구성, 연구 파일, 어노테이션을 포함합니다. 해시는 데이터베이스를 제외하므로 새 메모는 해시를 바꾸지 않습니다. 프로젝트 스냅숏을 참조하세요.

메모 API

Notes 패널은 /api/memos 아래의 REST API를 사용하며 어노테이터의 로그인 세션으로 인증됩니다. 스크립트도 같은 엔드포인트를 호출할 수 있습니다.

요청목적
GET /api/memos?instance_id=<id>사용자가 읽을 수 있는 한 항목의 메모와 답글이며, 각각 can_edit, can_delete, can_resolve, can_assign을 포함
POST /api/memosinstance_id, body, visibility, anchor로 새 메모를 만들며, 이슈에는 issue: true와 선택적 assignee를 추가
POST /api/memos/<id>/replybody가 있는 답글
PATCH /api/memos/<id>body, visibility, status(open 또는 resolved), assignee(비우면 지움)의 변경
DELETE /api/memos/<id>메모 삭제이며, 메모가 첫 번째 노트이면 답글도 함께 삭제
GET /api/memos/issues?status=open&assignee=me사용자가 읽을 수 있는 프로젝트 전체의 이슈

텍스트 앵커는 {"start": 48, "end": 98, "field": "text"}이고, 도형 앵커는 {"shape": {"schema": ..., "type": ..., "label": ..., "coordinates": ...}}입니다. 프로젝트에 없는 항목 ID에 대한 POST는 400을 반환합니다.

예제

Potato의 저장소에는 메모 예제가 포함되어 있습니다. Potato 체크아웃에서 예제를 실행하세요.

bash
python potato/flask_server.py start examples/advanced/memos-example/config.yaml -p 8000

이 예제는 감성 질문 하나가 있는 네 개의 짧은 제품 리뷰에 대해 비공개 메모를 켭니다. 이 예제에는 span 스킴이 없으므로 인용 보고서는 예제의 메모를 내보낼 수 없습니다. QDA 모드 예제에는 코드북 기반 span 스킴이 있습니다. 내보내기를 시험하려면 examples/advanced/qda-mode-example/config.yaml을 실행하세요.

더 읽을거리

구현 세부 사항은 소스 문서를 참조하세요.

참고문헌

Birks, M., Chapman, Y., and Francis, K. (2008). Memoing in qualitative research: Probing data and processes. Journal of Research in Nursing, 13(1), 68–75. doi:10.1177/1744987107081254