feat: Add CI/CD pipeline and code quality improvements

- Add GitHub Actions workflow for automated CI/CD
- Configure Node.js 18.x and 20.x matrix testing
- Add TypeScript type checking step
- Add ESLint code quality checks with enhanced rules
- Add Prettier formatting verification
- Add production build validation
- Upload build artifacts for deployment
- Set up automated testing on push/PR
- Replace console.log with environment-aware logger
- Add pre-commit hooks for code quality
- Exclude archive folder from linting

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
hansoo
2025-07-12 15:27:54 +09:00
parent 6a208d6b06
commit 9851627ff1
411 changed files with 14458 additions and 8680 deletions

View File

@@ -1,78 +1,91 @@
import { account } from '@/lib/appwrite/client';
import { showAuthToast } from '@/utils/auth';
import { getDefaultUserId } from '@/lib/appwrite/defaultUser';
import { account } from "@/lib/appwrite/client";
import { authLogger } from "@/utils/logger";
import { showAuthToast } from "@/utils/auth";
import { getDefaultUserId } from "@/lib/appwrite/defaultUser";
/**
* 로그인 기능 - Appwrite 환경에 최적화
*/
export const signIn = async (email: string, password: string) => {
try {
console.log('로그인 시도 중:', email);
authLogger.info("로그인 시도 중:", email);
// 비동기 작업을 마이크로태스크로 지연하여 UI 차단 방지
await new Promise<void>(resolve => queueMicrotask(() => resolve()));
await new Promise<void>((resolve) => queueMicrotask(() => resolve()));
// Appwrite 인증 방식 시도
try {
const session = await account.createSession(email, password);
const user = await account.get();
// 상태 업데이트를 마이크로태스크로 지연
await new Promise<void>(resolve => queueMicrotask(() => resolve()));
showAuthToast('로그인 성공', '환영합니다!');
await new Promise<void>((resolve) => queueMicrotask(() => resolve()));
showAuthToast("로그인 성공", "환영합니다!");
return { error: null, user };
} catch (authError: any) {
console.error('로그인 오류:', authError);
let errorMessage = authError.message || '알 수 없는 오류가 발생했습니다.';
authLogger.error("로그인 오류:", authError);
let errorMessage = authError.message || "알 수 없는 오류가 발생했습니다.";
let fallbackMode = false;
// Appwrite 오류 코드에 따른 사용자 친화적 메시지
if (authError.code === 401) {
errorMessage = '이메일 또는 비밀번호가 올바르지 않습니다.';
errorMessage = "이메일 또는 비밀번호가 올바르지 않습니다.";
} else if (authError.code === 429) {
errorMessage = '너무 많은 로그인 시도가 있었습니다. 잠시 후 다시 시도해주세요.';
errorMessage =
"너무 많은 로그인 시도가 있었습니다. 잠시 후 다시 시도해주세요.";
} else if (authError.code === 404 || authError.code === 503) {
// 서버 연결 문제인 경우 기본 사용자 ID를 활용한 대체 로직 시도
errorMessage = '서버 연결에 문제가 있어 일반 모드로 접속합니다.';
errorMessage = "서버 연결에 문제가 있어 일반 모드로 접속합니다.";
fallbackMode = true;
try {
// 기본 사용자 ID를 활용한 대체 로직
const defaultUserId = getDefaultUserId();
console.log('기본 사용자 ID를 활용한 대체 로직 시도:', defaultUserId);
authLogger.info(
"기본 사용자 ID를 활용한 대체 로직 시도:",
defaultUserId
);
// 일반 모드로 접속하는 경우 사용자에게 알림
showAuthToast('일반 모드 접속', '일반 모드로 접속합니다. 일부 기능이 제한될 수 있습니다.', 'default');
showAuthToast(
"일반 모드 접속",
"일반 모드로 접속합니다. 일부 기능이 제한될 수 있습니다.",
"default"
);
// 기본 사용자 정보를 가진 가상의 사용자 객체 생성
const fallbackUser = {
$id: defaultUserId,
name: '일반 사용자',
name: "일반 사용자",
email: email,
$createdAt: new Date().toISOString(),
$updatedAt: new Date().toISOString(),
status: true,
isFallbackUser: true // 기본 사용자임을 표시하는 플래그
isFallbackUser: true, // 기본 사용자임을 표시하는 플래그
};
return { error: null, user: fallbackUser, isFallbackMode: true };
} catch (fallbackError) {
console.error('기본 사용자 대체 로직 오류:', fallbackError);
authLogger.error("기본 사용자 대체 로직 오류:", fallbackError);
// 대체 로직도 실패한 경우 원래 오류 반환
}
}
if (!fallbackMode) {
showAuthToast('로그인 실패', errorMessage, 'destructive');
showAuthToast("로그인 실패", errorMessage, "destructive");
}
return { error: authError, user: null };
}
} catch (error) {
console.error('로그인 예외 발생:', error);
showAuthToast('로그인 오류', '서버 연결 중 오류가 발생했습니다.', 'destructive');
authLogger.error("로그인 예외 발생:", error);
showAuthToast(
"로그인 오류",
"서버 연결 중 오류가 발생했습니다.",
"destructive"
);
return { error, user: null };
}
};