/* * 백엔드 API 계약 타입 (단일 출처: _workspace/01_backend_contracts.md · 04_backend_public_auth.md) * ★ 백엔드 응답 shape과 정확히 일치해야 한다. 불일치 발견 시 _workspace/에 기록·보고. */ // ── 0-1 응답 봉투 ── export interface ApiError { code: ApiErrorCode; message: string; } export interface ApiResponse { success: boolean; data: T | null; error: ApiError | null; } export interface PageResponse { items: T[]; page: number; size: number; total: number; } // ── 0-2 오류 코드 ── export type ApiErrorCode = | 'VALIDATION' | 'UNAUTHORIZED' | 'FORBIDDEN' | 'NOT_FOUND' | 'CONFLICT' | 'EMAIL_TAKEN' | 'COMPLIANCE_BLOCKED' | 'RENDER_QUOTA_EXCEEDED' | 'NOT_REGISTERED_COMPANY' | 'NOT_IMPLEMENTED' | 'ACCOUNT_LOCKED' | 'OTP_REQUIRED' | 'OTP_INVALID' | 'INTERNAL'; // ── 0-5 역할 ── export type EventRole = 'ORGANIZER' | 'EXHIBITOR' | 'CONTRACTOR' | 'HALL_MANAGER'; // ── 2. 인증·워크스페이스 (SCR-01) ── export interface WorkspaceDto { eventId: string; eventName: string; startDate: string; endDate: string; hallLabel: string; myRole: EventRole; dday: number; } export interface AuthUser { userId: string; displayName: string; hallManager: boolean; // 전역 역할(app_user.role_code — 'ADMIN' | 'MANAGER' | …). 공유 백엔드 /api/auth/login 이 // 웹과 동일하게 반환한다(웹 LoginResponse.user 와 동일 shape). 관람객 등 미지정 계정은 null/undefined. // 역할별 랜딩 판정(roleTrack.resolveLandingTrack)이 admin/ops 우선순위 결정에 사용. roleCode?: string | null; } export interface LoginResponse { accessToken: string; expiresInSeconds: number; user: AuthUser; workspaces: WorkspaceDto[]; } // ── 공개 인증 (04_backend_public_auth.md) ── export interface RegisterRequest { email: string; displayName: string; password: string; companyName?: string; inviteCode?: string; } export interface RegisterResponse { userId: string; email: string; displayName: string; joinedEvent: string | null; } export interface MessageResponse { message: string; } // ── 6. M5 나노바나나 RenderJob (SCR-06/12) ── export type RenderJobStatus = 'QUEUED' | 'RUNNING' | 'DONE' | 'FAILED'; export interface RenderJobDto { jobId: string; boothId: string; shotPreset: string; // S1..S7 status: RenderJobStatus; imageUrl: string | null; schemaHash: string | null; modelVersion: string | null; /** AI 생성 이미지 고지 — 항상 true (제거 불가). */ watermarkRequired: boolean; watermarkText: string; notice?: string; createdAt?: string; } // ── 헬스체크 ── export interface HealthDto { status: string; service: string; time: string; } // ── 내정보(SCR-M 프로필) ── // GET /api/auth/me → KintexPrincipal(백엔드 record). 이메일·부서·전화는 현 계약 미포함(백엔드 인계 대상). export interface MePrincipal { userId: string; displayName: string; eventRoles: Record; hallManager: boolean; roleCode: string | null; tenantId: string | null; } // GET /api/auth/otp/status → { otpEnabled, verifyMethod }. export interface OtpStatusDto { otpEnabled: boolean; verifyMethod: string; } /** 아바타 업로드 응답(제안 계약 — 백엔드 미구현 시 degrade). */ export interface AvatarUploadResponse { photoUrl: string; } // ── B2C 관람객: 혼잡·주차 (parking_congestion_contract.md) ── /** 혼잡/점유 수준. 여유/보통/혼잡 3단계. */ export type CongestionLevel = 'FREE' | 'NORMAL' | 'BUSY'; /** 주차장 현황 — GET /api/public/parking/lots (공개). */ export interface ParkingLotStatusDto { lotId: string; code: string; name: string; exhibitionCenter: number | null; // 1|2|null(공용) totalCapacity: number; occupied: number; available: number; occupancyPercent: number; congestionLevel: CongestionLevel; congestionLabel: string; // 여유|보통|혼잡 hourlyRate: number; dailyMax: number | null; passPrice: number; // 사전 주차권(1일권) 가격 note?: string | null; updatedAt: string; } /** 사전 주차권 구매 요청 — POST /api/parking/passes (인증). */ export interface PurchasePassRequest { lotId: string; useDate: string; // YYYY-MM-DD, 오늘 이후 eventId?: string; vehiclePlate?: string; // 마스킹 후 폐기·미저장 payMethod?: 'card' | 'easy' | 'bank'; } /** 주차권 — POST/GET 응답 공통 shape. */ export interface ParkingPassDto { passNo: string; status: 'PAID' | 'CANCELLED' | 'USED'; lotId: string; lotName: string; eventId: string | null; useDate: string; vehiclePlateMasked: string | null; // 원문 미저장(마스킹만) amount: number; payMethod: string | null; payApprovalNo: string | null; issuedAt: string; } /** 내 주차권 — GET /api/parking/passes/me. */ export interface MyPassesDto { passes: ParkingPassDto[]; } /** 혼잡 영역 — 게이트/주차/인기 공간 공통. occupancyPercent는 계측 부재 시 null. */ export interface CongestionAreaDto { id: string; label: string; level: CongestionLevel; levelLabel: string; occupancyPercent: number | null; } /** 혼잡 요약 — GET /api/public/congestion?eventId= (공개). */ export interface CongestionOverviewDto { eventId: string; overallLevel: CongestionLevel; overallLabel: string; onSiteCount: number; entryGates: CongestionAreaDto[]; parking: CongestionAreaDto[]; popularSessions: CongestionAreaDto[]; updatedAt: string; } // ── B2C 관람객: 라이브 공지 (cms_backlog_contract.md) ── /** 공지 카테고리 — 배지 색상 매핑(URGENT=red·PROGRAM=amber·INFO=blue·GENERAL=slate). */ export type LiveNoticeCategory = 'URGENT' | 'PROGRAM' | 'GENERAL' | 'INFO'; /** 라이브 공지 — GET /api/public/events/{eventId}/live-notices (공개). */ export interface LiveNoticeDto { id: string; eventId: string; category: LiveNoticeCategory; title: string; body?: string | null; pinned: boolean; status: string; // published|archived authorName?: string | null; createdAt: string; updatedAt: string; }