사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.
앱 & 라이브러리▾
도메인▾
스칼라▾
애셋 폴더
앱과 라이브러리는 파일 애셋을
lib/, ui/와 나란히 루트의 두 폴더에 둡니다. 어느 폴더에 둘지는 "브라우저가 이 파일을 받아 가도 되는가?" 하나로 정합니다.public/
브라우저가 받아 가도 되는 파일
URL로 바로 서빙됩니다. 이미지, PDF, 내려받는 JSON, 아이콘을 둡니다.
public/images/hero.png → /images/hero.pngprivate/
서버만 읽는 파일
서빙되지 않습니다. seed 데이터, 비공개 JSON, 모델 파일, 서버 작업용 리소스를 둡니다. 서버를 싣는 데스크톱 앱은 이 폴더를 사용자 컴퓨터에 평문으로 싣습니다.
private/model/yolo.onnx- 감싸는 폴더는 없습니다.
asset/폴더 없이public/과private/이 루트에 바로 놓입니다. - 라이브러리에도 같은 두 폴더가 있습니다. 그 라이브러리에 의존하는 모든 앱이 쓸 수 있으며, 아래 라이브러리 애셋에서 다룹니다.
public 애셋
서버는
public/ 아래 파일을 정적 파일로 그대로 서빙합니다. URL은 파일 경로에서 apps/myapp/public을 뺀 것입니다:URL파일
/docs/product-guide.pdf
apps/myapp/public/docs/product-guide.pdf/data/sample-products.json
apps/myapp/public/data/sample-products.json/images/hero.png
apps/myapp/public/images/hero.png- URL에 언어가 붙지 않습니다. 페이지는
/ko/…,/en/…아래에 있지만 public 파일은 그렇지 않아서,/ko/images/hero.png는 404를 돌려줍니다. - 파일 링크는 일반
<a>로 겁니다.akanjs/ui의Link는 언어를 붙이고 페이지로 이동하므로 파일을 찾지 못합니다. - 프로덕션에서는 5분간 캐시됩니다. 파일을 바꿔도 그동안은 예전 버전이 보일 수 있습니다. 개발 서버는 캐시하지 않습니다.
PDF 링크는 일반
<a> 태그로 겁니다:apps/myapp/ui/ProductGuideLink.tsx
JSON 파일은 브라우저에서 URL로 불러옵니다:
apps/myapp/webkit/useSampleProducts.tsx
window.fetch를 씁니다.@apps/myapp/client에서 import하는fetch는 브라우저의 fetch가 아니라 Akan API 클라이언트입니다.- 브라우저 전용입니다. 서버에는 상대 URL이 가리킬 origin이 없으므로 이 코드는
webkit/에 둡니다. 서버 코드는 아래 private 애셋처럼 디스크에서 파일을 읽습니다.
이미지 최적화
public/의 UI 이미지는 일반 <img> 태그 대신 akanjs/ui의 Image로 그립니다. Next.js의 이미지 최적화처럼 서버가 더 작고 가벼운 버전을 보냅니다:apps/myapp/ui/HeroImage.tsx
- 크기를 줄이고 캐시합니다. 이미지는 그려지는 폭에 맞게 줄여, 브라우저가 WebP를 지원하면 WebP로 보냅니다. SVG 파일은 그대로 보냅니다.
width와height를 지정합니다. 서버가 보낼 크기를 정하고, 이미지가 오기 전에 자리를 잡아 둡니다.priority는 첫 화면에만 씁니다. 이미지를 미리 불러와 바로 그립니다. 나머지 이미지는 화면에 가까워질 때 불러옵니다.- 나머지는 설정입니다. 외부 호스트의 이미지는
akan.config.ts의images.remotePatterns에, 75가 아닌quality값은images.qualities에 등록해야 합니다.
private 애셋
private/ 아래 파일은 서빙되지 않으므로 어떤 URL로도 접근할 수 없습니다. 서버 코드가 디스크에서 읽어 데이터를 불러오고, 추론을 돌리고, 서비스를 초기화하는 데 씁니다. 다만 서버 파일을 가진 사람에게는 비밀이 아닙니다. 서버를 싣는 데스크톱 앱(native.desktop.server)은 이 파일을 평문으로 실으므로, 남에게 보이면 안 되는 키와 라이선스 파일은 그런 앱에 두지 않습니다.| 파일 |
|---|
| ↳ 용도 |
| apps/myapp/private/seed/products.json |
| 서버가 불러오는 seed 데이터입니다. |
| apps/myapp/private/model/yolo.onnx |
| 서버에서 추론할 때 쓰는 모델 파일입니다. |
| libs/shared/private/recommendation/default-rules.json |
| 라이브러리의 내부 규칙으로, 아래 라이브러리 애셋에서 다룹니다. |
앱 폴더 기준으로 읽기
경로는 앱 자신의 폴더인
AKAN_APP_DIR에서 만듭니다. srvkit/에 작은 헬퍼 하나를 둡니다:apps/myapp/srvkit/privateFile.ts
AKAN_APP_DIR값은 어디서나 앱 폴더입니다.akan start에서는apps/myapp, 빌드에서는dist/apps/myapp입니다. 서버는 앱 모듈을 불러오기 전에 이 값을 정하며, 데스크톱 앱에 넣은 서버도 같습니다. 서버 밖에서 도는 스크립트에는 값이 없어서 헬퍼가Bun.main의 폴더로 대신합니다.srvkit/에 둡니다.Bun이나process.env를 건드리는 코드는 그곳에 두고, 페이지나 클라이언트 파일에는 두지 않습니다.


./private/…로 바로 읽지 마세요. 상대 경로는 작업 디렉터리를 따라가는데, akan start에서는 그것이 워크스페이스 루트입니다. 같은 코드가 빌드에서는 파일을 찾고 개발 중에는 놓칩니다.데이터와 모델 불러오기
JSON 파일은 헬퍼로 읽습니다:
apps/myapp/srvkit/seedProducts.ts
모델 파일은 서버가 시작할 때
adapt() 클래스 안에서 한 번만 불러옵니다:apps/myapp/srvkit/yoloDetector.ts
onInit은 프로세스마다 한 번 실행됩니다. 가중치는 요청마다 읽지 않고 시작할 때 한 번만 읽습니다.- 서비스에는
plug(YoloDetector)로 주입합니다.loadYoloModel과YoloModel은 사용하는 ONNX 런타임의 로더로 바꿔 넣을 자리입니다.
라이브러리 애셋
라이브러리는 애셋을 자기
public/과 private/에 둡니다. 그 라이브러리에 의존하는 모든 앱이 둘 다 libs/<lib>/ 아래로 받습니다. public은 URL로, private은 서버 코드 전용으로 씁니다:위치경로
라이브러리 public/
libs/shared/public/banner/logo.png앱 안에서
apps/myapp/public/libs/shared/banner/logo.png브라우저 URL
/libs/shared/banner/logo.png라이브러리 private/
libs/shared/private/recommendation/default-rules.json앱 안에서
apps/myapp/private/libs/shared/recommendation/default-rules.json서버 코드가 읽는 경로
privateFile("libs/shared/recommendation/default-rules.json")public/libs와private/libs는 생성되는 폴더입니다.akan sync가 다시 만들고 git은 무시하므로, 직접 만든 파일을 두지 마세요.- 서버를 싣는 데스크톱 앱은 이 파일도 싣습니다. 라이브러리에 의존하는 어느 앱이든
native.desktop.server를 켤 수 있고, 그러면 그 앱의 사용자가 라이브러리의private/를 평문으로 읽을 수 있습니다. 남에게 보이면 안 되는 키와 라이선스 파일은 두지 마세요. - 라이브러리의 서버 코드도 앱 경로로 읽습니다. 앱 안에서 실행되고, 빌드에는 라이브러리 소스 폴더가 없기 때문입니다.
라이브러리 이미지는
/libs/… URL로 그립니다:apps/myapp/ui/SharedLogo.tsx
라이브러리의 private 파일은
private/libs/<lib>를 거쳐 읽습니다:apps/myapp/srvkit/defaultRules.ts
어느 폴더에 둘까
인터넷의 누구든 이 파일을 받아 가도 되는지 묻습니다. 된다면
public/, 안 된다면 private/입니다.예시 파일
public/
private/
누구나 받아 가도 되는 파일
images/hero.png
✓
UI 이미지와 아이콘으로,
akanjs/ui의 Image로 그립니다.docs/product-guide.pdf
✓
사용자가 내려받는 PDF 같은 파일입니다.
data/sample-products.json
✓
브라우저가 URL로 불러오는 JSON입니다.
서버만 읽어야 하는 파일
seed/products.json
✓
seed 레코드 같은 내부 데이터입니다.
model/yolo.onnx
✓
모델 가중치 파일입니다.
recommendation/default-rules.json
✓
서버 전용 설정과 규칙입니다.
✓여기에 둡니다여기가 아닙니다
- 애매하면
private/에 둡니다. public 파일은 로그인이 필요 없어서, URL을 아는 사람은 누구나 받아 갈 수 있습니다. - UI 이미지는
Image로 그립니다.akanjs/ui의Image를 써야 서버가 최적화합니다. - 공유는 라이브러리로 합니다. 여러 앱이 같은 파일을 쓴다면 앱마다 복사하지 말고 라이브러리 자신의
public/이나private/에 둡니다.
빌드에 들어가는 것
akan build는 두 폴더를 dist로 복사합니다. 덜어내는 것은 그 복사본뿐이고, 소스 폴더의 파일은 그대로 남습니다.| 폴더 |
|---|
| ↳ 빌드에서 |
private/ |
| 모든 빌드에 복사됩니다. |
public/ |
앱이 페이지를 서빙할 때 복사되고, API 전용 빌드(web: false)에는 들어가지 않습니다. |
public/의 폰트 |
참조되지 않는 폰트는 assets.pruneFonts가 빼고, 남길 폰트는 assets.keepFonts에 적습니다. |