테마
로컬 개발 셸 — 포탈 없이 화면과 API를 함께 실행한다
@starj-portal/bp-dev-shell은 포탈 없이 업무패키지(Business Package, 이하 BP)의 위젯과 백엔드를 함께 실행하는 개발 도구입니다. 명령은 starj-bp-dev입니다.
위젯 번들은 Portal Shell(포탈 셸)의 App 화면과 같은 틀에 마운트됩니다. 백엔드는 SDK의 가상 호스트(createFakeBpHost) 위에서 실행됩니다. 브라우저 하나에서 사용자와 권한을 바꿔 가며 BP의 모든 화면을 점검할 수 있습니다.
화면과 업무 로직은 이 셸에서 개발합니다. 실제 포탈에서만 확인할 수 있는 항목(§7)은 개발 서버의 포탈에서 확인합니다.
1. 설치
bash
# BP 루트(pnpm 워크스페이스 루트)에서
pnpm add -D -w @starj-portal/bp-dev-shell
# 백엔드 패키지에서 — 개발 셸은 포탈과 같은 Fastify 위에서 BP를 실행한다
pnpm add -D @nestjs/platform-fastify@11.1.28@nestjs/platform-fastify의 버전은 @nestjs/core와 같게 고정합니다. 개발 셸은 Nest와 reflect-metadata를 BP 쪽에서 해석해 적재합니다. 셸이 자기 사본을 쓰면 데코레이터 메타데이터 저장소가 둘로 분리되기 때문입니다.
갓 게시된 버전은 pnpm의 최소 공개 경과시간 정책에 걸려 설치되지 않을 수 있습니다. 그때는 pnpm-workspace.yaml의 minimumReleaseAgeExclude에 그 버전을 넣습니다(패키지와 설치).
2. 설정 — starj-dev.config.mjs
BP 루트에 둡니다. 경로는 모두 각 항목의 dir 기준입니다.
js
export default {
businessPackageId: "task-bp",
domainId: "portal", // 생략하면 "portal"
backend: {
dir: "backend", // 생략하면 BP 루트
entry: "src/register.ts", // register()를 export하는 파일
nodeArgs: ["--import", "@oxc-node/core/register"], // TS 소스를 직접 실행할 때의 로더
watch: ["src"], // 바뀌면 백엔드를 다시 시작할 경로
databaseUrl: "file:./.data/task-bp-devshell.db", // 생략하면 .starj-dev/bp.db
// 기동 전에 한 번 실행한다. DATABASE_URL이 주어진다.
prepare: "pnpm exec prisma generate && pnpm exec prisma migrate deploy",
},
frontend: {
dir: "frontend",
bundle: "dist/bundle.js", // 배포하는 IIFE 산출물과 같은 파일
watch: "pnpm exec vite build --watch", // 생략하면 산출물만 감시한다
},
// 생략하면 매니페스트의 defaultAuthorities에서 사용자 명부를 만든다(§4)
// users: [{ userNo: 1, displayName: "홍길동", authorities: ["TASK_ADMIN"] }],
};prepare에는 새로 내려받은 저장소에 없는 산출물을 만드는 명령을 넣습니다. Prisma 생성 클라이언트처럼 git에 올리지 않는 파일이 그 예입니다.frontend.bundle은 배포 산출물과 같은 IIFE 번들입니다. 개발 셸은 소스 모듈이 아니라 이 번들을 적재하므로, 셸에서 확인한 결과가 포탈에서의 결과와 같습니다.
3. 실행
bash
pnpm exec starj-bp-dev # 기본 포트 4300
pnpm exec starj-bp-dev --port 4100http://localhost:4300/을 엽니다. 백엔드는 다음 포트(4301)에서 실행되고, 셸이 /bp/ 요청을 그쪽으로 넘깁니다. 위젯은 포탈에서처럼 같은 출처의 /bp/{businessPackageId}로 API를 호출합니다.
| 무엇이 바뀌면 | 개발 셸이 하는 일 |
|---|---|
backend.watch 아래 파일 | 백엔드를 다시 시작하고 화면을 새로 적재합니다 |
| 위젯 번들 | 화면을 새로 적재합니다. 위젯 안의 입력 중인 값은 사라집니다 |
상태 파일(부여 표, onInstall 실행 기록, 가상 호스트 데이터)은 BP 루트의 .starj-dev/에 남습니다. 이 폴더는 .gitignore에 넣습니다.
4. 사용자와 권한
포탈에서 BP 화면을 보는 사람은 Authority를 부여받은 사용자입니다. 개발 셸도 사용자 명부와 부여 표를 따로 둡니다.
- 설정에
users가 없으면 매니페스트의defaultAuthorities로 명부를 만듭니다. 1번 사용자는 모든 Authority를 갖고, 2번부터는 Authority 하나씩을 갖습니다. - 패널의 "부여된 권한"은 관리자 화면의 Authority 부여와 같습니다. 바꾸면 바로 반영됩니다.
- 권한 판정은 포탈과 같습니다. 부여된 Authority의 App rw를 OR로 합치고, read는 1 비트, update는 2 비트를 봅니다.
5. 패널
| 영역 | 하는 일 |
|---|---|
| 사용자 | 로그인 사용자를 바꿉니다 |
| 부여된 권한 | 선택한 사용자의 Authority를 부여하거나 회수합니다 |
| 테마 | 위젯에 넘기는 theme과 Portal Shell 테마 토큰을 라이트·다크로 바꿉니다 |
| 화면 폭 | PC·태블릿·모바일 폭으로 바꿉니다. 화면 틀이 iframe이라 밀도 토큰의 미디어 쿼리도 함께 바뀝니다 |
| 언어 | 위젯에 넘기는 locale을 바꿉니다 |
| 셸 버전 | 호스트 계약 1.0.0 셸처럼 viewer·canWrite·features와 선택 액션을 넘기지 않습니다. 위젯이 그 부재를 견디는지 확인할 때 씁니다 |
| 설치된 기능 | 위젯의 features.has()와 백엔드 host.features의 설치 여부를 함께 바꿉니다. 백엔드를 다시 시작합니다 |
| 셸 호출 | 위젯이 호출한 toast·confirm·navigateToApp·카드 조작·reportError와 마운트 결과입니다 |
| 호스트 호출 | 백엔드가 가상 호스트로 발행한 알림·감사 기록, 권한 거부, 로그입니다 |
부여 표와 가상 호스트 데이터는 서버 하나를 여러 브라우저 창이 함께 봅니다. 사용자·테마 같은 보기 설정은 브라우저마다 따로입니다.
6. 포탈과 같게 동작하는 것
- 로그인 쿠키가 없는
/bp/요청은 컨트롤러에 닿기 전에 401입니다(backend-guide.md §3). - 읽기 권한이 없는 App은 메뉴에서 감추고, 그 주소로 들어오면 위젯을 마운트하지 않습니다.
- 카드 조작은 이 BP가 소유하고 매니페스트에 선언한 카드만 받습니다.
toast와confirm은 위젯의 Shadow DOM 밖, 셸 레이어에 그립니다.- 알림 수신자는 명부에 있는 사용자로 거릅니다(가상 호스트의
strictUsers). bp-manifest.yaml의version이 처음 나타나면onInstall을 실행합니다.- BP가
@starj-portal/bp-backend-sdk를 직접 설치했으면 그 사본의 가상 호스트를 씁니다. BP가 빌드 기준으로 삼는 계약 버전과 같아야, 그 버전에 없는 표면을 호출하는 실수를 개발 셸에서 찾을 수 있기 때문입니다. 기동 로그에 어느 사본을 썼는지 표시됩니다.
7. 개발 서버의 포탈에서 확인할 것
개발 셸은 다음 항목을 흉내 내지 않습니다.
- IdP 로그인, Token Exchange, Destination으로 외부 시스템에 접속하는 경로
- 운영자가 실제로 구성한 메뉴 배치와 권한
- PostgreSQL 방언, BP 전용 스키마와 계정 분리
- 다른 BP와의
services.require연동, 다른 BP 화면으로의 이동(기록만 남깁니다) uploadFile(넘기지 않습니다), 도메인 전환, 홈 화면의 카드 렌더링- Portal Shell의 실제 레이아웃과 테마 세트. 테마 토큰은 포탈 디자인 시스템 토큰의 사본입니다