SKIX Framework Architecture — 구조·용어·의존성 규칙
Framework 구조와 신규 코드 판단의 대표 문서. 폴더를 고르기 전에 책임·상태 소유자·의존성 방향을 결정한다. 기준: 2026-09-22 MR7 작업 트리. 아래 규칙은 신규/수정 코드의 기준이며, 기존 이름이 모두 정리됐다는 뜻은 아니다.
전체 책임 지도
사용자가 정리한 App → API → Binder → EntryPoint → Task/Domain → Port/Adapter → 장치 구조를 기준으로 한다. Control은 공통 기반이고, 조회·관측이 모두 Task를 생성하지 않는다. 도메인 실행기는 공통 Task 계약을 사용하며 공통 TaskManager가 각 도메인 구현을 import하지 않는다. 맨 아래 AMR은 서버 AMR Domain과 다른 AMR 장치/주행 스택이다.
Architecture Rule — 한 장 요약
기능 하나에 Manager → Service → Runtime → Provider → Adapter를 모두 만들지 않는다. 상태의 단일 소유자, 외부 계약, 독립적인 교체 지점 중 하나를 설명할 수 있을 때만 타입을 분리한다. 단순 위임만 한다면 기존 클래스의 메서드를 우선한다. 접미사는 새 계층을 만들 수 있는 허가가 아니다.
| 이름 | 이 이름을 쓰는 조건 | 허용 의존성과 금지 | 실제 예시 |
|---|---|---|---|
| Manager | 앱이 사용하는 도메인별 SDK 진입 API | SDK 계약과 클라이언트 transport에 의존. 서버 구현·장치 상태의 소유자가 되지 않음 | SkixTaskManager |
| Service / ManagerService | 서버의 지속적인 책임과 lifecycle을 가진 소유자. ManagerService는 SDK Manager에 대응하는 서버 관례 |
소속 계층의 하위 계약만 사용. Android Service와 구분하며 동일 책임의 Manager와 Service를 서버에 중복 생성하지 않음 |
TaskManagerService, CleaningManagerService |
| Runtime | 여러 서비스/실행 구성요소를 같은 수명으로 조립하고 연결 | server/runtime에서 하위 계층을 조립. control/execution/domain이 이 패키지를 역참조하지 않음. 단일 명령 실행기는 Executor/기존 실행 타입으로 표현 |
ManagedTtsRuntime |
| Port | 도메인이 외부에 요구하는 최소 행위 계약(interface) | 계약은 소비 도메인 소유. SDK 값 타입/도메인 계약만 사용하며 Android·구현 Adapter 참조 금지. 외부 구현이 Port를 구현 | AmrExecutionPort, CleaningExecutionPort |
| Adapter | 원본 프로토콜·값·콜백을 기존 계약으로 번역하는 구현 | 원본과 목적 계약에 의존. 정책·Task 상태의 최종 소유자가 되지 않음. 순수 변환은 core, Android/벤더 참조는 외곽 구현에 둠 | BatteryObservationAdapter |
| Endpoint | 요청 진입점에서 호출자 검증/인가 후 유스케이스에 위임 | entrypoint → domain/execution/control. 장치 명령·상태 머신·조립을 소유하지 않음. 하위 계층은 Endpoint를 참조하지 않음 | TaskManagerEndpoint |
| Gateway | 프로세스/시스템을 건너는 명시적 transport 계약 | AIDL과 Android 경계에 둠. 내부로는 typed 요청/관측을 전달. 같은 프로세스의 단순 위임 클래스에는 사용하지 않음 | IPowerObservationGateway |
| Ingress | 들어오는 관측의 세션·수명·순번을 검증하고 내부 소유자에 전달 | 소속 도메인과 control의 관측 계약만 사용. Gateway/Binder/제품 transport 참조 금지. 정책 판단이나 장치 명령 발행은 맡지 않음 | PowerObservationIngress |
| Authority | 상태 변경·토큰 발급/폐기를 독점하는 내부 객체 | 해당 Service가 소유. 같은 상태에 두 Authority를 두지 않음. domain/control/execution의 필요한 계약만 사용, 외곽 진입/조립 참조 금지 | AmrStateAuthority |
| Provider | 명시된 기능 계약의 실행 제공자이며 연결·준비 상태를 갖는 구현 | 소비자가 정의한 계약/Port와 준비 상태 계약에 의존. Service의 동의어로 사용하지 않음. provider 반환/ACK는 물리 완료가 아님 | ManagedTtsRelayProvider |
Host는 수명 소유자, Runtime은 조립, Executor/Dispatcher는 실행·배정이다. Session은 시작/종료되는 상호작용, Token은 발급자·세대·폐기 조건이 있는 증표, Claim은 작업 배정권, Permit은 실행 허가다. 문자열 ID는 Id로 부르며 Token/Permit으로 승격하지 않는다. Evidence는 관측 근거, Policy는 허용 판단이다. 이 이름들 역시 책임이 실제 존재할 때만 쓴다.
리뷰에서 확인할 4가지: ① 기존 타입으로 처리할 수 없는 이유 ② 상태/수명 소유자 한 곳 ③ 아래 의존성 방향 ④ 실패·종료·권한 철회의 영향 테스트. 새로운 접미사나 예외는 이 문서에 의미·이유·해소 조건을 먼저 적는다.
폴더와 의존성 방향
화살표는 코드 의존성이다. 실행 순서가 아니다. 아래 계층에서 위 계층으로 되돌아오는 참조는 금지한다.
services/runtime/ Android Service · Binder · 제품 transport 구현
│
▼
services/core/.../server/runtime/ 조립 · 시작/종료 · provider 연결
├──► entrypoint/ 인증·인가된 요청 진입
│ │
│ ▼
├──► domain/ AMR · Cleaning · Power 등 제품 행동
│ │
│ ▼
├──► execution/ 공통 Task · Workflow · Scheduler · Evidence
│ │
│ ▼
└──► control/ 상태 · 정책 · 자원 · capability · lifecycle
base/core/ SDK 계약·값 타입·클라이언트 API (server 참조 금지)
compatibility/ · 외곽 adapters 기존 IPC/제품 규격 → 내부 계약으로 번역
| 소스 계층 | 직접 참조 가능한 서버 계층 | 금지/제한 |
|---|---|---|
| control | control | execution/domain/entrypoint/runtime/integration/legacy 금지 |
| execution | execution, control | domain/entrypoint/runtime/integration/legacy 금지 |
| domain | 자기 domain, execution, control | entrypoint/runtime/integration/legacy 금지. 타 도메인은 명시적 인계 계약만 사용 |
| entrypoint | domain, execution, control 및 자체 진입 계약 | runtime 구현 의존은 금지 방향. 아래 기존 TTS 예외를 별도 관리 |
| runtime | 필요한 entrypoint/domain/execution/control | 조립만 소유. 도메인의 상태 전이를 복제하지 않음 |
| integration/legacy 구현 | 해당 제품 원본과 소비 도메인의 계약 | 공통 상태/실행/인가를 우회하지 않음. integration → entrypoint/control/execution은 현 검사에서도 금지 |
모든 서비스 core는 Android 독립이다. Android 구현은 services/runtime/java에 둔다. base/api, adapters, services/systemserver, data/etc에는 아직 README 위주의 경계가 있으므로 폴더 존재를 구현 완료로 읽지 않는다. 상세 폴더 설명은 base README, 작업 현황은 인수인계를 본다.
새 도메인은 필요한 책임만 추가한다
domain/<name>/
├── XxxManagerService.java 기존 lifecycle에 등록할 독립 기능 소유자가 필요할 때
├── state/ 선택: 유지할 상태/전이/세대가 있을 때
├── policy/ 선택: 별도 제품 판단 규칙이 있을 때
├── execution/ 선택: 추적할 비동기 실행이 있을 때
├── observation/ 선택: 외부 측정/사실을 받아야 할 때
└── port/ 선택: 교체할 외부 행위 계약이 있을 때
이 트리는 생성 템플릿이 아니다. 예를 들어 기존 Vision 서비스에 조회 기능 하나를 추가한다면 기존 계약과 구현을 확장하는 것으로 충분할 수 있다. 별도 CameraRuntime/Provider/Session/Authority를 기본 세트로 만들지 않는다. 독립 기능 소유자조차 필요 없으면 새 ManagerService도 만들지 않는다.
| 값/규칙 | 의미와 경계 |
|---|---|
| Observation | 외부에서 들어온 사실/측정과 출처·시각·순번. 원본이 제공하지 않은 상관관계를 합성하지 않음 |
| State | 관측과 내부 전이로 유지되는 canonical 상태. 요청 의도와 실제 관측 상태를 구분하고 미확인은 unknown으로 유지 |
| Policy | State·Request·호출 맥락에 대한 허용/거부/조건 판단. 직접 HW 명령을 발행하지 않음 |
| Task | owner와 식별자·상태·결과로 추적하는 실행 단위. 접수/ACK를 물리 완료로 해석하지 않음 |
향후 확장 고려사항
Planner는 향후 외부 확장 대상으로만 고려한다. 이번 리팩터링의 구현·우선순위·완료 기준에는 포함하지 않는다. 향후 연결도 Framework의 공개 계약과 요청 검증을 거치도록 경계만 유지한다.
현재 강제 범위와 남은 차이
- 경계 검사: verify-skix-layer-boundaries.sh가 import 방향을 검사한다. control/execution/domain → entrypoint/runtime 금지를 포함한다.
SkixFrameworkService의 GradlepreBuild가 이 검사를 실행한다. - 검사 한계: 현재 검사는 Java/Kotlin import 문 중심이다. 완전 수식 이름, reflection, 모든 도메인 간 의존성을 증명하지 않는다. APK 빌드 성공은 Soong 경계나 실제 기기 검증이 아니다.
- 빌드 모듈: base/Android.bp는 소스
filegroup이다. 별도 컴파일/클래스패스 경계가 아니다. Gradle 앱도 core/runtime 소스를 함께 컴파일한다. 아직control/task/domain/entrypoint/runtime별 컴파일 격리는 없다. - 기존 순환:
entrypoint/binder/ManagedTtsEndpoint가runtime/ManagedTtsRuntime을 참조하고 runtime도 entrypoint를 참조한다. 신규 코드의 선례로 쓰지 않는다. Endpoint에 필요한 도메인 유스케이스 계약을 추출해 주입한 후 역참조를 제거하고 검사로 닫아야 한다. 이번에 TTS 동작은 변경하지 않았다. - 기존 이름:
MovementRuntime/CorrelatedMovementRuntime/ManagedMovementRuntime은 도메인 실행 계약/구현에도 Runtime을 사용한다. 새 Runtime 계층을 복제하지 말고 이동 실행 변경 묶음에서 호출자·역할을 함께 정리한다. 동작 확인 없이 일괄 rename하지 않는다. - 의도된 도메인 연결: AMR–Cleaning 자원 인계는 기존 명시적 계약이다. 모든 도메인이 서로 ManagerService를 호출해도 된다는 뜻이 아니다.
빌드 경계 강화 순서
- 현재 import 그래프의 예외/순환을 줄이고 용어 규칙을 적용한다. 이번 문서 및 역참조 검사 보강이 이 단계다.
- Android 독립 SDK 계약을 legacy 클라이언트 구현과 분리할 수 있는지 확인한다.
base/core전체를 곧바로 순수 Java 라이브러리로 간주하지 않는다. contracts ← control ← task/execution ← domain ← entrypoint ← runtime방향으로 실제 컴파일 단위를 나눈다. 필요한 하위 계층 직접 의존은 허용한다.skix-framework-core/control/task/domain/entrypoint/runtime은 후보 이름이며, 파일 수에 맞춘 분할 목표가 아니다.- Gradle과 Soong의 입력·의존성·중복 패키징을 일치시키고, 금지 참조가 컴파일에서 실패하는 음성 테스트를 둔다. Soong 선언만 추가하고 AOSP 빌드 완료로 보고하지 않는다.
문서의 역할
이 문서는 구조/명명/의존성 판단의 정본이다. 날짜별 리팩터링 현황·검증 로그는 상태 기록, 다음 작업은 인수인계에 둔다. Wiki의 Blueprint/폴더 지도/WBS는 이 규칙과 연결해 읽고, 구현 상태는 현재 소스와 검증 기록을 기준으로 판단한다.
그림의 코드 근거
| 책임 | 근거 소스 또는 현재 범위 |
|---|---|
| Public API / Binder | base/core/java/com/sk/airbot/framework/manager/SkixTaskManager.java, base/core/aidl, services/runtime/java/.../entrypoint/binder |
| EntryPoint | services/core/java/.../server/entrypoint/binder/TaskManagerEndpoint.java, entrypoint/identity, entrypoint/validation |
| Task | services/core/java/.../server/execution/task/TaskManagerService.java |
| Control | services/core/java/.../server/control/{capability,policy,resource,state,lifecycle,health} |
| Domain / Port | server/domain/{amr,cleaning,llm}, domain/amr/port/AmrExecutionPort.java, domain/cleaning/port/CleaningExecutionPort.java |
| 관측 | domain/power/observation/PowerObservationIngress.java, base/compatibility/aidl/.../IPowerObservationGateway.aidl |
| 제품 Adapter | apps/DeviceAgent/app/src/main/java의 제품 명령·관측 연결. 모든 장치의 managed transport 완료를 뜻하지 않음 |
| Runtime / 빌드 | server/runtime/FrameworkHostComposition.java, apps/SkixFrameworkService/app/build.gradle, base/Android.bp, tools/verify-skix-layer-boundaries.sh |
Connections
저장소의 대표 원문은 skix-framework/ARCHITECTURE.md이다. 규칙 변경 시 이 페이지와 함께 갱신한다. 점수 평가 대신 실제 소스·검사·미완료 항목으로 구조를 판단한다.