# ntfy 푸시 알림 서버 — 운영 매뉴얼

## 개요

ntfy는 Web Push(VAPID)의 iOS 제한, 전송 보장 부재 등을 보완하는 푸시 알림 채널이다.
모바일 ntfy 앱으로 알림을 수신하고, 탭하면 딥링크로 해당 페이지로 이동한다.

- **Docker 서비스명**: `ntfy`
- **내부 URL**: `http://ntfy:80` (Docker 네트워크)
- **외부 URL**: `https://ntfy.technicalkorea.net` (Cloudflare Tunnel)
- **호스트 포트**: `30750`
- **설정 파일**: `ntfy/etc/server.yml`
- **데이터**: `ntfy_cache` Docker 볼륨 (`/var/cache/ntfy`)

## 초기 설정 (최초 1회)

### 1. Cloudflare Tunnel 설정

Zero Trust 대시보드 → Tunnels → Public Hostname 추가:

| Subdomain | Domain | Service |
|-----------|--------|---------|
| ntfy | technicalkorea.net | http://ntfy:80 |

### 2. 컨테이너 기동

```bash
docker compose up -d ntfy
```

### 3. 관리자 계정 + 토큰 발급

```bash
# 관리자 계정 생성 (비밀번호 입력 프롬프트)
docker exec -it tk-ntfy ntfy user add --role=admin admin

# API 토큰 발급
docker exec -it tk-ntfy ntfy token add admin
# 출력 예: tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2
```

### 4. .env에 토큰 설정

```env
NTFY_PUBLISH_TOKEN=<위에서 발급받은 토큰>
```

## 메시지 발행 (서버 → 사용자)

### curl로 테스트

```bash
# 기본 메시지
curl -H "Authorization: Bearer $NTFY_PUBLISH_TOKEN" \
     -d "테스트 메시지입니다." \
     http://localhost:30750/tkfactory-test

# 제목 + 딥링크 포함
curl -H "Authorization: Bearer $NTFY_PUBLISH_TOKEN" \
     -H "Title: 설비수리 요청" \
     -H "Tags: wrench" \
     -H "Click: https://tkfb.technicalkorea.net/pages/admin/repair-management.html" \
     -d "A동 CNC 설비 수리 요청이 접수되었습니다." \
     http://localhost:30750/tkfactory-user-1

# 우선순위 높은 알림 (5=max, 3=default, 1=min)
curl -H "Authorization: Bearer $NTFY_PUBLISH_TOKEN" \
     -H "Title: 긴급 안전 알림" \
     -H "Priority: 5" \
     -H "Tags: warning" \
     -d "즉시 확인이 필요합니다." \
     http://localhost:30750/tkfactory-user-1
```

### 토픽 네이밍 규칙

| 토픽 | 용도 |
|------|------|
| `tkfactory-user-{userId}` | 사용자별 개인 알림 (Phase 2에서 사용) |
| `tkfactory-test` | 테스트용 |

### 주요 헤더

| 헤더 | 설명 | 예시 |
|------|------|------|
| `Title` | 알림 제목 | `설비수리 요청` |
| `Click` | 탭 시 열릴 URL (딥링크) | `https://tkfb.technicalkorea.net/pages/work/tbm.html` |
| `Tags` | 이모지 태그 ([목록](https://docs.ntfy.sh/emojis/)) | `wrench`, `warning`, `white_check_mark` |
| `Priority` | 1(min) ~ 5(max) | `5` |
| `Authorization` | 인증 토큰 | `Bearer tk_...` |

## 사용자 관리

```bash
# 사용자 목록
docker exec tk-ntfy ntfy user list

# 일반 사용자 추가
docker exec -it tk-ntfy ntfy user add username

# 사용자 삭제
docker exec tk-ntfy ntfy user del username

# 특정 토픽 접근 권한 부여 (read-write / read-only / write-only)
docker exec tk-ntfy ntfy access username 'tkfactory-user-*' read-only

# 토큰 발급
docker exec tk-ntfy ntfy token add username

# 토큰 목록
docker exec tk-ntfy ntfy token list

# 토큰 삭제
docker exec tk-ntfy ntfy token remove username tk_...
```

## 모바일 앱 설정 (수신자용)

### Android
1. Play Store에서 **ntfy** 설치
2. 설정(⚙️) → **Default server** → `https://ntfy.technicalkorea.net` 입력
3. 우측 상단 사용자 아이콘 → 로그인 (발급받은 계정/비밀번호 또는 토큰)
4. **+** → 토픽 `tkfactory-user-{본인userId}` 구독

### iOS
1. App Store에서 **ntfy** 설치
2. Settings → **Default server** → `https://ntfy.technicalkorea.net` 입력
3. 로그인 후 토픽 구독 (Android와 동일)

## 서버 설정 (server.yml)

| 항목 | 현재 값 | 설명 |
|------|---------|------|
| `auth-default-access` | `deny-all` | 인증 없이 접근 불가 |
| `cache-duration` | `72h` | 메시지 보관 기간 (주말 포함 3일) |
| `visitor-request-limit-burst` | `60` | 버스트 요청 한도 |
| `visitor-request-limit-replenish` | `5s` | 요청 한도 보충 주기 |

설정 변경 후 컨테이너 재시작:
```bash
docker compose restart ntfy
```

## 트러블슈팅

### 401 Unauthorized
- 토큰이 맞는지 확인: `docker exec tk-ntfy ntfy token list`
- `auth-default-access: deny-all` 상태에서 토큰 없이 요청하면 발생

### 모바일 앱에서 알림이 안 옴
- Cloudflare Tunnel Public Hostname에 `ntfy.technicalkorea.net` 등록되었는지 확인
- 앱의 Default server URL이 `https://ntfy.technicalkorea.net`인지 확인
- 앱에서 로그인했는지, 토픽을 구독했는지 확인
- 폰 설정에서 ntfy 앱 알림 권한이 켜져 있는지 확인

### 컨테이너 로그 확인
```bash
docker logs tk-ntfy --tail 50
docker logs tk-ntfy -f  # 실시간
```

## Phase 2 예정 사항 (참고)

- `system1-factory/api/models/notificationModel.js`의 `sendPushToUsers()`에서 ntfy 발송 연동
- `push_subscriptions` 테이블에 `channel` 컬럼 추가 (`web_push` | `ntfy`)
- ntfy 구독 사용자에게는 Web Push 미발송 (중복 방지)
- notification-bell.js에서 ntfy 구독 토글 UI 추가
