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,6 +1,6 @@
import { useState, useEffect, useCallback } from 'react';
import { account } from '@/lib/appwrite';
import { ID } from 'appwrite';
import { useState, useEffect, useCallback } from "react";
import { account } from "@/lib/appwrite";
import { ID } from "appwrite";
// 인증 상태 인터페이스
interface AuthState {
@@ -29,7 +29,7 @@ export const useAppwriteAuth = () => {
const [authState, setAuthState] = useState<AuthState>({
user: null,
loading: true,
error: null
error: null,
});
// 컴포넌트 마운트 상태 추적
@@ -43,7 +43,7 @@ export const useAppwriteAuth = () => {
setAuthState({
user,
loading: false,
error: null
error: null,
});
}
return user;
@@ -52,7 +52,7 @@ export const useAppwriteAuth = () => {
setAuthState({
user: null,
loading: false,
error: error as Error
error: error as Error,
});
}
return null;
@@ -60,97 +60,101 @@ export const useAppwriteAuth = () => {
}, [isMounted]);
// 이메일/비밀번호로 로그인
const login = useCallback(async ({ email, password }: LoginCredentials) => {
try {
setAuthState(prev => ({ ...prev, loading: true, error: null }));
// 비동기 작업 시작 전 UI 스레드 차단 방지
await new Promise(resolve => setTimeout(resolve, 0));
const session = await account.createEmailPasswordSession(email, password);
const user = await account.get();
if (isMounted) {
setAuthState({
user,
loading: false,
error: null
});
const login = useCallback(
async ({ email, password }: LoginCredentials) => {
try {
setAuthState((prev) => ({ ...prev, loading: true, error: null }));
// 비동기 작업 시작 전 UI 스레드 차단 방지
await new Promise((resolve) => setTimeout(resolve, 0));
const session = await account.createEmailPasswordSession(
email,
password
);
const user = await account.get();
if (isMounted) {
setAuthState({
user,
loading: false,
error: null,
});
}
return { user, session };
} catch (error) {
if (isMounted) {
setAuthState((prev) => ({
...prev,
loading: false,
error: error as Error,
}));
}
throw error;
}
return { user, session };
} catch (error) {
if (isMounted) {
setAuthState(prev => ({
...prev,
loading: false,
error: error as Error
}));
}
throw error;
}
}, [isMounted]);
},
[isMounted]
);
// 회원가입
const signup = useCallback(async ({ email, password, name }: SignupCredentials) => {
try {
setAuthState(prev => ({ ...prev, loading: true, error: null }));
// 비동기 작업 시작 전 UI 스레드 차단 방지
await new Promise(resolve => setTimeout(resolve, 0));
const user = await account.create(
ID.unique(),
email,
password,
name
);
// 회원가입 후 자동 로그인
await account.createEmailPasswordSession(email, password);
if (isMounted) {
setAuthState({
user,
loading: false,
error: null
});
const signup = useCallback(
async ({ email, password, name }: SignupCredentials) => {
try {
setAuthState((prev) => ({ ...prev, loading: true, error: null }));
// 비동기 작업 시작 전 UI 스레드 차단 방지
await new Promise((resolve) => setTimeout(resolve, 0));
const user = await account.create(ID.unique(), email, password, name);
// 회원가입 후 자동 로그인
await account.createEmailPasswordSession(email, password);
if (isMounted) {
setAuthState({
user,
loading: false,
error: null,
});
}
return user;
} catch (error) {
if (isMounted) {
setAuthState((prev) => ({
...prev,
loading: false,
error: error as Error,
}));
}
throw error;
}
return user;
} catch (error) {
if (isMounted) {
setAuthState(prev => ({
...prev,
loading: false,
error: error as Error
}));
}
throw error;
}
}, [isMounted]);
},
[isMounted]
);
// 로그아웃
const logout = useCallback(async () => {
try {
setAuthState(prev => ({ ...prev, loading: true }));
setAuthState((prev) => ({ ...prev, loading: true }));
// 현재 세션 삭제
await account.deleteSession('current');
await account.deleteSession("current");
if (isMounted) {
setAuthState({
user: null,
loading: false,
error: null
error: null,
});
}
} catch (error) {
if (isMounted) {
setAuthState(prev => ({
setAuthState((prev) => ({
...prev,
loading: false,
error: error as Error
error: error as Error,
}));
}
throw error;
@@ -161,7 +165,7 @@ export const useAppwriteAuth = () => {
useEffect(() => {
setIsMounted(true);
getCurrentUser();
// 정리 함수
return () => {
setIsMounted(false);
@@ -175,7 +179,7 @@ export const useAppwriteAuth = () => {
login,
signup,
logout,
getCurrentUser
getCurrentUser,
};
};