2025 덕성여자대학교 컴퓨터공학과 졸업프로젝트 TopHat 팀의 프론트엔드 레포지토리입니다.
본 프로젝트는 멀티모달 AI를 활용하여 학습자의 손글씨 풀이를 실시간 인식·분석하는 인터랙티브 수학 학습 서비스입니다.
문제 이미지를 텍스트로 변환하고, AI가 풀이 과정과 정답을 자동 생성하여 단계별로 안내합니다.
학습자의 풀이 중단 지점을 감지하고, 부족한 개념과 다음 풀이 방향을 맞춤형으로 제공하여
학습자의 논리적 사고력과 자기주도 학습 능력을 효과적으로 지원합니다.
기존 정답 제공 중심 서비스와 달리, 학습자가 막힌 지점에서 맞춤형 피드백과 단계별 해설을 제공하며
문제 해결 과정 전반을 학습할 수 있도록 설계되었습니다.
-
전체/단계별 풀이
문제 이미지 또는 문제+풀이 이미지를 업로드하면 AI가 풀이와 단계별 해설 제공 -
개인 맞춤 학습
마이페이지에서 질문했던 문제 확인 및 부족한 개념 안내 -
PDF 추출
풀이 결과를 PDF로 저장하고 복습/공유 가능
| 한수정 |
|---|
| |
| @hansoojeongsj |
main(=master): 오직 배포를 위한 브랜치 → 특별한 상황이 아니라면 배포만 진행develop: 작업한 내용을 취합하는 곳 (default branch)feat(=feature): 각 작업물을 분기해 새로 만들어 사용할 브랜치
Commit 메시지 종류 설명
| 제목 | 내용 |
|---|---|
feat |
퍼블리싱 및 모든 새로운 기능 |
setting |
패키지 설치, 개발 설정 |
fix |
버그 수정 |
chore |
빌드 테스트 업데이트, 패키지 매니저 설정, 그 외 기타 수정 |
style |
CSS 등 사용자 UI 디자인 변경 |
refactor |
프로덕션 코드 리팩토링 및 QA 반영 |
deploy |
배포 작업 |
!HOTFIX |
급하게 치명적인 버그 수정 |
!BREAKING CHANGE |
커다란 API 변경 |
|-- 📁 node_modules
|-- 📁 public
|-- 📁 svg
|-- 📁 src
|-- 📁 shared
|-- 📁 apis
|-- 📁 asset
|-- 📁 svgs
|-- 📁 images
|-- 📁 components (공통 컴포넌트)
|-- 📁 Button (예시 컴포넌트)
|-- Button.tsx
|-- Button.style.ts
|-- 📁 hooks (커스텀 훅을 담아두는 폴더)
|-- 📁 styles ( global.ts, theme.ts )
|-- 📁 types
|-- 📁 utils ( 재사용이 높은 함수모음 폴더 )
|-- 📁 constants
|-- 📁 mocks
|-- 📁 pages
|-- 📁onboarding
|-- 📁components
|-- 📁types
|-- 📁hooks
|-- Onboarding.tsx
|-- Onboarding.style.ts
|-- 📁 routes
|-- routePath.ts
|-- Layout.ts
|-- pageRoutes.ts
|-- App.tsx
|-- main.tsx
|-- .eslintrc.json
|-- .gitignore
|-- .prettierignore
|-- .prettierrc
|-- README.md
|-- package.json
|-- tsconfig.json
|-- vite.config.ts
자세히보기
### 1. 기본 (Default)- 컴포넌트 / class
PascalCase - 폴더명
carmelCase - 파일 명 (컴포넌트 제외)
carmelCase - 변수, 함수
carmelCase - 파라미터
carmelCase - 상수
BIG_SNAKE_CASE
- interface는 필수로
PascalCase사용 - Props 타입 →
컴포넌트명+Types- 예시
interface PostPagePropTypes { title: string | undefined; setTitle: (e: React.ChangeEvent<HTMLTextAreaElement>) => void; tempContent: string; editContent: string; setEditorContent: (content: string) => void; setContentWithoutTag: (content: string) => void; } const PostPage = (props: PostPagePropTypes) => { const {title, setTitle, tempContent, editContent, setEditorContent, setContentWithoutTag ... }
- 예시
- 일반 타입 →
… + Types
- semantic tag는 적극 활용!
- **
aria-label**도 적극적으로 활용할 수 있게 노력
- **
- SVG 파일 사용시
- svgr로 컴포넌트화 후 사용하므로 svg이름을 그대로 변환하여 사용
-
이벤트 핸들러 네이밍
handle + 기능 + 이벤트- 예시
const handleBtnClick = () => {}; const handleTabChange = () => {};
→ props로 넘길 때 key값은
on + 이벤트- 예시
const BoxComponent = () => { return <memoComponent onClick={handleBtnClick} />; };
- 예시
-
유틸(utils) 함수 네이밍
동사(기능) + 명사(대상) -
값이 boolean일 경우는
is + 상태(default)- 예시
const [isLogined, setIsLogined] = useState(false);
→ 추가적으로
can / should / has정도를 상황에 맞게 추가 - 예시
-
api 함수
HTTP 메서드 + 명사- 예시
const getList = () => {}; const getMovie = () => {};
- 예시
-
assets (Icon이나 Img)의 경우 피그마 네이밍을 적극 활용
→
Ic + 피그마 네이밍(icon의 경우)으로 사용 -
URL, HTML 같은 범용적인 대문자 약어는 대문자 그대로 사용
-
변수/최대한 직관적으로 작성하여 네이밍을 보고도 무슨 데이터, 행위인지 바로 유추할 수 있도록 작성
- 주석이 필요한 경우에는 어떤 역할을 하는지 다른 사람이 이해할 수 있도록 작성
- 변수/함수 명은 20자 미만, 주석으로 변수 설명
-
주석은 작성하려고 하는 대상 바로 위에 작성
자세히보기
### 변수- var 금지
const→let순서로 위부터 선언- 변수를 조합하여 문자열 생성시 “+ “ 금지. → 리터럴 사용(백틱 ```)
- 변수명 : 의미를 확실히 나타낼 수 있도록
- 예시 : 배열에 Arr 보다는 변수s = fruits, userlists 등등
- 줄임말 쓰지말기. 이름이 길어지더라도 어떤 변수인지 정확하게
- 예시 : Btn X → Button으로 사용
- map 사용시 변동되는 리스트라면 key값을 고유하게 잘 설정해주기
index 사용 금지- 서버에서 내려주는 id값 or uuid 사용
- 전역 변수는 되도록 사용하지 않기
- 화살표 함수 사용, function 키워드 사용하지 않기
- 중복함수는 utils 폴더에 모아서 재사용할 수 있도록 노력
- 변수/함수 명은 20자 미만
- 최대한 네이밍에 의미를 담아서 작성하고 필요 시에 주석으로 설명 추가
- 필요하다면 early return 패턴을 적극적으로 활용
- 예시
**// early return 패턴** function processUser(user) { if (!user || !user.isActive) return; // **조건이 맞지 않으면 일찍 반환** // 나머지 처리 코드... }
- 예시
rafce→ 고정- 의미없는 div 또는 컴포넌트 최상단은 fragment 사용
const InfoText = () => {
return (
<>
<h1>Welcome!</h1>
<p>This our new page, we're glad you're are here!</p>
</>
);
};- children이 불필요할 땐 selfClosing사용
<Component/> - children 적극적으로 활용
- object → interface
- 단일 변수 → type alias
- 컴포넌트 인자에 대한 타입은 컴포넌트 상단에
- 그 외의 타입들은 types 폴더에
- api response 타입명은 OOOResponseTypes
-
배열 복사 시 → 스프레드 연산자(…) 사용
const copys = […originals]
-
for 보단,
forEach/map을 사용 -
구조 분해 할당을 적극 이용
interface userDataProps { userName: string; userBirth: string; } function checkIsUser({ userName, userBirth }: userDataProps) {}
-
불필요한 반복문 지양 : filter, array.include() 등
- 조건부로 데이터를 확인하거나 뽑아야하는 로직을 사용할 때에는
Map이나Object처럼key값을 이용해서 원소를 찾는 자료형을 이용하는것을 고려해보거나, 배열을 순회하지 않고 index로 바로 접근할 수 있는 방법이 없는지 고려
- 조건부로 데이터를 확인하거나 뽑아야하는 로직을 사용할 때에는
-
button 태그에 **
type**은 명시적으로 작성 -
비교 연산자는 **
===**와 **!==**만을 사용 -
axios 안에서
then/catch대신async/await지향