Files
tradeing/frontend/lib/api.ts
T
chpark c4e6aab7b2 React + FastAPI 풀 마이그레이션 — Streamlit 제거
- backend/ — FastAPI + JWT + 모든 REST 엔드포인트
- frontend/ — Next.js 14 + Tailwind + 7페이지 (대시보드/트레이드/거래소/자동매매/설정/내정보/로그인)
- core_logic.py — 신호계산/알림 로직 분리 (기존 app_streamlit.py 에서 추출)
- users_db.py + bcrypt 인증, exchange_keys.py + Fernet 암호화
- trades_db.py — 진입/청산 lifecycle 추적, signal_events raw 로그
- settings_db.py — 모든 운영 파라미터 DB 영속 저장 (RSI/거래량/펀딩비 임계값 포함)
- docker-compose: frontend / backend / postgres + Traefik 라우팅
- assets/logo.svg — JUNGGOMOA 그라디언트 로고

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:27:11 +09:00

42 lines
1.5 KiB
TypeScript

// 클라이언트 API wrapper. JWT 는 localStorage 에 보관.
const TOKEN_KEY = 'jm_token';
export function getToken(): string | null {
if (typeof window === 'undefined') return null;
return localStorage.getItem(TOKEN_KEY);
}
export function setToken(t: string) { localStorage.setItem(TOKEN_KEY, t); }
export function clearToken() { localStorage.removeItem(TOKEN_KEY); }
async function request<T = any>(path: string, opts: RequestInit = {}): Promise<T> {
const token = getToken();
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...(opts.headers as any),
};
if (token) headers['Authorization'] = `Bearer ${token}`;
const res = await fetch(path, { ...opts, headers });
if (res.status === 401) {
clearToken();
if (typeof window !== 'undefined' && window.location.pathname !== '/login') {
window.location.href = '/login';
}
throw new Error('unauthorized');
}
if (!res.ok) {
const text = await res.text();
let msg = text;
try { msg = JSON.parse(text).detail || text; } catch {}
throw new Error(msg || `${res.status}`);
}
if (res.status === 204) return undefined as any;
return res.json();
}
export const api = {
get: <T = any>(p: string) => request<T>(p),
post: <T = any>(p: string, body: any) => request<T>(p, { method: 'POST', body: JSON.stringify(body) }),
put: <T = any>(p: string, body: any) => request<T>(p, { method: 'PUT', body: JSON.stringify(body) }),
delete: <T = any>(p: string) => request<T>(p, { method: 'DELETE' }),
};