Skip to content

won-seoop/content-safety-ops-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

6 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

content-safety-ops-api

์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ ๊ฒŒ์‹œ๊ธ€์„ ์šด์˜์ •์ฑ… ๋ฃฐ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž๋™ ๊ฒ€์ˆ˜ํ•˜๊ณ , ์ŠคํŒธ/์‚ฌ๊ธฐ/์–ด๋ทฐ์ง• ์œ„ํ—˜๋„๋ฅผ ๊ณ„์‚ฐํ•ด ALLOW, REVIEW, BLOCK ์ค‘ ํ•˜๋‚˜๋กœ ํŒ์ •ํ•ฉ๋‹ˆ๋‹ค.

ALLOW BLOCK REVIEW
image image image

1. ๋ฌธ์ œ ์ƒํ™ฉ

์šด์˜ํŒ€์€ ๋งค์ผ ๋งŽ์€ ๊ฒŒ์‹œ๊ธ€์„ ๊ฒ€์ˆ˜ํ•ด์•ผ ํ•˜๊ณ , ๋ฐ˜๋ณต์ ์ธ ์ •์ฑ… ์œ„๋ฐ˜ ํ‚ค์›Œ๋“œ ํƒ์ง€์™€ ์œ„ํ—˜๋„ ํŒ๋‹จ์€ ์ˆ˜์ž‘์—…์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ์†๋„์™€ ์ผ๊ด€์„ฑ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

ํŠนํžˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŒจํ„ด์€ ๋น ๋ฅด๊ฒŒ ๊ฐ์ง€ํ•ด ์šด์˜์ž๊ฐ€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์žก์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์„ ์ž…๊ธˆ ์š”๊ตฌ
  • ์™ธ๋ถ€ ์—ฐ๋ฝ ์œ ๋„
  • ๊ณ„์ขŒ/์†ก๊ธˆ ์œ ๋„
  • ๋ถˆ๋ฒ• ๊ฑฐ๋ž˜ ํ‚ค์›Œ๋“œ
  • ์ŠคํŒธ์„ฑ ํ‘œํ˜„

์ˆ˜์ž‘์—… ๊ฒ€์ˆ˜๋งŒ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ๊ฒฝ์šฐ ๋‹ค์Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ ์„ค๋ช…
์ฒ˜๋ฆฌ ์ง€์—ฐ ๊ฒŒ์‹œ๊ธ€์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ๊ฒ€์ˆ˜ ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ์ฆ๊ฐ€
ํŒ๋‹จ ์ผ๊ด€์„ฑ ๋ถ€์กฑ ์šด์˜์ž๋งˆ๋‹ค ์ •์ฑ… ์œ„๋ฐ˜ ํŒ๋‹จ ๊ธฐ์ค€์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ
๋ฐ˜๋ณต ์—…๋ฌด ์ฆ๊ฐ€ ๋‹จ์ˆœ ํ‚ค์›Œ๋“œ ๊ฒ€์ˆ˜์—๋„ ์šด์˜ ๋ฆฌ์†Œ์Šค๊ฐ€ ์†Œ๋ชจ๋จ
์‚ฌํ›„ ๋Œ€์‘ ๊ฐ€๋Šฅ์„ฑ ์œ„ํ—˜ ์ฝ˜ํ…์ธ ๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋…ธ์ถœ๋œ ๋’ค ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ์Œ

๋ฌธ์ œ ์ƒํ™ฉ ์บก์ฒ˜

์œ„ํ—˜ ํ‚ค์›Œ๋“œ๊ฐ€ ํฌํ•จ๋œ ํ…Œ์ŠคํŠธ ๊ฒŒ์‹œ๊ธ€ ์˜ˆ์‹œ ์บก์ฒ˜๋ฅผ ๋„ฃ๋Š” ์˜์—ญ์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ ์ƒํ™ฉ ์˜ˆ์‹œ


2. ์„ ํƒํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

๋ณธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์šด์˜์ •์ฑ… ๋ฃฐ์„ ์ฝ”๋“œ์— ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ์•Š๊ณ  DB์— ์ €์žฅํ•œ ๋’ค, ํ™œ์„ฑํ™”๋œ ๋ฃฐ๋งŒ ๊ฒ€์ˆ˜์— ์‚ฌ์šฉํ•˜๋„๋ก ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์šด์˜์ •์ฑ… ๋ฃฐ์„ PostgreSQL์— ์ €์žฅ
  • ์ œ๋ชฉ๊ณผ ๋ณธ๋ฌธ์—์„œ ํ‚ค์›Œ๋“œ ๋งค์นญ
  • ๋งค์นญ๋œ ๋ฃฐ์˜ ์ ์ˆ˜๋ฅผ ํ•ฉ์‚ฐํ•ด ์œ„ํ—˜๋„ ๊ณ„์‚ฐ
  • ์ ์ˆ˜ ๊ธฐ์ค€์— ๋”ฐ๋ผ ALLOW, REVIEW, BLOCK ํŒ์ •
  • ๊ฒ€์ˆ˜ ๊ฒฐ๊ณผ์™€ ๋งค์นญ๋œ ๋ฃฐ์„ PostgreSQL์— ๋กœ๊ทธ๋กœ ์ €์žฅ
  • ๋™์ผ ์ฝ˜ํ…์ธ  ์žฌ๊ฒ€์ˆ˜๋Š” Redis ์บ์‹œ๋กœ ์‘๋‹ต

ํŒ์ • ๊ธฐ์ค€์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ ์ˆ˜ ๋ฒ”์œ„ ํŒ์ • ์˜๋ฏธ
0 ~ 39 ALLOW ์ •์ƒ ๊ฒŒ์‹œ๊ธ€
40 ~ 79 REVIEW ์šด์˜์ž ๊ฒ€ํ†  ํ•„์š”
80 ์ด์ƒ BLOCK ์ฐจ๋‹จ ๋Œ€์ƒ

3. ๊ธฐ์ˆ  ์Šคํƒ

๊ตฌ๋ถ„ ๊ธฐ์ˆ 
Language Python 3.11+
Framework FastAPI
Database PostgreSQL
ORM SQLAlchemy
Migration Alembic
Validation Pydantic
Cache Redis
Infra Docker Compose
Test pytest
API Docs FastAPI Swagger UI

4. ์•„ํ‚คํ…์ฒ˜ ๋‹ค์ด์–ด๊ทธ๋žจ

flowchart LR
    Client[Client / ์šด์˜์ž] --> API[FastAPI Server]

    API --> Redis[(Redis)]
    API --> DB[(PostgreSQL)]

    DB --> Rules[moderation_rules]
    DB --> Logs[moderation_logs]

    API --> Hash[Content Hash ์ƒ์„ฑ]
    Hash --> Redis

    API --> RuleEngine[Rule Engine]
    RuleEngine --> Decision[ALLOW / REVIEW / BLOCK]
    Decision --> Logs
Loading

์•„ํ‚คํ…์ฒ˜ ์บก์ฒ˜

GitHub README์˜ Mermaid ๋ Œ๋”๋ง ํ™”๋ฉด ๋˜๋Š” mermaid.live์—์„œ PNG๋กœ ๋ฝ‘์€ ์ด๋ฏธ์ง€๋ฅผ ๋„ฃ๋Š” ์˜์—ญ์ž…๋‹ˆ๋‹ค.

์•„ํ‚คํ…์ฒ˜ ๋‹ค์ด์–ด๊ทธ๋žจ


5. ์‹œ์Šคํ…œ ํ๋ฆ„

  1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ POST /api/moderations/check๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
  2. ์„œ๋ฒ„๊ฐ€ title + content + price + category๋กœ contentHash๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  3. Redis์—์„œ moderation:content:{contentHash} key๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
  4. cache hit์ด๋ฉด ๋ฃฐ ๊ณ„์‚ฐ๊ณผ DB ์กฐํšŒ ์—†์ด ์ฆ‰์‹œ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.
  5. cache miss์ด๋ฉด ํ™œ์„ฑํ™”๋œ ๋ฃฐ์„ DB์—์„œ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
  6. ์ œ๋ชฉ๊ณผ ๋ณธ๋ฌธ์—์„œ ํ‚ค์›Œ๋“œ๋ฅผ ๋งค์นญํ•ฉ๋‹ˆ๋‹ค.
  7. ๋งค์นญ๋œ ๋ฃฐ์˜ ์ ์ˆ˜๋ฅผ ํ•ฉ์‚ฐํ•ด ์œ„ํ—˜ ์ ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
  8. ์œ„ํ—˜ ์ ์ˆ˜ ๊ธฐ์ค€์œผ๋กœ ALLOW, REVIEW, BLOCK์„ ํŒ์ •ํ•ฉ๋‹ˆ๋‹ค.
  9. ๊ฒ€์ˆ˜ ๋กœ๊ทธ๋ฅผ PostgreSQL์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  10. ๊ฒ€์ˆ˜ ๊ฒฐ๊ณผ๋ฅผ Redis์— 5๋ถ„ TTL๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  11. ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ํŒ์ • ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

6. ๊ฒŒ์‹œ๊ธ€ ๊ฒ€์ˆ˜ ์‹œํ€€์Šค

sequenceDiagram
    participant Client as Client
    participant API as FastAPI Server
    participant Redis as Redis
    participant DB as PostgreSQL

    Client->>API: POST /api/moderations/check
    API->>API: title + content + price + category๋กœ contentHash ์ƒ์„ฑ
    API->>Redis: moderation:content:{contentHash} ์กฐํšŒ

    alt Cache Hit
        Redis-->>API: ์บ์‹œ๋œ ๊ฒ€์ˆ˜ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
        API-->>Client: decision, riskScore, matchedRules ๋ฐ˜ํ™˜
    else Cache Miss
        API->>DB: enabled=true ์šด์˜์ •์ฑ… ๋ฃฐ ์กฐํšŒ
        DB-->>API: ํ™œ์„ฑํ™”๋œ rules ๋ฐ˜ํ™˜
        API->>API: ํ‚ค์›Œ๋“œ ๋งค์นญ
        API->>API: riskScore ๊ณ„์‚ฐ
        API->>API: ALLOW / REVIEW / BLOCK ํŒ์ •
        API->>DB: moderation_logs ์ €์žฅ
        API->>Redis: ๊ฒ€์ˆ˜ ๊ฒฐ๊ณผ ์บ์‹ฑ, TTL 5๋ถ„
        API-->>Client: decision, riskScore, matchedRules ๋ฐ˜ํ™˜
    end
Loading

์‹œํ€€์Šค ๋‹ค์ด์–ด๊ทธ๋žจ ์บก์ฒ˜

ํฌํŠธํด๋ฆฌ์˜ค ๋ฌธ์„œ์— ๋„ฃ๊ธฐ ์ข‹์€ ํ•ต์‹ฌ ์บก์ฒ˜์ž…๋‹ˆ๋‹ค.

๊ฒŒ์‹œ๊ธ€ ๊ฒ€์ˆ˜ ์‹œํ€€์Šค


7. ERD ๋‹ค์ด์–ด๊ทธ๋žจ

erDiagram
    MODERATION_RULES {
        int id PK
        string ruleName
        string keyword
        int score
        string action
        string category
        boolean enabled
        datetime createdAt
        datetime updatedAt
    }

    MODERATION_LOGS {
        int id PK
        int userId
        string title
        string contentHash
        int riskScore
        string decision
        string matchedRules
        string reason
        datetime createdAt
    }
Loading

ERD ์บก์ฒ˜

ERD ๋‹ค์ด์–ด๊ทธ๋žจ


8. ERD ์„ค๋ช…

moderation_rules

์šด์˜์ •์ฑ… ๋ฃฐ์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

ํ•„๋“œ ์„ค๋ช…
id ๋ฃฐ ID
ruleName ๋ฃฐ ์ด๋ฆ„
keyword ๊ฐ์ง€ ํ‚ค์›Œ๋“œ
score ์œ„ํ—˜ ์ ์ˆ˜
action ๊ธฐ๋ณธ ์•ก์…˜ ํžŒํŠธ
category ์ •์ฑ… ์นดํ…Œ๊ณ ๋ฆฌ
enabled ๋ฃฐ ํ™œ์„ฑํ™” ์—ฌ๋ถ€
createdAt ์ƒ์„ฑ ์‹œ๊ฐ
updatedAt ์ˆ˜์ • ์‹œ๊ฐ

moderation_logs

๊ฒ€์ˆ˜ ์š”์ฒญ์˜ ํŒ์ • ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

ํ•„๋“œ ์„ค๋ช…
id ๋กœ๊ทธ ID
userId ์ž‘์„ฑ์ž ID
title ๊ฒŒ์‹œ๊ธ€ ์ œ๋ชฉ
contentHash ์ฝ˜ํ…์ธ  ํ•ด์‹œ
riskScore ์œ„ํ—˜ ์ ์ˆ˜
decision ์ตœ์ข… ํŒ์ •
matchedRules ๋งค์นญ๋œ ๋ฃฐ ์ด๋ฆ„ ๋ชฉ๋ก
reason ํŒ์ • ์‚ฌ์œ 
createdAt ์ƒ์„ฑ ์‹œ๊ฐ

9. API ๋ช…์„ธ

FastAPI ์ž๋™ ๋ฌธ์„œ๋Š” ์‹คํ–‰ ํ›„ ์•„๋ž˜ ์ฃผ์†Œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์šด์˜ ํ™•์ธ UI๋Š” ์‹คํ–‰ ํ›„ http://localhost:8000/์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

UI์˜ ๋ถ€ํ•˜ํ…Œ์ŠคํŠธ / ๊ด€์ธก ์˜์—ญ์—์„œ ์š”์ฒญ ์ˆ˜, ๋™์‹œ์„ฑ, cached/unique ๋ชจ๋“œ๋ฅผ ์„ ํƒํ•ด ๋ถ€ํ•˜ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹คํ–‰ ๊ฒฐ๊ณผ๋กœ RPS, ํ‰๊ท  ์ง€์—ฐ, p95 ์ง€์—ฐ, ์—๋Ÿฌ ์ˆ˜, RSS ๋ฉ”๋ชจ๋ฆฌ, DB ์ปค๋„ฅ์…˜ํ’€ checked-out/overflow, Redis ping, ๋ณ‘๋ชฉ ํžŒํŠธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

http://localhost:8000/docs

Swagger ์บก์ฒ˜

Swagger API ๋ฌธ์„œ


9-1. ์ฝ˜ํ…์ธ  ๊ฒ€์ˆ˜ API

POST /api/moderations/check

Request

{
  "userId": 1,
  "title": "์•„์ดํฐ ์‹ธ๊ฒŒ ํŒ๋‹ˆ๋‹ค",
  "content": "์„ ์ž…๊ธˆํ•˜๋ฉด ํƒ๋ฐฐ ๋ณด๋‚ด๋“œ๋ ค์š”. ์นดํ†ก ์ฃผ์„ธ์š”.",
  "price": 100000,
  "category": "DIGITAL"
}

Response

{
  "decision": "REVIEW",
  "riskScore": 70,
  "matchedRules": [
    "PREPAYMENT_KEYWORD",
    "EXTERNAL_CONTACT_KAKAO"
  ],
  "reason": "์šด์˜์ •์ฑ…์ƒ ๊ฒ€ํ† ๊ฐ€ ํ•„์š”ํ•œ ํ‚ค์›Œ๋“œ๊ฐ€ ๊ฐ์ง€๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
}

๊ฒ€์ˆ˜ API ์‘๋‹ต ์บก์ฒ˜

๊ฒ€์ˆ˜ API ์‘๋‹ต


9-2. ์šด์˜์ •์ฑ… ๋ฃฐ ๊ด€๋ฆฌ API

Method Endpoint ์„ค๋ช…
POST /api/ops/rules ์šด์˜์ •์ฑ… ๋ฃฐ ๋“ฑ๋ก
GET /api/ops/rules ์šด์˜์ •์ฑ… ๋ฃฐ ๋ชฉ๋ก ์กฐํšŒ
PATCH /api/ops/rules/{id}/status ์šด์˜์ •์ฑ… ๋ฃฐ ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™”

์šด์˜์ •์ฑ… ๋ฃฐ ์กฐํšŒ ์บก์ฒ˜

์šด์˜์ •์ฑ… ๋ฃฐ ์กฐํšŒ


9-3. ๊ฒ€์ˆ˜ ๋กœ๊ทธ ์กฐํšŒ API

GET /api/ops/moderation-logs?limit=50&offset=0

๊ฒ€์ˆ˜ ๋กœ๊ทธ ์กฐํšŒ ์บก์ฒ˜

๊ฒ€์ˆ˜ ๋กœ๊ทธ ์กฐํšŒ


10. Redis ์บ์‹ฑ ์ „๋žต

๋™์ผ ์ฝ˜ํ…์ธ ์— ๋Œ€ํ•œ ๋ฐ˜๋ณต ๊ฒ€์ˆ˜ ์š”์ฒญ์€ Redis ์บ์‹œ๋ฅผ ํ†ตํ•ด DB ๋ฃฐ ์กฐํšŒ์™€ ์œ„ํ—˜ ์ ์ˆ˜ ๊ณ„์‚ฐ์„ ์ƒ๋žตํ•ฉ๋‹ˆ๋‹ค.

ํ•ญ๋ชฉ ๋‚ด์šฉ
Hash Source title + content + price + category
Hash Algorithm SHA-256
Redis Key moderation:content:{contentHash}
TTL 5๋ถ„
Cache Hit ๋ฃฐ ๊ณ„์‚ฐ๊ณผ DB ์กฐํšŒ ์ƒ๋žต
Cache Miss DB ๋ฃฐ ๊ธฐ๋ฐ˜ ๊ฒ€์ˆ˜ ํ›„ Redis ์ €์žฅ

Redis ์บ์‹œ Key ์˜ˆ์‹œ

moderation:content:3f1e9b3f2a2c9a...

Redis ์บ์‹œ ์บก์ฒ˜

Redis CLI ๋˜๋Š” RedisInsight์—์„œ key๊ฐ€ ์ €์žฅ๋œ ํ™”๋ฉด์„ ์บก์ฒ˜ํ•ฉ๋‹ˆ๋‹ค.

Redis ์บ์‹œ ํ‚ค


11. ์‹คํ–‰ ๋ฐฉ๋ฒ•

docker compose up --build

์•ฑ ์ปจํ…Œ์ด๋„ˆ ์‹œ์ž‘ ์‹œ Alembic migration์„ ์ ์šฉํ•˜๊ณ  ์ดˆ๊ธฐ seed rule์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

Docker ์‹คํ–‰ ์บก์ฒ˜

Docker Compose ์‹คํ–‰


12. ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pytest

ํ…Œ์ŠคํŠธ๋Š” SQLite์™€ fake Redis๋ฅผ ์‚ฌ์šฉํ•ด ์™ธ๋ถ€ ์„œ๋น„์Šค ์—†์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค

ํ…Œ์ŠคํŠธ ๊ธฐ๋Œ€ ๊ฒฐ๊ณผ
์ •์ƒ ๊ฒŒ์‹œ๊ธ€ ALLOW
์„ ์ž…๊ธˆ ํฌํ•จ ๊ฒŒ์‹œ๊ธ€ REVIEW
์„ ์ž…๊ธˆ + ์นดํ†ก + ๊ณ„์ขŒ ํฌํ•จ ๊ฒŒ์‹œ๊ธ€ BLOCK ๋˜๋Š” ๊ธฐ์ค€์— ๋งž๋Š” ๊ณ ์œ„ํ—˜ ํŒ์ •
๋ถˆ๋ฒ• ํ‚ค์›Œ๋“œ ํฌํ•จ ๊ฒŒ์‹œ๊ธ€ BLOCK
๋™์ผ ์ฝ˜ํ…์ธ  ์žฌ์š”์ฒญ Redis ์บ์‹œ ์‚ฌ์šฉ

pytest ๊ฒฐ๊ณผ ์บก์ฒ˜

pytest ๊ฒฐ๊ณผ


13. DB ์ €์žฅ ๊ฒฐ๊ณผ

๊ฒ€์ˆ˜ ๊ฒฐ๊ณผ๋Š” moderation_logs ํ…Œ์ด๋ธ”์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
์ด๋ฅผ ํ†ตํ•ด ์šด์˜์ž๋Š” ์–ด๋–ค ๊ฒŒ์‹œ๊ธ€์ด ์–ด๋–ค ๋ฃฐ์— ์˜ํ•ด ๊ฒ€์ˆ˜๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

moderation_logs ์บก์ฒ˜

moderation_logs ํ…Œ์ด๋ธ”

moderation_rules ์บก์ฒ˜

moderation_rules ํ…Œ์ด๋ธ”


14. ๊ฒ€์ฆ ๊ฒฐ๊ณผ

์•„๋ž˜ ์ˆ˜์น˜๋Š” ์‹ค์ œ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋„ฃ๋Š” ์˜์—ญ์ž…๋‹ˆ๋‹ค.
์‹ค์ œ ์ธก์ • ์ „์—๋Š” ์ž„์˜ ์ˆ˜์น˜๋ฅผ ๋„ฃ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ํ•ญ๋ชฉ ๊ฒฐ๊ณผ
Docker Compose ์‹คํ–‰ ์„ฑ๊ณต
Swagger ์ ‘๊ทผ ์„ฑ๊ณต
์ฝ˜ํ…์ธ  ๊ฒ€์ˆ˜ API ์„ฑ๊ณต
์šด์˜์ •์ฑ… ๋ฃฐ ๋“ฑ๋ก/์กฐํšŒ/์ˆ˜์ • ์„ฑ๊ณต
๊ฒ€์ˆ˜ ๋กœ๊ทธ ์ €์žฅ ์„ฑ๊ณต
Redis ์บ์‹œ ์ €์žฅ ์„ฑ๊ณต
pytest ํ†ต๊ณผ ์„ฑ๊ณต

๊ฒ€์ฆ ์บก์ฒ˜ ๋ชจ์Œ

์บก์ฒ˜ ํŒŒ์ผ ๊ฒฝ๋กœ
Swagger ๋ฌธ์„œ docs/images/swagger-docs.png
๊ฒ€์ˆ˜ API ์‘๋‹ต docs/images/moderation-check-response.png
์šด์˜์ •์ฑ… ๋ฃฐ ์กฐํšŒ docs/images/rules-list-response.png
๊ฒ€์ˆ˜ ๋กœ๊ทธ API docs/images/moderation-logs-response.png
PostgreSQL ๋กœ๊ทธ ํ…Œ์ด๋ธ” docs/images/moderation-logs-db.png
Redis ์บ์‹œ ํ‚ค docs/images/redis-cache-key.png
pytest ๊ฒฐ๊ณผ docs/images/pytest-result.png
Docker ์‹คํ–‰ docs/images/docker-compose-up.png

15. ๋‹น๊ทผ ์šด์˜๊ฐœ๋ฐœํŒ€ JD์™€์˜ ์—ฐ๊ฒฐ์ 

๋‹น๊ทผ ์šด์˜๊ฐœ๋ฐœํŒ€ ์š”๊ตฌ ํ”„๋กœ์ ํŠธ ์—ฐ๊ฒฐ
์šด์˜ ์ž๋™ํ™” ์šด์˜์ •์ฑ… ๋ฃฐ ๊ธฐ๋ฐ˜ ์ž๋™ ๊ฒ€์ˆ˜ API
์ŠคํŒธ/์‚ฌ๊ธฐ/์–ด๋ทฐ์ง• ํƒ์ง€ ์œ„ํ—˜ ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ์ ์ˆ˜ ๊ณ„์‚ฐ
๊ฑด๊ฐ•ํ•œ ์ฝ˜ํ…์ธ  ๋„๋‹ฌ ALLOW, REVIEW, BLOCK ํŒ์ •
๋Œ€์šฉ๋Ÿ‰ ํŠธ๋ž˜ํ”ฝ ๊ณ ๋ ค Redis ์บ์‹ฑ์œผ๋กœ ๋™์ผ ์ฝ˜ํ…์ธ  ์žฌ๊ฒ€์ˆ˜ ๋น„์šฉ ๊ฐ์†Œ
DB/์บ์‹œ ์ดํ•ด PostgreSQL, Redis ํ™œ์šฉ
AI ๊ด€์‹ฌ ๋ฐ ํ™•์žฅ์„ฑ pgvector, AI ๋ณด์กฐ ํŒ๋‹จ ํ™•์žฅ ๊ตฌ์กฐ ์ œ์‹œ
์šด์˜ ํŒ๋‹จ ๊ทผ๊ฑฐ matchedRules, reason, moderation_logs ์ €์žฅ

16. ํ™•์žฅ ๋ฐฉํ–ฅ

16-1. pgvector ๊ธฐ๋ฐ˜ ์œ ์‚ฌ ์œ„ํ—˜ ๋ฌธ๊ตฌ ํƒ์ง€

ํ˜„์žฌ๋Š” ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ๊ฒ€์ˆ˜ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
์ถ”ํ›„์—๋Š” pgvector๋ฅผ ํ™œ์šฉํ•ด ๊ธฐ์กด ์œ„ํ—˜ ๋ฌธ๊ตฌ์™€ ์œ ์‚ฌํ•œ ํ‘œํ˜„๋„ ํƒ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

๊ธฐ์กด ์œ„ํ—˜ ๋ฌธ๊ตฌ ์šฐํšŒ ํ‘œํ˜„
์„ ์ž…๊ธˆํ•˜๋ฉด ๋ณด๋‚ด๋“œ๋ฆด๊ฒŒ์š” ๋จผ์ € ๋ณด๋‚ด์ฃผ์‹œ๋ฉด ํƒ๋ฐฐ ์ ‘์ˆ˜ํ• ๊ฒŒ์š”
์นดํ†ก ์ฃผ์„ธ์š” ใ…‹ใ…Œ ์ฃผ์„ธ์š”
๊ณ„์ขŒ๋กœ ๋ณด๋‚ด์ฃผ์„ธ์š” ใ„ฑใ…ˆ๋กœ ๋ณด๋‚ด์ฃผ์„ธ์š”

16-2. AI ๋ณด์กฐ ํŒ๋‹จ

๋ชจ๋“  ๊ฒŒ์‹œ๊ธ€์„ AI๋กœ ํŒ๋‹จํ•˜๋ฉด ๋น„์šฉ๊ณผ ์‘๋‹ต ์‹œ๊ฐ„์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ REVIEW ํŒ์ • ๊ฒŒ์‹œ๊ธ€๋งŒ AI ๋ณด์กฐ ํŒ๋‹จ ๋Œ€์ƒ์œผ๋กœ ๋„˜๊ธฐ๋Š” ๋ฐฉ์‹์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ALLOW โ†’ ์ฆ‰์‹œ ํ†ต๊ณผ
REVIEW โ†’ AI ๋ณด์กฐ ํŒ๋‹จ ๋˜๋Š” ์šด์˜์ž ๊ฒ€์ˆ˜
BLOCK โ†’ ์ฐจ๋‹จ ๋˜๋Š” ๊ฐ•ํ•œ ๊ฒ€์ˆ˜ ํ ๋“ฑ๋ก

16-3. ์‹ ๊ณ  ์‹œ์Šคํ…œ ์—ฐ๋™

์‚ฌ์šฉ์ž ์‹ ๊ณ ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ๊ธฐ์กด ๊ฒ€์ˆ˜ ๋กœ๊ทธ์™€ ์—ฐ๊ฒฐํ•ด ์šด์˜์ž ๊ฒ€์ˆ˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์‹ ๊ณ 
โ†’ ๊ธฐ์กด moderation_log ์กฐํšŒ
โ†’ ์œ„ํ—˜ ์ ์ˆ˜ ์žฌ๊ณ„์‚ฐ
โ†’ ์šด์˜์ž ๊ฒ€์ˆ˜ ํ ๋“ฑ๋ก

16-4. Slack/Discord ์žฅ์•  ์•Œ๋ฆผ

๊ฒ€์ˆ˜ API ์žฅ์• ๋‚˜ ๋น„์ •์ƒ์ ์ธ BLOCK ๊ธ‰์ฆ ์ƒํ™ฉ์„ ์šด์˜ ์ฑ„๋„๋กœ ์•Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์กฐ๊ฑด ์•Œ๋ฆผ
API ์‹คํŒจ์œจ ์ฆ๊ฐ€ ์žฅ์•  ์•Œ๋ฆผ
p95 ์‘๋‹ต ์‹œ๊ฐ„ ์ฆ๊ฐ€ ์„ฑ๋Šฅ ์ €ํ•˜ ์•Œ๋ฆผ
BLOCK ํŒ์ • ๊ธ‰์ฆ ์ด์ƒ ํŒจํ„ด ์•Œ๋ฆผ

16-5. ์šด์˜์ž ๊ด€๋ฆฌ์ž ํ™”๋ฉด

์šด์˜์ž๊ฐ€ ์ง์ ‘ ๋ฃฐ์„ ๋“ฑ๋ก/์ˆ˜์ •/๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๊ด€๋ฆฌ์ž ํ™”๋ฉด์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


17. ์ฃผ์š” curl ์˜ˆ์‹œ

์ฝ˜ํ…์ธ  ๊ฒ€์ˆ˜

curl -X POST http://localhost:8000/api/moderations/check \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 1,
    "title": "์•„์ดํฐ ์‹ธ๊ฒŒ ํŒ๋‹ˆ๋‹ค",
    "content": "์„ ์ž…๊ธˆํ•˜๋ฉด ํƒ๋ฐฐ ๋ณด๋‚ด๋“œ๋ ค์š”. ์นดํ†ก ์ฃผ์„ธ์š”.",
    "price": 100000,
    "category": "DIGITAL"
  }'

์šด์˜์ •์ฑ… ๋ฃฐ ์กฐํšŒ

curl http://localhost:8000/api/ops/rules

์šด์˜์ •์ฑ… ๋ฃฐ ๋“ฑ๋ก

curl -X POST http://localhost:8000/api/ops/rules \
  -H "Content-Type: application/json" \
  -d '{
    "ruleName": "WIRE_TRANSFER_KEYWORD",
    "keyword": "์†ก๊ธˆ",
    "score": 30,
    "action": "REVIEW",
    "category": "FRAUD",
    "enabled": true
  }'

์šด์˜์ •์ฑ… ๋ฃฐ ๋น„ํ™œ์„ฑํ™”

curl -X PATCH http://localhost:8000/api/ops/rules/1/status \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'

๊ฒ€์ˆ˜ ๋กœ๊ทธ ์กฐํšŒ

curl "http://localhost:8000/api/ops/moderation-logs?limit=20&offset=0"

18. ํ”„๋กœ์ ํŠธ ์˜์˜

์ด ํ”„๋กœ์ ํŠธ๋Š” ๋‹จ์ˆœํ•œ ํ‚ค์›Œ๋“œ ํ•„ํ„ฐ๋ง์ด ์•„๋‹ˆ๋ผ, ์šด์˜์ •์ฑ…์„ ๋ฐ์ดํ„ฐํ™”ํ•˜๊ณ  ์ž๋™ํ™”ํ•˜๋Š” ๋ฐฑ์—”๋“œ ๊ตฌ์กฐ๋ฅผ ๊ตฌํ˜„ํ•œ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.

์šด์˜์ž๋Š” ๋ฃฐ์„ ์ง์ ‘ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ๊ณ , ๊ฒ€์ˆ˜ ๊ฒฐ๊ณผ๋Š” ๋กœ๊ทธ๋กœ ์ €์žฅ๋˜์–ด ์‚ฌํ›„ ๋ถ„์„์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ Redis ์บ์‹ฑ์„ ํ†ตํ•ด ๋ฐ˜๋ณต ์š”์ฒญ ๋น„์šฉ์„ ์ค„์˜€์œผ๋ฉฐ, ์ถ”ํ›„ pgvector ๊ธฐ๋ฐ˜ ์œ ์‚ฌ ๋ฌธ๊ตฌ ํƒ์ง€, AI ๋ณด์กฐ ํŒ๋‹จ, ์‹ ๊ณ  ์‹œ์Šคํ…œ, ์žฅ์•  ์•Œ๋ฆผ์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

About

๐Ÿฅ• ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ ๊ฒŒ์‹œ๊ธ€์„ ์šด์˜์ •์ฑ… ๋ฃฐ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž๋™ ๊ฒ€์ˆ˜ํ•˜๊ณ , ์ŠคํŒธ/์‚ฌ๊ธฐ/์–ด๋ทฐ์ง• ์œ„ํ—˜๋„๋ฅผ ๊ณ„์‚ฐํ•ด ALLOW, REVIEW, BLOCK ์ค‘ ํ•˜๋‚˜๋กœ ํŒ์ •ํ•ฉ๋‹ˆ๋‹ค.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors