TgWitness / 문서

테스트된 내용 →

참고 문헌 / 아카이브 및 연동 기능

Telegram · Case Board 참조

북마크, 정확한 하이라이트, 액션 슬라이스, 토론, 범위 지정 액세스 및 Case Board에서 사용하는 서명된 주석 내역.

TgWitness / 문서 · 조사

조사

Case Board는 수사팀에게 저장된 자료에 대한 공유 작업 화면을 제공합니다. 관찰 내용을 북마크하고, 정확한 구절을 강조 표시하며, 일련의 조치를 저장하고, 동료들과 논의할 수 있습니다. 카드에는 원본 참조 정보와 서명된 수정 내역이 유지됩니다. 팀의 주석은 작업 공간에 남아 있으며, 원본 텔레그램 관찰 내용과 별도로 식별할 수 있습니다.

증거 모델 · 접근 · 보고서

합성 수사 피드

이 페이지에서

사건 처리#

‘조사(Investigation)’ → ‘케이스 보드(Case Board)’를 표준(Standard) 또는 전문가(Expert) 모드로 엽니다. 언어는 패널에 따라 달라집니다. 일지 기록이나 저장된 채팅 메시지 옆의 ‘To board’를 사용하거나, 해당 항목을 선택한 후 B 키를 누르십시오. 한 번의 클릭으로 북마크가 ‘수신함’에 추가됩니다. 제목, 라벨 및 메모를 편집하거나, 컬렉션으로 이동할 수 있습니다. 변경된 카드에는 서명된 수정 내역이 추가되며, 카드를 삭제해도 기록 내역은 보존됩니다.

첫 번째 사례를 위해 수집 항목을 선택하고, 한 가지 질문에 대한 답이 되는 기록을 추가하십시오. 주석을 사용하여 해석을 검토한 다음, ‘프레젠테이션’을 통해 카드와 원본 문맥을 차례로 살펴보십시오. 결과물을 준비할 때 ‘리포트 스튜디오’에서 케이스 보드 자료를 별도로 선택하십시오. 슬라이스를 저장한다고 해서 보고서의 데이터 필터가 자동으로 구성되는 것은 아닙니다.

저장된 채팅 메시지 내에서 텍스트를 선택하면 ‘하이라이트 → 보드’가 표시됩니다. 색상을 선택하고 메모를 추가하세요. 서버는 이모티콘, RTL 텍스트 및 결합 기호를 포함하여 정확한 인용문과 저장된 버전을 확인합니다. 인터페이스는 마스킹되거나 변환된 텍스트를 통해 선택 영역을 매핑하지 않습니다.

한 채팅에서 두 개의 기록을 Shift 키를 누른 채 클릭하여 ‘Slice between’을 실행하거나, ‘Slice by time’을 사용하거나, 저널의 현재 채팅, 기간 및 이벤트 유형 필터를 저장할 수 있습니다. 저장된 슬라이스에는 고유한 권위적 술어가 적용됩니다. 저널에서 이를 열면 여러 채팅, 메시지 수 제한 및 행위자 필터도 함께 적용됩니다. '북마크 이후 추가된 기록 표시'를 선택하면 이후에 추가된 항목만 분리하여 볼 수 있습니다. 저널 필터를 변경하면 슬라이스에서 나옵니다. '사람'에서 '이 사람의 행동 슬라이스'를 선택하면 기록된 행위자 ID가 사용되며, 메시지 작성자가 메시지를 편집, 삭제 또는 반응했다고 가정하지 않습니다.

슬라이스 대화 상자는 생성 허용 전에 개수를 미리 보여줍니다. ‘all’에는 스냅샷, 편집, 삭제, 반응, 멤버십/서비스 업데이트, 사용자 자신의 행동, 버튼, 미디어 결과, 복구된 메시지 및 향후 이벤트 유형을 포함한 모든 기록 유형이 포함됩니다. 이 선택 항목은 저장된 관측 결과를 설명합니다. 알 수 없는 채팅 삭제 알림은 별도의 컨텍스트로, 전체 워크스페이스 액세스 권한이 있는 사용자만 볼 수 있으며, 선택된 채팅 중 어느 하나에도 귀속되지 않습니다.

컬렉션에는 명시된 채팅 범위가 있습니다. 범위가 비어 있으면 전체 작업 공간을 의미합니다. 컬렉션은 해당 범위 외부의 카드를 포함할 수 없으며, 채팅 범위가 제한된 참여자는 더 광범위한 컬렉션을 읽을 수 없습니다. 받은 편지함은 할당되지 않은 카드를 위한 가상 컬렉션입니다. 검색 및 필터는 표시된 카드에만 적용되며, 스레드와 멘션은 상위 카드의 접근 권한을 상속받습니다. 삭제된 댓글은 토론창에 ‘무덤표시’가 남습니다. 조회 기록은 기록되지 않습니다.

프레젠테이션 모드에서는 선택한 컬렉션의 모든 카드가 열리며, ‘카드’, ‘소스 컨텍스트’ 및 ‘팀 코멘트’ 보기와 키보드의 ‘이전/다음’ 제어 기능이 제공됩니다. 편집 기능은 제공되지 않습니다. 일반 피드는 페이지 단위로 구성되어 있으며, 프레젠테이션 모드는 목록을 페이지 단위로 불러와 한 번에 하나의 카드 세부 정보를 불러옵니다.

권한#

모든 작업에는 view, 작업 공간/채팅 범위 및 board.read 권한이 필요합니다. board.write는 카드 추가, 댓글 작성, 이동 및 열기/검토 상태 설정을 수행합니다. board.manage는 수집 관리, 확인/기각 상태 설정, 타인의 카드 수정/삭제를 허용합니다. 상태는 팀의 결정 사항이며, 암호학적 검증 결과가 아닙니다.

양식 사전 설정에 액세스: 검토자 = 읽기; 분석가 = 읽기/쓰기; 운영자 = 읽기/쓰기/관리, 기존 권한에 추가됩니다. 기존 권한 부여는 새로운 권한을 자동으로 부여하지 않습니다. 주 관리자는 모든 권한을 가지며, ‘주 관리자’로 게시합니다. 출처 표기를 위해 명명된 권한 부여를 사용하십시오. 멘션 목록에는 상위 카드 전체를 읽을 수 있는 현재 접근 권한만 표시됩니다.

채팅 A에 대한 승인 권한은 ID를 추측하거나 잘못된 target.chat_id를 제공하더라도 A+B에 대한 카드나 슬라이스를 얻을 수 없습니다. 대상 메타데이터는 서버에서 서명된 이벤트 해시를 통해 확인됩니다. 응답 전에 수집 내역, 토론 횟수, 관련 카드 및 실시간 알림이 필터링됩니다. 내보내기를 위해서는 export 권한과 board.read 권한이 모두 필요합니다. 보드 액세스 권한이 없는 기존 내보내기 담당자는 팀 메모가 포함되지 않은 일반 증거 아카이브만 받게 됩니다. SSE는 각 배치 처리 전에 현재 부여된 권한을 재확인합니다.

저장된 계약서#

관찰 내용과 마찬가지로, 주석도 작업 공간 내의 추가 전용 SQLite 테이블에 트랜잭션 방식으로 기록됩니다. annotations.jsonl은 events.jsonl과 동일한 읽기 스냅샷에서 추출한 정확한 표준 내보내기 파일입니다. 별도의 주석 저장소는 없으며, board.activity 저널 이벤트도 존재하지 않습니다.

각 줄에는 정확히 다음 내용이 포함되어야 합니다:

{
  "seq": 1,
  "at": "2026-11-02T14:00:00.000+00:00",
  "access_id": "admin",
  "access_label": "Main administrator",
  "kind": "board.bookmark",
  "payload": {"id": "32 lowercase hex digits", "target": {"event_hash": "64 lowercase hex digits"}},
  "previous_hash": "64 zeroes for the first record",
  "hash": "SHA-256 described below",
  "signature": "base64 Ed25519 signature"
}

위의 축약된 예시는 외피(envelope)를 보여줍니다. 실제 페이로드에는 모델 기본값과 서버에서 해결된 대상 필드가 포함됩니다. API 요청 스키마는 tgwitness/schemas에 있으며, python tools/build_board_schemas.py가 런타임 Pydantic 모델에서 생성합니다. 추가 요청 필드는 거부됩니다. ID는 생략된 경우 서버 측에서 생성됩니다. 작성자, 시간, 스냅샷 및 서명은 호출자가 제공할 수 없습니다. 명명된 권한 부여 ID는 Access의 기존 16-hex 형식을 따르며, 카드 ID는 32-hex입니다.

정규화된 JSON은 UTF-8이며, 객체 키는 정렬되어 있고, 토큰 사이에 공백이 없으며, 유니코드는 이스케이프 처리되지 않았으며, NaN/무한대 값이 포함되어 있지 않습니다. 주석 해시는 format: "tgwitness-annotations-v1" 형식과 previous_hash까지의 7개 엔벨로프 필드를 모두 포함하는 정규화된 객체의 SHA-256 해시입니다. 이 형식 태그는 해시 도메인을 관측값과 구분합니다. 서명은 32바이트의 원시 해시에 대해 Ed25519 알고리즘을 적용한 것입니다. 시퀀스는 1부터 시작합니다. 개정판은 카드 ID를 유지하며, supersedes 필드에 이전 주석 해시의 이름을 명시합니다. 채팅 범위는 변경할 수 없습니다. 이동, 상태 변경 및 삭제는 별도의 레코드로 처리됩니다. SQLite 테이블은 UPDATE 및 DELETE 문을 허용하지 않습니다.

case-board.json에는 {statement, signature}이 포함됩니다. 정식 진술문은 워크스페이스 키로 서명되며, format: "tgwitness-case-board-v1", public_key, created_at, journal_head, meaning 및 state을 포함합니다. 상태는 결정론적 재현으로, annotations_head, 정렬된 items 배열(컬렉션, 카드, 툼스톤을 포함한 댓글) 및 status_history으로 구성됩니다. 항목은 수정 과정을 거치면서도 마지막 주석 해시, 순서, 작성자 및 시간뿐만 아니라 원래의 생성자와 생성 시간도 유지합니다. 재현 과정에서는 수정 내역, 상위 항목, 컬렉션 참조 및 중복 작업 ID를 확인합니다. manifest.json과 새로운 체크포인트도 annotations_head을 바인딩합니다. 체크포인트를 독립적으로 보관하여, 복사된 서명 키를 이용한 데이터 잘림이나 재작성을 감지할 수 있습니다.

텍스트 버전#

range.start는 0을 기준으로 하는 유니코드 코드 포인트 오프셋이며, length는 양의 코드 포인트 개수이고, quote는 대상 이벤트에서 payload.text 또는 payload.caption의 정확한 부분 문자열과 일치해야 합니다. NFC/NFKC, 대소문자 변환 또는 그래펨 정규화는 적용되지 않습니다. Python 문자열 슬라이스와 JavaScript의 `Array.from(text)`은 동일한 인덱싱 방식을 구현합니다. 마크와 ZWJ 이모지를 결합하면 여러 코드 포인트를 차지할 수 있습니다. `range.version`은 대상 이벤트의 해시이며, 현재 메시지 버전이나 Telegram의 UTF-16 엔티티 오프셋이 아닙니다. 이후 편집 시 하이라이트 위치가 자동으로 변경되지 않습니다.

신원 및 시간 정보 분리#

query는 정확히 하나의 chat_id 또는 비어 있지 않은 chat_ids, 선택 사항인 포괄적 from/to, 포괄적 메시지 ID 범위(단일 채팅만 해당), kinds: "all" 또는 정확한/접두사 와일드카드 종류, 명시적 actors, search, hide_system 및 include_unscoped를 허용합니다. 저널 종류 그룹은 정확한 술어로 확장됩니다. 검색은 서명된 원본 텍스트를 변경하지 않고 저널의 NFC/대소문자 변환된 페이로드 검색을 사용합니다. 날짜는 시간대를 필요로 하며 UTC로 정규화됩니다. 날짜는 observed_at을 필터링합니다. 텔레그램의 source_at는 별도로 표시됩니다. 소스 타임스탬프가 없는 삭제 기록에는 임의로 생성된 삭제 시간이 없습니다. 특정 시간 간격 외부에서 관측된 늦은 기록은 해당 간격에 포함되지 않습니다. 메시지 ID 슬라이스에는 해당 메시지 ID에 대한 이후의 삭제 기록이 포함될 수 있습니다.

snapshot는 생성 시간, 저널 시퀀스/해시 경계, 일치 횟수, 첫 번째/마지막 시퀀스 및 result_hash를 고정합니다. 후자는 일치하는 이벤트 해시의 UTF-8 정규화된 JSON 배열에 대해 사전순으로 정렬된 SHA-256 해시이며, 빈 슬라이스의 경우 []를 포함합니다. 또한 정확한 종류 수와 24-bin 관측 시간 미니어처를 포함합니다. 슬라이스는 중복된 소스 레코드가 아닌 쿼리를 저장합니다. 내보낼 때, board/slices/<id>.json에는 현재 해시와 추가/제거된 시퀀스가 나열됩니다. 검증기는 생성 시점을 기준으로 원래 결과를 재구성한 다음, 현재 결과를 재구성합니다. 추가된 레코드는 변경 사실로 보고됩니다. 원래 이벤트를 제거하면 불변 증거 체인이 깨지며, 이는 슬라이스에서 일반적인 제거로 간주되어 묵인되지 않습니다.

반응 스냅샷에는 최근 참여자 목록이 불완전합니다. 탐색기는 동일한 채팅/메시지의 인접한 스냅샷을 비교하며(슬라이스 외부의 이전 스냅샷 포함), 관측값 간의 누적 개수 변화를 보고합니다. 누락된 최근 참여자에 대해서는 반응을 삭제했다고 간주하지 않습니다. 첫 번째 스냅샷에는 추론된 이전 상태가 없습니다. 행위자 관측값은 가상화된 행동 시점이 아닌, 해당 관측값이 제공된 스냅샷에 귀속됩니다.

API 및 내보내기#

GET /api/board는 collection/chat/author/label/state/from/to/q/kind/comments, offset/limit 및 newest/oldest 정렬 순서를 허용합니다. GET /api/board/card/{id}는 카드, 소스 미리보기, 스레드, 상태 이력 및 관련 카드를 반환합니다. 참가자 서브루트는 해당되는 멘션 선택 항목을 반환합니다. POST /api/board/{bookmark|highlight|slice|collection|comment|status|move|remove}는 레코드를 추가합니다. POST /api/board/slice-preview는 쿼리를 계산합니다. 슬라이스 레코드는 GET /api/board/slice/{id}/records에서 페이지 단위로 제공되며, 재계산 시에는 항상 현재의 안정된 읽기 스냅샷이 사용됩니다. 라이브 /api/stream는 저널 커서와 별도로 페이로드가 없는 board 알림을 전송합니다.

GET /api/board/export는 서명된 문서를 반환합니다. 채팅 제한 접근 권한을 가진 사용자는 명확하게 표시된 서명된 공개 정보를 수신하며, 다른 채팅의 주석이나 전체 대화 내역은 절대 제공되지 않습니다. 전체 증거 ZIP 파일에는 annotations.jsonl, 서명된 case-board.json 및 슬라이스 JSON 부록이 포함됩니다. HTML/PDF/JSON 보고서 설정에서는 보드를 선택하지 않거나, 토론 내용이 없는 북마크/슬라이스, 또는 댓글이 포함된 카드를 선택할 수 있습니다. 해당 섹션은 팀의 의견과 관찰 내용을 명확하게 구분합니다. 보고서 데이터 필터는 읽을 수 있는 메모도 제한하지만, 증거 ZIP 파일에 포함된 전체 서명된 원본 파일은 완전한 상태로 유지됩니다.

GET /api/board/slice/{id}/export는 서명된 tgwitness-board-selection-v1 JSON 발췌본을 생성합니다. ?format=csv는 별도의 서명이 없는 편리한 표 형식의 데이터를 생성합니다. JSON 및 ZIP 파일은 그대로 유지하십시오:

python -m tgwitness.verify evidence.zip --fingerprint TRUSTED_KEY_SHA256 --board
python -m tgwitness.verify board-slice.json --evidence evidence.zip --fingerprint TRUSTED_KEY_SHA256
python -m tgwitness.verify case-board.json --evidence evidence.zip --fingerprint TRUSTED_KEY_SHA256

선택 확인은 서명된 진술, 정확한 원본 기록 및 지정된 경계에서 쿼리의 완전성을 인증합니다. 증거 ZIP 파일은 더 최신 버전일 수 있으나 반드시 해당 접두사를 포함해야 합니다. 연결되지 않은 대상은 명시적으로 보고됩니다. 다른 원본 슬라이스 스냅샷, 변경된 주석, 일치하지 않는 재생 상태 또는 변경된 원본은 검증에 실패합니다. 주석이 없는 기존 아카이브는 기존의 검증 동작을 유지합니다.

인계 설정은 기본적으로 ‘포함하지 않음’으로 설정되어 있습니다. 명시적 포함은 이미 최소화된 기록을 통해 카드를 표시하고, 접근 불가능하거나 생략된 대상을 제외하며, 원본 텍스트가 최소화된 하이라이트는 비공개 처리하고, 동일한 멘션/연락처 규칙에 따라 팀 텍스트를 정리하며, 선택적으로 메타데이터 및 메모 내 알려진 발생 사례에서 조사관 라벨을 R01, R02…로 대체합니다. 원본 annotations.jsonl은 공개되지 않습니다. 서명된 tgwitness-case-board-handover-v1 사이드카와 보고서에는 동일한 축소된 자료가 포함됩니다. 슬라이스 수는 공개된 기록만을 나타내며, 원본 스냅샷/쿼리 행위자 세부 정보는 비공개로 처리됩니다. 미니마이저가 인식하지 못하는 자유 텍스트 이름은 일반적인 인계 절차와 마찬가지로 여전히 검토가 필요합니다. 이 파생본은 편집 후 원본 주석 서명을 보존한다고 주장하지 않습니다.

운영 제한 사항#

매개변수에는 10,000개의 카드 및 50,000개의 댓글에 대한 소프트 제한, 최대 5,000개의 기록을 포함하는 슬라이스 페이지, 미디어 미리보기 제어 기능이 포함됩니다. 소프트 제한은 기록을 삭제하지 않고 경고만 표시합니다. 피드 페이지에는 최대 200장의 카드가 표시됩니다. 독립형 JSON 슬라이스 발췌본은 64 MiB로 제한되며, 더 큰 용량의 자료의 경우 쿼리를 좁히거나 서명된 ZIP 파일을 사용하십시오. 독립형 검증기는 주석 재생을 256 MiB로 제한합니다. Case Board에서는 외부 댓글 알림 기능이 활성화되거나 구현되어 있지 않습니다.

이 기능의 자동 승인 과정에서는 가상의 데이터와 시뮬레이션된 텔레그램 전송을 사용하여 저장, 액세스, 렌더링 및 내보내기 기능을 확인합니다. 증거 확인 범위에 대해서는 검증 범위를 참조하십시오.