progress PARKLAB
DEVELOPER GUIDE

작업이 있는 곳에서 보고하세요.

HTTP API로 진척을 보내고, 공유 URL에서 바로 확인합니다. 수치형과 작업 목록형을 지원하며, 브라우저는 WebSocket으로 최신 상태를 받습니다.

대화형 API 문서 열기 ↗

01. 빠른 시작

API 기본 주소: https://progress.parklab.work. 페이지 생성에는 인증이 필요하지 않습니다.

curl -X POST https://progress.parklab.work/api/v1/progress \
  -H 'Content-Type: application/json' \
  -d '{"title":"데이터셋 전처리","total":100000,"unit":"records","precision":6}'

응답의 url은 공유 링크이고, write_token은 수정·삭제·보고용 비밀 토큰입니다. 토큰은 생성 시 한 번만 반환됩니다. 공개 메시지나 URL에 넣지 말고 안전하게 보관하세요. 서버에는 해시만 남습니다.

curl -X POST "https://progress.parklab.work/api/v1/progress/$ID/reports" \
  -H "Authorization: Bearer $WRITE_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"completed":68421,"status":"running","message":"레코드 정규화 중"}'

02. 실행 가능한 Python 샘플

샘플에는 생성·재시작·진척 보고·리소스 측정·429 재시도·완료·실패 보고가 포함됩니다. HTTPX와 psutil을 사용하며, uv가 필요한 패키지를 준비합니다. 실제 처리 코드는 예제의 time.sleep(args.delay) 자리에 넣으세요.

report.py 다운로드 ↓

# report.py를 내려받은 후
uv run report.py --mode numeric

# 별도 체크리스트 페이지 (동일 IP 생성은 60초에 1개)
uv run report.py --mode checklist --state .checklist-state.json

# 같은 state 파일로 실행하면 기존 페이지를 이어서 사용합니다.
# state 파일에는 쓰기 토큰이 있습니다. 버전 관리에 넣지 마세요.
Python 샘플 전체 코드 보기
코드를 불러오는 중입니다.

03. 더 작은 단위, 더 정밀한 진척

보고 주체는 작업을 충분히 세분화하세요. “준비 / 실행 / 완료” 세 단계만 보내기보다 레코드·파일·바이트·테스트 케이스처럼 실제로 측정할 수 있는 작은 단위를 사용합니다. 100,000개 레코드라면 total=100000과 실제 완료 건수를 보냅니다.

입력 작업량은 소수점 6자리까지, 퍼센트 표시 자릿수 precision은 0–6을 지원합니다. 퍼센트는 서버가 Decimal로 계산하고 문자열로 반환합니다. 아직 끝나지 않은 작업이 반올림으로 100%가 되지 않도록 내림 표시합니다. 작은 작업 단위와 잦은 HTTP 요청은 별개입니다. 내부 카운터는 자주 갱신하되 보고는 보통 1초에 한 번으로 묶으세요.

증분 +1 대신 누적 완료량을 전송합니다. 재시도해도 수치가 중복 증가하지 않습니다. 단, 보고 이력에는 재시도 요청도 남을 수 있습니다. 총량이 미정이면 total:null로 생성하고, 파악한 뒤 총량을 수정하세요. 이때는 임의의 퍼센트를 표시하지 않습니다.

04. 긴 프로젝트는 작업 목록으로

POST /api/v1/progress
{
  "title": "프로젝트 구현", "mode": "checklist", "precision": 6,
  "items": [
    {"title": "설계", "weight": 1},
    {"title": "API 구현", "total": 100, "weight": 5},
    {"title": "검증 및 배포", "total": 20, "weight": 2}
  ]
}

각 항목은 UUID를 가지며 title, status, completed, total, weight, message를 가집니다. 가중치는 항목 간 상대 작업량입니다. 전체 진척은 Σ(weight × completed / total) / Σ(weight) × 100입니다. 기본 가중치·총량은 1이므로 단순 체크리스트로도 사용할 수 있습니다.

PATCH /api/v1/progress/{id}/items/{item_id}
Authorization: Bearer YOUR_WRITE_TOKEN
{"completed": 42, "status": "running", "message": "라우트 42개 구현"}

# 항목 완료 시 completed가 total에 맞춰집니다.
{"status": "completed"}

모든 항목이 완료되면 전체 상태도 완료됩니다. 페이지당 최대 1,000개 항목을 지원합니다. 더 큰 작업은 별도 페이지로 나눌 수 있습니다.

05. 실행 중 분모와 범위를 바꾸기

새 작업이 발견되면 분모를 늘려도 됩니다. 진척률이 내려가는 것은 실제 작업 범위 변경을 반영한 것입니다. 과거 보고에는 당시 분모와 퍼센트가 그대로 보존됩니다.

# 숫자형 총량 변경. completed보다 작은 total은 422.
PATCH /api/v1/progress/{id}
{"total": 150000, "message": "추가 데이터 발견"}

# 항목 추가 / 일부 수정 / 삭제
POST   /api/v1/progress/{id}/items
PATCH  /api/v1/progress/{id}/items/{item_id}
DELETE /api/v1/progress/{id}/items/{item_id}

# 전체 목록 교체: GET으로 최신 version 및 항목을 확인한 뒤 요청
PUT /api/v1/progress/{id}/items
{"expected_version": 12, "items": [ ...전체 항목 목록... ]}

목록 교체 시 유지할 항목은 기존 id를 포함하세요. expected_version이 최신 버전과 다르면 409가 반환되어 다른 에이전트의 보고를 덮어쓰지 않습니다. 일반 보고와 항목 수정에서도 이 필드를 선택적으로 사용할 수 있습니다. 완료된 페이지에 미완료 작업을 추가하면 진행 중으로 돌아갑니다.

06. CPU · Memory · Disk

보고하는 에이전트 또는 스크립트의 호스트 자원을 보냅니다. 각 값은 선택 항목이며, 사용률 범위는 0–100입니다. 디스크는 측정한 마운트 지점의 사용량입니다.

POST /api/v1/progress/{id}/reports
{
  "metrics": {
    "cpu_percent": 42.8, "memory_percent": 61.2, "disk_percent": 28.4,
    "memory_used_bytes": 5257039872, "memory_total_bytes": 8589934592,
    "disk_used_bytes": 30500000000, "disk_total_bytes": 107374182400,
    "measured_at": "2026-10-06T00:00:00+09:00"
  }
}

metrics를 생략하면 마지막 측정치를 유지하고, 객체를 보내면 전체 측정치를 교체합니다. null을 보내면 지웁니다. 측정 시각은 timezone을 포함해야 하며, 생략 시 서버 수신 시각을 사용합니다. 값이 없는 지표는 0% 대신 ‘미보고’로 표시됩니다.

07. 이력 및 CSV 다운로드

공유 페이지의 ‘보고 이력’ 탭은 최근 30개 보고를 WebSocket으로 받습니다. ‘전체 이력 CSV’ 버튼은 모든 보고를 내려받습니다.

GET /api/v1/progress/{id}/history.csv
GET /api/v1/progress/{id}/events?after=0&limit=100

# Python으로 CSV 파일 저장 (조회 토큰 불필요)
with httpx.stream("GET", f"{base}/api/v1/progress/{id}/history.csv") as response:
    response.raise_for_status()
    with open("history.csv", "wb") as file:
        for chunk in response.iter_bytes():
            file.write(chunk)

CSV는 UTF-8 BOM을 포함합니다. sequence, kind, reported_at, version, title, mode, status, completed, total, unit, percent, message, items_done, item_count, 리소스 지표, measured_at, item_changes_json을 저장합니다. 목록형의 completed/total은 가중 작업량입니다. 빈 지표는 미보고를 뜻하며, 수식으로 해석될 수 있는 텍스트 앞에는 작은따옴표를 붙입니다. 이력 JSON은 next_cursor를 다음 요청의 after로 사용해 페이지를 넘깁니다. 이력 JSON과 WebSocket에서는 큰 목록 교체 내용을 항목 수로 요약하며, 전체 항목 변경 데이터는 CSV에 보존됩니다. CSV는 IP당 분당 10회까지 허용합니다.

08. WebSocket · 폴링 없음

const socket = new WebSocket(
  `wss://progress.parklab.work/api/v1/progress/${id}/ws`
);
socket.onmessage = ({data}) => {
  const event = JSON.parse(data);
  if (event.type === "ping") socket.send("pong");
  if (event.type === "snapshot") render(event.progress, event.events);
  if (event.type === "deleted") socket.close();
};

연결 즉시 최신 progress와 최근 events가 포함된 snapshot을 받고, 변경 때마다 새 snapshot을 받습니다. 느린 수신자는 중간 화면 업데이트를 건너뛸 수 있으나 모든 수락된 보고는 DB와 CSV에 남습니다. 서버가 약 20초마다 ping을 보내면 텍스트 pong으로 답합니다. 끊겼을 때 지수 백오프와 jitter로 재연결하면 최신 상태로 복구됩니다. 서버는 삭제 시 deleted, 종료 시 shutdown을 보낼 수 있습니다.

09. 인증과 요청 제한

OpenAPI JSON · 전체 엔드포인트와 스키마