feat(release): prepare 1.1.0 candidate
This commit is contained in:
parent
5a34f66981
commit
5205dcdfa9
736 changed files with 115667 additions and 12203 deletions
184
docs/v3/play/05-content-reporting-operations.md
Normal file
184
docs/v3/play/05-content-reporting-operations.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
# AI 콘텐츠 신고 운영 runbook
|
||||
|
||||
기준일: 2026-08-24
|
||||
|
||||
이 문서는 D3RO Voice의 AI 결과 신고를 production에서 접수·검토·종결·정리하는
|
||||
절차다. 현재는 구현과 local 검증만 완료됐으며, production 배포·운영 담당 지정·자동
|
||||
purge·실제 설치본 E2E는 완료되지 않았다.
|
||||
|
||||
## 1. 책임과 접근 경계
|
||||
|
||||
출시 전에 다음 값을 실제 담당자로 교체한다.
|
||||
|
||||
| 역할 | 책임 | 현재 상태 |
|
||||
| ----------------- | -------------------------------------------------- | -------------------------------- |
|
||||
| moderation owner | 매 영업일 queue 확인, SLA와 종결 품질 관리 | `<PLACEHOLDER_MODERATION_OWNER>` |
|
||||
| safety escalation | 아동 안전, 자해·폭력, 명백한 불법 콘텐츠 즉시 판단 | `<PLACEHOLDER_SAFETY_ON_CALL>` |
|
||||
| privacy owner | 개인정보·계정 삭제·보관 예외 검토 | `<PLACEHOLDER_PRIVACY_OWNER>` |
|
||||
| purge owner | 매일 purge 실행·실패 알림·월간 보관 감사 | `<PLACEHOLDER_PURGE_OWNER>` |
|
||||
|
||||
- 일반 사용자는 authenticated `content-report` Edge Function으로만 신고한다.
|
||||
- `content_generation_receipts`, `content_reports`,
|
||||
`content_report_review_actions`는 `anon`과 `authenticated`의 직접 접근을 모두
|
||||
거부한다.
|
||||
- queue 조회·상태 변경 RPC는 `profiles.role`이 `manager`, `admin`,
|
||||
`super_admin`인 인증 사용자만 호출할 수 있다.
|
||||
- `profiles.role`과 `profiles.tier`는 일반 사용자의 column UPDATE 권한에서 제외한다.
|
||||
표시 이름, 아바타, locale만 self-service 수정이 가능하다.
|
||||
- service-role key는 모바일 앱, 브라우저, 로그, 티켓, Play reviewer 안내에 넣지 않는다.
|
||||
|
||||
근거 마이그레이션:
|
||||
|
||||
- `server/supabase/migrations/20260824000029_content_reporting.sql`
|
||||
- `server/supabase/migrations/20260824000030_profile_managed_field_acl.sql`
|
||||
|
||||
## 2. Production 배포 순서
|
||||
|
||||
다음 순서를 한 release window 안에서 수행한다.
|
||||
|
||||
1. 권위 있는 release commit과 production Supabase project ref를 기록한다.
|
||||
2. migration `20260824000029`, `20260824000030`의 dry-run diff를 검토한 뒤 적용한다.
|
||||
3. `llm-proxy`와 `content-report`를 같은 source SHA에서 배포한다.
|
||||
4. Talk, Commands, Actions 클라이언트를 포함한 AAB를 배포한다.
|
||||
5. purge job과 실패 알림을 활성화한다.
|
||||
6. Free/Pro+ 테스트 계정으로 제출→queue→검토→종결→감사 원장 E2E를 수행한다.
|
||||
|
||||
예시 명령의 placeholder는 실행 전에 secret manager와 release record의 실제 값으로
|
||||
대체한다. 이 문서의 명령 실행 자체가 production 배포 승인인 것은 아니다.
|
||||
|
||||
```powershell
|
||||
supabase db push --linked --dry-run
|
||||
supabase db push --linked
|
||||
supabase functions deploy llm-proxy --project-ref '<PROJECT_REF>'
|
||||
supabase functions deploy content-report --project-ref '<PROJECT_REF>'
|
||||
```
|
||||
|
||||
배포 직후 다음을 확인한다.
|
||||
|
||||
- `X-D3RO-Generation-Purpose`가
|
||||
`talk_response|command_response|action_response`만 허용된다.
|
||||
- 성공한 provider 응답에는 UUID `X-D3RO-Generation-Id`가 있다.
|
||||
- receipt에는 user/model/purpose/expiry만 있고 prompt·AI 출력은 없다.
|
||||
- 신고에는 사용자가 미리 확인한 snapshot, reason, 선택 comment만 있다.
|
||||
- 음성, 전체 대화, 원래 prompt는 자동 첨부되지 않는다.
|
||||
- 일반 사용자 role/tier 직접 UPDATE와 ledger 직접 SELECT/INSERT가 거부된다.
|
||||
|
||||
## 3. Queue와 처리 SLA
|
||||
|
||||
운영 도구는 로그인한 manager 이상 사용자의 access token으로 다음 RPC를 호출한다.
|
||||
브라우저 콘솔이나 공유 스크립트에 token을 붙여 넣지 않는다.
|
||||
|
||||
```ts
|
||||
const { data, error } = await supabase.rpc('admin_list_content_reports_v1', {
|
||||
p_status: 'pending',
|
||||
p_limit: 100,
|
||||
p_before: null
|
||||
})
|
||||
```
|
||||
|
||||
권장 SLA:
|
||||
|
||||
- 아동 성적 학대·착취 또는 즉각적인 생명 위험: 발견 즉시 escalation
|
||||
- 개인정보 노출, 구체적 폭력 위협, 자해 조장: 4시간 이내 1차 검토
|
||||
- 혐오·괴롭힘·성적·사기·스팸·오정보·기타: 1영업일 이내 1차 검토
|
||||
- 미처리 `pending`의 최장 age가 24시간을 넘으면 moderation owner와 on-call에 알림
|
||||
|
||||
검토자는 snapshot과 사용자가 선택한 사유·comment만 필요한 범위에서 본다. 다른
|
||||
대화, 녹음, 계정 데이터는 자동으로 확장 조회하지 않는다.
|
||||
|
||||
## 4. 검토와 종결
|
||||
|
||||
각 조치는 새 UUID idempotency key와 3~1000자의 사실 기반 note가 필요하다.
|
||||
|
||||
```ts
|
||||
await supabase.rpc('admin_act_on_content_report_v1', {
|
||||
p_report_id: reportId,
|
||||
p_idempotency_key: crypto.randomUUID(),
|
||||
p_action: 'begin_review',
|
||||
p_note: 'Initial policy review started'
|
||||
})
|
||||
```
|
||||
|
||||
허용 전이는 다음뿐이다.
|
||||
|
||||
| action | 결과 상태 | 사용 조건 |
|
||||
| ------------------- | ----------- | -------------------------------------------- |
|
||||
| `begin_review` | `reviewing` | 담당자가 증거를 확인하기 시작함 |
|
||||
| `dismiss` | `dismissed` | 정책 위반이 아니거나 증거가 불충분함 |
|
||||
| `confirm_violation` | `actioned` | 정책 위반을 확인하고 별도 완화 조치를 기록함 |
|
||||
|
||||
`confirm_violation`은 원장 상태를 확정하지만 계정 정지나 provider 차단을 자동 실행하지
|
||||
않는다. 필요한 계정·모델·prompt 정책 조치는 기존 승인된 관리자 절차에서 별도로
|
||||
수행하고, 신고 note에는 비밀이나 snapshot 원문을 복제하지 말고 조치 식별자만 남긴다.
|
||||
|
||||
의도적인 허위·보복·반복 남용 신고는 신고 자체를 삭제해 숨기지 않는다. `dismiss`로
|
||||
종결하고 반복 패턴은 별도 abuse case로 escalation한다. 선의의 신고자에게 불이익을
|
||||
주지 않는다.
|
||||
|
||||
## 5. 보관과 purge
|
||||
|
||||
- generation receipt: 생성 후 30일
|
||||
- `pending`, `reviewing` 신고 증거: 해결할 때까지
|
||||
- `dismissed`, `actioned` 신고 증거: 해결 시점부터 180일
|
||||
- 계정 삭제: reporter/reviewer identity와 moderation audit actor는 `NULL`로 분리하지만,
|
||||
미해결 또는 180일 보관 창의 선택 증거는 moderation·분쟁 대응을 위해 남을 수 있다.
|
||||
- general audit log에는 snapshot이나 전체 생성 결과를 복제하지 않는다.
|
||||
|
||||
정리는 `purge_expired_content_reporting_data_v1()`만 사용한다. 이 RPC는
|
||||
service-role만 실행할 수 있다. scheduler는 secret manager에서 service credential을
|
||||
주입하는 서버 측 job이어야 하며, 모바일·브라우저 job은 금지한다.
|
||||
|
||||
성공 응답 예시는 다음과 같다.
|
||||
|
||||
```json
|
||||
{ "purgedReports": 3, "purgedReceipts": 121 }
|
||||
```
|
||||
|
||||
매일 실행 결과에 실행 시각, release SHA, 숫자만 기록한다. report ID, snapshot,
|
||||
comment, service credential은 scheduler log에 남기지 않는다. 24시간 동안 성공 실행이
|
||||
없거나 RPC가 실패하면 purge owner에게 알리고, 72시간 이내 복구되지 않으면 privacy
|
||||
owner에게 escalation한다.
|
||||
|
||||
## 6. 모니터링과 월간 감사
|
||||
|
||||
운영 모니터는 원문 없이 다음 집계만 보관한다.
|
||||
|
||||
- status별 수와 최장 pending age
|
||||
- 시간·일 rate-limit 발생 수
|
||||
- 제출 4xx/5xx와 idempotency conflict 수
|
||||
- review action 성공·실패 수
|
||||
- 마지막 purge 성공 시각과 삭제 건수
|
||||
|
||||
매월 다음을 표본 확인한다.
|
||||
|
||||
- 일반 사용자 role/tier self-update가 계속 거부되는가
|
||||
- expired receipt가 남아 있지 않은가
|
||||
- resolved report가 180일 이후 purge되는가
|
||||
- pending/reviewing 증거가 time purge되지 않는가
|
||||
- audit log에 snapshot·comment·prompt가 복제되지 않았는가
|
||||
- manager/admin/super_admin 이외 계정이 moderation RPC를 호출하지 못하는가
|
||||
|
||||
## 7. Release 증거와 rollback
|
||||
|
||||
release evidence에는 비밀이나 신고 원문 없이 다음만 보관한다.
|
||||
|
||||
- source commit SHA와 migration/function deployment ID
|
||||
- local SQL, Edge HTTP, Deno test 결과
|
||||
- Play 설치본의 Talk/Commands/Actions 신고 왕복 캡처
|
||||
- queue 도달, `begin_review`, terminal action의 report ID 해시와 상태 시각
|
||||
- purge job 설정, 마지막 성공 시각, alert test
|
||||
- privacy/terms 공개 URL과 해당 버전의 hash
|
||||
|
||||
배포 후 신고 제출이나 generation receipt가 실패하면 AI 생성 경로를 정상처럼 계속
|
||||
노출하지 않는다. 영향 surface를 비활성화하거나 이전 검증 release로 rollback하고,
|
||||
receipt와 report schema를 임의로 drop하거나 moderation evidence를 수동 삭제하지 않는다.
|
||||
|
||||
## 현재 미해결 gate
|
||||
|
||||
- production migration/Edge/mobile 동시 배포
|
||||
- manager용 moderation UI 또는 승인된 내부 operator client
|
||||
- 실제 운영 담당자와 on-call 지정
|
||||
- 매일 purge scheduler와 실패 알림
|
||||
- provider safety/filter 검증
|
||||
- Play가 서명한 실기기 신고 E2E
|
||||
- Talk/Commands/Actions 밖의 AI 생성 문서 신고 범위
|
||||
Loading…
Add table
Add a link
Reference in a new issue