diff --git a/negodata/front/src/features/partners/types.ts b/negodata/front/src/features/partners/types.ts index 539e01f..3608843 100644 --- a/negodata/front/src/features/partners/types.ts +++ b/negodata/front/src/features/partners/types.ts @@ -1,11 +1,4 @@ -import type { SupplierData } from '@/api/generated/model/supplierData'; - -// UI에서 쓰는 협력사 타입. 서버 SupplierData에 화면 전용 파생 필드만 얹는다. -// (level/rank/status 등 서버 미연동 가짜 필드는 두지 않는다 — 표시 가능한 건 priority뿐.) -export type Partner = SupplierData & { - deleted?: boolean; - id?: string; -}; +export type { Partner } from '@/types'; // 우선순위 필터 목록. 'ALL'은 필터 전용(폼에서는 제외). export const prioritiesList = ['ALL', 'HIGH', 'MEDIUM', 'LOW']; diff --git a/negodata/front/src/features/products/types.ts b/negodata/front/src/features/products/types.ts index 59610e6..f1b2602 100644 --- a/negodata/front/src/features/products/types.ts +++ b/negodata/front/src/features/products/types.ts @@ -1,14 +1,4 @@ -import type { ItemData } from '@/api/generated/model/itemData'; - -// UI에서 쓰는 상품 타입. 서버 ItemData에 화면 전용 파생 필드를 얹는다. -export type Product = ItemData & { - deleted?: boolean; - id?: string; - minPrice?: number; - status?: string; -}; - -// 분류 카테고리는 서버 items 에서 distinct 로 파생한다(useProducts). 하드코딩 상수 제거됨. +export type { Product } from '@/types'; // 인터넷 최저가 데모 산정(표준 단가의 83%). 서버 미연동 — 표시/초기값 용도. export const toMinPrice = (price?: number | null) => Math.round((price || 0) * 0.83); diff --git a/negodata/front/src/types.ts b/negodata/front/src/types.ts index 5341ea5..6693cd6 100644 --- a/negodata/front/src/types.ts +++ b/negodata/front/src/types.ts @@ -1,306 +1,35 @@ -// ============================================================ -// Negosium/NegoData ERD Type Definitions (TypeScript) -// ------------------------------------------------------------ -// 기준: postgres-init/01-schema.sql (negosium_db, 도메인별 schema) + 현행 백엔드 API 계약. -// 표기 규칙: -// - 코드값(status/role/type/quantity_unit/delivery_type 등)은 DB에서 SMALLINT 정수코드지만, -// 현행 API(openapi.json) 가 문자열로 직렬화하므로 여기서는 string 으로 둔다(주석에 DB 타입 명시). -// - DB 에 대응 테이블/컬럼이 없는 항목은 "⚠ DB 없음" 으로 표시한다. -// ============================================================ +// 2개 이상 feature가 공유하는 타입만 둔다. 단일 feature 전용은 그 feature/types.ts 로. +import type { ItemData } from '@/api/generated/model/itemData'; +import type { SupplierData } from '@/api/generated/model/supplierData'; -// Base abstract structure properties -interface BaseEntity { - created_at: string; - updated_at: string; - deleted: boolean; -} - -// 1. Companies (고객사) — company.companies -export interface Company extends BaseEntity { - company_id: string; // uuid (Primary Key) - name: string; // 회사명 - business_number: string | null; // 사업자등록번호 - code: number | null; // 회사코드 (내부 인덱스용) - representative_name: string | null; // 대표자 명 - email: string | null; // 대표 이메일 - contact_number: string | null; // 대표 연락처 - website_url: string | null; // 홈페이지 URL - industry: string | null; // 업종 (DB: SMALLINT 코드) - status: string; // 상태 (DB: SMALLINT NOT NULL, 1=active 2=inactive) -} - -// 2. Users (유저) — company.users -export interface User extends BaseEntity { - user_id: string; // uuid (Primary Key) - company_id: string; // 회사 아이디 (company.companies.company_id) - id: string; // 로그인시, 입력 아이디 - password: string; // 비밀번호 (해시) - name: string | null; // 이름 - email: string | null; // 이메일 - contact_number: string | null; // 전화번호 - last_accessed_at: string; // 마지막 접속 시간 - status: string; // 상태 (DB: SMALLINT, 1=active 2=inactive) - role: string; // 권한 (DB: SMALLINT, 1=user 2=manager) -} - -// 3. User Tokens (유저 토큰) — company.user_tokens -export interface UserToken extends BaseEntity { - user_tokens_id: string; // uuid (Primary Key) — DB 컬럼명 user_tokens_id - user_id: string; // 유저 아이디 (company.users.user_id) - type: string; // 토큰 타입 (DB: SMALLINT 코드) - token: any; // 토큰 값 (JSONB) - issued_at: string; - expired_at: string; -} - -// 4. Suppliers (협력사) - 기존 Partner 대응 — partner.suppliers -export interface Supplier extends BaseEntity { - supplier_id: string; // uuid (Primary Key) - company_id: string; // 회사 아이디 (company.companies.company_id) - user_id: string; // 등록 유저 (company.users.user_id) — DB NOT NULL - name: string; // 협력사명 - code: string | null; // 협력사코드 - manager_name: string | null; // 담당자명 - manager_email: string | null; // 담당자 이메일 - manager_contact_number: string | null; // 담당자 연락처 (DB 철자 정상 — 기존 typo 가정은 오류였음) - priority: string | null; // 우선순위 (DB: VARCHAR, 고객사별 문자열 유지) -} - -// 5. Items (상품 정보) - 기존 Product 대응 — partner.items -export interface Item extends BaseEntity { - item_id: string; // uuid (Primary Key) - company_id: string; // 회사 아이디 (company.companies.company_id) - user_id: string; // 등록 유저 (company.users.user_id) — DB NOT NULL - name: string; // 상품명 - code: string | null; // 상품코드 - price: number | null; // 상품 단가 (DB: BIGINT) - category: string | null; // 상품 카테고리 (free text) - category_type: number; // 카테고리 조회용 정수 (DB: INTEGER NOT NULL DEFAULT 1, 자동증가 아님) - image_url: string | null; // 상품 이미지 URL - model_name: string | null; // 상품 모델명 - spec: string | null; // 상품 규격 - moq: string | null; // 상품 MOQ - lead_time: number | null; // 상품 리드타임 (DB: SMALLINT) - manufacturer: string | null; // 상품 제조사 - made_in: string | null; // 상품 제조 국가 - quantity_unit: string | null; // 상품 취급 단위 (DB: SMALLINT 코드) - delivery_type: string | null; // 상품 배송형태 (DB: SMALLINT 코드) - vat_yn: boolean | null; // VAT 포함 여부 - delivery_fee_yn: boolean | null; // 배송비 포함 여부 - internet_lowest_price_yn: boolean; // 인터넷 최저가 보조 플래그 -} - -// 6. Item Internet Lowest Prices — partner.item_internet_lowest_prices -// (※ 기존 url/crawled_at 필드는 DB 에 없어 제거. 실제 DB 컬럼에 맞춤.) -export interface ItemInternetLowestPrice extends BaseEntity { - lp_id: string; // uuid (Primary Key) - item_id: string; // 상품 아이디 (partner.items.item_id) - lp_price: number | null; // 크롤링한 최저가 (DB: BIGINT) - website: number; // 크롤링 대상 사이트 (DB: SMALLINT 코드) - success_yn: boolean; // 크롤링 성공 여부 - fail_reason: string | null; // 실패 사유 - ai_model: number | null; // 사용한 AI 모델 (DB: SMALLINT 코드) - crawl_duration_ms: number | null; // 크롤링 소요 시간(ms) - crawl_end_time: string; // 크롤링 종료 시각 -} - -// 7. Quotation Settings (견적 세팅) — quotation.quotation_settings -// (※ DB·API 모두 user_id 보유. 전역 기본 설정은 NULL 가능.) -export interface QuotationSetting extends BaseEntity { - qt_setting_id: string; // uuid (Primary Key) - user_id: string; // 유저 아이디 (company.users.user_id). DB 는 nullable(전역 기본=NULL)이나 UI 매퍼가 '' 로 정규화 - target_margin: string; // 목표 마진율 (DB: NUMERIC(8,6)) - anchoring_value: string; // 앵커링 설정 값 (DB: NUMERIC(8,6)) - card_use_count: string; // 협상 카드 사용 횟수 (DB: card_count INTEGER) -} - -// 8. Quotations (견적) - 기존 Estimate 대응 — quotation.quotations -// (※ company_id 는 DB/API 모두에 없어 제거. 회사 스코프는 user_id 경유.) -export interface Quotation extends BaseEntity { - qt_id: string; // uuid (Primary Key) - user_id: string; // 유저 아이디 (company.users.user_id) - qt_setting_id: string; // 견적 세팅 아이디 (quotation.quotation_settings.qt_setting_id) - version_id: string; // 협상전략 버전 (card.versions.version_id) — DB NOT NULL - name: string; // 견적 명 - number: string; // 견적 번호 - type: string; // 견적 타입 (DB: SMALLINT, 1=renego 2=requote) - round: number; // 견적 차수 (기본 1) - status: string; // 견적 상태 (DB: SMALLINT 코드) - start_time: string; // 견적 시작 시간 - end_time: string; // 견적 마감 시간 - manager_name: string | null; // 견적 담당자 명 - manager_email: string | null; // 견적 담당자 이메일 - manager_contact_number: string | null; // 견적 담당자 연락처 - memo: string | null; // 견적 안내사항 - iteration: number; // 반복 횟수 (DB NOT NULL DEFAULT 0) - preferred_sp_yn: boolean | null; // 선호 공급사 지정 여부 - preferred_sp_id: string | null; // 선호 공급사 (partner.suppliers.supplier_id) - preferred_sp_name: string | null; // 선호 공급사명(스냅샷) - equal_bid_yn: boolean | null; // 동일가 입찰 발생 여부 - equal_bid_data: any | null; // 동일가 입찰 상세 (JSONB) -} - -// 9. Nego Cards (협상카드) — card.nego_cards -// (※ company_id 는 DB 에 없어 제거. 소유는 user_id(nullable) 만.) -export interface NegoCard extends BaseEntity { - nego_card_id: string; // uuid (Primary Key) - user_id: string | null; // 유저 아이디 (o2o 기본 카드는 NULL) - name: string | null; // 카드 이름 - number: string | null; // 카드 번호 (식별번호) - script: string | null; // 스크립트 - edit_script: any | null; // 편집 스크립트 (JSONB) -} - -// 10. Wild Cards (와일드 카드) — card.wild_cards -// (※ company_id 는 DB 에 없어 제거.) -export interface WildCard extends BaseEntity { - wild_card_id: string; // uuid (Primary Key) - user_id: string | null; // 유저 아이디 (o2o 기본 카드는 NULL) - name: string | null; // 카드 이름 - number: string | null; // 카드 번호 (식별번호) - script: string | null; // 스크립트 - edit_script: any | null; // 편집 스크립트 (JSONB) - condition: string | null; // 카드 사용 조건 - available: boolean; // 협상 적용 가능 여부 - memo: string | null; // 메모 -} - -// 11. Sessions (세션) - 기존 ChatSession 대응 — negotiation.sessions -// (※ user_id, bid_summary_id 는 DB sessions 에 없어 제거. bid_summary 개념은 quotations 로 흡수됨.) -export interface Session extends BaseEntity { - session_id: string; // uuid (Primary Key) - quotation_id: string; // 소속 견적 (quotation.quotations.qt_id) — DB 컬럼명 quotation_id - item_id: string; // 상품 아이디 (partner.items.item_id) - supplier_id: string; // 협력사 아이디 (partner.suppliers.supplier_id) - qt_number: string; // 견적번호(스냅샷) - qt_round: number; // 견적 차수(스냅샷) - qt_type: string; // 견적 타입(스냅샷, DB: SMALLINT) - target_price: number; // 목표 가격 (DB: BIGINT) - status: string; // 협상 상태 (DB: SMALLINT 코드) - bid_price: number | null; // 최종 입찰 가격 - bid_at: string | null; // 최종 입찰 시간 - end_time: string; // 협상 종료 시간 - reject_reason: string | null; // 협상 거부 사유 - reject_price: number | null; // 협상 거부 가격 - reject_delivery_type: string | null; // 협상 거부 시 배송 형태 (DB: SMALLINT 코드) -} - -// 12. Bid Summary (견적 입찰 정보) -// ⚠ DB 없음: 별도 테이블이 없고 quotation.quotations 의 preferred_sp_* / equal_bid_* 컬럼으로 흡수됨. -// UI(QuotationDetailSheet) 의 입찰 요약 표시용 파생 모델로만 존재. -export interface BidSummary { - bid_summary_id: string; // (파생) UI 식별자 - qt_id: string; // 견적 아이디 (quotation.quotations.qt_id) - qt_type: string; // 견적 타입 (재협상/재견적) - qt_iteration: number; // 견적 반복횟수 (← quotations.iteration) - status: string; // 입찰 상태 (← quotations.status) - has_preferred: boolean; // ← quotations.preferred_sp_yn - preferred_sp_id: string | null; // ← quotations.preferred_sp_id - preferred_sp_name: string | null; // ← quotations.preferred_sp_name - equal_data: any | null; // ← quotations.equal_bid_data (JSONB) -} - -// 13. Results (세션 결과) — negotiation.results (스키마 미확정 스텁) -export interface Result extends BaseEntity { - result_id: string; // uuid (Primary Key) — DB 컬럼명 result_id -} - -// 14. Quotation Cards (견적↔카드 연결) -// API(QuotationCardResponse) 로는 노출되나, 33KB DB 에는 quotation_cards 테이블이 없고 -// card.version_nego_cards / card.version_wild_cards (버전↔카드) 매핑으로 실현된다 -// (quotation.version_id → version_*_cards → nego/wild_cards). -export interface QuotationCard { - session_card_id: string; // uuid (Primary Key, API 기준) - wild_card_id: string | null; // 와일드 카드 아이디 (card.wild_cards.wild_card_id) - nego_card_id: string | null; // 협상카드 아이디 (card.nego_cards.nego_card_id) - qt_id: string | null; // 견적 아이디 (quotation.quotations.qt_id) - type: string | null; // 카드 타입 (DB: SMALLINT, 1=nego 2=wild) -} - -// 15. Chats (채팅 내역) — negotiation.chats -// (※ API(ChatMessageResponse) 는 순번 컬럼을 index 로, DB 는 seq 로 부른다.) -export interface Chat extends BaseEntity { - chat_id: string; // uuid (Primary Key) - session_id: string; // 소속 세션 (negotiation.sessions.session_id) - card_id: string | null; // 사용된 카드 (card.nego_cards/wild_cards, 다형성) - seq: number; // 세션 내 메시지 순번 (API: index) - sender: string; // 발신자 구분 (DB: SMALLINT 코드) - target_price: number; // 제시 목표가 (DB: BIGINT) - card_used_yn: boolean | null; // 카드 사용 여부 - indicator_value: number | null; // 지표값 (DB: NUMERIC(8,6)) - card_type: string | null; // 카드 유형 (DB: SMALLINT, 1=nego 2=wild) -} - -// 16. CopyOfChat (채팅 임시/백업) -// ⚠ DB 없음: 대응 테이블 없음 (프론트 임시 보관용). -export interface CopyOfChat extends BaseEntity { - id: string; -} - -// ============================================================ -// React UI Compatibility Helper Types -// ============================================================ - -export type Product = Partial & { - id?: string; // item_id back-compatibility map - minPrice?: number; // UI minimum reserve limit - status?: string; // UI lifecycle state +export type Product = ItemData & { + deleted?: boolean; + id?: string; + minPrice?: number; + status?: string; }; -export type Partner = Partial & { - id?: string; // supplier_id back-compatibility map - managerName?: string; // manager_name - managerEmail?: string; // manager_email - managerPhone?: string; // manager_contact_number - manager_contact_number?: string; // DB 컬럼 직접 매핑(철자 정상) - rank?: 'A' | 'B' | 'C' | 'S'; // computed from priority - status?: string; // mapped to deleted - memo?: string; // back-compatible details +export type Partner = SupplierData & { + deleted?: boolean; + id?: string; + managerName?: string; + managerEmail?: string; + managerPhone?: string; + rank?: 'A' | 'B' | 'C' | 'S'; + status?: string; + memo?: string; }; -export type Estimate = Partial & { - id?: string; // qt_id back-compatibility map - dueDate?: string; // end_time - title?: string; // mapped to name in UI - productId?: string; // mapped to association - productName?: string; // 서버 목록 조인 상품명(products 목록에 없을 때 폴백) - partnerIds?: string[]; // mapped B2B suppliers - participationCount?: number; - winnerPartnerId?: string | null; - finalPrice?: number; - isEqualPrice?: boolean; - usedCardIds?: string[]; - settingApplied?: boolean | string; -}; - -// UI Chat Message definition (corresponds to in-memory/rendered chats) -export interface ChatMessage { - id: string; - sender: 'BOT' | 'PARTNER' | 'SYSTEM'; - timestamp: string; - content: string; - editorScript?: any; // Slate JSON structure -} - -export interface ChatSession { - id: string; // matches supplier_id (or supplier.supplier_id) - partnerName: string; - status: 'NEGOTIATING' | 'COMPLETED' | 'REJECTED' | '협상생성' | '협상중' | '협상완료' | '미참여' | '협상거부'; - currentBid: number; - bidTime: string; - messages: ChatMessage[]; -} - export interface NegotiationCard { - id: string; // nego_card_id or wild_card_id - isWildcard: boolean; // mapping based on source table - code: string; // number (식별번호) or custom code - title: string; // name - scriptPreview: string; // script - editorScript: any; // edit_script (JSON) + id: string; + isWildcard: boolean; + code: string; + title: string; + scriptPreview: string; + editorScript: any; status: 'ACTIVE' | 'INACTIVE'; - triggerCondition?: string; // wild_card's condition - memo?: string; // wild_card's memo + triggerCondition?: string; + memo?: string; } export type PageType = 'PRODUCTS' | 'PARTNERS' | 'QUOTATION' | 'CARDS';