{"id":22116907,"url":"https://github.com/hyrmzz1/shared-note","last_synced_at":"2026-04-10T12:01:51.282Z","repository":{"id":265688448,"uuid":"881293191","full_name":"hyrmzz1/shared-note","owner":"hyrmzz1","description":"Practice for User authentication / CRUD / Task-based data synchronization / Error Handling","archived":false,"fork":false,"pushed_at":"2024-12-19T13:56:24.000Z","size":194,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T05:46:13.290Z","etag":null,"topics":["axios","jwt","react","react-hook-form","react-query","tailwind-css","zustand"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hyrmzz1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-31T09:31:03.000Z","updated_at":"2024-12-19T13:56:27.000Z","dependencies_parsed_at":"2024-11-30T14:38:45.115Z","dependency_job_id":"e63dfb20-84ad-4655-820d-a30053459324","html_url":"https://github.com/hyrmzz1/shared-note","commit_stats":null,"previous_names":["hyrmzz1/shared-note"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hyrmzz1/shared-note","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyrmzz1%2Fshared-note","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyrmzz1%2Fshared-note/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyrmzz1%2Fshared-note/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyrmzz1%2Fshared-note/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hyrmzz1","download_url":"https://codeload.github.com/hyrmzz1/shared-note/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyrmzz1%2Fshared-note/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31641492,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["axios","jwt","react","react-hook-form","react-query","tailwind-css","zustand"],"created_at":"2024-12-01T13:19:19.723Z","updated_at":"2026-04-10T12:01:51.251Z","avatar_url":"https://github.com/hyrmzz1.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Shared Note\n\n## Introduce\n\n- 이 프로젝트는 제공된 [Todolist CRUD 서버](https://github.com/starkoora/wanted-pre-onboarding-challenge-fe-1-api)를 활용하여 Todo App의 클라이언트를 구현한 과제입니다.\n  - **제공된 서버 레포지토리를 프로젝트의 server/ 디렉토리로 복사하여 사용했습니다.**\n  - **구현된 클라이언트(Todo App)는 프로젝트의 client/ 디렉토리에 위치합니다.**\n- 모든 유저가 하나의 Todo list를 공유하며(유저별로 분리된 Todo list 관리 기능을 제공하지 않습니다.), 전형적인 Todo list의 기능인 토글 기능이 요구사항에 포함되지 않아 프로젝트명을 **Shared Note**로 변경했습니다.\n\n### 주요 화면\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg alt=\"로그인 화면\" src=\"https://github.com/user-attachments/assets/2bcb5b78-083c-4683-9063-b4cf50d45469\"\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg alt=\"로그인 비활성화 화면\" src=\"https://github.com/user-attachments/assets/fed9f9c8-b04c-410d-8121-dd43772bdf44\"\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\" align=\"center\"\u003e\u003cb\u003e로그인 페이지 (\u003ccode\u003e/auth/login\u003c/code\u003e)\u003c/b\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\" align=\"center\"\u003e입력 필드가 비어 있거나 형식이 맞지 않으면 폼이 비활성화됩니다.\u003cbr\u003e로그인 성공 시 토큰을 로컬 스토리지에 저장하고 루트 경로로 이동합니다.\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg width=\"1552\" alt=\"회원가입 화면\" src=\"https://github.com/user-attachments/assets/91c89df5-2b0e-4ad2-b675-1138329d204a\"\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg width=\"1552\" alt=\"회원가입 비활성화 화면\" src=\"https://github.com/user-attachments/assets/e217314f-a560-490a-9933-50cc14ffdd05\"\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\" align=\"center\"\u003e\u003cb\u003e회원가입 페이지 (\u003ccode\u003e/auth/signup\u003c/code\u003e)\u003c/b\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\" align=\"center\"\u003e입력 필드가 비어 있거나 형식이 맞지 않으면 폼이 비활성화됩니다.\u003cbr\u003e비밀번호 확인 값이 일치하지 않을 경우에도 폼이 비활성화됩니다.\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg width=\"1552\" alt=\"글 목록\" src=\"https://github.com/user-attachments/assets/9824d809-3f09-4989-8c5b-eeff51e15786\"\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg width=\"1552\" alt=\"글 작성 화면\" src=\"https://github.com/user-attachments/assets/516f2ad4-d776-446a-9845-7d7caecacc59\"\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\" align=\"center\"\u003e\u003cb\u003eTodo 목록 및 추가 페이지 (\u003ccode\u003e/todos\u003c/code\u003e)\u003c/b\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\" align=\"center\"\u003eTodo 목록을 조회하거나, 새 Todo를 추가할 수 있습니다.\u003cbr\u003e추가된 Todo는 실시간으로 목록에 반영됩니다.\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003cimg width=\"1552\" alt=\"글 상세보기 화면\" src=\"https://github.com/user-attachments/assets/42448532-904f-4f51-a695-e878c7eda1cd\"\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cimg width=\"1552\" alt=\"글 수정 화면\" src=\"https://github.com/user-attachments/assets/da0e1cd8-f29e-4bc3-80da-96a3f0297fd5\"\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\" align=\"center\"\u003e\u003cb\u003e글 상세보기 (\u003ccode\u003e/todos/:id\u003c/code\u003e)\u003c/b\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\" align=\"center\"\u003eTodo의 제목과 내용을 확인할 수 있습니다.\u003cbr\u003e수정하거나 삭제한 내용은 목록에 실시간으로 반영됩니다.\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n  \n### 기술 스택\n\n| **분류**               | **기술**                                                                                                      |\n|-------------------------|--------------------------------------------------------------------------------------------------------------|\n| **언어 / 프레임워크 및 라이브러리**               | \u003cimg src=\"https://img.shields.io/badge/typescript-3178C6?style=for-the-badge\u0026logo=typescript\u0026logoColor=white\"\u003e \u003cimg src=\"https://img.shields.io/badge/react-61DAFB?style=for-the-badge\u0026logo=react\u0026logoColor=black\"\u003e |\n| **라우팅**             | \u003cimg src=\"https://img.shields.io/badge/react router v6-CA4245?style=for-the-badge\u0026logo=reactrouter\u0026logoColor=white\"\u003e |\n| **상태 관리**          | \u003cimg src=\"https://img.shields.io/badge/reactquery-FF4154?style=for-the-badge\u0026logo=reactquery\u0026logoColor=white\"\u003e \u003cimg src=\"https://img.shields.io/badge/zustand-DD6620?style=for-the-badge\u0026logo=zustand\u0026logoColor=white\"\u003e     |\n| **폼 관리 및 유효성 검사** | \u003cimg src=\"https://img.shields.io/badge/react hook form-EC5990?style=for-the-badge\u0026logo=reacthookform\u0026logoColor=white\"\u003e |\n| **스타일링**           | \u003cimg src=\"https://img.shields.io/badge/tailwind css-06B6D4?style=for-the-badge\u0026logo=tailwindcss\u0026logoColor=white\"\u003e |\n| **빌드 도구**           | \u003cimg src=\"https://img.shields.io/badge/vite-646CFF?style=for-the-badge\u0026logo=vite\u0026logoColor=white\"\u003e            |\n| **HTTP 클라이언트**     | \u003cimg src=\"https://img.shields.io/badge/axios-5A29E4?style=for-the-badge\u0026logo=axios\u0026logoColor=white\"\u003e          |\n\n### What I Learned\n\n\u003e 프로젝트 구현 과정에서 배운 것들에 대해 작성한 포스팅입니다.\n\n- [React-hook-form 적용기 : 공통 컴포넌트 설계 및 상태 동기화 문제 해결](https://hyrmzz1.tistory.com/169)\n- [server state 관리 방식을 Zustand에서 React Query로 마이그레이션해보았답니다](https://hyrmzz1.tistory.com/171)\n- [두유노 '리액트 에러 바운더리'?: 에러 핸들링 With React-Query](https://hyrmzz1.tistory.com/168)\n\n## 요구사항\n\n\u003e `server/db/db.json`이 DB 역할을 하게 됩니다. 해당 파일을 삭제하면 DB는 초기화 됩니다.\n\n### Login / Signup\n\n- [x] `/auth` 경로에 로그인 / 회원가입 기능을 개발합니다\n  - [x] 로그인, 회원가입을 별도의 경로로 분리해도 무방합니다\n  - [x] 최소한 이메일, 비밀번호 input, 제출 button을 갖도록 구성해주세요\n- [x] 이메일과 비밀번호의 유효성을 확인합니다\n  - [x] 이메일 조건 : 최소 `@`, `.` 포함\n  - [x] 비밀번호 조건 : 8자 이상 입력\n  - [x] 이메일과 비밀번호가 모두 입력되어 있고, 조건을 만족해야 제출 버튼이 활성화 되도록 해주세요\n- [x] 로그인 API를 호출하고, 올바른 응답을 받았을 때 루트 경로로 이동시켜주세요\n  - [x] 응답으로 받은 토큰은 로컬 스토리지에 저장해주세요\n  - [x] 다음 번에 로그인 시 토큰이 존재한다면 루트 경로로 리다이렉트 시켜주세요\n  - [x] 어떤 경우든 토큰이 유효하지 않다면 사용자에게 알리고 로그인 페이지로 리다이렉트 시켜주세요\n- [x] 로그아웃은 클라이언트 단에서 localStorage에 저장된 token을 삭제하는 방식으로 간단히 구현해주세요.\n\n## Todo List\n\n- [x] Todo List API를 호출하여 Todo List CRUD 기능을 구현해주세요.\n  - [x] 목록 / 상세 영역으로 나누어 구현해주세요.\n  - [x] Todo 목록을 볼 수 있습니다.\n  - [x] Todo 추가 버튼을 클릭하면 할 일이 추가 됩니다.\n  - [x] Todo 수정 버튼을 클릭하면 수정 모드를 활성화하고, 수정 내용을 제출하거나 취소할 수 있습니다.\n  - [x] Todo 삭제 버튼을 클릭하면 해당 Todo를 삭제할 수 있습니다.\n- [x] 한 화면 내에서 Todo List와 개별 Todo의 상세를 확인할 수 있도록 해주세요.\n  - [x] 새로고침을 했을 때 현재 상태가 유지되어야 합니다.\n  - [x] 개별 Todo를 조회 순서에 따라 페이지 뒤로가기를 통하여 조회할 수 있도록 해주세요.\n- [x] 한 페이지 내에서 새로고침 없이 데이터가 정합성을 갖추도록 구현해주세요.\n  - [x] 수정되는 Todo의 내용이 목록에서도 실시간으로 반영되어야 합니다.\n\n## 프로젝트 구조\n\n```js\n📦server  // 과제 수행을 위해 제공된 Todolist CRUD 서버\n📦client  // 수행 과제\n ┣ 📂public // 정적 파일 (favicon)\n ┣ 📂src  // 소스 코드 디렉터리\n ┃ ┣ 📂api  // API 요청 함수 모음\n ┃ ┣ 📂assets // 이미지 및 SVG 파일\n ┃ ┣ 📂components // 재사용 가능한 공통 컴포넌트\n ┃ ┣ 📂hooks  // 커스텀 훅\n ┃ ┣ 📂pages  // 페이지 컴포넌트\n ┃ ┣ 📂router // 라우팅 관련 코드\n ┃ ┣ 📂stores // Zustand 상태 관리\n ┃ ┣ 📂types  // 타입 정의 파일\n ┃ ┣ 📜App.tsx  // 앱 루트 컴포넌트\n ┃ ┣ 📜index.css  // 전역 스타일\n ┃ ┣ 📜main.tsx\n ┃ ┗ 📜vite-env.d.ts\n ┣ 📜.env // 환경 변수 파일\n ┣ 📜index.html\n ┣ 📜.gitignore\n ┣ 📜package.json\n ┗ 📜vite.config.ts\n```\n\n## 프로젝트 실행 방법\n\n1. 프로젝트 복제\n\n   ```bash\n   git clone https://github.com/hyrmzz1/shared-note.git\n\n   # 루트 디렉터리로 이동\n   cd shared-note\n   ```\n\n2. 백엔드 서버 설치 및 실행\n\n   ```bash\n    # server 디렉터리로 이동\n    cd server\n\n    # 의존성 설치 및 개발 서버 실행\n    yarn\n    yarn start # http://localhost:8080\n   ```\n\n3. 환경변수 파일 생성\n\n   ```bash\n   # `/client` 디렉터리에 `.env` 파일 생성 후 아래 내용 추가\n   VITE_API_URL=http://localhost:8080\n   ```\n\n4. 프론트엔드 설치 및 실행\n\n   ```bash\n    # 현재 server 디렉터리에 있다면 상위 디렉터리로 이동\n    cd ..\n\n    # client 디렉터리로 이동\n    cd client\n\n    # 의존성 설치 및 개발 서버 실행\n    npm install\n    npm run dev\n   ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyrmzz1%2Fshared-note","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhyrmzz1%2Fshared-note","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyrmzz1%2Fshared-note/lists"}