사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.
네이티브 앱 아키텍처
Akan은 같은 제품을 웹, 앱스토어, 데스크톱에 함께 내보내며, 어느 쪽에도 앱을 따로 만들지 않습니다. 웹용으로 만든 화면이 얇은 네이티브 앱 안에서 그대로 돌아가고, 패키징과 서명, 기기 기능처럼 정말로 기기가 필요한 부분만 네이티브가 맡습니다.
정확히 말하면 Akan 네이티브 앱은 akanjs의 자체 런타임인 @akanjs/native가 만들어 내는 네이티브 shell 안에서 실행되는 CSR 웹 클라이언트입니다. 제품 화면은 여전히 Akan page, UI, state, service 패턴으로 만들고, 런타임이 akan.config.ts의 선언을 바탕으로 shell, 앱 식별 정보, 스토어 패키지, 디바이스 브리지를 제공합니다.
같은 target으로 macOS, Windows, Linux 앱도 빌드합니다. 데스크톱 앱은 폰처럼 공유 백엔드를 부르거나, native.desktop.server를 켜면 앱의 서버를 함께 싣습니다. 이 서버는 창과 함께 loopback 포트로 떠서 데이터를 그 컴퓨터에 두고, 페이지가 부르는 유일한 백엔드가 되므로 다른 곳에 서버 없이 앱이 동작합니다.

이 페이지에서 쓰는 말
용어설명
CSR
클라이언트 사이드 렌더링입니다. 기기 안의 JavaScript가 모든 화면을 직접 그립니다.
native runtime
akanjs 안에 들어 있는 @akanjs/native입니다. CSR 클라이언트를 iOS, Android, macOS, Windows, Linux 앱으로 빌드하며, 따로 관리할 Xcode 프로젝트, Gradle 파일, CocoaPods가 없습니다.
native shell
웹 클라이언트를 감싸는 작은 네이티브 앱이며, dist/native/<app>/<target>/build 아래에 생성되어 앱 아이콘, ID, 서명을 가집니다.
plugin
camera, push, iap처럼 기기 기능 하나를 JavaScript에 열어 주는 네이티브 런타임 plugin입니다. 이것이 네이티브 브리지입니다.
target
Akan 앱에서 만들어지는 네이티브 패키지 하나입니다. 이름과 app ID를 따로 가집니다.
세 부분이 나눠 맡는 일
하나의 UI 표면
한 번 쓰고 웹과 함께 씁니다
웹과 네이티브 앱은 같은 Akan page tree, client router, generated fetch 호출, dictionary, UI component를 공유합니다.
네이티브 shell 경계
네이티브 런타임이 만드는 몫
네이티브 코드는 패키징, signing, app capability, plugin linking, store 배포를 담당합니다.
공유 백엔드
이미 돌리고 있는 그 서버
웹 client와 네이티브 앱은 같은 Akan service를 호출하고 auth, permission, database rule, app-level domain을 공유할 수 있습니다. 서버를 싣는 target의 데스크톱 앱은 대신 자기가 싣고 있는 서버를 호출합니다.
네이티브 Target
하나의 제품이 스토어에서는 두 개의 앱일 때가 있습니다. 예를 들어 고객용 앱과 직원용 앱이죠. 각자 이름과 app ID는 달라야 하지만 백엔드는 같이 써야 합니다. 네이티브 target은 바로 이럴 때 씁니다.
네이티브 target은 Akan 앱에서 만들어지는 하나의 네이티브 패키지입니다. 하나의 Akan 앱은 각 target이 서로 다른 basePath를 열도록 설정해 여러 패키지를 배포할 수 있고, 백엔드 모듈은 그대로 공유할 수 있습니다. target은 자기가 적지 않은 값을 native에서 받습니다.

apps/myapp/akan.config.ts
routes— basePath마다 도메인을 하나씩 줍니다.native— 모든 target이 함께 쓰는 값이며, 여기서는 버전과 빌드 번호입니다.native.targets— 패키지마다 항목 하나이며, 각자 basePath, 표시 이름, app ID를 가집니다.


basePath마다 host는 따로 주어야 합니다. 서버는 들어온 host를 정확히 하나의 basePath로만 해석하므로, 두 basePath가 도메인을 공유하면 한쪽은 열리지 않습니다.


패키지별로 app ID, 표시 이름, 진입 화면, 권한, 딥링크, 스토어 릴리즈 트랙이 다르면 target을 나누세요.
CSR 런타임
앱이 네이티브처럼 느껴지는 건 작은 것들 덕분입니다. 화면이 밀려 들어오고, 내용이 노치를 피하고, 탭 바는 제자리에 있고, 키보드가 입력칸을 가리지 않습니다. 이 모두를 네이티브 UI를 다시 만들지 않고 얻습니다.

네이티브 shell 안에서 Akan은 CSR router와 모바일 page frame을 사용합니다. Page transition, safe area, navbar/bottom inset layer, keyboard accessory, page cache는 네이티브 UI를 다시 작성하지 않고 client runtime layer에서 처리됩니다. 페이지는 page() 체인의 .config() 단계로 이를 선언합니다.
page/store/product/[productId].tsx
.config()에 선언할 수 있는 frame 설정은 다음과 같습니다:
transition"none" | "fade" | "bottomUp" | "stack" | "scaleOut"
CSR page motion을 제어해 네이티브 shell 안의 내비게이션이 네이티브 앱에 가깝게 느껴지도록 합니다.
safeAreaboolean | "top" | "bottom" | { top, bottom }
노치, 홈 인디케이터, Android system bar 같은 OS 영역을 처리합니다.
topInset / bottomInsetnumber | boolean
navbar, tab, fixed action 같은 앱 chrome 자리를 px 단위로 비워 page content와 나눕니다. true는 48px입니다.


keyboard accessory 고정.
keyboardSticky를 쓰는 BottomInset은 contentAnchor="bottom"을 선택해, 키보드와 함께 scrollable content 크기를 줄이고 content의 하단 기준을 보존할 수 있습니다.네이티브 브리지
카메라, 푸시 알림, 파일 시스템은 웹 코드만으로는 닿지 않습니다. 디바이스 기능은 네이티브 런타임의 plugin을 통해 접근하고, Akan은 앱 레벨 API를 작게 유지합니다. 기능 하나를 쓰는 데는 세 단계면 됩니다:
- 필요한 네이티브 기능을 선언합니다. native.permissions의 permission이나 native.plugins의 plugin입니다.
- 앱을 빌드하거나 실행합니다(akan build-ios, akan start-android, …). shell은 그 plugin을 넣은 채로 만들어집니다.
- CSR 앱에서 해당 client hook 또는 plugin wrapper(akanjs/client/native)를 호출합니다.
브리지가 다루는 것
Permissions
Permissions는 네이티브 target이 사용하려는 네이티브 기능을 설명합니다.
Files
google-services.json이나 알림음 같은 네이티브 파일은 app 폴더에 두고, config에 각 파일이 들어갈 자리를 적습니다.
Deep links
네이티브 scheme, universal link, app link는 정규화된 route로 Akan CSR router에 들어옵니다.
Push notifications
Push는 iOS에서는 APNs, Android와 웹에서는 FCM으로 나가고, 클릭 라우팅은 표준 data.url 필드를 사용합니다.
구체적인 설정 절차
Cheatsheet의 네이티브 문서에서 단계별로 따라 할 수 있습니다: