# Cursor에서 실행하는 CSV Worker

Python 3.10 이상이면 외부 패키지나 가상환경 없이 실행합니다.
이 폴더를 Cursor의 **File → Open Folder**로 여세요.
Worker는 한 개만 실행하세요. 단일 Worker 교육용 파일 대기열입니다.

## 실행

**Terminal → New Terminal**에서 버전을 확인합니다.

~~~powershell
py --version
~~~

py가 없으면 python --version을 확인하고 아래 명령의 py를 모두 python으로 바꿉니다.
둘 다 없다면 Python을 설치한 뒤 Cursor를 다시 엽니다.

터미널 1에서 작업을 두 개 접수합니다.

~~~powershell
py submit.py sample.csv
py submit.py sample.csv
~~~

Terminal → New Terminal로 터미널 2를 추가하고 Worker를 실행합니다.

~~~powershell
py worker.py
~~~

Worker 터미널은 대기 상태로 열어 둡니다.
터미널 1에서 같은 접수 명령을 다시 실행해 보세요.
종료하려면 터미널 2에서 Ctrl+C를 누릅니다.

## 결과

Cursor 파일 탐색기에서 jobs/results/작업ID.json을 엽니다.
sample.csv는 헤더를 제외한 4행이며 누락값은 project 0, owner 2, status 1입니다.

| 폴더 | 의미 |
|---|---|
| jobs/inputs | 접수 당시 CSV 복사본 |
| jobs/pending | 대기 작업 JSON |
| jobs/processing | 처리 중 작업 JSON |
| jobs/completed | 완료 작업 기록 |
| jobs/failed | 실패 작업 기록과 error |
| jobs/results | 완료한 요약 리포트 |

작업 접수 시 원본 CSV를 복사하므로 접수 후 원본을 수정해도 해당 작업 입력은 바뀌지 않습니다.
작업 기록은 상태 폴더 사이로 이동하고, JSON의 status에도 상태가 기록됩니다.
processing 상태는 짧아서 직접 보지 못할 수 있습니다. 터미널 로그의 [processing]으로 확인하세요.

빈 물리적 줄은 제외하고, 쉼표로 구분된 빈 셀은 누락값으로 집계합니다.
공백만 있는 셀도 누락입니다. UTF-8 및 UTF-8 BOM을 지원합니다.
첫 번째 비어 있지 않은 행을 헤더로 사용합니다. 헤더는 비어 있거나 중복될 수 없습니다.
헤더만 있으면 0행 리포트입니다. 잘못된 열 개수·인코딩·CSV 문법은 실패로 기록됩니다.

## 실패도 실습하기

Cursor에서 다음 내용의 invalid.csv를 만들고 접수합니다.

~~~csv
project,owner,status
Survey E,Mina
~~~

~~~powershell
py submit.py invalid.csv
py submit.py sample.csv
~~~

잘못된 작업은 jobs/failed에 오류를 남기고 정상 작업은 이어서 완료됩니다.
없는 경로를 접수하면 접수 단계에서 오류가 나며 대기 작업은 생기지 않습니다.

## 종료와 재시작

파일에 저장한 작업과 결과는 종료 후에도 남습니다.
Worker를 끄고 작업을 접수한 뒤 다시 켜면 남은 pending 작업을 처리합니다.
이미 completed/failed가 된 작업은 자동으로 다시 처리하지 않습니다.

Ctrl+C가 작업 도중 들어오거나 프로세스를 강제로 종료하면 processing에 기록이 남을 수 있습니다.
다음 실행 시 이를 안내하지만 자동 재시도하지 않습니다.
같은 ID의 results 파일과 processing 기록을 먼저 확인하고,
새 결과가 필요하면 해당 inputs/작업ID.csv를 접수하거나 원본을 다시 접수하세요.
새 접수는 새로운 작업 ID를 만듭니다.

## 범위

로컬 파일 접근 권한만 사용합니다. HTTP 서버, API, 인증, DB, 병렬 처리, 자동 재시도는 없습니다.
운영 서비스에서는 파일 대기열 대신 작업 큐와 권한·재시도·중복 처리 정책이 필요합니다.
jobs/는 실행 결과이므로 Git에 커밋하지 않습니다.
