원클릭으로
scc-app-add-screen
React Native 앱에 새 화면을 추가합니다. ScreenLayout, Navigation 등록, SccXxx 컴포넌트 사용을 포함합니다.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
React Native 앱에 새 화면을 추가합니다. ScreenLayout, Navigation 등록, SccXxx 컴포넌트 사용을 포함합니다.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
SCC 앱 OTA 배포 + 웹 배포 절차. "OTA 배포해줘", "앱 출시", "웹 배포", "web-deploy", "프로덕션에 올려줘" 같은 명시적 배포 요청 시에만 사용. 배포는 one-way door — 이 skill의 절차를 벗어나 임의로 배포하지 않는다.
Notion에 작성한 콘텐츠를 web.staircrusher.club/articles 정적 페이지로 발행해 검색엔진(SEO) + AI답변엔진(AEO/GEO)에 노출시킨다. "노션 글 발행해줘", "아티클 올려줘", "articles 갱신", "노션 콘텐츠 검색에 걸리게", "article list DB 렌더링" 같은 요청 시 사용. 사람은 Notion에 제목+본문만 쓰고, 이 스킬이 메타데이터(slug/summary/ogImage/tags/faq)를 LLM으로 생성해 DB에 라이트백한 뒤, 결정론적 노드 스크립트로 본문을 HTML로 변환한다. last_edited_time 기반 incremental — 신규/변경/삭제 문서만 처리해 토큰을 아낀다.
SCC 앱 작업 후 검증 절차 + 네이티브(iOS/Android) 코드 규칙. 코드 변경 후 lint/tsc 검증, ios/android 디렉토리 변경 시 Release 빌드 검증, 네이티브 모듈(RCTBridgeModule/ReactContextBaseJavaModule) 작성 규칙을 다룬다. "네이티브 모듈 추가", "iOS 빌드 깨져", "release 빌드 검증", "브릿지 메서드", "CI에서만 빌드 실패", "Bridgeless" 같은 작업/증상 시, 그리고 scc-app 코드 변경을 마무리할 때 사용.
뿌클로드 페이지 개발. 새 venue 추가, 기존 venue 수정, Figma 디자인 반영 시 사용.
새로운 뿌클로드 페이지를 추가합니다. Figma 디자인 분석, 데이터 추가, 브라우저 렌더링 검증을 포함합니다.
| name | scc-app-add-screen |
| description | React Native 앱에 새 화면을 추가합니다. ScreenLayout, Navigation 등록, SccXxx 컴포넌트 사용을 포함합니다. |
src/screens/
└── {ScreenName}/
├── index.ts # Export
├── {ScreenName}.tsx # 메인 컴포넌트
└── sections/ # (선택) 섹션 컴포넌트
import React, { useCallback } from 'react';
import { ScrollView } from 'react-native';
import styled from 'styled-components/native';
import { ScreenProps } from '@/navigation/Navigation.screens';
import { ScreenLayout } from '@/components/ScreenLayout';
import { SccButton, SccPressable } from '@/components/atoms';
export interface {ScreenName}Params {
// route params 정의
}
export default function {ScreenName}({
route,
navigation
}: ScreenProps<'{ScreenName}'>) {
return (
<ScreenLayout isHeaderVisible={true}>
<ScrollView>
<Container>
{/* 컨텐츠 구현 */}
</Container>
</ScrollView>
</ScreenLayout>
);
}
// Styled components
const Container = styled.View`
padding: 16px;
`;
src/navigation/Navigation.screens.ts:
// 1. Import 추가
import {ScreenName}, { {ScreenName}Params } from '@/screens/{ScreenName}';
// 2. ScreenParams 타입에 추가
export type ScreenParams = {
{ScreenName}: {ScreenName}Params;
// ... 기존 화면들
};
// 3. MainNavigationScreens 배열에 추가
export const MainNavigationScreens = [
{
name: '{ScreenName}',
component: {ScreenName},
options: {
headerShown: true,
headerTitle: '화면 제목',
// presentation: 'modal', // 모달인 경우
},
},
// ... 기존 화면들
];
export { default } from './{ScreenName}';
export type { {ScreenName}Params } from './{ScreenName}';
모달, 확인 다이얼로그, 오버레이는 BottomSheet 컴포넌트 사용:
// 확인 모달
<BottomSheet isVisible={isVisible} onPressBackground={handleClose}>
<ContentsContainer>
<Title>Confirm Action</Title>
<BottomSheetButtonGroup
layout={BottomSheetButtonGroupLayout.HORIZONTAL_1X2}
positiveButton={{text: 'Confirm', onPressed: handleConfirm}}
negativeButton={{text: 'Cancel', onPressed: handleCancel}}
/>
</ContentsContainer>
</BottomSheet>
// 옵션 선택
<BottomSheet isVisible={isVisible}>
<OptionSelector>
{options.map(option => (
<SccButton
key={option.id}
text={option.text}
onPress={() => handleSelect(option)}
elementName={`option-${option.id}`}
/>
))}
</OptionSelector>
</BottomSheet>
Logger.logElementView/logElementClick 직접 호출 금지 (TS 에러 + ESLint warn, src/logging/*·useSccEventLogging.ts만 예외). 컴포넌트에서는 반드시 useLogger() hook 사용:
import {useLogger} from '@/logging/useLogger';
const logger = useLogger();
logger.logElementView('event_name', {custom_param: 'value'});
// → globalLogParams + route.name 자동 주입
// useCallback/useEffect 안에서 사용 시 — loggerRef 패턴
// useLogger()는 매 렌더마다 새 객체를 반환하므로 deps에 넣으면 매번 재생성 → 자식 리렌더 유발.
// ref로 감싸서 "항상 최신값이지만 deps를 트리거하지 않는" 안정 참조를 만든다.
const logger = useLogger();
const loggerRef = useRef(logger);
loggerRef.current = logger; // 매 렌더마다 최신 logger로 갱신
const handleScroll = useCallback(() => {
loggerRef.current.logElementView('section', {id: sectionId});
}, [sectionId]); // logger가 deps에 없어도 항상 최신값
섹션/화면 단위로 공통 로깅 파라미터(예: displaySectionName)를 하위 컴포넌트에 자동 전파할 때 사용. 개별 logParams에 직접 넣지 말 것:
import {LogParamsProvider, useLogParams} from '@/logging/LogParamsProvider';
// 섹션 컴포넌트에서 Provider로 감싸기
export default function MySection() {
return (
<LogParamsProvider params={{displaySectionName: '섹션명'}}>
{/* 하위 SccPressable, SccButton 등에 자동 적용됨 */}
<SccPressable elementName="my-button" logParams={{buttonId: 1}} />
</LogParamsProvider>
);
}
// 직접 Logger 호출 시 useLogParams()로 전역 params 병합
const globalLogParams = useLogParams();
Logger.logElementClick({
name: 'custom-event',
currScreenName: 'MyScreen',
extraParams: {...globalLogParams, customParam: 'value'},
});
element_view는 마운트 시, element_click은 press 시 자동 로깅. 전역 registry가 같은 elementName+params 중복을 감지원격 URL 이미지는 <Image source={{uri}}> 직접 사용 금지 — SccRemoteImage 사용 (Image.getSize + 메모리 캐시 + 비율 자동 계산 내장):
import SccRemoteImage from '@/components/SccRemoteImage';
// width 지정 → height 원본 비율로 자동 계산
<SccRemoteImage imageUrl={imageUrl} style={{width: 300}} resizeMode="cover" />
// height 고정 모드 (width 자동 계산)
<SccRemoteImage imageUrl={imageUrl} fixedHeight={200} resizeMode="cover" />
wrapperBackgroundColor로 로딩 중 배경색 제어 (null이면 투명)전환 사이에 중간 프레임(다른 색 화면)이 잠깐 보이면 배경색이 아니라 타이밍을 고친다:
contentStyle 등)은 증상만 가리는 defensive fix — 원인은 비원자적 네비게이션 dispatchpop() + pop() + navigate())를 단일 액션으로 합친다: navigation.popTo(name, params) (v7 native-stack), CommonActions.reset, StackActions.pop(n) + params mergeSccButton, SccPressable 등 사용elementName prop 필수 - 고유하고 의미있는 이름logParams로 추가 로깅 데이터ScreenLayout 컴포넌트 사용isHeaderVisible 설정 (Navigation options와 일치)isKeyboardAvoidingView={true}@/generated-sources/openapi의 타입 사용useQuery, useMutation) 사용get_design_context로 디자인 분석yarn lint # ESLint 통과
yarn tsc --noEmit # TypeScript 통과
CLAUDE.md - 전체 개발 가이드라인src/screens/ 디렉토리