AWS IoT Domain Framework 상세 설계
구조 원칙: AWS IoT Core 연결·인증서·물리 Topic 입출력은
IotAgent하나가 소유한다. Client Service App은SkixIotCoreManager를 통해 허용된 domain과 channel만 선택해subscribe,publish,request를 사용한다. 실제 정책과 상태는 Binder 뒤의SkixIotCoreService가 소유한다.
이 설계는 기존 MQTT 경로를 교체하는 안이 아니다. 현재 제품 메시지와
sendModuleCommand(Bundle)는 그대로 유지하고, 여러 Client가 AWS IoT Core 기능을 안전하게
공유해야 하는 경우에만 Domain API를 선택적으로 사용한다. 기존
MQTT Task Contract는 Task·Workflow의
응용 메시지 형식을, 이 문서는 Client별 양방향 통신과 그 생명주기를 다룬다.
1. 목표와 책임 경계
제공할 기능
- Client A와 Client B가 같은 domain/channel을 각각 구독하고 독립 callback과 수명을 갖는다.
- Client는 필요한 domain만 선택하고, domain 안에서도 subscribe와 publish 권한을 따로 받는다.
- Framework가 연결 상태, 재구독, publish 전달 단계, timeout과 Client 종료를 추적한다.
- 기존 domain은 코드 변경 없이 계속 동작하고, 신규 domain은 기본적으로 선언 파일과 검증으로 추가한다.
- Shadow, Jobs, Request/Response 같은 AWS IoT Core 기능은 목적별 typed API로 제한 제공한다.
소유권
| 계층 | 소유하는 것 | 소유하지 않는 것 |
|---|---|---|
| Client Service App | 필요한 domain 선택, payload 생성, callback 처리 | 인증서, endpoint, raw Topic, 재연결 |
SkixIotCoreManager |
호출 API, Service bind·재bind, 앱 친화형 callback | 정책, 구독 원장, MQTT 연결 |
SkixIotCoreService |
caller 검증, domain 권한, logical handle, 전달 상태와 격리 | 인증서, 실제 MQTT socket |
IotAgent |
자격 증명, 단일 MQTT 연결, 물리 subscribe/publish, Shadow·Jobs owner | Client별 권한과 callback queue |
| Domain Adapter | 기존 제품 메시지 해석과 domain payload 변환 | 공통 연결·재시도 정책 |
Client가 보는 것은 안정된 domain API이고, Topic·인증서·AWS SDK는 Framework 내부 구현이다.
2. 현재 코드에서 확인된 사실
현재 기준은 a1-packages-mr6 작업 폴더의 quber/mr7 브랜치, commit 7695c9a다.
| 근거 | 현재 확인된 동작 | 리팩터링 필요점 |
|---|---|---|
apps/IotAgent/.../IIotControl.aidl |
registerCallback, sendModuleCommand(Bundle) 중심 |
domain·channel·handle이 공개 계약에 없음 |
apps/IotAgent/.../IIotControlCallback.aidl |
범용 Bundle callback |
Client별 구독과 correlation 분리가 어려움 |
AWSIoTMQTTClient.java |
하나의 AWSIotMqttManager, 자동 재연결·재구독 |
단일 연결 owner로 재사용 가능 |
IotAgent.connectToIoT() |
제품 Topic을 코드에서 직접 구독 | 물리 구독 목록과 domain 선언을 분리해야 함 |
SubscribeHelper.java |
Topic 해석과 제품 dispatch가 결합 | Broker 수신과 Client별 fan-out을 분리해야 함 |
| IotAgent OTA 경로 | AWS IoT Jobs 흐름 보유 | Jobs owner를 새 Framework가 중복 소유하면 안 됨 |
이 표는 현재 구현이다. 이후의 Manager, Service, Registry와 Descriptor는 목표 구조이며 구현 완료 API가 아니다.
3. 목표 설계
그림 1. Domain별 양방향 통신 구조 — Client는 Manager API를 사용하고,
SkixIotCoreService가 Client별 관계와 정책을 관리한다. IotAgent는 기존과 같이 단일 물리 연결을 유지한다. 원본 SVG 열기
- 이 그림이 답하는 질문: 앱의 IoT 구독·발행 요청은 어떤 책임자를 지나 AWS IoT까지 가는가?
- 읽는 순서: 앱의 IoT 창구에서 시작해 도메인 권한·구독 관리, IotAgent, AWS IoT 순서로 읽는다.
- 현재 검증 범위: API와 정책 계약을 설명하는 목표 구조다. 실제 AWS 계정·Broker와 제품 이미지 연결 완료를 뜻하지 않는다.
Android 계층
Client Service App
-> SkixIotCoreManager // SDK/AAR의 앱 호출 창구
-> Binder / AIDL
-> SkixIotCoreService // Framework의 상태·정책 owner
-> DomainCapabilityRegistry // 공개 가능한 domain 목록
-> InternalDescriptorRegistry // Topic·schema·caller 정책
-> ClientSubscriptionRegistry // Client별 logical handle
-> SubscriptionMultiplexer // 공유 physical subscription
-> DeliveryTracker // publish와 request 결과
-> LegacyDomainDispatcher // 기존 제품 처리와 신규 fan-out
-> IotAgentAdapter
-> IotAgent // 인증서와 단일 AWS 연결 owner
-> AWS IoT Core
핵심 구성요소
| 구성요소 | 책임 |
|---|---|
SkixIotCoreManager |
domain 조회, subscribe·publish·request, 연결·전달 상태 관찰 |
SkixIotCoreService |
Binder caller 확인, 정책 적용, 원장·queue·복구 생명주기 소유 |
DomainCapabilityRegistry |
Client가 사용할 수 있는 domain·channel·방향·schema version 제공 |
InternalDescriptorRegistry |
exact Topic template, caller group, quota와 Root Policy 관리 |
ClientSubscriptionRegistry |
UID·package·Binder token별 handle, callback, quota와 상태 관리 |
SubscriptionMultiplexer |
여러 logical 구독을 하나의 physical 구독으로 병합 |
PublishPolicyGateway |
방향·schema·크기·rate·offline 정책 검증 |
DeliveryTracker |
접수·queue·전송·PUBACK·응답·실패를 publishId로 추적 |
LegacyDomainDispatcher |
기존 메시지와 신규 Client 전달을 한 번만 분배 |
IotAgentAdapter |
Framework 내부 계약을 기존 IotAgent 호출·callback으로 변환 |
CleaningIotManager, MobilityIotManager 같은 전용 Manager는 선택적인 편의 API다. 공통
SkixIotCoreManager를 우회하지 않으며 별도 MQTT 연결이나 별도 정책을 만들지 않는다.
4. 공개 계약과 내부 계약을 분리한다
Client에 공개하는 DomainCapability
{
"domainId": "cleaning",
"displayName": "청정",
"apiVersion": 2,
"channels": [
{"name": "command", "direction": "SUBSCRIBE", "schemaId": "cleaning.command", "maxSchemaVersion": 2},
{"name": "state", "direction": "PUBLISH", "schemaId": "cleaning.state", "maxSchemaVersion": 3}
],
"features": ["REQUEST_RESPONSE"]
}
Client는 자신에게 허용된 capability만 조회한다. raw Topic, wildcard, caller group, quota 계산식, 인증 정보는 공개하지 않는다.
Framework 내부 DomainDescriptor
DomainDescriptor는 Topic과 정책을 가진 내부 서명 계약이다.
{
"domainId": "cleaning",
"descriptorVersion": 7,
"subscribeChannels": [{
"channel": "command",
"topicTemplate": "device/{thingName}/cleaning/command",
"schema": "cleaning.command.v2",
"qos": 1,
"allowedCallerGroups": ["SYSTEM_CLEANING", "SYSTEM_DEVICE_AGENT"]
}],
"publishChannels": [{
"channel": "state",
"topicTemplate": "device/{thingName}/cleaning/state",
"schema": "cleaning.state.v3",
"qos": 1,
"maxPayloadBytes": 16384,
"ratePerMinute": 120,
"offlinePolicy": "LATEST_ONLY",
"allowedCallerGroups": ["SYSTEM_CLEANING"]
}],
"requestResponse": [{"requestChannel": "query", "responseChannel": "query-response"}],
"shadowNames": ["cleaning"]
}
Framework가 template을 exact Topic으로 컴파일한다. Client가 #, +, $aws/ 또는 임의 Topic을
전달하는 API는 제공하지 않는다.
최종 허용 판단
Root Policy ∩ signed DomainDescriptor ∩ caller grant ∩ operation request를 적용한다.
쉽게 말하면 시스템 상한, domain 선언, 호출 앱 권한, 이번 요청 조건을 모두 통과해야 한다.
Client 요청만으로 권한 범위가 넓어지지 않는다.
5. Framework API 계약
Java Manager API
public interface SkixIotCoreManager {
List<DomainCapability> listAvailableDomains();
SubscriptionHandle subscribe(
DomainSubscriptionRequest request,
DomainMessageCallback callback,
SubscriptionStatusCallback statusCallback);
void unsubscribe(String subscriptionId);
PublishReceipt publish(
DomainPublishRequest request,
PublishStatusCallback statusCallback);
PublishStatus getPublishStatus(String publishId);
RequestHandle request(
DomainRequest request,
DomainResponseCallback callback);
ConnectionState getConnectionState();
ObserverHandle observeConnectionState(ConnectionStateCallback callback);
}
PublishReceipt는 최초 접수 결과의 snapshot이다. Binder로 반환된 객체가 이후 저절로 바뀌지
않으므로, 최종 상태는 PublishStatusCallback 또는 getPublishStatus()로 확인한다.
Binder 계약
interface ISkixIotCoreService {
List<DomainCapability> listAvailableDomains();
SubscriptionHandle subscribe(
in DomainSubscriptionRequest request,
in IDomainMessageCallback messageCallback,
in ISubscriptionStatusCallback statusCallback);
void unsubscribe(String subscriptionId);
PublishReceipt publish(
in DomainPublishRequest request,
in IPublishStatusCallback statusCallback);
PublishStatus getPublishStatus(String publishId);
RequestHandle request(in DomainRequest request, in IDomainResponseCallback callback);
ConnectionState getConnectionState();
IObserverHandle observeConnectionState(in IConnectionStateCallback callback);
}
Service는 Binder의 실제 UID, package와 signature를 caller identity로 사용한다. payload의 package name이나 role은 권한 근거로 사용하지 않는다.
메시지 봉투
{
"messageId": "msg-01J...",
"domainId": "cleaning",
"channel": "command",
"schemaId": "cleaning.command",
"schemaVersion": 2,
"correlationId": "req-20260901-001",
"receivedAtMs": 1788220800000,
"retained": false,
"duplicate": false,
"payload": {}
}
DomainMessage의 schemaId와 version으로 codec을 선택한다. QoS 1 중복, retained message,
재연결 후 지연 수신을 구분할 수 있도록 messageId, duplicate, retained, 수신 시각을 보존한다.
6. 양방향 데이터 흐름
AWS → Client: subscribe
- Client가
domainId,channel, schema version과 callback을 전달한다. - Service가 caller 권한과 내부 descriptor를 검증한다.
ClientSubscriptionRegistry에 Client별 Logical Subscription을 만든다.- 같은 exact Topic의 physical 구독이 있으면 reference만 증가시킨다.
- 없으면 IotAgent의 기존 연결로 한 번 subscribe한다.
- 수신 메시지는
LegacyDomainDispatcher에서 기존 제품 handler와 허용된 Client callback으로 각각 한 번만 전달한다.
Client A: cleaning.command -> Handle A1
Client B: cleaning.command -> Handle B1
Physical Subscription(cleaning.command, effective QoS 1)
-> existing product handler: 1회
-> Client A queue: 1회
-> Client B queue: 1회
Physical Subscription의 key는 exact Topic이다. 여러 Client가 서로 다른 QoS를 요구하면 descriptor 상한 안에서 가장 높은 effective QoS로 한 번 구독하고, 각 logical handle에는 실제 적용 QoS를 기록한다.
Client → AWS: publish
- Client 요청을
PublishPolicyGateway가 권한·schema·크기·rate·TTL 기준으로 검증한다. - Service가
publishId를 발급하고LOCAL_ACCEPTED또는 즉시 실패를 반환한다. - 연결 상태와 channel 정책에 따라 바로 전송하거나 offline queue에 저장한다.
SENT,PUBACKED,RESPONDED,FAILED,EXPIRED를 callback과 조회 API로 전달한다.
Request/Response
request()는 response channel을 먼저 subscribe하고 correlationId를 등록한 뒤 request channel에
publish한다. 응답·timeout·Client 종료 중 하나가 발생하면 임시 handle과 correlation record를
정리한다. 빠른 응답 유실과 영구 구독 누수를 방지하기 위한 순서다.
7. 신규 Domain 등록과 동적 도메인 추가
그림 2. 신규 Domain 등록 — 기본 경로는 제품 이미지에 포함된 로컬 built-in descriptor다. 원격 서명 catalog는 설치된 기능의 활성화·축소·회수만 수행한다. 원본 SVG 열기
- 이 그림이 답하는 질문: 제품마다 다른 IoT 기능과 허용 채널을 앱이 어떻게 안전하게 찾는가?
- 읽는 순서: 로컬·원격 기능 목록 후보에서 시작해 서명·스키마·정책 검증 후 앱에 공개되는 기능 목록으로 읽는다.
- 현재 검증 범위: catalog와 descriptor 계약 설계 범위다. 원격 catalog가 설치되지 않은 실행 코드를 추가하는 구조는 포함하지 않는다.
가장 단순한 추가 경로
| 추가하려는 것 | 필요한 작업 | Framework Core 변경 |
|---|---|---|
| 기존 JSON/CBOR codec을 쓰는 새 channel | descriptor·schema·caller grant·계약 테스트 추가 | 없음 |
| 새 domain이지만 공통 봉투와 codec 사용 | 로컬 built-in descriptor와 domain adapter 등록 | 없음 |
| typed Manager가 필요한 핵심 domain | descriptor에서 wrapper 생성 또는 얇은 AAR facade 추가 | 없음 |
| 새 payload codec | codec plugin과 호환성 테스트 추가 | Registry 확장만 |
| 새 하드웨어 동작·native executor | domain 구현과 펌웨어/HAL 배포 | 별도 제품 개발 필요 |
로컬 built-in descriptor가 source of truth다. 빌드 시 schema, Topic 충돌, 권한과 version을 검증하고
제품 이미지에 함께 배포한다. 새 domain을 추가하기 위해 SkixIotCoreService의 분기문을 수정하지
않는다.
원격 catalog의 역할
skix-domain-catalog named Device Shadow 또는 서명된 catalog 패키지는 다음만 수행한다.
- 설치된 domain/channel의 enable·disable
- quota와 만료 시간을 Root Policy 이내로 축소
- schema 호환 version 선택
- 긴급 revoke와 last-known-good rollback
원격 catalog는 설치되지 않은 실행 코드를 만들 수 없다. 새 codec, adapter, native 기능을 임의로 다운로드해 실행하지도 않는다. 따라서 단순 domain 추가 경로와 원격 운영 경로를 분리한다.
8. 전체 생명주기
그림 3. 연결·구독·발행 생명주기 — Broker 재연결은 handle을 유지하지만 Framework Service 재시작은 기존 Binder handle을 무효화하므로 Client 재등록이 필요하다. 원본 SVG 열기
- 이 그림이 답하는 질문: MQTT 연결, 앱별 구독 또는 Framework가 끊겼을 때 어느 범위까지 다시 연결하는가?
- 읽는 순서: 연결 준비, 정상 사용, 연결 끊김, 다시 연결을 따라간 뒤 아래 장애 범위 격리 규칙을 읽는다.
- 현재 검증 범위: 앱별 handle과 공통 연결을 분리한 목표 lifecycle이다. 장시간 네트워크 단절과 실 AWS 복구 시험은 남아 있다.
세 생명주기를 분리하면 연결 장애는 전체 통신 복구로, Client 종료는 해당 구독 정리로, 발행 실패는 해당 메시지 재처리로 제한할 수 있어 정상 Client와 메시지에 장애가 번지는 것을 막는다.
Broker 연결 생명주기
DISCONNECTED -> CONNECTING -> CONNECTED -> RESTORING -> READY
^ | |
+---- BACKOFF <-+--------------+
복구 순서는 IotAgent control Topic, 제품 필수 Topic, active Client Physical Subscription이다.
MQTT persistent session의 sessionPresent가 유효하면 불필요한 재구독을 피하고, 세션이 없으면
현재 logical 원장에서 물리 구독을 복원한다.
Client별 Domain Subscription 생명주기
REQUESTED -> AUTHORIZED -> SUBSCRIBING -> ACTIVE
-> SUSPENDED -> RESTORING -> ACTIVE
ACTIVE -> CLOSED
ACTIVE -> REVOKED -> CLOSED
- Broker 단절 시 logical handle은
SUSPENDED로 유지한다. - 명시적 unsubscribe와 Binder death는 해당 Client handle만 닫는다.
- 마지막 logical reference가 사라질 때만 실제 Broker unsubscribe를 수행한다.
- descriptor나 caller grant가 축소되면
REVOKED사유를 전달하고 닫는다.
Publish 추적 생명주기
RECEIVED -> LOCAL_ACCEPTED -> QUEUED_OFFLINE -> SENT -> PUBACKED
| | | |
+----------> FAILED <-----------+------------+
^
EXPIRED
PUBACKED는 Broker 수신 증거이지 cloud 처리나 실제 기기 동작 완료가 아니다. 응용 응답이 필요한
channel만 RESPONDED 상태를 추가로 사용한다.
Client 프로세스 종료
Binder death 시 죽은 Client의 callbacks, handles, requests와 offline quota만 회수한다. 다른 Client의 logical handle과 제품 필수 구독은 유지한다.
IotAgent 종료·재시작
SkixIotCoreService가 살아 있으면 logical handle을 보존한다. IotAgent 재bind 뒤 descriptor와
caller grant를 다시 검증하고 physical subscription을 복원한다. Client에는 SUSPENDED와
ACTIVE 전환을 알린다.
Framework Service 종료·재시작
기존 Binder handle과 callback은 유효하지 않다. Client의 SkixIotCoreManager는 Service 재bind 후
자신이 보관한 subscription intent를 다시 제출하고 새 handle을 받는다. Framework가 durable
subscription을 지원하더라도 이전 Binder 객체를 되살리지 않는다. 앱 재시작도 같은 규칙을 따른다.
부팅·패키지 교체
부팅 후 IotAgent가 CONNECTED를 보고하고 built-in descriptor 검증이 끝나야 READY가 된다.
Client package 교체 또는 signature 변경 시 기존 grant와 handle을 폐기하고 재승인한다.
카탈로그 회수
channel 제거 또는 권한 축소 시 신규 operation을 즉시 차단한다. 영향 handle에는 revoke 이유를 전달하고, 보내지 않은 offline publish는 폐기 사유를 기록한다.
9. 전달·순서·오프라인 정책
| 상태 | 의미 |
|---|---|
LOCAL_ACCEPTED |
로컬 권한·schema 검증 통과 |
QUEUED_OFFLINE |
channel 정책에 따라 암호화 queue 저장 |
SENT |
MQTT client에 전달 |
PUBACKED |
QoS 1 Broker PUBACK 수신 |
RESPONDED |
correlation된 응용 응답 수신 |
FAILED |
정책·schema·queue·transport 실패 |
EXPIRED |
TTL 또는 request timeout 만료 |
- AWS IoT Core의 MQTT QoS는 0과 1만 허용한다.
- QoS 1은 중복 전달 가능성이 있으므로
messageId와 idempotency 정책을 사용한다. - 서로 다른 Topic 사이의 전체 순서를 보장하지 않는다. 순서가 필요한 흐름은 같은 channel의 sequence 또는 상위 Task/Workflow 계약으로 관리한다.
- 상태 channel은
LATEST_ONLY, 이벤트 channel은FIFO, 명령 channel은NO_OFFLINE처럼 descriptor에 정책을 선언한다. - retained message는
retained=true로 표시하고 일반 실시간 event와 구분한다.
10. AWS IoT Core 기능 공개 범위
| 기능 | Client 공개 방식 | 소유권 |
|---|---|---|
| MQTT Pub/Sub | 공통 Domain API | Service 정책, IotAgent 물리 I/O |
| Request/Response | correlation을 포함한 helper API | Service |
| Device Shadow | domain별 typed get/update/observe | IotAgent 단일 owner |
| AWS IoT Jobs | 상태 조회·승인 등 제한된 typed API | IotAgent·UpdateAgent 단일 owner |
| 연결 상태 | getConnectionState, observeConnectionState |
Service가 IotAgent 상태를 정규화 |
| Credential·endpoint·AWS policy | 공개하지 않음 | IotAgent·제품 보안 영역 |
named Device Shadow는 연결 여부와 무관하게 상태를 공유하는 AWS 저장 모델이다. 일반 Pub/Sub로 reserved Topic을 열지 않고, desired/reported 책임과 version 검증이 있는 typed API만 제공한다. AWS IoT Jobs도 firmware update, reboot 같은 원격 작업의 기존 owner를 유지한다.
11. 기존 경로와 동시성 호환
선택적 도입
- 기존 Client는
IIotControl.sendModuleCommand(Bundle)와 기존 MQTT JSON을 그대로 사용한다. - 신규 Domain API를 사용하는 Client만
SkixIotCoreManager에 bind한다. - 한 domain씩 전환할 수 있으며 전체 MQTT Topic과 cloud payload를 동시에 바꾸지 않는다.
- TaskManager용
request.task는 응용 실행 계약이고 Domain API 사용 여부와 독립적이다.
중복 구독 금지
같은 Topic을 기존 connectToIoT()와 신규 Multiplexer가 각각 subscribe하면 callback 중복,
QoS 충돌과 unsubscribe 경쟁이 발생한다. 1단계에서 기존 필수 Topic을 built-in descriptor로
표현하되, LegacyDomainDispatcher가 기존 handler를 그대로 호출하도록 한다. 물리 subscribe는
IotAgent 안에서 한 경로만 소유한다.
기존 메시지 처리
AWS message
-> IotAgent physical callback 1회
-> LegacyDomainDispatcher
-> 기존 제품 handler 1회
-> 허용된 Client logical queues 각각 1회
기존 직접 호출과 관리형 Task가 같은 기기 기능을 동시에 요청하는 문제는 MQTT Framework가 아니라 TaskManager·Policy·Resource 계층이 조정한다. Domain API는 통신 권한과 전달 수명을 관리하며, 기기 동작 충돌 정책을 중복 구현하지 않는다.
12. 오류와 관측
| 오류 | 의미 |
|---|---|
DOMAIN_NOT_FOUND |
active capability에 domain 없음 |
CHANNEL_NOT_FOUND |
요청 방향에 맞는 channel 없음 |
PERMISSION_DENIED |
시스템·domain·caller·operation 조건 중 하나가 거부 |
SCHEMA_MISMATCH |
schema version 또는 payload 형식 위반 |
QUOTA_EXCEEDED |
구독 수·rate·queue 상한 초과 |
BROKER_UNAVAILABLE |
연결 불가이며 offline queue 미허용 |
SUBSCRIPTION_REVOKED |
descriptor 또는 caller 권한 회수 |
CALLBACK_OVERFLOW |
해당 Client callback queue 포화 |
SERVICE_RESTARTED |
이전 Binder handle 무효, Client 재등록 필요 |
RESPONSE_TIMEOUT |
응용 응답 제한 시간 만료 |
관측 항목은 연결 상태, logical/physical subscription 수, multiplex 비율, Client별 queue와 drop, publish 상태별 건수, reconnect·restore 시간, revoke와 재등록 결과다. payload, 인증서와 개인 정보는 로그에 기록하지 않는다.
13. 단계적 전환
| 단계 | 변경 | 완료 기준 |
|---|---|---|
| 1. 물리 입출력 단일화 | 기존 Topic을 로컬 built-in descriptor로 표현하고 기존 handler 연결 | 메시지·QoS·호출 횟수 회귀 동일 |
| 2. Service 경계 | SkixIotCoreService, caller 검증과 연결 상태 API 추가 |
bind·재bind·권한 테스트 |
| 3. 구독 API | 단일 Client에 logical handle 기반 subscribe 제공 | Binder death·Broker 복구 검증 |
| 4. 발행 API | publishId, callback/query와 channel별 offline 정책 추가 | 접수·PUBACK·실패 구분 |
| 5. 다중 Client | 같은 Topic fan-out과 독립 queue 적용 | 한 Client 종료·포화가 타 Client에 무영향 |
| 6. Domain 개발 키트 | descriptor validator, schema test, wrapper 생성 제공 | Core 수정 없이 새 domain 추가 |
| 7. 원격 운영 | 서명 catalog의 enable·축소·revoke·rollback 제공 | 위변조·만료·권한 확대 거부 |
| 8. 기존 경로 축소 | 전환 완료 domain만 legacy adapter로 이동 | 중복 subscribe 0건, 회귀 통과 |
14. 검증 기준
- Client A/B가 같은 channel을 구독하고 각각 한 번만 메시지를 받는다.
- A unsubscribe 또는 Binder death 후 B는 계속 받는다.
- Broker 재연결 뒤 logical handle을 유지하고 중복 없이 복구한다.
- Framework Service 재시작 뒤 Manager가 새 handle로 재등록한다.
- publish snapshot과 callback/query가
LOCAL_ACCEPTED,PUBACKED,FAILED를 구분한다. - QoS 1 duplicate와 retained message가
DomainMessage에 표시된다. - 느린 Client callback이 다른 Client와 기존 제품 handler를 막지 않는다.
- 기존 MQTT Client는 새 필드 없이 동일하게 동작한다.
- descriptor-only domain은 Framework Core 분기문 수정 없이 등록된다.
- wildcard·reserved Topic, 비허가 caller, schema 위반과 원격 권한 확대를 거부한다.
15. 확정안과 구현 전 선택
확정안
- IotAgent는 단일 AWS 연결과 credential의 유일한 owner다.
SkixIotCoreManager는 Client API,SkixIotCoreService는 정책·상태 owner다.- 공개
DomainCapability와 내부DomainDescriptor를 분리한다. - 구독은
SubscriptionHandle, 발행은publishId와 callback/query로 추적한다. - 신규 domain의 기본 추가 경로는 로컬 선언이며 원격 catalog는 운영 제어에 한정한다.
- 기존 제품 처리와 신규 Client 전달은 하나의 physical callback에서 fan-out한다.
구현 전 선택
SkixIotCoreService배치 프로세스와 서명 권한 이름- callback overflow 기본값과 Client별 queue 상한
- offline queue 저장소, 암호화, 최대 수명과 재부팅 보존 여부
- descriptor schema와 wrapper code generation 도구
- MQTT persistent session 사용 여부와 session expiry
- request correlation envelope와 기본 timeout