بنقرة واحدة
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/ 디렉토리