@pickme/auth
    Preparing search index...

    @pickme/auth

    사용자 관리 마이크로 꾸러미 조각

    Single-Spa Parcel 구성

    Amazon Cognito
    Single-SPA Userscript
    React React Query React_Hook_Form Jotai
    Chakra UI Axios Yup JWT
    Vite Rollup.js Terser
    ESLint FSDSteiger Prettier TypeScript
    Vitest TypeDoc Postman

    이 애플리케이션은 Amazon Cognito를 이용해 사용자 회원가입, 로그인, 로그아웃 등의 인증 기능을 제공합니다.
    회원가입 시 이메일 인증을 통해 사용자를 확인하며, 로그인 후에는 액세스 토큰, 리프레시 토큰, ID 토큰을 로컬 스토리지에 저장하여 인증 상태를 유지합니다.
    안전하고 신뢰할 수 있는 사용자 인증 흐름을 제공합니다.


    웹 및 모바일 앱을 위한 자격 증명 플랫폼
    사용자 디렉터리, 인증 서버, OAuth 2.0 액세스 토큰 및 자격 증명에 대한 권한 부여 서비스

    Cognito 사용자 풀 옵션

    • 사용자 풀 로그인 옵션: 사용자 이름 (아이디)
    • 가입 필수 옵션: 사용자 이름, 이메일

    환경변수

    VITE_COGNITO_USER_POOL_ID= # Cognito 사용자  아이디
    VITE_COGNITO_CLIENT_ID= # Cognito 앱클라이언트 아이디
    • idToken; 클라이언트에서 사용자 정보를 가져올 때 사용
    • accessToken; 백엔드 서비스에 접근할 때 사용
    • refreshToken; 두 토큰의 만료 시 갱신에 사용

    테스트 케이스 통과 여부 및 커버리지 현황 등을 시각적으로 제공합니다.
    이 테스트 리포트는 매 릴리즈 업데이트 시 자동으로 최신 상태로 배포됩니다.

           Vitest 테스트 리포트 바로가기



    프로젝트에서 사용되는 타입 정의를 문서화한 자료입니다.
    이 타입 문서는 매 릴리즈 업데이트 시 자동으로 최신 상태로 배포됩니다.

           TypeDoc 타입 문서 바로가기



    sequenceDiagram
    actor User
    participant Frontend
    participant Cognito
    participant API Gateway
    participant Backend

    User ->> Frontend: 로그인 정보 입력
    Frontend ->> Cognito: 인증 요청 (username, password)
    Cognito -->> Frontend: 토큰(ID/Access/Refresh)
    note over Frontend: 토큰(ID/Access/Refresh)은 localStorage에 저장됨
    Frontend ->> Frontend: ID Token을 디코딩해 사용자 정보 추출

    alt Access Token 만료됨
    alt Refresh Token 유효
    Frontend ->> Cognito: 새 Access Token 요청 (Refresh Token)
    Cognito -->> Frontend: 새 Access Token 응답
    Frontend ->> API Gateway: API 요청
    else Refresh Token도 만료됨
    Frontend -->> User: 재로그인 요청
    end
    else Access Token 유효
    loop API 요청 반복
    Frontend ->> API Gateway: API 요청 (Authorization: Bearer Access Token)
    API Gateway ->> Cognito: Access Token 검증 (User Pool Authorizer)
    Cognito -->> API Gateway: 검증 결과 (Claim 포함)
    note over API Gateway: 백엔드에서 디코딩 하지 않고 전달받은 사용자 Claim 사용
    API Gateway ->> Backend: API 요청 전달 (Claim 포함)
    Backend -->> API Gateway: 응답 데이터
    API Gateway -->> Frontend: 응답 데이터
    end
    end

           GitHubActions GitHub Actions 바로가기

    graph LR
    subgraph CD[🚀 CD 영역]
    direction LR
    Tag[태그 푸시] --> DeployGH[gh-pages에 배포] --> |자동 워크플로 실행|pages-build-deployment[GitHub Pages 배포 완료]
    Tag --> DeployAWS[Amazon S3에 배포] --> |콘텐츠 서빙|CloudFront[Amazon CloudFront]
    end

    Build -.-> |📦 아티팩트|Tag

    subgraph CI[🧪 CI 영역]
    direction LR
    Push[브랜치 푸시] --> Lint[린트]
    Lint --> |🟢 통과|Test[테스트]
    Test --> |🟢 통과|Docs[문서화] --> Review
    Test --> |🟢 통과|Build[빌드]
    Build --> |🟢 통과|Review[리뷰]
    Review -->|✔️ 승인|Merge[머지]
    end

    click Build "https://github.com/Daily1Hour/PickMe-Auth-Parcel/actions/workflows/vite-build.yml"
    click Review "https://github.com/Daily1Hour/PickMe-Auth-Parcel/actions/workflows/auto-assign.yml"
    click DeployGH "https://github.com/Daily1Hour/PickMe-Auth-Parcel/actions/workflows/deploy-gh-pages.yml"
    click pages-build-deployment "https://github.com/Daily1Hour/PickMe-Auth-Parcel/actions/workflows/pages/pages-build-deployment"
    click DeployAWS "https://github.com/Daily1Hour/PickMe-Auth-Parcel/actions/workflows/deploy-aws-s3.yml"
    열기
    PickMe-Auth-Parcel
    ├─ src
    │ ├─ main.tsx # 개발 서버 진입점
    │ ├─ parcel.tsx # single-spa Parcel 빌드 진입점
    │ ├─ app
    │ │ └─ App.tsx # 프로바이더 스택
    │ ├─ entities # 도메인 모델
    │ │ └─ auth
    │ │ ├─ index.ts
    │ │ ├─ api
    │ │ │ └─ dto.ts # dto 모델
    │ │ ├─ config
    │ │ │ └─ userPool.ts # Cognito 유저풀 정보 및 인스턴스
    │ │ ├─ model # 모델 및 유효성 검사
    │ │ │ ├─ index.ts
    │ │ │ ├─ LoginCredential.ts
    │ │ │ └─ SignupCredential.ts
    │ │ ├─ repository # 브라우저 데이터 접근
    │ │ │ └─ getLoggedIn.ts
    │ │ └─ service # 유즈케이스
    │ │ ├─ index.ts
    │ │ ├─ login # 로그인
    │ │ │ ├─ login.ts
    │ │ │ │ ├─ login.test.ts
    │ │ │ │ └─ login.usage.ts
    │ │ │ ├─ forgotPassword.ts
    │ │ │ │ ├─ forgotPassword.test.ts
    │ │ │ │ └─ forgotPassword.usage.ts
    │ │ │ └─ resetPassword.ts
    │ │ ├─ session # 토큰 사용
    │ │ │ ├─ getTokens.ts
    │ │ │ │ ├─ getTokens.test.ts
    │ │ │ │ └─ getTokens.usage.ts
    │ │ │ └─ getUser.ts
    │ │ └─ signup # 회원가입
    │ │ ├─ signup.ts
    │ │ │ ├─ signup.test.ts
    │ │ │ └─ signup.usage.ts
    │ │ └─ confirm.test.ts
    │ │ └─ confirm.ts
    │ ├─ features # 기능 구현체
    │ │ ├─ authActions # 로그인/회원가입 기능
    │ │ │ ├─ index.ts
    │ │ │ ├─ api # 쿼리
    │ │ │ │ ├─ index.ts
    │ │ │ │ ├─ useLoginFetch.ts
    │ │ │ │ ├─ useForgotPasswordFetch.ts
    │ │ │ │ ├─ useResetPasswordFetch.ts
    │ │ │ │ ├─ useSignupFetch.ts
    │ │ │ │ └─ useConfirmFetch.ts
    │ │ │ ├─ atom # 상태저장소
    │ │ │ │ ├─ index.ts
    │ │ │ │ └─ actionTypeAtom.ts
    │ │ │ ├─ hook # 폼 커스텀훅
    │ │ │ │ ├─ index.ts
    │ │ │ │ ├─ useLoginForm.ts
    │ │ │ │ ├─ useForgotPasswordForm.ts
    │ │ │ │ ├─ useResetPasswordForm.ts
    │ │ │ │ ├─ useSignupForm.ts
    │ │ │ │ └─ useConfirmForm.ts
    │ │ │ ├─ model # 스키마
    │ │ │ │ ├─ index.ts
    │ │ │ │ ├─ LoginSchema.ts
    │ │ │ │ ├─ ForgotPasswordSchema.ts
    │ │ │ │ ├─ ResetPasswordSchema.ts
    │ │ │ │ ├─ SignupSchema.ts
    │ │ │ │ └─ ConfirmSchema.ts
    │ │ │ └─ ui
    │ │ │ ├─ index.ts
    │ │ │ ├─ forms
    │ │ │ │ ├─ Field.tsx # 필드
    │ │ │ │ ├─ Layout.tsx # 폼 레이아웃
    │ │ │ │ ├─ LoginForm.tsx # 로그인 폼
    │ │ │ │ ├─ ForgotPasswordForm.tsx # 비밀번호 찾기 폼
    │ │ │ │ ├─ ResetPasswordForm.tsx # 비밀번호 리셋 폼
    │ │ │ │ ├─ SocialLoginForm.tsx # 소셜로그인 폼
    │ │ │ │ ├─ SignupForm.tsx # 회원가입 폼
    │ │ │ │ └─ ConfirmForm.tsx # 회원가입 인증 폼
    │ │ │ ├─ ActionLayout.tsx # 액션 레이아웃
    │ │ │ └─ PopoverLayout.tsx # 팝오버 레이아웃
    │ │ └─ userMenu # 로그인 인증 후 사용자메뉴 기능
    │ │ ├─ index.ts
    │ │ ├─ api
    │ │ │ ├─ index.ts
    │ │ │ ├─ useLoggedIn.ts
    │ │ │ └─ useUserInfo.ts
    │ │ └─ ui
    │ │ └─ UserMenu.tsx
    │ ├─ pages # 페이지
    │ │ └─ auth
    │ │ ├─ index.tsx
    │ │ ├─ hook
    │ │ │ └─ useTokens.ts
    │ │ └─ ui
    │ │ ├─ index.ts
    │ │ ├─ AuthControls.tsx # 로그인/회원가입 컨트롤
    │ │ └─ TokenInfo.tsx # 로그인 후 토큰 정보
    │ ├─ shared # 공용
    │ │ ├─ ActionType.ts
    │ │ ├─ theme.ts
    │ │ ├─ trans-ko.ts
    │ │ ├─ styles
    │ │ │ ├─ global.css
    │ │ │ └─ index.js
    │ │ └─ ui
    │ │ ├─ atoms
    │ │ │ ├─ index.ts
    │ │ │ ├─ ButtonBackground.tsx
    │ │ │ └─ StyledButton.tsx
    │ │ ├─ index.ts
    │ │ └─ molecules
    │ │ ├─ index.ts
    │ │ ├─ CircleButton.tsx
    │ │ ├─ PrimaryButton.tsx
    │ │ └─ SecondaryButton.tsx
    │ ├─ third-party
    │ │ └─ chakra-ui
    │ └─ userscript # 유저스크립트
    │ ├─ widget.meta.ts # 메타데이터
    │ └─ widget.user.js # 스크립트
    ├─ tsconfig.json # ts 설정
    │ ├─ tsconfig.app.json
    │ ├─ tsconfig.node.json
    │ └─ typedoc.json # 문서화 설정
    ├─ package.json # 의존성 설정
    │ ├─ .prettierrc # 포맷터 설정
    │ ├─ eslint.config.js # 린트 설정
    │ └─ steiger.config.ts # FSD 린트 설정
    └─ vite.config.ts # Vite 설정 파일
    └─ vite-env.d.ts # 환경변수 타입 정의

    $ npm install
    $ npm run dev
    1. 빌드
    2. 배포 또는 프리뷰
    3. 배포 주소를 parcelURL로 사용하여 다른 애플리케이션에 주입
    $ npm install
    $ npm run build
    • React

      import Parcel from "single-spa-react/parcel";

      export function myComponent(): React.ReactElement {
      const [parcelConfig, setParcelConfig] = useState<any>(null);

      useEffect(() => {
      const loadParcel = async () => {
      const { parcel: config } = await import(parcelURL);
      setParcelConfig(config);
      };
      loadParcel();
      }, []);

      return parcelConfig ? <Parcel config={parcelConfig} /> : <div>Loading...</div>;
      }
    • Vue

      <template>
      <Parcel
      :config="parcelConfig"
      :mountParcel="mountParcel"
      />
      </template>

      <script lang="ts">
      import Parcel from "single-spa-vue/parcel";
      import { mountRootParcel } from "single-spa";

      export default {
      components: { Parcel },
      data() {
      return {
      parcelConfig: import(parcelURL).then((module) => module.parcel),
      mountParcel: mountRootParcel,
      };
      },
      };
      </script>
    • Svelte

      <script lang="ts">
      import { onMount } from "svelte";
      import { mountRootParcel } from "single-spa";

      let container: HTMLDivElement;

      onMount(() => {
      let parcel: any;
      const loadParcel = async () => {
      const { parcel: parcelConfig } = await import(parcelURL);

      parcel = mountRootParcel(parcelConfig, {
      domElement: container,
      });
      };
      loadParcel();

      return () => {
      if (parcel) {
      parcel.unmount();
      }
      };
      });
      </script>

      <div bind:this={container}></div>
    • getTokens 함수
      현재 로그인되어있는 사용자의 토큰 3종을 읽어옵니다.
      이 기능은 동일 도메인에서 로그인되어 있어야 작동합니다.

      const { getTokens } = await import(parcelURL);

      const { idToken, accessToken, refreshToken } = await getTokens();

    @pickme/auth를 위젯 형태로 페이지에 삽입하여,
    사용자 관리 애플리케이션을 페이지에 통합할 필요 없이 개발 페이지에서도 사용할 수 있도록 합니다.

    1. 유저 스크립트 관리자 설치

    2. 스크립트 다운로드 (스크립트 관리자를 설치했으면 자동으로 감지합니다.)

      Download

    3. 개발 서버로 열린 http://localhost 도메인에서 자동으로 @pickme/auth가 페이지에 삽입됩니다.