CBA — Backstage 인증 어소시에이트 · 앱 저장소와 플러그인 만들기 · 실습
Backstage 앱 저장소와 플러그인 배선
목표
create-app 이 만들어 내는 Backstage 앱 저장소의 구조를 직접 세우고, 사내 플러그인을 하나 만들어 프런트엔드와 백엔드 양쪽에 배선합니다. 실습 파드는 인터넷이 막혀 있어 노드 의존성을 받을 수 없으므로 빌드는 하지 않고 구조와 배선만 다룹니다.
왜 중요한가
Backstage 를 쓴다는 것은 여러분 소유의 모노레포를 하나 갖는다는 뜻입니다. 그래서 "어느 파일을 고쳐야 하는가" 에 답하지 못하면 아무것도 커스터마이즈할 수 없고, 화면에서 찾을 수 있는 답도 없습니다. 특히 세 가지가 실무에서 반복해 사람을 막습니다. 첫째, package.json 의 역할 표시 하나가 그 패키지의 빌드 방식을 정합니다. 둘째, 새 백엔드 시스템에서는 플러그인과 모듈이 다른 것이고, 이름에 module 이 들어간 것은 짝이 되는 플러그인 없이는 아무 일도 하지 않습니다. 셋째, 엔티티 페이지에 탭만 붙이고 앱 라우트를 등록하지 않으면 탭은 보이는데 눌렀을 때 빈 화면이 뜨고 오류도 나오지 않습니다. 이 실습은 그 세 자리를 손으로 만들어 봅니다.
단계
1. /root/cba-app/package.json 을 작성하세요 — private: true, workspaces.packages 에 packages/* 와 plugins/* 두 개, scripts 에 dev·build:all·tsc·test:all 네 개. build:all 은 backstage-cli repo build 로 시작하는 명령, test:all 은 backstage-cli repo test 로 시작하는 명령입니다.
2. /root/cba-app/packages/app/package.json 을 작성하세요 — name: app, backstage.role: frontend, scripts.start 는 backstage-cli package start. /root/cba-app/packages/backend/package.json 도 작성하세요 — name: backend, backstage.role: backend, main 은 dist/ 로 시작하는 경로, scripts.start 는 같은 명령입니다.
3. /root/cba-app/packages/backend/src/index.ts 를 작성하세요 — @backstage/backend-defaults 에서 createBackend 를 가져와 호출하고, backend.add(import('...')) 를 정확히 일곱 번 씁니다. 등록할 패키지는 @backstage/plugin-app-backend, @backstage/plugin-catalog-backend, @backstage/plugin-catalog-backend-module-github, @backstage/plugin-scaffolder-backend, @backstage/plugin-techdocs-backend, @backstage/plugin-auth-backend, @backstage/plugin-auth-backend-module-github-provider 입니다. 마지막에 backend.start() 를 부르고, createRouter·PluginEnvironment·apiRouter 같은 구 백엔드 방식의 흔적은 남기지 마세요.
4. /root/cba-app/plugins/oncall/package.json 을 작성하세요 — name: @internal/plugin-oncall, backstage.role: frontend-plugin, sideEffects: false, dependencies 에 @backstage/core-plugin-api. /root/cba-app/plugins/oncall-backend/package.json 도 작성하세요 — name: @internal/plugin-oncall-backend, backstage.role: backend-plugin, main 은 dist/ 로 시작하는 경로, dependencies 에 @backstage/backend-plugin-api.
5. /root/cba-app/plugins/oncall/src/ 아래 세 파일을 작성하세요. routes.ts 는 createRouteRef 로 id: 'oncall' 인 rootRouteRef 를 만들어 내보냅니다. plugin.ts 는 ./routes 에서 그 참조를 가져와 createPlugin 으로 oncallPlugin 을 만들고, createRoutableExtension 으로 OncallPage 를 만들되 mountPoint: rootRouteRef 를 겁니다. plugin.ts 안에서 createRouteRef 를 다시 부르지 마세요. index.ts 는 oncallPlugin 과 OncallPage 두 개를 다시 내보냅니다.
6. /root/cba-app/packages/app/src/components/catalog/EntityPage.tsx 를 작성하세요 — @internal/plugin-oncall 에서 OncallPage 를 가져오고, isKind('component') 조건 안에서 EntityLayout.Route 로 path="/oncall" title="On-call" 탭을 답니다. /root/cba-app/packages/app/src/App.tsx 도 작성하세요 — 같은 플러그인을 가져와 path="/oncall" 라우트에 <OncallPage /> 를 element 로 겁니다.
7. /root/cba-app/packages.txt 에 packages/ 와 plugins/ 아래 모든 패키지의 이름과 역할을 이름=역할 형식으로 한 줄에 하나씩, 중복 없이 정렬해 적으세요.
8. /root/cba-app/.github/workflows/ci.yaml 을 작성하세요 — pull_request 트리거, jobs.build.runs-on: ubuntu-latest, steps 는 정확히 여섯 개입니다. 첫째는 actions/checkout, 둘째는 actions/setup-node, 그다음 네 개는 순서대로 yarn install --immutable, yarn tsc, yarn build:all, yarn test:all 을 run 으로 실행합니다.
참고
- 역할 값은
frontend,backend,frontend-plugin,backend-plugin네 가지를 씁니다. - 이름에
-module-이 들어간 백엔드 패키지는 짝이 되는 플러그인의 확장점에 끼우는 조각입니다. - 흔한 실수 1: 탭만 붙이고 앱 라우트를 빠뜨리는 것. 화면에 오류가 없어서 원인을 찾기 어렵습니다.
- 흔한 실수 2: 라우트 참조를
plugin.ts안에서 만드는 것. 순환 임포트를 막으려고 파일을 나눈 것이므로 의미가 사라집니다. - 흔한 실수 3: CI 에서
--immutable을 빼는 것. 잠금 파일이 조용히 바뀌면 어제 통과한 커밋이 오늘 다르게 빌드됩니다.
단계 8개
- 워크스페이스 루트
- 앱 두 개와 역할
- 새 백엔드 시스템 배선
- 사내 플러그인 패키지
- 플러그인 소스 세 파일
- 엔티티 페이지 탭과 앱 라우트
- 패키지 인벤토리
- CI 게이트