# StreamZet xSpan SDK 0.2.1

Documentation revision: 2026-09-21

https://streamzet.com/docs

## StreamZet 개발자 문서

장비를 연결하고, 제품에 원격 지원을 통합하세요. xSpan SDK 0.2.1의 설치부터 제품 연동까지 안내합니다.

### 목적에 맞는 시작점

- [먼저 장비에서 테스트하기](https://streamzet.com/docs/xspan/quickstart)
- [C/C++ 제품에 SDK 연동하기](https://streamzet.com/docs/xspan/integration)
- [전달 패키지와 체크섬 확인](https://streamzet.com/docs/xspan/packages)

설치 테스트에는 미리 빌드된 실행 엔진을 사용합니다. 제품 연동에는 C 어댑터와 같은 엔진을 함께 배포합니다. 두 방식 모두 기기별 영구 상태를 사용하며, 같은 상태를 동시에 실행하면 안 됩니다.

### xSpan에서 제공하는 기능

| 기능 | 현재 범위 |
| --- | --- |
| Auto enrollment | 최초 실행 후 계정의 Devices에 자동 등록. 네트워크 연결이 필요합니다. |
| 원격 터미널 | 브라우저에서 대화형 sh 터미널. 장비에 설치된 에이전트의 OS 권한으로 실행합니다. |
| 일괄명령 | 여러 온라인 장비 선택 또는 전체 선택, 장비별 상태·stdout·stderr·종료 코드. |
| RFID 대시보드 | 장비별 인증서 등록 후 원본 OEM 대시보드에 접근. 기존 OEM 로그인이 필요합니다. |

### 지원 및 검증 범위

| 항목 | 검증 환경 |
| --- | --- |
| Reader | Impinj xSpan R660 |
| CPU / ABI | ARMv5TE · soft-float · static musl engine |
| Linux / OEM libc | 2.6.39.4 / glibc 2.19 |
| Octane firmware | 6.2.2.240 |
| OEM application | RFID Overhead 360° 2.22.11.30 |
| SDK / documentation | 0.2.1 / 2026-09-21 |

> 실제 R660 1대에서 등록·터미널·일괄명령·SDK 시작/종료·웹 대시보드를 검증했습니다. 다른 모델/펌웨어, 완전 재부팅, 실제 다수 장비 부하는 별도 인수 테스트가 필요합니다.

### 다른 플랫폼

이 문서의 설치 명령과 바이너리는 xSpan 전용입니다. Android AAR/테스트 APK와 현대 Linux용 SDK 프리뷰는 별도 산출물입니다. Android 화면 공유는 사용자 동의가 필요하고, 실제 HHT 인수 테스트·정식 서명 배포와 Linux 대상 ABI 검증은 별도입니다.

> 기존 glibc 앱은 POSIX 프로세스 어댑터를 사용하세요. musl 정적 라이브러리를 기존 glibc 앱에 그대로 링크하는 방식은 검증되지 않았습니다.

## 빠른 시작: 장비 테스트

전용 컴퓨터에서 기기별 설치 디렉터리를 준비하고, 한 대의 xSpan에 설치해 연결을 확인합니다.

### 1. 준비 사항

- 지원 환경의 xSpan R660, 승인된 SSH 또는 OEM 공장 프로비저닝 접근.
- 테스트 설치 ZIP, 별도로 받은 등록 키 파일과 StreamZet 운영 계정.
- 준비 컴퓨터의 Python 3, 장비의 정확한 시간·DNS·외부 TCP 443 연결. 장비에는 Python이 필요하지 않습니다.

> 아래 경로와 READER_HOST는 예시입니다. reader-001 디렉터리는 오직 한 장비에만 사용하세요. 기존 설치를 업데이트할 때 이 초기 설치 절차로 상태를 덮어쓰지 마세요.

### 2. 압축 해제와 무결성 확인

```sh
shasum -a 256 -c streamzet-xspan-evaluation-0.2.1-20260921.zip.sha256
unzip streamzet-xspan-evaluation-0.2.1-20260921.zip -d xspan-evaluation
cd xspan-evaluation
shasum -a 256 -c SHA256SUMS
```

Linux에서는 shasum 대신 sha256sum -c를 사용할 수 있습니다. 체크섬 파일도 ZIP과 함께 전달받으세요.

### 3. 기기별 설치 디렉터리 생성

```sh
umask 077
mkdir -p ./provisioning
python3 device/prepare-device.py \
  --registration-key /secure/JCI-production-key.txt \
  --output ./provisioning/reader-001 \
  --name 'xSpan R660 001'
```

새 디렉터리에 실행 엔진, CA 파일, 시작/종료 스크립트, 등록 키와 고유한 64바이트 엔트로피 시드가 생성됩니다. 기존 출력 디렉터리를 재사용하면 도구가 거부합니다. 최초 실행 후 state/identity에 기기 UUID와 비밀정보가 저장됩니다.

### 4. 장비로 전송하고 시작

SSH 호스트 키를 검증한 연결 또는 승인된 공장 프로비저닝 경로를 사용하세요. 다음 예시는 아직 /mnt/spp/streamzet-jci가 없는 테스트 장비를 가정합니다. 설치 위치는 OEM의 영구 저장소 정책에 맞게 조정하세요.

```sh
# On the provisioning computer
scp -pr ./provisioning/reader-001 root@READER_HOST:/mnt/spp/streamzet-jci

# In the reader's authorized shell
cd /mnt/spp/streamzet-jci
chmod 700 . state streamzet-embedded start.sh stop.sh
chmod 600 registration.key cacert.pem device-name state/entropy.seed
./start.sh
```

> 비밀번호나 등록 키를 명령줄 인자로 직접 넣지 마세요. 기존 장비의 state 디렉터리를 다른 장비에 복사하지 마세요.

### 5. 연결 확인

1. StreamZet에 로그인하고 Devices에서 지정한 이름의 장비가 온라인으로 나타나는지 확인합니다.
2. 터미널을 열어 아래 읽기 전용 명령을 실행합니다. 출력이 실제 장비와 일치해야 합니다.
3. Fleet → Linux → sh · xSpan / embedded에서 이번 테스트 장비 한 대만 선택하고 같은 명령을 실행합니다. 장비별 결과와 종료 코드를 확인합니다.

```sh
printf 'STREAMZET_TEST_OK\n'
uname -m
uptime
```

일괄명령 큐는 약 30초 간격으로 확인합니다. 최초 등록은 비동기이므로 설치 명령의 성공만으로 온라인 상태가 보장되지는 않습니다.

- [자동 시작과 운영 절차](https://streamzet.com/docs/xspan/operations)
- [장비가 나타나지 않을 때](https://streamzet.com/docs/xspan/troubleshooting)

## C/C++ 제품 연동

제품의 생명주기에 원격 지원을 연결합니다. 기존 glibc 앱에는 POSIX 프로세스 어댑터를 권장합니다.

### 통합 구조

```text
OEM application (your ETK / libc)
  └─ streamzet_product.c  [start / poll / stop]
       └─ streamzet-embedded  [static ARMv5 engine]
            └─ outbound TLS :443 → StreamZet
                 └─ enrollment · terminal · Fleet · dashboard
```

작은 C 어댑터를 OEM 앱에 컴파일하고, 검증된 정적 실행 엔진을 함께 배포합니다. TLS와 C 런타임은 별도 프로세스에 있으므로 OEM 앱의 glibc와 공유하지 않습니다. 통신·등록·재연결은 엔진이 처리하고, 호스트 앱은 자식 프로세스의 시작·감시·종료를 담당합니다.

### 필요한 파일

| 파일 | 역할 |
| --- | --- |
| sdk/product/streamzet_product.h | C/C++ 공개 인터페이스 |
| sdk/product/streamzet_product.c | OEM ETK로 컴파일하는 POSIX 어댑터 |
| sdk/product/example.c | 시작·감시·종료·회수 예제 |
| device/streamzet-embedded | 검증된 ARMv5 정적 실행 엔진 |
| device/cacert.pem | 서버 인증용 CA 번들 |
| registration.key + state/ | 기기별 준비 과정에서 생성·유지 |

### 제품의 툴체인으로 컴파일

```sh
# Set CC to the matching OEM ETK C compiler.
"$CC" -std=c99 -D_POSIX_C_SOURCE=200809L \
  -Isdk/product sdk/product/example.c sdk/product/streamzet_product.c \
  -o streamzet-product-example
```

C++ 제품은 streamzet_product.c를 C로 컴파일한 객체를 링크하고 헤더를 포함하면 됩니다. 배포할 예제 실행 파일을 준비된 장비에 복사한 다음 아래처럼 실행합니다. 기존 start.sh 엔진을 먼저 종료하고, 완전히 종료된 뒤 같은 상태로 시작하세요.

```sh
./streamzet-product-example \
  /mnt/spp/streamzet-jci/streamzet-embedded \
  /mnt/spp/streamzet-jci/registration.key \
  /mnt/spp/streamzet-jci/cacert.pem \
  /mnt/spp/streamzet-jci/state \
  'xSpan R660 001'
```

### 호스트 생명주기 예제

```c
#include "streamzet_product.h"

static stz_product support = {0};

int start_remote_support(void) {
    const stz_product_config config = {
        .engine_path = "/mnt/spp/streamzet-jci/streamzet-embedded",
        .registration_file = "/mnt/spp/streamzet-jci/registration.key",
        .ca_file = "/mnt/spp/streamzet-jci/cacert.pem",
        .state_directory = "/mnt/spp/streamzet-jci/state",
        .device_name = "xSpan R660 001"
    };
    return stz_product_start(&support, &config);
}

/* Call periodically from the same host thread. */
int poll_remote_support(int *wait_status) {
    return stz_product_poll(&support, wait_status);
}

/* Request stop, then keep polling until the child is reaped. */
int stop_remote_support(void) {
    return stz_product_stop(&support);
}
```

- start가 0을 반환하면 프로세스 생성에 성공한 것입니다. 온라인 확인은 StreamZet 장비 상태로 합니다.
- 동일 핸들에 대한 호출을 직렬화하고 다른 SIGCHLD 핸들러가 이 자식을 회수하지 않게 하세요.
- 호스트의 불필요한 파일 디스크립터에 close-on-exec을 설정하세요. 어댑터의 자식은 stdout/stderr를 상속합니다.
- 네트워크 재접속은 자동입니다. 프로세스 자체가 종료되면 poll로 확인하고 OEM의 재시작 정책을 적용하세요.
- SDK 모드에서는 start.sh를 동시에 실행하지 마세요. 종료 요청 후 poll로 회수하기 전 핸들을 재사용하지 마세요.

- [필드·반환값·오류 코드](https://streamzet.com/docs/xspan/api)

### 저수준 정적 라이브러리

SDK의 sdk/musl에는 libstreamzet-embedded.a와 TLS 라이브러리·헤더가 있습니다. 새 musl ARMv5 앱에서는 stz_create → 작업 스레드에서 stz_run → stz_stop → 스레드 join → stz_destroy 순서를 사용합니다. 엔트로피·기기 식별자 영속화와 단일 TLS 런타임 계약도 따라야 합니다.

> 이 경로는 기존 glibc 앱에 대한 드롭인 SDK가 아닙니다. 직접 인프로세스 연동은 해당 ETK·ABI·스레딩·TLS 검증 후 채택하세요. 파트너 첫 연동에는 위의 프로세스 어댑터를 사용하세요.

## C API 레퍼런스

streamzet_product.h의 공개 계약입니다. 이 API는 실행 엔진의 생명주기를 제어합니다.

### stz_product_config

| 필드 | 형식과 요구 사항 |
| --- | --- |
| engine_path | const char* · 실행 엔진의 절대 경로 |
| registration_file | const char* · 등록 키 파일의 절대 경로. 소유 사용자만 읽기/쓰기(0600). |
| ca_file | const char* · CA PEM 파일의 절대 경로 |
| state_directory | const char* · 기기별 영구 디렉터리(0700)의 절대 경로 |
| device_name | const char* · 비어 있지 않은 UTF-8 이름, 최대 128바이트 |

경로는 1,024바이트 미만이어야 합니다. 포인터는 start 호출이 끝날 때까지 유효해야 합니다. 준비 도구는 장비 이름의 제어문자를 거부합니다. stz_product 핸들은 {0}으로 초기화하고 복사하여 공유하지 마세요.

### stz_product_start

```c
int stz_product_start(stz_product *product,
                      const stz_product_config *config);
```

| 반환값 | 의미 |
| --- | --- |
| 0 | 자식 생성 성공. 등록과 네트워크 연결은 이후 비동기 실행. |
| EINVAL | 잘못된 인자·상대 경로·경로 길이·장비 이름 |
| EALREADY | 해당 핸들에 실행 중인 자식이 있음 |
| ECHILD | 기존 자식 상태를 확인/회수할 수 없음 |
| ENOENT / EACCES / other errno | posix_spawn 또는 설정 단계 오류. 반환값을 errno 코드로 해석. |

파일 내용과 네트워크 설정 오류는 생성 이후 엔진 종료로 나타날 수 있습니다. start의 성공 뒤에도 poll을 지속해야 합니다.

### stz_product_poll

```c
int stz_product_poll(stz_product *product, int *wait_status);
```

| 반환값 | 의미 |
| --- | --- |
| 1 | 자식이 계속 실행 중. 블로킹하지 않음. |
| 0 | 이미 정지했거나 종료를 회수함. 핸들의 PID를 0으로 초기화. |
| -1 | NULL 핸들 또는 waitpid 오류 |

wait_status는 NULL이어도 됩니다. 이번 호출이 자식을 회수했다면 sys/wait.h의 WIFEXITED/WEXITSTATUS 또는 WIFSIGNALED/WTERMSIG로 상태를 해석하세요. 이미 정지한 핸들에서는 새 종료 상태가 기록되지 않습니다.

### stz_product_stop

```c
int stz_product_stop(stz_product *product);
```

실행 중이면 SIGTERM을 요청합니다. 성공 또는 이미 정지한 경우 0, 잘못된 핸들은 EINVAL, 자식 상태 오류는 ECHILD, 신호 전달 오류는 errno 값을 반환합니다. 종료 완료를 기다리는 함수가 아니므로 poll로 자식을 회수하세요.

### 스레드 및 상태 소유권

같은 핸들의 모든 호출은 한 스레드 또는 외부 잠금으로 직렬화하세요. 어댑터는 키 값이 아닌 파일 경로를 자식에게 전달하며, 별도의 셸을 통해 인자를 평가하지 않습니다. 동일 state 디렉터리는 엔진의 파일 잠금으로 동시 사용을 거부합니다.

## 운영과 일괄명령

자동 시작, 원격 접속, 장비별 대시보드 연결과 상태를 보존하는 업데이트 절차입니다.

### 부팅 시 자동 시작

단독 설치에서는 검증된 R660의 /cust/start에 StreamZet start.sh 호출을 추가합니다. 기존 OEM 줄을 보존하고 원본을 백업하세요. SDK 연동 제품에서는 제품 앱이 stz_product_start를 호출하므로 별도 start.sh 부팅 훅이 필요하지 않습니다.

```sh
# Standalone mode: add once to the OEM-approved startup hook
/mnt/spp/streamzet-jci/start.sh
```

> 동작 중인 장비에서 /cust/start 전체를 다시 실행하지 마세요. 기존 RFID 앱도 중복 실행할 수 있습니다. OEM CAP/펌웨어 업데이트가 훅을 교체할 수 있으므로 정식 제품 패키지에 포함하고 재부팅 인수 테스트를 수행하세요.

### 여러 장비에 일괄명령 전송

1. Fleet에서 Linux와 sh · xSpan / embedded를 선택합니다.
2. 대상 장비를 선택하거나 전체 선택을 사용합니다. 현재 계정에서 제어 가능한 온라인 장비가 대상입니다.
3. 명령을 실행하고 장비별 대기·실행·완료·실패·만료 상태와 출력을 확인합니다.

```sh
printf 'FLEET_CHECK_OK\n'
uname -m
uptime
```

> 일괄 전송은 여러 장비에서 정확히 같은 시각에 실행됨을 보장하지 않습니다. 큐 확인 주기와 네트워크에 따라 시작 시점이 달라집니다. 연결이 끊긴 명령은 자동 재실행하지 않으므로 결과를 확인한 뒤 재시도하세요.

### RFID 대시보드 열기

장비 목록 또는 터미널의 xSpan 대시보드 열기 버튼을 누르면 원본 OEM 화면이 새 탭에 열립니다. OEM 관리자 계정으로 로그인합니다. StreamZet 터미널과 동시에 사용할 수 있습니다.

> 새 장비는 터미널 자동등록 후 별도의 대시보드 활성화가 필요합니다. 담당자에게 StreamZet 장비 UUID와 신뢰할 수 있는 경로로 확인한 HTTPS 9000 인증서 SHA256 지문을 전달하세요. 서버에 핀과 기능이 등록된 후 버튼이 표시됩니다. 인증서를 교체하면 핀도 갱신해야 합니다.

웹 연결은 30분 후 만료되며 닫기 버튼으로 즉시 종료할 수 있습니다. 장시간 비활성 탭은 다시 열어야 할 수 있습니다. 공유된 URL만으로는 다른 브라우저에서 접속할 수 없습니다.

### 실행 한도

| 항목 | 한도 |
| --- | --- |
| 터미널 | 장비당 1개, 세션당 최대 30분 |
| 명령 동시 실행 | 장비당 최대 2개 |
| 명령 길이 | 4,096 UTF-8 bytes |
| 명령 제한 시간 | 100–120,000ms, 현재 Fleet UI는 30,000ms |
| 출력 | stdout+stderr 합계 65,536바이트, 초과 시 잘림 표시 |
| 큐 확인 | 약 30초 간격 |

### 업데이트와 제거

1. 새 파일의 체크섬을 확인하고 현재 엔진과 시작 설정을 백업합니다.
2. StreamZet만 정상 종료하고 실제 종료를 확인합니다. 원격 터미널만으로 엔진 교체를 시도하면 연결이 끊기므로 OEM 배포 경로를 사용합니다.
3. 엔진과 필요한 CA/스크립트만 교체합니다. state/, registration.key, 장비 이름과 소유권을 보존합니다.
4. 재시작하고 같은 장비 UUID로 온라인 복귀하는지 확인합니다. 실패하면 백업한 실행 파일로 복원합니다.

제거하려면 StreamZet을 종료한 뒤 해당 시작 훅만 제거하세요. 다시 설치할 계획이면 기기 식별 상태를 유지합니다. 장비 폐기 시에는 관리 담당자가 서버의 해당 기기 자격정보를 폐기하고 로컬 비밀정보를 안전하게 삭제해야 합니다.

## 네트워크와 인증

설치 네트워크 요건, 자격정보의 역할과 운영 권한을 확인합니다.

### 네트워크 요건

| 구간 | 요건 |
| --- | --- |
| 장비 → 중계 | streamzet-embedded.plitsoft.workers.dev · TCP 443 · HTTPS/WSS |
| 운영 브라우저 | streamzet.com · streamzet-embedded.plitsoft.workers.dev · *.supabase.co · HTTPS/WSS |
| OEM 웹 대시보드 | streamzet-xspan-dashboard.plitsoft.workers.dev · HTTPS |
| 장비 내부 | 대시보드는 loopback TLS 9000으로 연결. 장비의 외부 포트 개방 불필요. |

장비가 외부로 TLS 연결을 시작하므로 NAT 내부에서도 동작합니다. DNS와 정확한 시각이 필요하고 WebSocket을 차단하는 프록시는 사용할 수 없습니다. 검증된 CA와 호스트 이름 검사를 유지하세요.

### 자격정보의 역할

| 자격정보 | 사용 범위 |
| --- | --- |
| 등록 키 | 새 장비를 계정에 등록. 운영자 터미널·일괄명령 권한은 부여하지 않음. |
| 기기 비밀정보 | state/identity에 저장. 기기별로 고유하며 장비의 접속에 사용. |
| 운영자 로그인 | 장비 소유권을 확인한 뒤 터미널·명령·대시보드 접속 허용. |
| OEM 로그인 | 원본 RFID 대시보드의 별도 Basic 인증. |

> 등록 키·계정 비밀번호·기기 상태는 공개 문서, 소스 저장소, SDK ZIP, 로그에 넣지 마세요. 준비 디렉터리는 0700, 비밀 파일은 0600으로 유지하고 장비 간 복제하지 마세요.

### 실행 권한과 인증 경계

셸은 설치된 에이전트의 OS 사용자 권한으로 실행합니다. 검증 장비의 OEM 환경은 root입니다. 실제 제품에서 사용할 UID와 파일 접근 범위는 OEM이 결정하고 인수 테스트해야 합니다.

RFID UI는 StreamZet 콘솔과 별도의 웹 출처에서 제공됩니다. 일회용 연결 티켓과 HttpOnly 세션 쿠키를 사용하고 운영자 Bearer 토큰을 장비로 전달하지 않습니다. 장비 HTTPS 인증서는 등록된 SHA256 지문으로 확인합니다.

## 문제 해결과 인수 테스트

증상별 진단 순서와 파트너가 확인할 테스트 항목입니다.

### 증상별 확인 순서

| 증상 | 확인 방법 |
| --- | --- |
| 장비가 나타나지 않음 | 시간·DNS·외부 443·등록 키 권한·계정 한도를 확인. 동일 이름이 아니라 UUID로 구분. |
| Private state directory is unavailable or already in use | state 경로와 소유권/0700 권한 확인. start.sh와 SDK가 동시에 실행 중인지 확인. |
| Private enrollment configuration, entropy or identity failed | 키/시드/식별 상태 파일의 소유권·0600·내용 확인. 다른 기기의 상태로 대체하지 않기. |
| Invalid configuration, CA bundle or entropy source | 배포 CA 파일과 시드·엔진 설정 확인. 인증서 검증을 끄지 않기. |
| start 성공 후 바로 종료 | poll의 자식 종료 상태와 stderr를 확인. start는 spawn 성공만 의미. |
| 명령이 대기 중 | 장비 온라인 여부·소유 계정·약 30초 큐 주기를 확인. |
| 터미널이 이미 사용 중 | 기존 세션에서 정상 종료. 다른 운영자의 세션을 강제로 덮어쓰지 않기. |
| 대시보드 버튼이 없음 | 온라인 상태와 기기별 인증서 핀/대시보드 활성화 여부를 담당자에게 확인. |
| 대시보드 401/만료 | StreamZet의 버튼으로 새 연결 생성. OEM 인증 요청이면 OEM 자격정보 사용. |
| 대시보드 연결 오류 | OEM 9000 서비스와 인증서 교체 여부 확인. 업데이트된 지문은 신뢰 경로로 전달. |

### 포그라운드 진단

start.sh는 출력을 버립니다. 필요하면 실행 중인 StreamZet을 먼저 종료하고 종료를 확인한 뒤, 승인된 장비 셸에서 아래 명령으로 stderr를 확인합니다. Ctrl+C로 종료한 후 원래 운영 시작 방식을 복원하세요.

```sh
cd /mnt/spp/streamzet-jci
./streamzet-embedded --production \
  streamzet-embedded.plitsoft.workers.dev \
  /mnt/spp/streamzet-jci/registration.key \
  /mnt/spp/streamzet-jci/cacert.pem \
  /mnt/spp/streamzet-jci/state 'xSpan R660 001'
```

### 파트너 인수 체크리스트

- 첫 시작 후 자동 등록되고 운영 계정에서 장비가 보이는가.
- 실제 장비의 터미널 출력과 Fleet 성공/실패 결과를 확인했는가.
- 앱/엔진 재시작 후 같은 UUID를 유지하고, 네트워크 단절 후 복구하는가.
- SDK 시작·poll·정상 종료·자식 회수가 OEM 앱에서 동작하는가.
- 승인된 정비 시간에 전체 장비 재부팅과 CAP/펌웨어 업데이트 후 자동 시작을 확인했는가.
- 실제 운영 부하에서 CPU·메모리·RFID 처리와 다수 장비 일괄 실행을 확인했는가.
- 대시보드 핀 등록·로그인·실시간 이벤트·터미널 동시 사용을 확인했는가.

문의 시 SDK 버전, 장비 모델/펌웨어, UUID, 발생 시각과 시간대, 재현 단계, 비밀정보를 제거한 종료 코드/로그를 전달하세요. 키·비밀번호·state/identity는 보내지 마세요.

- [기술 지원 문의](mailto:support@streamzet.com)

## 패키지와 전달 파일

설치 테스트용과 제품 연동용 파일을 선택하고, 전달받은 파일의 무결성을 확인하세요.

### 버전 0.2.1 · 2026-09-21 전달본

| 패키지 | 내용 |
| --- | --- |
| streamzet-xspan-evaluation-0.2.1-20260921.zip | ARMv5 실행 엔진, CA, 기기별 준비 도구, 시작/종료 스크립트, 문서와 라이선스. 컴파일 없이 설치 테스트. |
| streamzet-jci-xspan-sdk-0.2.1-20260921.zip | 평가용 파일 + C/C++ 프로세스 어댑터·예제·musl 라이브러리·소스·고정 의존성과 빌드 지침. |
| *.zip.sha256 / SHA256SUMS | 압축 파일 및 내부 파일의 SHA256. 아래 릴리스 정보와 함께 대조. |

> 바이너리와 SDK는 담당자가 파트너에게 별도로 전달합니다. 이 공개 문서에는 운영 계정·등록 키 또는 기기 비밀정보가 포함되지 않습니다. 전달받을 파일은 아래 체크섬으로 검증할 수 있습니다.

### 별도 전달 항목

- StreamZet 운영 계정: 장비 확인·원격 접속·Fleet 사용.
- 등록 키 파일: 기기별 prepare-device.py 실행 시 사용. SDK 소스에 하드코딩하지 않기.
- OEM 대시보드 계정 및 신규 장비 대시보드 활성화 담당자.

일반 Linux/Android용 JCI-sdk-config.json은 이 xSpan 어댑터가 읽지 않습니다. xSpan 엔진은 등록 키 파일·CA·영구 상태 경로를 사용하고 배포된 중계 주소로 접속합니다.

### 오프라인 문서

- [한국어 연동 가이드 다운로드 (.md)](https://streamzet.com/docs-assets/xspan/integration-ko.md)
- [영어 연동 가이드 다운로드 (.md)](https://streamzet.com/docs-assets/xspan/integration-en.md)

동일한 가이드가 두 전달 ZIP의 docs/ 디렉터리에 포함됩니다. API의 정확한 계약은 SDK에 포함된 streamzet_product.h를 기준으로 합니다.

## 릴리스와 검증 기록

실행 엔진 버전과 문서·패키지 개정일을 구분해 기록합니다.

### 2026-09-21 · 문서/패키지 개정

- 엔진은 검증된 0.2.1 그대로 유지. 테스트 설치용 ZIP과 개발자 SDK ZIP을 분리.
- 한·영 연동 문서, API 계약, 설치·운영·문제 해결·인수 체크리스트 제공.
- 서버/웹에서 xSpan 대시보드 접속과 고정 터미널 커서 제공. 대시보드는 신규 장비별 설정 필요.

엔진 SHA256: d666b63e3040bef74828de0b6850e5f2fd4fd3c2fc06df84fc179f466ee512c0. 실행 파일 크기: 500,920바이트.

### 0.2.1 · 2026-09-17

중계 소켓의 TCP_NODELAY를 활성화했습니다. 같은 시기 중계 배치 변경으로 테스트 경로의 실제 터미널 응답 중앙값이 850ms에서 359ms로 줄었습니다. 이는 특정 네트워크의 측정값이며 일반 SLA가 아닙니다. 기기 식별자와 프로토콜은 유지됩니다.

### 0.2.0 · 최초 운영 연동

계정 기반 자동등록, 장비별 식별정보, 인증된 원격 터미널, sh 일괄명령과 POSIX 제품 어댑터를 제공했습니다.

### 완료된 검증과 남은 검증

| 검증 | 범위 |
| --- | --- |
| 실제 R660 | 등록, 터미널, Fleet 성공/실패/시간초과/출력 제한, SDK 생명주기, 같은 UUID 복귀 |
| 실제 브라우저 | OEM 대시보드 메뉴·새로고침·SSE 이벤트·동시 터미널·비인증 접근 거부 |
| 자동화 | ARM926 에뮬레이션·게이트웨이 race/접근 제어·웹 타입/빌드·1,101개 모의 장비 페이지네이션 |
| 파트너 환경에서 추가 확인 | OEM ETK 빌드, 다른 펌웨어, 완전 재부팅, 운영 RFID 부하, 실제 다수 장비 |
