사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.
| 명령 | 기본 --env |
|---|---|
| ↳ 결과 | |
| start-android | local |
에뮬레이터나 폰에서 실행합니다. --release를 주면 개발 서버 대신 웹 빌드를 넣습니다. | |
| build-android | debug |
| 앱이 빌드되는지 확인하는, 로컬 debug 키로 서명한 APK를 만듭니다. | |
| release-android | main |
업로드 키로 서명한 Play Store용 AAB를 만듭니다. --assemble-type apk면 APK입니다. | |
main 백엔드로 만듭니다:MYAPP_RELEASE_STORE_FILE은 앱 폴더 기준 경로입니다. keystore 파일은 secrets/에 두고, public/에는 두지 마세요.apps/myapp/.akan/native/default/build/android에 생기며, release-android가 경로를 출력합니다.native.targets의 키나 all입니다. target이 하나뿐이면 자동으로 고르며, start-*는 한 번에 하나만 실행합니다.aab는 Play Store 업로드용, apk는 파일을 직접 설치할 때 씁니다.--env local을 허용합니다. 로컬 테스트용입니다.akan start myapp을 켜 둔 채 시뮬레이터에서 앱을 실행하거나, 페어링한 iPhone 이름을 줍니다:--device로 기기를 고릅니다. 시뮬레이터 이름이나 UDID, 페어링한 iPhone 이름을 받습니다. 생략하면 켜져 있는 iPhone 시뮬레이터를 쓰고, 없으면 가장 최신 것을 띄웁니다.--team으로 고릅니다.native.appId와 같아야 합니다. 와일드카드 ID는 앱이 푸시도 associated domains도 요청하지 않을 때만 씁니다.| 명령 | 기본 --env |
|---|---|
| ↳ 결과 | |
| start-ios | local |
시뮬레이터나 폰에서 실행합니다. --release를 주면 개발 서버 대신 웹 빌드를 넣습니다. | |
| build-ios | debug |
| 앱이 빌드되는지 확인하는 시뮬레이터용 앱을 만듭니다. | |
| release-ios | main |
App Store용으로 서명한 iPhone 앱과 그 .ipa를 만듭니다. | |
main 백엔드로 만듭니다. release-ios는 기본으로 main을 씁니다:xcode-select --install).native에 desktop: { server: true }를 주면(한 타깃에만 주면 그 앱만 서버를 싣습니다) akan start-desktop은 떠 있는 개발 서버가 없을 때 같은 명령에서 akan start를 띄우고, akan build-desktop과 akan publish-update는 서버를 넣은 앱을 빌드합니다. 이 서버는 창과 함께 loopback 포트로 떠서 API만 서빙하고, SQLite 데이터를 앱 데이터 폴더의 server/에 둡니다(Windows는 %LOCALAPPDATA% 아래, --debug 빌드는 따로 server-debug/). 운영체제가 믿는 인증서를 믿고, 페이지처럼 사용자 세션의 프록시 변수를 따릅니다. 이 컴퓨터의 다른 프로그램도 그 포트를 부를 수 있으므로, 엔드포인트는 네트워크 서버처럼 가드합니다. 포트는 대개 지난번과 같지만 보장되지 않습니다. 그래서 redirect URI가 정확히 같아야 하는 로그인 공급자는 앱에 넣은 서버가 아니라 클라우드 서버의 adapter로 받습니다. 설치된 앱은 서버를 더하거나 빼는 업데이트를 받지 않으므로, 이미 배포한 앱에서 바꾸려면 다시 설치해야 합니다. 다시 설치해도 데이터는 옮겨지지 않습니다. 서버를 더하면 앱이 빈 로컬 데이터베이스로 시작하고, 빼면 페이지가 빌드에 적힌 백엔드를 부릅니다.basePath를 적지 않고, 앱을 하나만 내면 targets도 필요 없으므로 서버를 싣는 가장 짧은 설정은 이렇습니다. 첫 페이지가 /가 아니면 desktop 옆에 indexPath를 더합니다:database.modes에 single이 있어야 합니다. 앱에는 서버의 private/ 폴더(lib의 것도 private/libs/<lib>로), 빌드할 때의 --env에 해당하는 env.server.<env>.ts 하나, 앱이 쓰는 lib이 서버 env로 내보내는 기본값(lib의 env.server.testing.ts)이 평문으로 실립니다. 앱을 가진 사람은 누구나 그 파일과 값을 모두 읽을 수 있으니 클라우드 키 같은 배포용 비밀과 라이선스 파일은 두지 마세요. 앱에 넣은 서버에는 public/이 없고 작업 폴더는 데이터 폴더이므로, 실행 중에 읽는 파일은 process.cwd()가 아니라 앱 폴더(AKAN_APP_DIR, 없으면 Bun.main의 폴더) 기준으로 읽습니다.docker 단계가 하나도 들어가지 않습니다. 서버나 네이티브 플러그인이 실행하는 ffmpeg 같은 실행 파일은 akan.config.ts의 bin에 적습니다. 플랫폼마다 sha256로 확인하는 다운로드나 설정 파일 옆의 파일을 적습니다. 서버가 있든 없든 모든 데스크톱 빌드·실행·개발이 이 파일을 싣습니다. 빌드가 이 컴퓨터용 파일을 앱에 넣고 그 폴더를 앱의 PATH 맨 앞에 두므로, 서버의 spawn("ffmpeg")가 그 파일을 실행하고 사용자는 아무것도 설치하지 않으며, 네이티브 플러그인은 ctx.binDir에서 찾습니다. 설치하면서 스스로 빌드하는 패키지는 trustedDependencies에 적습니다.native.plugins에 file-picker를 추가하고 forServer: true로 고른 뒤, grant를 엔드포인트에 넘기면 서버가 NativeFile로 경로를 받습니다. 서버는 사용자가 고른 파일만 얻습니다.desktop.recovery: "reload"는 프로세스가 끝난 페이지를 매번 다시 불러오되 연달아 끝날수록 오래 기다리고, webview 브라우저 프로세스가 끝나면 앱을 다시 띄웁니다. desktop.window는 주 창을 첫 프레임부터 전체화면, 작업 표시줄 버튼 없이 열고, app.relaunch()는 데스크톱과 Android에서 앱을 새 프로세스로 다시 시작합니다. Windows에서 원격 지원을 하려면 desktop.screenCapture: "auto"가 getDisplayMedia()에 선택 창도 터치도 없이 첫 화면으로 답합니다. 모든 미디어 요청에 적용되므로 카메라나 마이크를 요청하는 앱에서는 켜지 않습니다.akan build-desktop myapp --installer true --env main을 실행하면 앱 폴더 옆에 설치 프로그램이 생깁니다(NSIS: winget install NSIS.NSIS). 현재 사용자로 설치하므로 업데이트가 관리자 권한 없이 앱을 바꿉니다. /S는 무인 설치, /RUN은 설치 뒤 실행으로, 원격 설치가 넘기는 인자입니다. WebView2 Runtime이 없는 PC에는 함께 설치합니다. /D= 없이 다시 실행하면 앱이 이미 있는 폴더에 설치하고, 다른 설치 프로그램이 도는 동안 띄운 것은 시작하지 않습니다. 아직 코드 서명이 없어서, 브라우저로 받은 파일은 SmartScreen 경고를 만납니다.rustup target add x86_64-pc-windows-msvc 뒤 x64 Bun(bun-windows-x64-baseline, AVX2가 없는 CPU에서도 도는 빌드)으로 akan을 실행하면 x64 PC용 앱이 나옵니다.akan update-keygen이 키를 한 번 만들고 native.updates에 넣을 공개 키를 출력합니다. akan publish-update는 릴리스(데스크톱은 앱 전체, 폰은 웹 번들)를 .akan/native/<target>/updates에 빌드합니다. 그 폴더에는 updates.url에 올릴 것만 있으며, manifest를 마지막에 올립니다. 새 릴리스는 첫 페이지가 마운트될 때까지 시험 실행입니다. 폰은 시작할 때와 앞으로 돌아올 때마다 새 웹 번들을 스스로 찾아 받고 다음 콜드 스타트부터 씁니다. 데스크톱은 릴리스가 앱 전체이고 재실행이 따르므로 언제 확인·다운로드·적용할지는 앱이 정합니다. akan pack-update는 키를 다른 곳에 두는 서명자를 위해 폰 업데이트를 서명 없이 씁니다.updates.url에 닿는 누구나 그 아래의 모든 것을 읽을 수 있고, 업데이터는 인증 정보를 보내지 않습니다. 데스크톱 릴리스는 앱 전체이므로 앱에 넣은 서버의 private/(앱과 lib의 것)와 env 파일도 들어 있습니다. 설치된 앱에도 두면 안 되는 것은 여기에도 두지 마세요.updates.channel이 정한 채널을, 없으면 빌드할 때의 --env를 따릅니다. 그래서 updates.channel이 없으면 자기 env로 게시한 릴리스만 받습니다. build-desktop의 기본값은 debug, publish-update는 main이므로 둘에 같은 --env를 줍니다. publish-update의 --channel은 쓸 매니페스트 이름만 정합니다. 안에 든 릴리스는 빌드할 때의 채널을 그대로 가지므로 받은 앱은 그 뒤로 그 채널을 따릅니다. 그래서 pilot 그룹에는 updates.channel이 pilot인 타깃을 따로 둡니다. publish-update는 채널의 직전 릴리스와 서버 유무가 다른 데스크톱 릴리스를 빌드하기 전에 거부합니다. updates.channel로 다른 채널에 게시하거나, 출력 폴더에서 그 <channel>.json을 지워 채널을 새로 시작합니다. 설치 폴더, 제거 항목, 데이터 폴더, 한 번에 하나만 뜨는 인스턴스, 업데이트 상태처럼 데스크톱 앱을 그 앱이게 하는 것은 env가 아니라 타깃의 appId와 이름에서 나옵니다. 그래서 한 타깃의 두 env를 한 컴퓨터에 두면 이것을 모두 함께 씁니다. 나란히 설치하려면 env마다 appId가 다른 타깃을 따로 둡니다.updates.check()는 그 릴리스에 available: false로 답하고, updates.apply()는 NOT_ALLOWED로 거부합니다. 적용하면 시험 실행이 실패했을 때 돌아갈 앱을 바꾸기 때문입니다. 서버를 싣는 앱은 그 서버가 응답하고 5초 동안 떠 있어야, 그리고 그때 떠 있어야 시험 실행을 확정하며, readyTimeout 시계도 그때 시작합니다. 서버가 포기하거나 시작하고 120초 안에 뜨지 않으면 곧바로 되돌립니다. 그 릴리스는 받은 채로 남아 다음 적용 때 다시 시도하고, 이렇게 세 번째 실패하면 더는 받지 않습니다. 서버를 더하거나 빼는 릴리스는 매니페스트만 보고 아무것도 받기 전에 거부하며, 앱을 다시 설치하면 이전 설치가 거부한 릴리스 목록이 비워집니다.app/과 files/ 아래 파일은 해시로 이름이 붙으므로 오래 캐시해도 됩니다. 하지만 <channel>.json과 <channel>.json.sig는 캐시하지 않거나 둘을 함께 무효화해야 합니다. manifest가 다른 릴리스의 서명과 짝지어지면 검증에 실패하고, 캐시가 만료될 때까지 모든 앱이 업데이트를 멈춥니다. app/과 files/를 먼저 올리고, 두 파일은 마지막에 함께 올립니다.android.filesres/…assets/…| 알림을 누르면 엉뚱한 화면이 열림 |
데이터에 url: "/some/path"를 넣어 보내고, 누르면 그 CSR route가 열리는지 확인합니다. |
native.android.googleServices가 그 앱의 google-services.json을 가리킵니다.aps-environment는 프로필을 따라 폰 실행에서는 development, 출시에서는 production입니다.native.android.googleServices원격 알림 백그라운드 모드와 aps-environment entitlement |
| speech | 아직 없음. 없이 빌드됩니다 | lib 플러그인이 선언한 것 | lib 플러그인이 선언한 것 |
appId가 다르면 완전히 다른 앱으로 봅니다.push