- Harness: kintex-mobile-dev agent + kintex-mobile-orchestrator skill (WISE mobile ref, Stitch-first design rule, dual app targets B2B/B2C) - design.md v2.1: full 84-screen inventory (web 51 / admin 10 / public 8 / mobile 15) with Stitch prompts incl. ticketing (SCR-P7/P8, M14/M15) - PLANNING v3.1: unified account + split signup tracks (2FA required for staff, light signup/guest for visitors), one codebase / two app targets - Deliverables: dev plan (21s), user/operator/developer guides (17/14/15s), program spec (44s, 65 programs, 8 flowcharts), DA (DB design 14s + table spec xlsx 35 tables/299 cols) - Benchmark: ticketing-app-benchmark.md (7 apps) -> IMPLEMENTATION_BACKLOG Phase F (14 items) - Stitch: 23 generated screens saved (mobile 10, admin 6, web core 5, ticket 2) - mobile/: Expo scaffold (SDK 51, expo-router, secure store JWT) - frontend: SCR-13~17 QA fixes, icons.tsx, kintexEvents, V10 seed migration - ci/: KINTEX CI logo assets Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
/*
|
|
* 인증 API 래퍼 — 로그인(2FA 대응)·회원가입·비밀번호 찾기/초기화.
|
|
* 근거: 01_backend_contracts.md §2 · 04_backend_public_auth.md.
|
|
* 비밀번호는 요청 body로만 전송하고 어디에도 저장하지 않는다.
|
|
*/
|
|
import { api, ApiRequestError } from './api';
|
|
import type {
|
|
LoginResponse,
|
|
MessageResponse,
|
|
RegisterRequest,
|
|
RegisterResponse,
|
|
} from './types';
|
|
|
|
export interface LoginParams {
|
|
email: string;
|
|
password: string;
|
|
/** 2차 인증 코드 — OTP_REQUIRED 재시도 시 동봉(백엔드 TOTP 방식). */
|
|
otp?: string;
|
|
}
|
|
|
|
/**
|
|
* 로그인. 성공 시 LoginResponse.
|
|
* 2FA: 백엔드가 OTP_REQUIRED(401)를 반환하면 호출부가 OTP 입력 UI를 띄우고
|
|
* otp를 포함해 재호출한다. OTP_INVALID면 코드 오류로 재입력 유도.
|
|
*/
|
|
export async function login(params: LoginParams): Promise<LoginResponse> {
|
|
const body: Record<string, unknown> = {
|
|
email: params.email.trim(),
|
|
password: params.password,
|
|
};
|
|
if (params.otp) body.otp = params.otp.trim();
|
|
return api.post<LoginResponse>('/api/auth/login', body, { anonymous: true });
|
|
}
|
|
|
|
/** OTP_REQUIRED 여부 판정 헬퍼(로그인 2단계 분기용). */
|
|
export function isOtpRequired(e: unknown): boolean {
|
|
return e instanceof ApiRequestError && e.code === 'OTP_REQUIRED';
|
|
}
|
|
|
|
export async function register(req: RegisterRequest): Promise<RegisterResponse> {
|
|
return api.post<RegisterResponse>('/api/auth/register', req, { anonymous: true });
|
|
}
|
|
|
|
export async function forgotPassword(email: string): Promise<MessageResponse> {
|
|
return api.post<MessageResponse>(
|
|
'/api/auth/password/forgot',
|
|
{ email: email.trim() },
|
|
{ anonymous: true },
|
|
);
|
|
}
|
|
|
|
export async function resetPassword(
|
|
email: string,
|
|
code: string,
|
|
newPassword: string,
|
|
): Promise<MessageResponse> {
|
|
return api.post<MessageResponse>(
|
|
'/api/auth/password/reset',
|
|
{ email: email.trim(), code: code.trim(), newPassword },
|
|
{ anonymous: true },
|
|
);
|
|
}
|