관리자 로그인
authentik으로 로그인앱 자체 OpenID Connect 로그인입니다. 승인된 계정만 관리할 수 있습니다.
복구용 관리자 키로 접속
앱·장치 등록
앱·장치 관리
앱 관리
이 앱에 푸시 발송 · 장치 등록 코드 발급 · 이 앱의 발송 이력장치 목록
마지막 접속은 보고 시각이며 실시간 온라인 상태가 아닙니다.
| 장치 | 앱 | 상태 | 마지막 접속 | 버전 | 관리 |
|---|
푸시 알림 발송
푸시 발송 이력
| 알림 / 메시지 ID | 앱 | 장치 | 상태 | 시도 | 실패 사유 | 다음 시도 | 생성 시각 | 기기 저장 확인 | 작업 |
|---|
서버 접수는 기기 수신 완료가 아니며, 기기 저장 확인은 OS 알림 표시 성공이 아닙니다.
발송 프로그램
외부 프로그램에는 관리자 키 대신 전용 발송 키를 발급하세요. 허용된 앱·활성 장치와 자기 발송 작업만 조회할 수 있습니다.
프로그램 목록
| 프로그램 / ID | 앱 권한 | 상태 | 생성 시각 | 관리 |
|---|
폐기는 즉시 새 인증을 거부하고 미발송 queued 전달을 cancelled로 바꿉니다. 이미 서버에 접수된 메시지는 회수하지 않습니다.
외부 프로그램 API
HTTPS 주소: https://push.nalke.net · 인증: Authorization: Bearer 프로그램키. 발송 프로그램에서 권한을 선택해 키를 발급하세요. 관리자 키를 외부 프로그램에 배포하지 마세요.
OpenAPI 3.1 JSON 명세 · Python SDK·CLI wheel 다운로드 (0.1.0)
대상 선택과 발송 구조
target에 appIds, deviceIds, allApps:true 중 정확히 하나를 지정합니다. 배열은 비어 있을 수 없습니다. allApps는 이 키에 허용된 앱 전체이며 제한 키의 권한을 확대하지 않습니다. 앱 선택은 해당 앱의 모든 활성 장치에 발송합니다.
{
"id": "mail-alert-20261013-001",
"title": "새 메일",
"body": "받은 편지함을 확인하세요.",
"target": {"appIds": ["mail"]}
}
선택 대상 예: {"deviceIds":["장치 ID"]} 또는 {"allApps":true}. 알 수 없는 앱·장치, 해제 장치, 권한 밖 대상이 하나라도 있으면 요청 전체가 거부됩니다. 전체 활성 대상이 0개면 404입니다.
선택적 id는 프로그램별 요청 ID (1~128자)입니다. 같은 ID와 같은 정규화된 내용·대상은 최초 대상 snapshot과 작업을 반환합니다. 내용이 달라지면 409입니다. 응답의 jobId는 서버 작업 ID이며 앱별 wire 메시지 ID는 deliveries[].messageId입니다.
작업 상태와 이력
GET /v1/send/apps · GET /v1/send/devices?app=mailPOST /v1/send/jobs · GET /v1/send/jobs/JOB_IDGET /v1/send/jobs?app=mail&state=received&q=메일&page=1&size=50
작업에는 제목·본문·대상·생성 시각·대상 수, 상태별 개수 summary, transportComplete, settled가 있습니다. 발송/단건 조회에는 장치별 deliveries도 포함됩니다. 이력은 {items,total,page,size}이며 자기 작업만 보입니다. 앱 필터의 집계는 작업 전체 기준입니다.
- queued
- 하나 이상 아직 발송 대기.
- accepted
- queued 없이 하나 이상 서버 접수. 기기 수신/OS 표시 성공은 아닙니다.
- received
- 모든 대상의 기기 저장 확인. OS 알림 표시 성공은 아닙니다.
- failed / cancelled
- 모든 대상이 최종 실패 / 취소.
- partial
- queued·accepted 없이 종료 상태가 혼합됨.
transportComplete: queued 0개. settled: queued·accepted 모두 0개. accepted에 기기 ACK가 오지 않으면 received 대기는 시간 초과할 수 있습니다. CLI/SDK는 실패와 시간 초과를 성공으로 표시하지 않으며 발송을 자동 재시도하지 않습니다.
이력의 from은 생성 Unix 초 시작 포함, until은 끝 미포함입니다. q는 제목·본문·작업 ID·요청 ID 부분 검색 (영문 대소문자 무시). 페이지는 1부터, 기본 50개·최대 100개입니다. 오류는 비성공 HTTP와 {"error":"설명"}입니다.
curl
NALKE_PUSH_KEY_FILE에 발급 키를 저장한 비공개 파일 경로를 지정하세요. 실제 앱 ID와 반환된 jobId로 예제를 바꿉니다. 헤더는 stdin으로 전달하며 쉘 tracing을 켜지 마세요.
export NALKE_PUSH_KEY_FILE="$HOME/.config/nalke-push/sender.key"
chmod 600 "$NALKE_PUSH_KEY_FILE"
curl --fail-with-body --silent --show-error --header @- \
https://push.nalke.net/v1/send/apps <<EOF
Authorization: Bearer $(cat "$NALKE_PUSH_KEY_FILE")
EOF
curl --fail-with-body --silent --show-error --header @- \
-H 'Content-Type: application/json' \
--data '{"id":"mail-alert-20261013-001","title":"새 메일","body":"받은 편지함을 확인하세요.","target":{"appIds":["mail"]}}' \
https://push.nalke.net/v1/send/jobs <<EOF
Authorization: Bearer $(cat "$NALKE_PUSH_KEY_FILE")
EOF
curl --fail-with-body --silent --show-error --header @- \
"https://push.nalke.net/v1/send/jobs/$JOB_ID" <<EOF
Authorization: Bearer $(cat "$NALKE_PUSH_KEY_FILE")
EOF
Python SDK·CLI 설치와 CLI
python3 -m pip install https://push.nalke.net/downloads/nalke_push-0.1.0-py3-none-any.whl export NALKE_PUSH_KEY_FILE="$HOME/.config/nalke-push/sender.key" nalke-push apps nalke-push devices --app mail nalke-push send --app mail --title '새 메일' --body '받은 편지함을 확인하세요.' \ --id mail-alert-20261013-001 --wait accepted --wait-timeout 30 nalke-push status "$JOB_ID" nalke-push history --app mail --state received --page 1 --size 50 nalke-push wait "$JOB_ID" --until received --wait-timeout 30
CLI 대상은 반복 가능한 --app, 반복 가능한 --device, --all 중 하나입니다. --server, --key-file은 전역 옵션이며 명령 앞에 둡니다. stdout은 JSON, 실패는 stderr와 nonzero exit입니다. 키 자체를 CLI 인자로 받지 않습니다.
Python
import os
from pathlib import Path
from nalke_push import Client, APIError, DeliveryFailed, WaitTimeout
key = Path(os.environ["NALKE_PUSH_KEY_FILE"]).read_text().strip()
client = Client("https://push.nalke.net", key, timeout=15)
try:
print(client.apps())
print(client.devices(app_id="mail"))
job = client.send("새 메일", "받은 편지함을 확인하세요.",
app_ids=["mail"], idempotency_id="mail-alert-20261013-001")
print(client.status(job["jobId"]))
print(client.wait(job["jobId"], until="received", timeout=30, interval=0.5))
except WaitTimeout as exc:
print(exc.last_status) # 마지막 상태를 확인하고 성공으로 처리하지 않음
raise
except (APIError, DeliveryFailed):
raise
SDK는 HTTPS 인증서 검증을 끄지 않고 인증 요청 redirect를 거부합니다. HTTP는 loopback 시험 주소만 허용합니다. 키는 브라우저·로그·공유 저장소에 넣지 마세요.
최근 전송 이력
전체 발송 이력 · 필터링서버 접수 ≠ 기기 수신. 기기 저장 확인 ≠ OS 알림 표시. 전송 오류는 30초 간격으로 최대 5회 시도합니다. 앱별 최근 200개.
| 알림 | 앱 / 장치 | 상태 | 시도 횟수 | 실패 사유 | 다음 시도 | 생성 | 작업 |
|---|