-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: Standardize technical terms to English in guides/examples Korean documentation #794
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,11 +12,11 @@ sidebar_position: 1 | |
|
||
## 사용자 로그인 정보 수집 방법 | ||
|
||
앱에서 사용자로부터 로그인 정보를 수집하는 방법을 알아보겠습니다. 만약에 OAuth를 사용하는 경우, OAuth 제공자의 로그인 페이지를 사용하여 [3단계](#how-to-store-the-token-for-authenticated-requests)로 바로 넘어갈 수 있습니다. | ||
앱에서 사용자로부터 로그인 정보를 수집하는 방법을 알아보겠습니다. 만약에 OAuth를 사용하는 경우, OAuth 제공자의 로그인 page를 사용하여 [3단계](#how-to-store-the-token-for-authenticated-requests)로 바로 넘어갈 수 있습니다. | ||
|
||
### 전용 로그인 페이지 만들기 | ||
### 전용 로그인 page 만들기 | ||
|
||
웹사이트에서 사용자 이름과 비밀번호를 입력하는 로그인 페이지를 제공하는 것이 일반적입니다. 이러한 페이지들은 구조가 단순하여 별도의 복잡한 분해 작업이 필요하지 않습니다. 다만, 로그인과 회원가입 양식은 외형이 비슷하기 때문에, 경우에 따라 두 양식을 하나의 페이지에서 통합하여 제공하기도 합니다. | ||
웹사이트에서 사용자 이름과 비밀번호를 입력하는 로그인 page를 제공하는 것이 일반적입니다. 이러한 page들은 구조가 단순하여 별도의 복잡한 분해 작업이 필요하지 않습니다. 다만, 로그인과 회원가입 양식은 외형이 비슷하기 때문에, 경우에 따라 두 양식을 하나의 page에서 통합하여 제공하기도 합니다. | ||
|
||
- 📂 pages | ||
- 📂 login | ||
|
@@ -28,9 +28,9 @@ sidebar_position: 1 | |
|
||
로그인과 회원가입 컴포넌트를 별도로 만들고, 필요에 따라 index 파일에서 export 할 수 있습니다. 이 컴포넌트들은 사용자로부터 로그인 정보을 입력받는 폼을 포함합니다. | ||
|
||
### 로그인 다이얼로그 만들기 | ||
### 로그인 widget 만들기 | ||
|
||
앱의 어디서나 사용할 수 있는 로그인 다이얼로그가 필요하다면, 이 다이얼로그를 재사용 가능한 위젯으로 만드는 것이 좋습니다. 이렇게 하면 불필요한 세분화를 피하면서도 어떤 페이지에서나 쉽게 로그인 다이얼로그를 띄울 수 있습니다. | ||
앱의 어디서나 사용할 수 있는 로그인 다이얼로그가 필요하다면, 이 다이얼로그를 재사용 가능한 widget으로 만드는 것이 좋습니다. 이렇게 하면 불필요한 세분화를 피하면서도 어떤 page에서나 쉽게 로그인 다이얼로그를 띄울 수 있습니다. | ||
|
||
- 📂 widgets | ||
- 📂 login-dialog | ||
|
@@ -39,11 +39,11 @@ sidebar_position: 1 | |
- 📄 index.ts | ||
- other widgets… | ||
|
||
가이드 나머지 부분은 전용 페이지 방식에 대해 설명하고 있지만, 동일한 원칙을 로그인 다이얼로그에도 적용할 수 있습니다. | ||
가이드 나머지 부분은 전용 page 방식에 대해 설명하고 있지만, 동일한 원칙을 로그인 다이얼로그에도 적용할 수 있습니다. | ||
|
||
### 클라이언트 측 검증 | ||
|
||
특히 회원가입의 경우, 사용자가 입력한 내용에 문제가 있을 때 빠르게 피드백을 제공하기 위해 클라이언트 측 검증을 수행하는 것이 좋습니다. 이를 위해 로그인 페이지의 `model` 세그먼트에서 검증 로직을 구현할 수 있습니다. 예를 들어 JS/TS에서는 [Zod][ext-zod]와 같은 스키마 검증 라이브러리를 사용할 수 있습니다: | ||
특히 회원가입의 경우, 사용자가 입력한 내용에 문제가 있을 때 빠르게 피드백을 제공하기 위해 클라이언트 측 검증을 수행하는 것이 좋습니다. 이를 위해 로그인 page의 `model` segment에서 검증 로직을 구현할 수 있습니다. 예를 들어 JS/TS에서는 [Zod][ext-zod]와 같은 스키마 검증 라이브러리를 사용할 수 있습니다: | ||
|
||
```ts title="pages/login/model/registration-schema.ts" | ||
import { z } from "zod"; | ||
|
@@ -58,7 +58,7 @@ export const registrationData = z.object({ | |
}); | ||
``` | ||
|
||
그런 다음, ui 세그먼트에서 이 스키마를 사용하여 사용자 입력을 검증할 수 있습니다: | ||
그런 다음, ui segment에서 이 스키마를 사용하여 사용자 입력을 검증할 수 있습니다: | ||
|
||
```tsx title="pages/login/ui/RegisterPage.tsx" | ||
import { registrationData } from "../model/registration-schema"; | ||
|
@@ -90,11 +90,11 @@ export function RegisterPage() { | |
|
||
## 로그인 정보 전송 방법 | ||
|
||
로그인 정보를 백엔드 서버로 전송하기 위한 요청 함수를 작성하세요. 이 함수는 상태 관리 라이브러리나 뮤테이션 라이브러리(예: TanStack Query)를 사용하여 호출할 수 있습니다. | ||
로그인 정보를 백엔드 서버로 전송하기 위한 요청 함수를 작성하세요. 이 함수는 상태 관리 라이브러리나 mutation 라이브러리(예: TanStack Query)를 사용하여 호출할 수 있습니다. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: why did you include "mutation" in the list of terms? It seems to me like a general concept from computer science that might be more understandable when translated There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You raise a good point. "뮤테이션" is just a phonetic translation of "mutation". Instead of this transliteration, we should explain what mutation means in TanStack Query's context. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since "mutation" specifically refers to How does this suggestion sound? Am I on the right track here? |
||
|
||
### 요청 함수 저장 위치 | ||
|
||
이 요청 함수를 저장할 수 있는 위치는 크게 두 가지입니다: `shared/api` 또는 페이지의 `api` 세그먼트입니다. | ||
이 요청 함수를 저장할 수 있는 위치는 크게 두 가지입니다: `shared/api` 또는 page의 `api` segment입니다. | ||
|
||
#### `shared/api`에 저장하기 | ||
|
||
|
@@ -108,7 +108,7 @@ export function RegisterPage() { | |
- 📄 client.ts | ||
- 📄 index.ts | ||
|
||
`📄 client.ts` 파일은 요청을 수행하는 원시 함수(예: `fetch()`)에 대한 래퍼를 포함합니다. 이 래퍼는 백엔드의 기본 URL 설정, 헤더 설정, 데이터 직렬화 등을 처리합니다. | ||
`📄 client.ts` 파일은 요청을 수행하는 원시 함수(예: `fetch()`)에 대한 wrapper를 포함합니다. 이 wrapper는 백엔드의 기본 URL 설정, 헤더 설정, 데이터 직렬화 등을 처리합니다. | ||
|
||
```ts title="shared/api/endpoints/login.ts" | ||
import { POST } from "../client"; | ||
|
@@ -122,9 +122,9 @@ export function login({ email, password }: { email: string, password: string }) | |
export { login } from "./endpoints/login"; | ||
``` | ||
|
||
#### 페이지의 `api` 세그먼트에 저장하기 | ||
#### page의 `api` segment에 저장하기 | ||
|
||
로그인 요청이 특정 페이지에만 필요한 경우, 로그인 페이지의 `api` 세그먼트에 함수를 저장할 수 있습니다: | ||
로그인 요청이 특정 page에만 필요한 경우, 로그인 page의 `api` segment에 함수를 저장할 수 있습니다: | ||
|
||
- 📂 pages | ||
- 📂 login | ||
|
@@ -143,15 +143,15 @@ export function login({ email, password }: { email: string, password: string }) | |
} | ||
``` | ||
|
||
이 함수는 페이지의 공개 API에서 내보낼 필요가 없습니다. 로그인 요청이 다른 곳에서 필요할 가능성이 낮기 때문입니다. | ||
이 함수는 page의 공개 API에서 내보낼 필요가 없습니다. 로그인 요청이 다른 곳에서 필요할 가능성이 낮기 때문입니다. | ||
|
||
### 이중 인증(2FA) | ||
|
||
앱이 이중 인증(2FA)을 지원하는 경우, 사용자가 일회용 비밀번호(OTP)를 입력할 수 있는 별도의 페이지로 이동해야 할 수 있습니다. 일반적으로 `POST /login` 요청은 사용자가 2FA를 활성화했음을 나타내는 플래그가 포함된 사용자 객체를 반환합니다. 이 플래그가 설정되면 사용자를 2FA 페이지로 리디렉션해야 합니다. | ||
앱이 이중 인증(2FA)을 지원하는 경우, 사용자가 일회용 비밀번호(OTP)를 입력할 수 있는 별도의 page로 이동해야 할 수 있습니다. 일반적으로 `POST /login` 요청은 사용자가 2FA를 활성화했음을 나타내는 플래그가 포함된 사용자 객체를 반환합니다. 이 플래그가 설정되면 사용자를 2FA page로 리디렉션해야 합니다. | ||
|
||
2FA 페이지는 로그인과 밀접하게 연관되어 있으므로 Pages 레이어의 `login` 슬라이스에 함께 저장하는 것이 좋습니다.<br/> | ||
2FA page는 로그인과 밀접하게 연관되어 있으므로 Pages layer의 `login` slice에 함께 저장하는 것이 좋습니다.<br/> | ||
|
||
이중 인증을 처리하기 위해서는 `login()` 함수와 유사한 또 다른 요청 함수가 필요할 것입니다. 이러한 함수들은 `Shared`나 로그인 페이지의 `api` 세그먼트에 함께 배치할 수 있습니다. | ||
이중 인증을 처리하기 위해서는 `login()` 함수와 유사한 또 다른 요청 함수가 필요할 것입니다. 이러한 함수들은 `Shared`나 로그인 page의 `api` segment에 함께 배치할 수 있습니다. | ||
|
||
## 인증된 요청의 토큰 저장 방법 {#how-to-store-the-token-for-authenticated-requests} | ||
|
||
|
@@ -163,7 +163,7 @@ export function login({ email, password }: { email: string, password: string }) | |
|
||
### Shared에 저장하기 | ||
|
||
`shared/api`에 저장하는 접근 방식은 API 클라이언트와 잘 맞아떨어집니다. 인증이 필요한 다른 요청 함수에서 이 토큰을 쉽게 사용할 수 있기 때문입니다. API 클라이언트에서 반응형 스토어나 모듈 수준 변수를 사용해 토큰을 저장하고, `login()/logout()` 함수에서 해당 상태를 업데이트할 수 있습니다. | ||
`shared/api`에 저장하는 접근 방식은 API 클라이언트와 잘 맞아떨어집니다. 인증이 필요한 다른 요청 함수에서 이 토큰을 쉽게 사용할 수 있기 때문입니다. API 클라이언트에서 반응형 store나 module 수준 변수를 사용해 토큰을 저장하고, `login()/logout()` 함수에서 해당 상태를 업데이트할 수 있습니다. | ||
|
||
토큰 자동 갱신은 API 클라이언트에서 미들웨어 형태로 구현할 수 있습니다. 모든 요청마다 실행되며, 아래와 같은 방식으로 동작합니다: | ||
|
||
|
@@ -177,49 +177,49 @@ export function login({ email, password }: { email: string, password: string }) | |
|
||
### Entities에 저장하기 | ||
|
||
FSD 프로젝트에서는 사용자 엔티티 또는 현재 사용자 엔티티를 사용하는 것이 일반적입니다. 두 엔티티는 같은 것을 가리킬 수도 있습니다. | ||
FSD 프로젝트에서는 user entity 또는 current user entity를 사용하는 것이 일반적입니다. 두 entity는 같은 것을 가리킬 수도 있습니다. | ||
|
||
:::note | ||
|
||
**현재 사용자**는 "viewer" 또는 "me"라고도 합니다. 이는 권한과 개인 정보를 가진 단일 인증 사용자와 공개적으로 접근 가능한 정보로 구성된 모든 사용자 목록을 구별하기 위해 사용됩니다. | ||
|
||
::: | ||
|
||
User 엔티티에 토큰을 저장하려면 `model` 세그먼트에 반응형 스토어를 생성해야 합니다. 이 스토어는 토큰과 사용자 객체를 모두 포함할 수 있습니다. | ||
User entity에 토큰을 저장하려면 `model` segment에 reactive store를 생성해야 합니다. 이 store는 토큰과 user 객체를 모두 포함할 수 있습니다. | ||
|
||
API 클라이언트는 일반적으로 `shared/api` 정의되거나 엔티티 전체에 분산되어 있습니다. 따라서 주요 과제는 레이어의 임포트 규칙([import rule on layers][import-rule-on-layers])을 위반하지 않으면서 다른 요청에서도 토큰을 사용할 수 있도록 하는 것입니다. | ||
API 클라이언트는 일반적으로 `shared/api` 정의되거나 entity 전체에 분산되어 있습니다. 따라서 주요 과제는 layer의 임포트 규칙([import rule on layers][import-rule-on-layers])을 위반하지 않으면서 다른 요청에서도 토큰을 사용할 수 있도록 하는 것입니다. | ||
|
||
> 레이어 규칙: 슬라이스의 모듈은 자기보다 낮은 레이어에 위치한 다른 슬라이스만 임포트할 수 있습니다. | ||
> Layer 규칙: slice의 module은 자기보다 낮은 layer에 위치한 다른 slice만 import할 수 있습니다. | ||
|
||
이 문제를 해결하기 위한 몇 가지 방법은 다음과 같습니다: | ||
|
||
1. **요청 시마다 토큰 수동 전달** | ||
이 방법은 가장 간단하지만, 번거롭고 타입 안전성이 보장되지 않으면 실수가 발생할 가능성이 큽니다. 또한 Shared의 API 클라이언트에 미들웨어 패턴을 적용하기 어렵습니다. | ||
2. **앱 전역에서 글로벌 스토어로 토큰 관리** | ||
토큰을 context나 `localStorage`에 저장하고, `shared/api`에 토큰 접근 키를 보관합니다. 토큰의 반응형 저장소는 User 엔터티에서 내보내며, 필요한 경우 context Provider는 App 레이어에서 설정합니다. 이 방법은 API 클라이언트 설계를 유연하게 만들지만, 상위 레이어에 context 제공이 필요하다는 암묵적인 의존성을 발생시킵니다. 따라서 context나 `localStorage`가 제대로 설정되지 않았을 경우, 유용한 오류 메시지를 제공하는 것이 좋습니다. | ||
2. **앱 전역에서 글로벌 store로 토큰 관리** | ||
토큰을 context나 `localStorage`에 저장하고, `shared/api`에 토큰 접근 키를 보관합니다. 토큰의 reactive store는 User entity에서 내보내며, 필요한 경우 context Provider는 App layer에서 설정합니다. 이 방법은 API 클라이언트 설계를 유연하게 만들지만, 상위 layer에 context 제공이 필요하다는 암묵적인 의존성을 발생시킵니다. 따라서 context나 `localStorage`가 제대로 설정되지 않았을 경우, 유용한 오류 메시지를 제공하는 것이 좋습니다. | ||
3. **토큰 변경 시 API 클라이언트 업데이트** | ||
반응형 스토어를 활용해 엔티티의 스토어가 변경될 때마다 API 클라이언트의 토큰 스토어를 업데이트하는 구독(subscribe)을 생성할 수 있습니다. 이 방법은 상위 계층에 암묵적인 의존성을 만든다는 점에서는 이전 해결책과 비슷하지만, 이 방법은 더 "명령형(push)" 접근이고, 이전 방법은 더 "선언형(pull)" 접근입니다. | ||
reactive store를 활용해 entity의 store가 변경될 때마다 API 클라이언트의 토큰 store를 업데이트하는 구독(subscribe)을 생성할 수 있습니다. 이 방법은 상위 layer에 암묵적인 의존성을 만든다는 점에서는 이전 해결책과 비슷하지만, 이 방법은 더 "명령형(push)" 접근이고, 이전 방법은 더 "선언형(pull)" 접근입니다. | ||
|
||
엔티티의 `model`에 토큰을 저장하여 문제를 해결하면, 토큰 관리와 관련된 더 많은 비즈니스 로직을 추가할 수 있습니다. 예를 들어, `model` 세그먼트에 토큰 만료 시 갱신하는 로직을 추가하거나, 일정 시간이 지나면 토큰을 무효화하는 로직을 포함할 수 있습니다. | ||
백엔드에 요청을 보내야 하는 경우에는 User 엔티티의 api 세그먼트나 `shared/api`를 사용할 수 있습니다. | ||
entity의 `model` segment에 토큰을 저장하여 문제를 해결하면, 토큰 관리와 관련된 더 많은 비즈니스 로직을 추가할 수 있습니다. 예를 들어, `model` segment에 토큰 만료 시 갱신하는 로직을 추가하거나, 일정 시간이 지나면 토큰을 무효화하는 로직을 포함할 수 있습니다. | ||
백엔드에 요청을 보내야 하는 경우에는 User entity의 api segment나 `shared/api`를 사용할 수 있습니다. | ||
|
||
### Pages/Widgets에 저장하기 (권장하지 않음) | ||
|
||
애플리케이션 전역에 적용되는 상태(예: 액세스 토큰)를 페이지나 위젯에 저장하는 것은 권장되지 않습니다. 예를 들어, 로그인 페이지의 `model` 세그먼트에 토큰 스토어를 배치하는 대신, 이 아티클에서 제시한 처음 두 해결책인 Shared나 Entities를 사용하는 것이 권장됩니다. | ||
애플리케이션 전역에 적용되는 상태(예: 액세스 토큰)를 page나 widget에 저장하는 것은 권장되지 않습니다. 예를 들어, 로그인 page의 `model` segment에 토큰 store를 배치하는 대신, 이 아티클에서 제시한 처음 두 해결책인 Shared나 Entities를 사용하는 것이 권장됩니다. | ||
|
||
## 로그아웃 및 토큰 무효화 | ||
|
||
로그아웃 기능은 애플리케이션에서 중요한 기능이지만, 이를 위한 별도의 페이지는 없는 경우가 많습니다. 이 기능은 백엔드에 인증된 요청을 보내고, 토큰 스토어를 업데이트하는 작업으로 구성됩니다. | ||
로그아웃 기능은 애플리케이션에서 중요한 기능이지만, 이를 위한 별도의 page는 없는 경우가 많습니다. 이 기능은 백엔드에 인증된 요청을 보내고, 토큰 store를 업데이트하는 작업으로 구성됩니다. | ||
|
||
모든 요청을 `shared/api`에 보관했다면, 로그인 함수 근처에 로그아웃 요청 함수를 두는 것이 좋습니다. 그렇지 않은 경우, 로그아웃 버튼이 있는 위치 근처에 로그아웃 요청 함수를 배치할 수 있습니다. 예를 들어, 모든 페이지에 나타나는 헤더 위젯에 로그아웃 링크가 있다면, 해당 요청을 그 위젯의 `api` 세그먼트에 배치하는 것이 좋습니다. | ||
모든 요청을 `shared/api`에 보관했다면, 로그인 함수 근처에 로그아웃 요청 함수를 두는 것이 좋습니다. 그렇지 않은 경우, 로그아웃 버튼이 있는 위치 근처에 로그아웃 요청 함수를 배치할 수 있습니다. 예를 들어, 모든 page에 나타나는 header widget에 로그아웃 링크가 있다면, 해당 요청을 그 widget의 `api` segment에 배치하는 것이 좋습니다. | ||
|
||
토큰 스토어에 대한 업데이트는 로그아웃 버튼이 위치한 곳(예: 헤더 위젯)에서 트리거되어야 합니다. 이 요청과 스토어 업데이트를 해당 위젯의 `model` 세그먼트에서 결합할 수 있습니다. | ||
토큰 store에 대한 업데이트는 로그아웃 버튼이 위치한 곳(예: header widget)에서 트리거되어야 합니다. 이 요청과 store 업데이트를 해당 widget의 `model` segment에서 결합할 수 있습니다. | ||
|
||
### 자동 로그아웃 | ||
|
||
로그아웃 요청 실패나 로그인 토큰 갱신 실패 시를 대비해 안전장치를 마련하는 것도 중요합니다. 이 두 경우 모두 토큰 스토어를 비워야 합니다. 토큰을 Entities에 저장하는 경우, 이 로직은 `model` 세그먼트에 배치할 수 있습니다. 토큰을 Shared에 저장하는 경우, 이 로직을 `shared/api`에 포함하면 세그먼트가 너무 복잡해질 수 있습니다. 따라서 토큰 관리 로직을 별도의 세그먼트(예: `shared/auth`)로 분리하는 것도 고려해볼 만합니다. | ||
로그아웃 요청 실패나 로그인 토큰 갱신 실패 시를 대비해 안전장치를 마련하는 것도 중요합니다. 이 두 경우 모두 토큰 store를 비워야 합니다. 토큰을 Entities에 저장하는 경우, 이 로직은 `model` segment에 배치할 수 있습니다. 토큰을 Shared에 저장하는 경우, 이 로직을 `shared/api`에 포함하면 segment가 너무 복잡해질 수 있습니다. 따라서 토큰 관리 로직을 별도의 segment(예: `shared/auth`)로 분리하는 것도 고려해볼 만합니다. | ||
|
||
[tutorial-authentication]: /docs/get-started/tutorial#authentication | ||
[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers | ||
[ext-remix]: https://remix.run | ||
[ext-zod]: https://zod.dev | ||
[ext-zod]: https://zod.dev |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: I think this is not intended — the original title is "Dialog for login", there was no intention to reference the FSD Widget
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I missed this part, I'll reflect it. Thank you.