move_detect/docs/영상보관-노조대응.md
유창욱 9c0cfd2fea feat(alert): 아무도 발행하지 않던 device_fault·monitoring_degraded 구현
두 유형은 타입 정의(edge/events.py)·서버 검증(EventValidator)·콘솔 필터·
통보 라벨까지 전 구간에 있었으나 생성하는 코드가 어디에도 없었다. 실제로
값을 넣는 것은 seed_demo.php 뿐이었고, 소개서가 내세운 "17종"은 15종이었다.

앞서 고친 EventValidator 누락과 정확히 반대 방향의 같은 병이다. 그때는
감지기가 있는데 서버가 막았고, 이번엔 서버·UI가 열려 있는데 감지기가 없다.
어느 쪽이든 화면은 멀쩡해 보인다.

엣지가 낼 수 없는 유형이라 서버에 둔다 — 전원·회선이 끊긴 노드는 자기가
죽었다고 신고할 수 없다. 하트비트의 부재로만 관측된다.

App\Alert\DeviceHealthWatch:
- dispatch_alerts.php 1분 크론의 1단계. 에스컬레이션·통보보다 앞에 두어
  같은 실행 안에서 발행된 장치 이벤트가 곧바로 통보 대상이 되게 했다.
- 멱등은 EscalationWatch와 같은 방식(event_uuid UNIQUE 충돌)이되, 장치
  건전성은 연속 상태라 uuid 앵커를 '장애 구간의 시작'으로 잡았다.
  device_fault는 last_heartbeat_at(장애 내내 불변) → 장애당 정확히 1건.
  monitoring_degraded는 창 안의 마지막 정상 하트비트 ts. 창 전체가 저하면
  시작을 볼 수 없으므로 창 버킷으로 폴백해 시간당 1회 재고지한다 —
  의도된 리마인더이고, 매 틱 재발행하는 앵커 드리프트가 아니다.
- 성능 저하는 지속을 요구(기본 5분). 한 번 튄 값에 울리면 운영자가 이
  유형을 무시하게 되고, 그러면 감시가 멈춘 날에도 아무도 보지 않는다.
  엣지 감지기들이 쓰는 규율과 같다.
- 하트비트를 한 번도 보낸 적 없는 장치는 장애가 아니다(미설치 노드).
  새 현장 첫날이 빨간 벽이 되면 그 사이트는 이 유형을 영영 신뢰하지 않는다.
- 죽은 노드에 degraded를 겹쳐 내지 않는다 — 한 고장에 두 알람은 소음이다.
- fps NULL을 0으로 강압하지 않는다(측정 실패 ≠ 정지). PdoDeviceMetric
  Repository가 NULL을 지키는 이유와 같다.
- 억제(정비 모드)는 여기서 보지 않는다. 기록은 남기고 통보 여부는
  AlertDispatcher가 정한다 — 정비 창은 전화를 끄는 것이지 노드가 죽었던
  기록을 지우는 것이 아니다.

camera_id는 NOT NULL인데 장치 단위 이벤트에는 카메라가 없다. '__device__'
센티넬을 쓰고, 콘솔은 "장치 전체"로 표시, 구역 편집기 카메라 목록에서는
제외한다(카메라 목록은 보고된 이벤트에서 파생되므로, 두면 존재하지 않는
카메라에 구역을 그리려는 일이 생긴다).

설정 4종 추가(device_stale_seconds 180 · degraded_sustain_seconds 300 ·
degraded_fps_ratio 0.6 · target_fps 12) — 두 config 템플릿에 한국어 설명과
함께. 낮은 프레임으로 운용하는 현장이 target_fps를 안 맞추면 전 노드가
영구 저하로 보고되므로 그 경고를 템플릿에 적었다.

검증: pytest 308 passed(3 skip: 모델 미동봉·shellcheck 미설치·AF_UNIX,
기존과 동일) · phpunit 240 passed(신규 16). dist 재생성으로 패리티 회복.
2026-08-25 10:36:48 +09:00

190 lines
13 KiB
Markdown

# 영상 보관 정책과 노조 대응 논리
> 작성 2026-08-24. **법률 자문이 아닙니다** — §5의 법령 해석은 실제 협의 전에
> 노무사·변호사 확인을 받으십시오. 이 문서는 제품이 무엇을 하는지(§1)와
> 그로부터 나오는 논리(§2~§4)를 정리한 것입니다.
## 1. 먼저, 이 제품은 영상을 녹화하지 않는다
질문의 전제("녹화된 영상을 어떻게 할까")가 이 제품에는 적용되지 않습니다.
코드 기준 실제 동작은 다음과 같습니다.
| 무엇 | 어디에 | 얼마나 | 근거 |
|---|---|---|---|
| 프레임 링버퍼 | **엣지 노드 RAM에만** | **90프레임 = 7.5초**(기본 12fps). 계속 덮어씀. **디스크에 쓰지 않음** | `edge/snapshot.py` `RingBuffer(maxlen=90)`, `TARGET_FPS=12` |
| 증거 스냅샷 | 서버 | **이벤트가 발생했을 때만 3장** — 이벤트 **2.5초 전·1초 전·그 순간**, 얼굴 블러 후 JPEG | `edge/app.py` `SNAPSHOT_OFFSETS_S = (2.5, 1.0, 0.0)` |
| 스냅샷 보관 | 서버 | **기본 7일 후 자동 삭제** | `Config::snapshotRetentionDays() = 7` |
| 이벤트 기록(텍스트) | 서버 | 기본 영구 — **개인 식별 정보 없음** | `Config::eventRetentionDays() = 0` |
> **"7.5초를 보관하는 것 아니냐"** — 그 7.5초는 열람할 수 있는 화면도 API도 없고, 12분의 1초마다
> 덮어씁니다. 이벤트가 나야 3장이 뽑히고, 나지 않으면 사라집니다. 버퍼가 존재하는 이유는
> 보관이 아니라 **판정 지연의 보상**입니다: 넘어짐 확정에 3초가 걸리므로, 확정 시점에서
> 2.5초 전을 되짚으려면 그만큼은 손에 들고 있어야 합니다. 즉 **사고 직전 2.5초가 남는 전부**입니다.
**얼굴 블러는 엣지에서, 업로드 전에 겁니다.** 블러 안 된 이미지는 네트워크로 나가지
않고, 서버에 존재한 적이 없습니다. 과거 프레임은 *그 프레임 자신의* 머리 위치로
블러합니다(현재 위치로 블러하면 과거 얼굴이 그대로 남으므로).
또한 **라이브뷰가 없습니다.** 지금 누가 무엇을 하고 있는지 실시간으로 볼 수 있는
화면 자체가 제품에 없습니다.
### 그래서 질문에 대한 직접적인 답
> "감지가 없다면 폐기하는 쪽이 맞을까?"
**이미 그보다 강한 것을 하고 있습니다.** 감지가 없으면 폐기하는 게 아니라,
**애초에 저장하지 않습니다.** 폐기 정책은 "저장은 했다"를 전제하지만, 여기서는
데이터가 생성된 적이 없습니다. 노조 앞에서 이 차이는 매우 큽니다.
---
## 2. 두 선택지 비교 — (b)는 최악의 선택이다
| | (a) 감지 없으면 폐기 | (b) 용량껏 보관하되 아무도 못 봄 |
|---|---|---|
| 성격 | **구조적 보장** — 데이터가 없다 | **행동에 대한 약속** — 안 보겠다 |
| 검증 가능성 | 저장소를 열어 보이면 끝 | 검증 불가. "안 봤다"는 증명할 수 없다 |
| 뒤집히는 조건 | 제품을 다시 만들어야 함 | **관리자 설정 하나** |
| 유출 시 | 유출될 것이 없음 | 피해 그대로 |
| 수사기관 영장 | 내줄 것이 없음 | 전량 제출 |
**노조가 공격하는 지점이 정확히 (b)입니다.** 노조의 불신은 "지금 사측이 볼 것이다"가
아니라 **"언젠가, 다른 경영진이, 다른 목적으로 볼 수 있다"** 입니다. (b)는 그 불신에
대해 "우리를 믿어달라"고 답하는 것이고, 그건 협상에서 가장 약한 카드입니다.
> **원칙**: 존재하지 않는 데이터는 열람될 수 없고, 유출될 수 없고, 목적 외로 쓰일 수 없다.
> 접근 통제는 되돌릴 수 있지만 미수집은 되돌릴 수 없다.
**권고 — (a). 그리고 이미 (a)를 넘어선 상태이므로, 바꾸지 말고 그대로 설명하십시오.**
---
## 3. "하루치 보관해서 화재·붕괴 조짐을 보자"는 권하지 않습니다
취지는 이해합니다. 사고 원인 분석에 이벤트 전후만이 아니라 더 긴 맥락이 필요할 수
있습니다. 그러나 이 기능을 넣는 순간 잃는 것이 얻는 것보다 큽니다.
1. **노조 방어 논리 전체를 잃습니다.** §2의 표에서 (a)가 (b)로 바뀝니다.
"우리는 녹화하지 않습니다"는 한 문장이 사라지고, 그 뒤로는 기간·열람권 협상만 남습니다.
2. **법적 성격이 바뀝니다.** 상시 녹화는 고정형 영상정보처리기기 규율(§5)에 정면으로
들어가고, 근참법상 '근로자 감시 설비' 성격이 뚜렷해집니다.
3. **실익이 생각보다 작습니다.** 붕괴·화재의 *조짐* 은 영상으로 사후에 판독하기 어렵고,
그건 애초에 이 제품의 감지 대상이 아닙니다(자세·구역 기반).
4. **대부분의 현장에는 이미 일반 CCTV가 있습니다.** 상시 녹화는 그쪽의 몫입니다.
이 제품이 녹화를 시작하면 **기존 CCTV의 열등한 복제품**이 되면서 고유 가치를 잃습니다.
포지션은 "기존 CCTV를 대체하는 물건"이 아니라 **"기존 CCTV가 못 하는 즉시 대응을 붙이는 물건"** 입니다.
5. **하드웨어가 감당하기 어렵습니다.** 노드당 다중 카메라 24시간치를 로컬에 쓰면
SD/SSD 수명과 용량이 모두 문제가 되고, 폐쇄망에서는 그 관리 부담이 현장에 남습니다.
**사고 원인 분석은 이렇게 답하십시오** — 이 제품이 남기는 것은 영상이 아니라
**타임라인**입니다. 이벤트 시각·유형·위치, 전후 3프레임, 통보 이력, 조치 이력,
위·변조 탐지 감사기록. 원인 분석에 실제로 필요한 것은 대부분 이쪽이고,
영상이 꼭 필요하면 **현장의 기존 CCTV에서 해당 시각을 찾아보면 됩니다** —
이 제품이 그 "몇 시 몇 분"을 정확히 짚어 줍니다.
---
## 4. 진짜 쟁점은 기간이 아니라 접근 구조다
노조 대응에서 가장 흔한 실수가 **보관기간 숫자로 협상하는 것**입니다.
> 90일 보관 + 얼굴 블러 + 모든 열람 기록 + 개인 식별 불가
> **<<** 24시간 보관 + 관리자 무제한 열람 + 기록 없음
**후자가 훨씬 더 감시적입니다.** 기간을 줄이는 것은 노조에게 실질적 안전장치를
주지 못하면서 사고 조사 능력만 깎습니다. 협상 카드로 내밀 것은 기간이 아니라 아래입니다.
### 이 제품이 이미 가진 것 (그대로 설명하면 되는 것)
- **라이브뷰 없음** — 실시간 감시 화면이 존재하지 않음
- **영상 녹화·전송 없음** — 이벤트 스냅샷 3장이 전부
- **얼굴 블러** — 엣지에서, 업로드 전에
- **개인 식별자 없음** — 사람을 임시 추적번호로만 다루고, **누구인지 모릅니다.**
사번·이름·얼굴 인식 어느 것도 없습니다
- **근무태도 관련 이벤트 0종** — 감지 17종 전부가 *위험 상태* 이고,
자리 비움·작업 속도·휴게 시간 같은 항목은 **설계상 존재하지 않습니다**
- **위·변조 탐지 감사기록** — 설정 변경·확인·오탐 처리가 해시 체인으로 남아
지우거나 고치면 검증에서 드러납니다
- **스냅샷 7일 자동 삭제**, 이후에는 통계와 텍스트 기록만 남음
### 아직 없는 것 — 보완을 권고합니다
**스냅샷을 누가 열람했는지가 감사기록에 남지 않습니다.** 현재 감사기록은 쓰기
동작(확인·오탐·구역 변경·설정 변경·로그인)만 기록합니다(`server/src/**` 의
`audit->append` 호출부 기준).
이것은 노조 협의에서 **가장 강한 카드가 될 수 있는 항목이 비어 있는 것**입니다.
"아무도 함부로 보지 않는다"를 약속이 아니라 **기록으로** 만들 수 있습니다.
권고 3가지:
1. **스냅샷 열람을 감사기록에 남긴다** — 누가, 언제, 어느 이벤트의 사진을 열었는지.
2. **노조 대표에게 열람 계정(viewer)과 감사기록 조회 권한을 준다** —
감시자를 감시할 수 있게 하는 것이 불신을 푸는 가장 빠른 길입니다.
3. **보관기간을 화면에 표시한다** — 설정 파일 안이 아니라 눈에 보이는 곳에.
---
## 5. 법적 근거 (참고 — 확인 필요)
### 5-1. 보관기간
**표준 개인정보 보호지침 제41조** — 개인영상정보는 보유 목적 달성을 위한 최소한의
기간으로 보유기간을 산정하되, **그 기간을 산정하기 곤란하면 수집 후 30일 이내**로
합니다. 30일이 상한이 아니라 *기간을 정하기 어려울 때의 기본값* 이라는 점이 중요합니다 —
목적이 명확하고 사유를 밝히면 다르게 정할 수 있습니다.
이 제품의 스냅샷 기본 **7일**은 그 기본값보다 짧고, "이벤트 확인·초기 대응"이라는
목적에 비추어 설명 가능한 값입니다. **7일을 늘릴 이유가 없습니다.**
### 5-2. 사고 기록 보존 의무 — 이미지와 분리해서 보십시오
**산업안전보건법 제164조**는 산업재해 발생 원인 등의 기록을 **3년** 보존하도록 합니다.
여기서 요구되는 것은 **기록**이지 영상이 아닙니다.
그래서 이 제품의 설계가 두 요구를 동시에 만족합니다.
- **개인 식별 이미지** → 7일 후 삭제 (개인정보 최소보유)
- **이벤트 기록·조치 이력·감사기록** → 장기 보존 (사고 조사 대응)
노조에게는 "사진은 일주일이면 사라지고, 남는 것은 몇 시에 무슨 일이 있었다는
기록뿐"이라고 설명할 수 있고, 사업주에게는 보존 의무를 충족한다고 설명할 수 있습니다.
### 5-3. 노조 협의는 이기고 지는 문제가 아니라 절차 문제입니다
**근로자참여 및 협력증진에 관한 법률 제20조**는 **"사업장 내 근로자 감시 설비의 설치"**
를 노사협의회 **협의 사항**으로 정하고 있습니다. 설치의 주된 목적이 근로자 감시가
아니더라도, 실질적으로 감시 효과를 갖는 설비면 해당할 수 있다고 해석됩니다.
**따라서 "이건 감시 설비가 아니다"라고 다투는 것은 좋은 전략이 아닙니다.**
협의 대상이 아니라고 우기다가 절차 하자가 생기면, 제품의 기술적 장점과 무관하게
도입 자체가 무효화될 수 있습니다. 권고하는 순서는 다음과 같습니다.
1. **협의 대상임을 인정하고 먼저 노사협의회에 올린다.**
2. §4의 목록을 그대로 설명한다 — 특히 **근무태도 이벤트가 0종**이라는 점.
3. **목적 외 사용 금지를 문서로 합의한다** — 국가인권위원회는 안전·보안 목적으로
설치한 CCTV를 근무 감독에 활용한 사례를 인권침해로 판단한 바 있습니다(2017).
이 제품은 애초에 근무태도 데이터를 만들지 않으므로 **지키기 쉬운 약속**입니다.
4. **노조에 감사기록 조회권을 준다**(§4 권고 2). 합의를 검증 가능하게 만듭니다.
5. 합의 내용을 회의록으로 남긴다.
### 참고 자료
- [표준 개인정보 보호지침 — 국가법령정보센터](https://www.law.go.kr/admRulLsInfoP.do?admRulSeq=2100000234592)
- [표준 개인정보 보호지침 제41조 해설 — IT위키](https://itwiki.kr/w/%ED%91%9C%EC%A4%80_%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4_%EB%B3%B4%ED%98%B8%EC%A7%80%EC%B9%A8_%EC%A0%9C41%EC%A1%B0)
- [근로자참여 및 협력증진에 관한 법률 제20조 — CaseNote](https://casenote.kr/%EB%B2%95%EB%A0%B9/%EA%B7%BC%EB%A1%9C%EC%9E%90%EC%B0%B8%EC%97%AC_%EB%B0%8F_%ED%98%91%EB%A0%A5%EC%A6%9D%EC%A7%84%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B2%95%EB%A5%A0/%EC%A0%9C20%EC%A1%B0)
- [산업안전보건법 제164조 — CaseNote](https://casenote.kr/%EB%B2%95%EB%A0%B9/%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EB%B3%B4%EA%B1%B4%EB%B2%95/%EC%A0%9C164%EC%A1%B0)
- ["CCTV 목적 외 근무태도 감독 활용은 인권침해" — 국가인권위원회 보도자료](https://www.humanrights.go.kr/site/program/board/basicboard/view?boardtypeid=24&boardid=7601831&menuid=001004002001)
- [사업장 내 CCTV 등 감시 설비 설치에 따른 법적 문제 — 노동연구원 웹진](https://www.erc.re.kr/webzine/vol50/15.jsp)
---
## 6. 한 문단 요약 (노조 설명용)
> 이 시스템은 영상을 녹화하지 않습니다. 실시간으로 들여다보는 화면도 없습니다.
> 넘어짐 같은 위험 상황이 감지된 그 순간에만 사진 3장이 남고, 그 사진은 카메라 쪽에서
> 얼굴을 가린 뒤에 전송되며, 7일이 지나면 자동으로 지워집니다. 시스템은 그 사람이
> 누구인지 모릅니다 — 이름도 사번도 얼굴 인식도 없습니다. 감지하는 17가지는 전부
> 위험한 상태에 관한 것이고, 자리를 비웠는지 일을 얼마나 했는지는 **만들 수 있는
> 기능 자체가 없습니다.** 설정을 바꾸거나 기록을 열어 본 사람은 지울 수 없는 형태로
> 남고, 그 기록은 노조도 확인할 수 있게 하겠습니다.