// D2 커뮤니티(종목게시판·예측·트랙레코드) 도메인 타입 // Backend Application/Features/Api/Forum/StockBoard/*/Response.cs + TrackRecord/*/Response.cs 대응. // ⚠️ D2 enum 은 숫자로 직렬화됨 (JsonStringEnumConverter 미적용 — 확인 완료). // 응답 DTO 는 숫자 코드(direction/status/tierCode)와 라벨 문자열(directionLabel/statusLabel/tier)을 함께 내려준다. // 색상은 숫자 코드로, 표시 텍스트는 라벨 문자열을 사용한다. 라벨/색 맵은 이 파일 하단에 한 곳으로 모은다. // ── 예측 방향 (Domain PredictionDirection: 1 Up / 2 Down) ── export const PredictionDirection = { Up: 1, Down: 2 } as const; export type PredictionDirectionValue = (typeof PredictionDirection)[keyof typeof PredictionDirection]; // ── 예측 상태 (Domain PredictionStatus: 0 Pending / 1 Hit / 2 Miss / 3 Void) ── export const PredictionStatus = { Pending: 0, Hit: 1, Miss: 2, Void: 3 } as const; export type PredictionStatusValue = (typeof PredictionStatus)[keyof typeof PredictionStatus]; // ── 트랙레코드 배지 등급 (Domain TrackRecordTier: 0 None / 1 Bronze / 2 Silver / 3 Gold / 4 GoldAnt) ── export const TrackRecordTier = { None: 0, Bronze: 1, Silver: 2, Gold: 3, GoldAnt: 4 } as const; export type TrackRecordTierValue = (typeof TrackRecordTier)[keyof typeof TrackRecordTier]; // ── 예측 기간 (5 또는 20 영업일만 허용, Backend CreatePost.AllowedHorizonDays) ── export const PredictionHorizon = { Short: 5, Long: 20 } as const; export type PredictionHorizonValue = (typeof PredictionHorizon)[keyof typeof PredictionHorizon]; // ── GET /api/stock-boards/{code}/posts ── export interface StockBoardStatsHeader { stockCode: string; stockName: string|null; posts: number; comments: number; lastPostAt: string|null; } export interface StockBoardPostRow { num: number; id: number; stockCode: string; subject: string; thumbnail: string|null; name: string|null; sid: string|null; hasPrediction: boolean; views: number; likes: number; comments: number; images: number; updatedAt: string|null; createdAt: string; } export interface StockBoardPostsResponse { total: number; stats: StockBoardStatsHeader; list: StockBoardPostRow[]; } // ── GET /api/stock-boards/trending ── export interface TrendingStockRow { rank: number; stockCode: string; stockName: string|null; closePrice: number|null; changeRate: number|null; posts: number; score: number; } export interface TrendingStocksResponse { list: TrendingStockRow[]; } // ── GET /api/posts/{id}/prediction ── export interface PostPredictionResponse { postID: number; memberID: number; stockCode: string; stockName: string|null; direction: PredictionDirectionValue; directionLabel: string; basePrice: number; targetPrice: number|null; horizonDays: number; dueDate: string; status: PredictionStatusValue; statusLabel: string; settledPrice: number|null; settledAt: string|null; createdAt: string; } // ── GET /api/members/{sid}/track-record ── export interface TrackRecordResponse { sid: string; hasRecord: boolean; tier: string; tierCode: TrackRecordTierValue; hitRate: number; predictions: number; hits: number; misses: number; voids: number; currentStreak: number; bestStreak: number; } // ── GET /api/track-records/leaderboard ── export interface LeaderboardRow { rank: number; sid: string; name: string; tier: string; tierCode: TrackRecordTierValue; hitRate: number; predictions: number; hits: number; misses: number; bestStreak: number; } export interface LeaderboardResponse { total: number; period: string; list: LeaderboardRow[]; } // ── POST /api/boards/stock/posts (body) ── export interface CreateStockPostPrediction { direction: PredictionDirectionValue; horizonDays: PredictionHorizonValue; targetPrice?: number|null; } export interface CreateStockPostRequest { stockCode: string; subject: string; content: string; prediction?: CreateStockPostPrediction|null; } export interface CreateStockPostResponse { id: number; } // ── GET /api/members/equipped-items?ids= (작성자 지위 배지) ── export interface EquippedItem { slot: number; kind: number; productName: string; effectPayload: string|null; thumbnail: string|null; } export interface MemberEquip { memberID: number; items: EquippedItem[]; } export interface EquippedItemsResponse { members: MemberEquip[]; } // ── 라벨·색 맵 (한 곳 집중) ── // 예측 방향 — 라벨/기호/방향키(색 클래스) export const DIRECTION_META: Record = { [PredictionDirection.Up]: { label: '상승', symbol: '▲', dir: 'up' }, [PredictionDirection.Down]: { label: '하락', symbol: '▼', dir: 'down' } }; // 예측 상태 — 라벨 + 상태 색 클래스 modifier (prediction-badge--{tone}) export const STATUS_META: Record = { [PredictionStatus.Pending]: { label: '진행중', tone: 'pending' }, [PredictionStatus.Hit]: { label: '적중', tone: 'hit' }, [PredictionStatus.Miss]: { label: '실패', tone: 'miss' }, [PredictionStatus.Void]: { label: '무효', tone: 'void' } }; // 트랙레코드 등급 — 라벨 + 색 클래스 modifier (tier-badge--{tone}) export const TIER_META: Record = { [TrackRecordTier.None]: { label: '무등급', tone: 'none' }, [TrackRecordTier.Bronze]: { label: '브론즈', tone: 'bronze' }, [TrackRecordTier.Silver]: { label: '실버', tone: 'silver' }, [TrackRecordTier.Gold]: { label: '골드', tone: 'gold' }, [TrackRecordTier.GoldAnt]: { label: '황금개미', tone: 'goldant' } }; // 예측 기간 라벨 export const HORIZON_LABEL: Record = { [PredictionHorizon.Short]: '5영업일', [PredictionHorizon.Long]: '20영업일' };