diff --git a/.agents/skills/dev-auto-pipeline/SKILL.md b/.agents/skills/dev-auto-pipeline/SKILL.md index c5342da..2fb6312 100644 --- a/.agents/skills/dev-auto-pipeline/SKILL.md +++ b/.agents/skills/dev-auto-pipeline/SKILL.md @@ -47,6 +47,8 @@ description: 기능 개발/버그 수정/리팩토링 같은 구현 요청에서 [3. 리팩토링/성능/가독성] - ... +- 파일 상단 역할 주석 반영 여부 +- 핵심 입력 데이터 흐름 추적표 포함 여부 [4. 테스트] - ... @@ -54,4 +56,9 @@ description: 기능 개발/버그 수정/리팩토링 같은 구현 요청에서 [5. 계획 대비 완료체크] - 완료/부분 완료/미완료 - 최종 판정: 배포 가능/보완 필요 + +[6. 핵심 입력 흐름 추적표] +- 입력값: (예: 전략 프롬프트) +- UI 입력 -> 핸들러 -> 훅/서비스 -> API -> route -> provider -> 결과 반영 +- 각 단계는 파일/라인 링크 포함 ``` diff --git a/.agents/skills/dev-refactor-polish/SKILL.md b/.agents/skills/dev-refactor-polish/SKILL.md index f21b70d..051b26a 100644 --- a/.agents/skills/dev-refactor-polish/SKILL.md +++ b/.agents/skills/dev-refactor-polish/SKILL.md @@ -96,12 +96,75 @@ description: 구현 완료 직후 가독성·데이터 흐름·성능을 다듬 1. 주석 보강 작업은 코드 로직(타입/런타임/동작/변수명/import)을 바꾸지 않는다. 2. 함수/API/쿼리 주석은 `[목적]`, `[사용처]`, `[데이터 흐름]` 중심으로 쉽게 쓴다. -3. 상태(`useState`, `useRef`, store)는 "화면에 어떤 영향을 주는지" 한 줄 주석을 단다. -4. 복잡한 로직/핸들러는 `1.`, `2.`, `3.` 단계 주석으로 흐름을 나눈다. +3. 상태(`useState`, `useRef`, `useMemo`, store 파생 상태)는 반드시 `[State]`, `[Ref]` 형식으로 역할 주석을 단다. + - 예: `// [State] 자동매매 실행 중 여부 (배너/버튼 상태에 사용)` + - 예: `// [Ref] 마지막 신호 요청 시각 (요청 과다 방지용)` +4. 복잡한 로직/핸들러는 반드시 `[Step 1]`, `[Step 2]`, `[Step 3]` 형식으로 흐름을 나눈다. + - 예: `// [Step 1] 입력값 유효성 검증` 5. 긴 JSX는 화면 구역 주석으로 나눠서 읽기 쉽게 만든다. - - 예: `{/* ===== 1. 상단: 페이지 제목 및 액션 버튼 ===== */}` -6. `@param`, `@see`, `@remarks` 같은 딱딱한 TSDoc 태그는 강제하지 않는다. -7. 결과 기준은 "주니어가 5분 내 파악 가능한지"로 잡는다. + - 예: `{/* ========== 1. 상단: 상태/액션 영역 ========== */}` +6. 데이터 흐름이 중요한 입력(UI prompt, 검색어, 주문 설정값)은 입력 지점에 "어디 API로 가는지"를 한 줄로 명시한다. + - 예: `// [데이터 흐름] textarea -> patchSetupForm -> compile API -> AI provider(OpenAI/CLI)` +7. `@param`, `@see`, `@remarks` 같은 딱딱한 TSDoc 태그는 강제하지 않는다. +8. 결과 기준은 "주니어가 5분 내 파악 가능한지"로 잡는다. + +### 파일 상단 역할 주석 (필수) + +1. 핵심 파일(`components`, `hooks`, `apis`, `lib`, `route.ts`)은 import 위(또는 `"use client"` 바로 아래)에 파일 역할 주석을 단다. +2. 형식은 아래 템플릿을 따른다. + +```ts +/** + * [파일 역할] + * 이 파일이 시스템에서 맡는 역할 + * + * [주요 책임] + * - 책임 1 + * - 책임 2 + * - 책임 3 + */ +``` + +### 흐름 추적 문서화 규칙 (필수) + +1. 사용자가 "이 값이 어디로 가는지"를 물으면 반드시 함수 체인을 파일/라인으로 답한다. +2. 형식은 `UI 입력 -> 핸들러 -> 훅/서비스 -> API 클라이언트 -> route -> provider -> 결과 반영` 순서를 유지한다. +3. 최종 답변에 최소 1개 이상의 "핵심 입력 흐름 추적표"를 포함한다. +4. 라인 표기는 `절대경로:라인` 링크 형식으로 제공한다. + +### 필수 주석 패턴 (컴포넌트/훅) + +1. State/Ref 선언부 + +```ts +// [State] 자동매매 설정 모달 열림 여부 +const [panelOpen, setPanelOpen] = useState(false); + +// [Ref] 최근 가격 캐시 (신호 생성용) +const recentPricesRef = useRef([]); +``` + +2. 핸들러/비즈니스 함수 + +```ts +const handleStart = async () => { + // [Step 1] 필수 입력값 검증 + // [Step 2] 전략 컴파일/검증 API 호출 + // [Step 3] 세션 시작 및 UI 상태 갱신 +}; +``` + +3. JSX 섹션 구분 + +```tsx +return ( + <> + {/* ========== 1. 상단: 상태 및 액션 ========== */} + {/* ========== 2. 본문: 설정 입력 영역 ========== */} + {/* ========== 3. 하단: 검증/시작 버튼 영역 ========== */} + +); +``` ## UI/브랜드/문구 규칙 @@ -134,6 +197,10 @@ description: 구현 완료 직후 가독성·데이터 흐름·성능을 다듬 [데이터 흐름 정리] - 어느 UI -> A 함수 호출 -> B 함수 호출 -> 리턴값 반영 +[핵심 입력 흐름 추적표] +- 입력값: (예: 전략 프롬프트) +- [파일:라인] -> 함수 -> 다음 호출 + [회귀 위험 점검] - ... ``` diff --git a/.env.example b/.env.example index 54fb7c7..aef12c7 100644 --- a/.env.example +++ b/.env.example @@ -7,3 +7,36 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY= # 세션 타임아웃(분 단위) NEXT_PUBLIC_SESSION_TIMEOUT_MINUTES=30 + +# 자동매매/AI 설정 +OPENAI_API_KEY= +AUTOTRADE_AI_MODEL=gpt-4o-mini +# auto | openai_api | subscription_cli | rule_fallback +AUTOTRADE_AI_MODE=auto +# subscription_cli 모드에서 사용할 CLI 선택값(auto | gemini | codex) +AUTOTRADE_SUBSCRIPTION_CLI=auto +# subscription_cli 공통 모델(옵션): vendor 전용 설정이 없을 때 fallback으로 사용 +AUTOTRADE_SUBSCRIPTION_CLI_MODEL= +# Codex CLI 전용 모델(옵션): 예) gpt-5-codex +AUTOTRADE_CODEX_MODEL= +# Gemini CLI 전용 모델(옵션): 예) auto | pro | flash | flash-lite | gemini-2.5-pro +AUTOTRADE_GEMINI_MODEL= +# subscription_cli 호출 타임아웃(ms) +AUTOTRADE_SUBSCRIPTION_CLI_TIMEOUT_MS=60000 +# subscription_cli 디버그 로그(1/true/on): Next 서버 콘솔에 CLI 호출/시도 로그 출력 +AUTOTRADE_SUBSCRIPTION_CLI_DEBUG=0 +# Codex CLI 실행 파일 경로(옵션): PATH 인식 문제 시 절대경로 지정 +AUTOTRADE_CODEX_COMMAND= +# Gemini CLI 실행 파일 경로(옵션): PATH 인식 문제 시 절대경로 지정 +AUTOTRADE_GEMINI_COMMAND= +AUTOTRADE_HEARTBEAT_TTL_SEC=90 +AUTOTRADE_MAX_DAILY_ORDERS_DEFAULT=20 +AUTOTRADE_CONFIDENCE_THRESHOLD_DEFAULT=0.65 +AUTOTRADE_DEV_BYPASS_TOKEN=autotrade-dev-bypass +# 워커 인증 토큰: 직접 랜덤 문자열 생성해서 앱/워커에 동일하게 넣어 주세요. +# 예) openssl rand -hex 32 +AUTOTRADE_WORKER_TOKEN=autotrade-worker-local +# 워커 점검 주기(ms) +AUTOTRADE_WORKER_POLL_MS=5000 +# 워커가 호출할 Next.js 앱 주소 +AUTOTRADE_APP_URL=http://127.0.0.1:3001 diff --git a/AGENTS.md b/AGENTS.md index 1093eee..288b995 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,3 +15,11 @@ 4. `dev-test-gate` 5. `dev-plan-completion-checker` - 단순 설명/문서 요약/잡담 요청에는 파이프라인 스킬을 강제하지 않는다. + +## 설명 방식 규칙 + +- 사용자 설명은 어려운 용어보다 쉬운 한국어를 우선 사용한다. +- 기술 용어를 써야 할 때는 바로 아래 줄에 쉬운 말로 다시 풀어쓴다. +- 데이터 흐름 설명은 항상 `입력 -> 처리 -> 결과` 순서의 짧은 단계로 말한다. +- 사용자가 헷갈린 상황에서는 추상 설명보다 "지금 화면에서 확인할 것"을 먼저 안내한다. +- 요청/응답 설명 시에는 핵심 필드 3~5개만 먼저 보여주고, 필요 시 상세를 추가한다. diff --git a/app/(home)/page.tsx b/app/(home)/page.tsx index be6aeee..e54982b 100644 --- a/app/(home)/page.tsx +++ b/app/(home)/page.tsx @@ -21,21 +21,21 @@ interface StartStep { const START_STEPS: StartStep[] = [ { step: "01", - title: "1분이면 충분해요", + title: "앱키 연결, 1분이면 끝", description: - "복잡한 서류나 방문 없이, 쓰던 계좌 그대로 안전하게 연결할 수 있어요.", + "복잡한 절차 없이, 지금 쓰는 계좌로 바로 시작할 수 있어요.", }, { step: "02", - title: "내 스타일대로 골라보세요", + title: "투자금/손실선만 입력하세요", description: - "공격적인 투자부터 안정적인 관리까지, 나에게 딱 맞는 전략이 준비되어 있어요.", + "어렵게 계산할 필요 없이, 내가 감당 가능한 금액만 정하면 돼요.", }, { step: "03", - title: "이제 일상을 즐기세요", + title: "신호 확인 후 자동 실행", description: - "차트는 JOORIN-E가 하루 종일 보고 있을게요. 마음 편히 본업에 집중하세요.", + "차트 감시는 JOORIN-E가 맡고, 당신은 중요한 순간만 확인하면 됩니다.", }, ]; @@ -50,7 +50,7 @@ export default async function HomePage() { } = await supabase.auth.getUser(); const primaryCtaHref = user ? AUTH_ROUTES.DASHBOARD : AUTH_ROUTES.SIGNUP; - const primaryCtaLabel = user ? "시작하기" : "지금 무료로 시작하기"; + const primaryCtaLabel = user ? "내 전략 시작하기" : "무료로 시작하기"; return (
@@ -69,21 +69,21 @@ export default async function HomePage() {
- 자동 매매의 새로운 기준, JOORIN-E + 처음 하는 자동매매도 쉽게, JOORIN-E

- 주식, 이제는 + 복잡한 차트 대신
- 마음 편하게 하세요. + 쉬운 자동매매로 시작하세요.

- 어렵고 불안한 주식 투자, 혼자 고민하지 마세요. + 감으로 사고파는 불안한 투자, 이제 줄여보세요.
- 검증된 원칙으로 24시간 당신의 자산을 지켜드릴게요. + 예산과 손실선을 먼저 지키는 방식으로, 주식을 더 편하게 도와드립니다.

@@ -111,14 +111,14 @@ export default async function HomePage() {

- 설계부터 실행까지 + 주식이 처음이어도
- 단 3단계면 끝. + 3단계면 준비 끝.

- 복잡한 계산과 감시는 JOORIN-E가 대신할게요. + 앱키 연결 -> 투자금/손실선 설정 -> 시작 버튼.
- 당신은 가벼운 마음으로 '시작' 버튼만 누르세요. + 어려운 용어 없이, 필요한 것만 빠르게 설정해보세요.

@@ -166,20 +166,18 @@ export default async function HomePage() {

- 내 계좌 정보, 서버에 저장되지 않나요? + 계좌 키/정보, 어디에 저장되나요?

- 네, 절대 저장하지 않으니 안심하세요. + 핵심 정보는 내 브라우저에만 저장됩니다.
- JOORIN-E는 여러분의 계좌 비밀번호와 API 키를 서버로 전송하지 - 않습니다. + JOORIN-E는 계좌 비밀번호를 저장하지 않으며,
- 모든 중요 정보는 여러분의 기기(브라우저)에만 암호화되어 - 저장되며, + API 키도 장기 보관하지 않도록 최소 범위로만 사용합니다.
- 매매 실행 시에만 증권사와 직접 통신하는 데 사용됩니다. + 매매 요청은 필요한 순간에만 증권사와 통신합니다.

@@ -190,9 +188,9 @@ export default async function HomePage() {

- 더 이상 미루지 마세요. + 감으로 매매하던 습관에서
- 지금 바로 경험해보세요. + 오늘부터 규칙 매매로 바꿔보세요.

+ + {!isRunning ? ( + + ) : ( + + )} +
+
+ + {/* ===== 3. 상태 카드 영역 ===== */} +
+ + + + +
+ + {/* ===== 4. 최근 로그 요약 ===== */} + {(logs.length > 0 || isRunning || isStopping) && ( +
+
+

+ 실시간 자동매매 안내 +

+
+ {isLogPanelOpen && ( + + )} + +
+
+ +
+

+ 입력: + {" "} + {latestPromptText || "아직 AI 요청 전입니다."} + {(isRunning || isStopping || isSignalResponsePending) && ( + + )} +

+ {latestRequestDataText && ( +

+ 요청 데이터: + {" "} + {latestRequestDataText} +

+ )} +

+ 답변: + {" "} + {latestAiReasonText ?? "아직 응답이 없습니다."} + {isSignalResponsePending && ( + + (새 분석 진행 중...) + + )} +

+
+ + {isLogPanelOpen && ( +
    + {logs.slice(0, 10).map((log) => { + const friendly = toFriendlyLog(log); + return ( +
  • +
    + + {new Date(log.createdAt).toLocaleTimeString("ko-KR")} + + + {log.level.toUpperCase()} + + {log.stage && ( + + {resolveLogStageLabel(log.stage)} + + )} +
    + +

    + {friendly.primary} +

    + {friendly.secondary && ( +

    + {friendly.secondary} +

    + )} + + {showTechnicalLog && log.detail && ( +
    +                            {log.detail}
    +                          
    + )} +
  • + ); + })} +
+ )} +
+ )} +
+ + + {/* ===== 5. 설정 모달 ===== */} + {panelOpen && ( +
+
+ + +

+ 자동매매 간편 설정 +

+

+ 처음 쓰셔도 쉽게 맞출 수 있게 핵심만 모았습니다. +

+ +
+ + + +
+ +
+ + + +
+ +
+
+ {/* 좌측: 판단 소스/전략 설정 */} + {setupTab === "ai" && ( + <> + + + +

+ {resolveFriendlyAiModeDescription(setupForm.aiMode)} +

+ + {shouldShowSubscriptionCliConfig && ( +
+

+ 모델 선택 +

+ + + + {setupForm.subscriptionCliVendor === "auto" ? ( +

+ 자동 선택은 Codex를 먼저 시도하고, 안 되면 Gemini를 시도합니다. +

+ ) : ( + <> + + {(selectedCliModelSelectValue === "__custom__" || + normalizedSubscriptionCliModel.length > 0) && ( + + handleSubscriptionCliModelInputChange(event.target.value) + } + placeholder="예) gpt-5.4, gpt-5.3-codex, gpt-5-codex-mini" + /> + )} + + )} +
+ )} + + )} + + {setupTab === "quick" && ( + <> + + + {/* [프롬프트 흐름] 1) textarea 입력 -> handlePromptChange -> patchSetupForm(prompt) */} + {/* [프롬프트 흐름] 2) 시작/검증 클릭 -> startAutotrade or previewValidation -> prepareStrategy */} + {/* [프롬프트 흐름] 3) prepareStrategy -> compileAutotradeStrategy -> /api/autotrade/strategies/compile */} +