Skip to content

Commit f174b70

Browse files
authored
docs: authentication guide translated into Korean (#736)
1 parent 68cc55f commit f174b70

File tree

1 file changed

+225
-0
lines changed
  • i18n/kr/docusaurus-plugin-content-docs/current/guides/examples

1 file changed

+225
-0
lines changed
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
---
2+
sidebar_position: 1
3+
---
4+
5+
# Authentication
6+
7+
๋ณดํ†ต ์ธ์ฆ์€ ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ๋‹จ๊ณ„๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค:
8+
9+
1. ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ๋กœ๊ทธ์ธ ์ •๋ณด(์•„์ด๋””, ๋น„๋ฐ€๋ฒˆํ˜ธ ๋“ฑ)์„ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค.
10+
2. ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ ํ•ด๋‹น ๋กœ๊ทธ์ธ ์ •๋ณด์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
11+
3. ์ธ์ฆ ํ›„ ๋ฐœ๊ธ‰๋ฐ›์€ ํ† ํฐ์„ ์ €์žฅํ•˜์—ฌ ์ดํ›„ ์š”์ฒญ์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
12+
13+
## ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์ •๋ณด ์ˆ˜์ง‘ ๋ฐฉ๋ฒ•
14+
15+
์•ฑ์—์„œ ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ์— OAuth๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, OAuth ์ œ๊ณต์ž์˜ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ [3๋‹จ๊ณ„](#how-to-store-the-token-for-authenticated-requests)๋กœ ๋ฐ”๋กœ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
16+
17+
### ์ „์šฉ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ
18+
19+
์›น์‚ฌ์ดํŠธ์—์„œ ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๋Š” ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํŽ˜์ด์ง€๋“ค์€ ๊ตฌ์กฐ๊ฐ€ ๋‹จ์ˆœํ•˜์—ฌ ๋ณ„๋„์˜ ๋ณต์žกํ•œ ๋ถ„ํ•ด ์ž‘์—…์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ๋กœ๊ทธ์ธ๊ณผ ํšŒ์›๊ฐ€์ž… ์–‘์‹์€ ์™ธํ˜•์ด ๋น„์Šทํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ๋‘ ์–‘์‹์„ ํ•˜๋‚˜์˜ ํŽ˜์ด์ง€์—์„œ ํ†ตํ•ฉํ•˜์—ฌ ์ œ๊ณตํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.
20+
21+
- ๐Ÿ“‚ pages
22+
- ๐Ÿ“‚ login
23+
- ๐Ÿ“‚ ui
24+
- ๐Ÿ“„ LoginPage.tsx (or your framework's component file format)
25+
- ๐Ÿ“„ RegisterPage.tsx
26+
- ๐Ÿ“„ index.ts
27+
- other pagesโ€ฆ
28+
29+
๋กœ๊ทธ์ธ๊ณผ ํšŒ์›๊ฐ€์ž… ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณ„๋„๋กœ ๋งŒ๋“ค๊ณ , ํ•„์š”์— ๋”ฐ๋ผ index ํŒŒ์ผ์—์„œ export ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ๋กœ๊ทธ์ธ ์ •๋ณด์„ ์ž…๋ ฅ๋ฐ›๋Š” ํผ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
30+
31+
### ๋กœ๊ทธ์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ ๋งŒ๋“ค๊ธฐ
32+
33+
์•ฑ์˜ ์–ด๋””์„œ๋‚˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋กœ๊ทธ์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด, ์ด ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์œ„์ ฏ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ์„ธ๋ถ„ํ™”๋ฅผ ํ”ผํ•˜๋ฉด์„œ๋„ ์–ด๋–ค ํŽ˜์ด์ง€์—์„œ๋‚˜ ์‰ฝ๊ฒŒ ๋กœ๊ทธ์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
34+
35+
- ๐Ÿ“‚ widgets
36+
- ๐Ÿ“‚ login-dialog
37+
- ๐Ÿ“‚ ui
38+
- ๐Ÿ“„ LoginDialog.tsx
39+
- ๐Ÿ“„ index.ts
40+
- other widgetsโ€ฆ
41+
42+
๊ฐ€์ด๋“œ ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์€ ์ „์šฉ ํŽ˜์ด์ง€ ๋ฐฉ์‹์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ณ  ์žˆ์ง€๋งŒ, ๋™์ผํ•œ ์›์น™์„ ๋กœ๊ทธ์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ์—๋„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
43+
44+
### ํด๋ผ์ด์–ธํŠธ ์ธก ๊ฒ€์ฆ
45+
46+
ํŠนํžˆ ํšŒ์›๊ฐ€์ž…์˜ ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋‚ด์šฉ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๋•Œ ๋น ๋ฅด๊ฒŒ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ํด๋ผ์ด์–ธํŠธ ์ธก ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์˜ `model` ์„ธ๊ทธ๋จผํŠธ์—์„œ ๊ฒ€์ฆ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด JS/TS์—์„œ๋Š” [Zod][ext-zod]์™€ ๊ฐ™์€ ์Šคํ‚ค๋งˆ ๊ฒ€์ฆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
47+
48+
```ts title="pages/login/model/registration-schema.ts"
49+
import { z } from "zod";
50+
51+
export const registrationData = z.object({
52+
email: z.string().email(),
53+
password: z.string().min(6),
54+
confirmPassword: z.string(),
55+
}).refine((data) => data.password === data.confirmPassword, {
56+
message: "๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค",
57+
path: ["confirmPassword"],
58+
});
59+
```
60+
61+
๊ทธ๋Ÿฐ ๋‹ค์Œ, ui ์„ธ๊ทธ๋จผํŠธ์—์„œ ์ด ์Šคํ‚ค๋งˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
62+
63+
```tsx title="pages/login/ui/RegisterPage.tsx"
64+
import { registrationData } from "../model/registration-schema";
65+
66+
function validate(formData: FormData) {
67+
const data = Object.fromEntries(formData.entries());
68+
try {
69+
registrationData.parse(data);
70+
} catch (error) {
71+
// TODO: Show error message to the user
72+
}
73+
}
74+
75+
export function RegisterPage() {
76+
return (
77+
<form onSubmit={(e) => validate(new FormData(e.target))}>
78+
<label htmlFor="email">์ด๋ฉ”์ผ</label>
79+
<input id="email" name="email" required />
80+
81+
<label htmlFor="password">๋น„๋ฐ€๋ฒˆํ˜ธ (์ตœ์†Œ 6์ž)</label>
82+
<input id="password" name="password" type="password" required />
83+
84+
<label htmlFor="confirmPassword">๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ</label>
85+
<input id="confirmPassword" name="confirmPassword" type="password" required />
86+
</form>
87+
)
88+
}
89+
```
90+
91+
## ๋กœ๊ทธ์ธ ์ •๋ณด ์ „์†ก ๋ฐฉ๋ฒ•
92+
93+
๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ ์ „์†กํ•˜๊ธฐ ์œ„ํ•œ ์š”์ฒญ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”. ์ด ํ•จ์ˆ˜๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ๋ฎคํ…Œ์ด์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(์˜ˆ: TanStack Query)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
94+
95+
### ์š”์ฒญ ํ•จ์ˆ˜ ์ €์žฅ ์œ„์น˜
96+
97+
์ด ์š”์ฒญ ํ•จ์ˆ˜๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์œ„์น˜๋Š” ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค: `shared/api` ๋˜๋Š” ํŽ˜์ด์ง€์˜ `api` ์„ธ๊ทธ๋จผํŠธ์ž…๋‹ˆ๋‹ค.
98+
99+
#### `shared/api`์— ์ €์žฅํ•˜๊ธฐ
100+
101+
๋ชจ๋“  API ์š”์ฒญ์„ `shared/api`์— ๋ชจ์•„์„œ ๊ด€๋ฆฌํ•˜๊ณ , ์—”๋“œํฌ์ธํŠธ๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•˜๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
102+
103+
- ๐Ÿ“‚ shared
104+
- ๐Ÿ“‚ api
105+
- ๐Ÿ“‚ endpoints
106+
- ๐Ÿ“„ login.ts
107+
- other endpoint functionsโ€ฆ
108+
- ๐Ÿ“„ client.ts
109+
- ๐Ÿ“„ index.ts
110+
111+
`๐Ÿ“„ client.ts` ํŒŒ์ผ์€ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์›์‹œ ํ•จ์ˆ˜(์˜ˆ: `fetch()`)์— ๋Œ€ํ•œ ๋ž˜ํผ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ž˜ํผ๋Š” ๋ฐฑ์—”๋“œ์˜ ๊ธฐ๋ณธ URL ์„ค์ •, ํ—ค๋” ์„ค์ •, ๋ฐ์ดํ„ฐ ์ง๋ ฌํ™” ๋“ฑ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
112+
113+
```ts title="shared/api/endpoints/login.ts"
114+
import { POST } from "../client";
115+
116+
export function login({ email, password }: { email: string, password: string }) {
117+
return POST("/login", { email, password });
118+
}
119+
```
120+
121+
```ts title="shared/api/index.ts"
122+
export { login } from "./endpoints/login";
123+
```
124+
125+
#### ํŽ˜์ด์ง€์˜ `api` ์„ธ๊ทธ๋จผํŠธ์— ์ €์žฅํ•˜๊ธฐ
126+
127+
๋กœ๊ทธ์ธ ์š”์ฒญ์ด ํŠน์ • ํŽ˜์ด์ง€์—๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ, ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์˜ `api` ์„ธ๊ทธ๋จผํŠธ์— ํ•จ์ˆ˜๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
128+
129+
- ๐Ÿ“‚ pages
130+
- ๐Ÿ“‚ login
131+
- ๐Ÿ“‚ api
132+
- ๐Ÿ“„ login.ts
133+
- ๐Ÿ“‚ ui
134+
- ๐Ÿ“„ LoginPage.tsx
135+
- ๐Ÿ“„ index.ts
136+
- other pagesโ€ฆ
137+
138+
```ts title="pages/login/api/login.ts"
139+
import { POST } from "shared/api";
140+
141+
export function login({ email, password }: { email: string, password: string }) {
142+
return POST("/login", { email, password });
143+
}
144+
```
145+
146+
์ด ํ•จ์ˆ˜๋Š” ํŽ˜์ด์ง€์˜ ๊ณต๊ฐœ API์—์„œ ๋‚ด๋ณด๋‚ผ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ ์š”์ฒญ์ด ๋‹ค๋ฅธ ๊ณณ์—์„œ ํ•„์š”ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
147+
148+
### ์ด์ค‘ ์ธ์ฆ(2FA)
149+
150+
์•ฑ์ด ์ด์ค‘ ์ธ์ฆ(2FA)์„ ์ง€์›ํ•˜๋Š” ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์ผํšŒ์šฉ ๋น„๋ฐ€๋ฒˆํ˜ธ(OTP)๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ„๋„์˜ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ `POST /login` ์š”์ฒญ์€ ์‚ฌ์šฉ์ž๊ฐ€ 2FA๋ฅผ ํ™œ์„ฑํ™”ํ–ˆ์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ”Œ๋ž˜๊ทธ๊ฐ€ ํฌํ•จ๋œ ์‚ฌ์šฉ์ž ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ”Œ๋ž˜๊ทธ๊ฐ€ ์„ค์ •๋˜๋ฉด ์‚ฌ์šฉ์ž๋ฅผ 2FA ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
151+
152+
2FA ํŽ˜์ด์ง€๋Š” ๋กœ๊ทธ์ธ๊ณผ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ด€๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ Pages ๋ ˆ์ด์–ด์˜ `login` ์Šฌ๋ผ์ด์Šค์— ํ•จ๊ป˜ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.<br/>
153+
154+
์ด์ค‘ ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” `login()` ํ•จ์ˆ˜์™€ ์œ ์‚ฌํ•œ ๋˜ ๋‹ค๋ฅธ ์š”์ฒญ ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜๋“ค์€ `Shared`๋‚˜ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์˜ `api` ์„ธ๊ทธ๋จผํŠธ์— ํ•จ๊ป˜ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
155+
156+
## ์ธ์ฆ๋œ ์š”์ฒญ์˜ ํ† ํฐ ์ €์žฅ ๋ฐฉ๋ฒ• {#how-to-store-the-token-for-authenticated-requests}
157+
158+
์ธ์ฆ ๋ฐฉ์‹์ด ๋กœ๊ทธ์ธ/๋น„๋ฐ€๋ฒˆํ˜ธ, OAuth, 2๋‹จ๊ณ„ ์ธ์ฆ ๋“ฑ ์–ด๋–ค ๊ฒƒ์ด๋“ , ๊ฒฐ๊ตญ ํ† ํฐ์ด ๋ฐœ๊ธ‰๋ฉ๋‹ˆ๋‹ค. ์ด ํ† ํฐ์€ ์ดํ›„ ์š”์ฒญ์—์„œ ์‚ฌ์šฉ์ž ์‹๋ณ„์„ ์œ„ํ•ด ์ €์žฅ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
159+
160+
์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” **์ฟ ํ‚ค**๋ฅผ ์‚ฌ์šฉํ•ด ํ† ํฐ์„ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ด๊ณ  ์ด์ƒ์ ์ธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ† ํฐ์„ ์ˆ˜๋™์œผ๋กœ ๊ด€๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ, ๋ณต์žกํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์„ ์ง€์›ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ(์˜ˆ: [Remix][ext-remix])๋ฅผ ์‚ฌ์šฉ ์ค‘์ด๋ผ๋ฉด, ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์ฟ ํ‚ค ์ธํ”„๋ผ๋ฅผ `shared/api`์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. Remix๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์‹œ๋Š” ํŠœํ† ๋ฆฌ์–ผ์˜ [์ธ์ฆ ์„น์…˜][tutorial-authentication]์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
161+
162+
๊ทธ๋Ÿฌ๋‚˜ ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์—์„œ๋Š”, ํ† ํฐ์„ ์ง์ ‘ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ, ํ† ํฐ ๋งŒ๋ฃŒ ์‹œ ๊ฐฑ์‹  ๋กœ์ง์„ ํ•จ๊ป˜ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ, ํ† ํฐ ๋งŒ๋ฃŒ ์‹œ ๊ฐฑ์‹  ๋กœ์ง์„ ํ•จ๊ป˜ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. FSD์—์„œ๋Š” ํ† ํฐ์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
163+
164+
### Shared์— ์ €์žฅํ•˜๊ธฐ
165+
166+
`shared/api`์— ์ €์žฅํ•˜๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์€ API ํด๋ผ์ด์–ธํŠธ์™€ ์ž˜ ๋งž์•„๋–จ์–ด์ง‘๋‹ˆ๋‹ค. ์ธ์ฆ์ด ํ•„์š”ํ•œ ๋‹ค๋ฅธ ์š”์ฒญ ํ•จ์ˆ˜์—์„œ ์ด ํ† ํฐ์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. API ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ฐ˜์‘ํ˜• ์Šคํ† ์–ด๋‚˜ ๋ชจ๋“ˆ ์ˆ˜์ค€ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ํ† ํฐ์„ ์ €์žฅํ•˜๊ณ , `login()/logout()` ํ•จ์ˆ˜์—์„œ ํ•ด๋‹น ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
167+
168+
ํ† ํฐ ์ž๋™ ๊ฐฑ์‹ ์€ API ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ฏธ๋“ค์›จ์–ด ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ์š”์ฒญ๋งˆ๋‹ค ์‹คํ–‰๋˜๋ฉฐ, ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค:
169+
170+
- ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜๋ฉด ์•ก์„ธ์Šค ํ† ํฐ๊ณผ ๊ฐฑ์‹  ํ† ํฐ์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
171+
- ์ธ์ฆ์ด ํ•„์š”ํ•œ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
172+
- ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜์–ด ์š”์ฒญ์ด ์‹คํŒจํ•˜๋ฉด, ๊ฐฑ์‹  ํ† ํฐ์„ ์‚ฌ์šฉํ•ด ์ƒˆ๋กœ์šด ํ† ํฐ์„ ์š”์ฒญํ•˜๊ณ  ์ €์žฅํ•œ ํ›„, ์›๋ž˜ ์š”์ฒญ์„ ๋‹ค์‹œ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.
173+
174+
์ด ๋ฐฉ๋ฒ•์˜ ๋‹จ์  ์ค‘ ํ•˜๋‚˜๋Š” ํ† ํฐ ๊ด€๋ฆฌ ๋กœ์ง์ด ์š”์ฒญ ๋กœ์ง๊ณผ ๊ฐ™์€ ์œ„์น˜์— ์žˆ์–ด, ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†๊ฒ ์ง€๋งŒ, ํ† ํฐ ๊ด€๋ฆฌ ๋กœ์ง์ด ๋ณต์žกํ•œ ๊ฒฝ์šฐ์—๋Š” ์š”์ฒญ๊ณผ ๊ด€๋ฆฌ ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์š”์ฒญ ๋ฐ API ํด๋ผ์ด์–ธํŠธ๋Š” `shared/api`์— ๋‘๊ณ , ํ† ํฐ ๊ด€๋ฆฌ ๋กœ์ง์€ `shared/auth`์— ๋‘๋Š” ๋ฐฉ์‹์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
175+
176+
๋˜ ๋‹ค๋ฅธ ๋‹จ์ ์€ ๋ฐฑ์—”๋“œ๊ฐ€ ํ† ํฐ๊ณผ ํ•จ๊ป˜ ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ, ์ด ์ •๋ณด๋ฅผ ๋ณ„๋„๋กœ ์ €์žฅํ•˜๊ฑฐ๋‚˜ `/me` ๋˜๋Š” `/users/current`์™€ ๊ฐ™์€ ์—”๋“œํฌ์ธํŠธ์—์„œ ๋‹ค์‹œ ์š”์ฒญํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.
177+
178+
### Entities์— ์ €์žฅํ•˜๊ธฐ
179+
180+
FSD ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์‚ฌ์šฉ์ž ์—”ํ‹ฐํ‹ฐ ๋˜๋Š” ํ˜„์žฌ ์‚ฌ์šฉ์ž ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ๋‘ ์—”ํ‹ฐํ‹ฐ๋Š” ๊ฐ™์€ ๊ฒƒ์„ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
181+
182+
:::note
183+
184+
**ํ˜„์žฌ ์‚ฌ์šฉ์ž**๋Š” "viewer" ๋˜๋Š” "me"๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ถŒํ•œ๊ณผ ๊ฐœ์ธ ์ •๋ณด๋ฅผ ๊ฐ€์ง„ ๋‹จ์ผ ์ธ์ฆ ์‚ฌ์šฉ์ž์™€ ๊ณต๊ฐœ์ ์œผ๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์ •๋ณด๋กœ ๊ตฌ์„ฑ๋œ ๋ชจ๋“  ์‚ฌ์šฉ์ž ๋ชฉ๋ก์„ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
185+
186+
:::
187+
188+
User ์—”ํ‹ฐํ‹ฐ์— ํ† ํฐ์„ ์ €์žฅํ•˜๋ ค๋ฉด `model` ์„ธ๊ทธ๋จผํŠธ์— ๋ฐ˜์‘ํ˜• ์Šคํ† ์–ด๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์Šคํ† ์–ด๋Š” ํ† ํฐ๊ณผ ์‚ฌ์šฉ์ž ๊ฐ์ฒด๋ฅผ ๋ชจ๋‘ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
189+
190+
API ํด๋ผ์ด์–ธํŠธ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ `shared/api` ์ •์˜๋˜๊ฑฐ๋‚˜ ์—”ํ‹ฐํ‹ฐ ์ „์ฒด์— ๋ถ„์‚ฐ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ฃผ์š” ๊ณผ์ œ๋Š” ๋ ˆ์ด์–ด์˜ ์ž„ํฌํŠธ ๊ทœ์น™([import rule on layers][import-rule-on-layers])์„ ์œ„๋ฐ˜ํ•˜์ง€ ์•Š์œผ๋ฉด์„œ ๋‹ค๋ฅธ ์š”์ฒญ์—์„œ๋„ ํ† ํฐ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
191+
192+
> ๋ ˆ์ด์–ด ๊ทœ์น™: ์Šฌ๋ผ์ด์Šค์˜ ๋ชจ๋“ˆ์€ ์ž๊ธฐ๋ณด๋‹ค ๋‚ฎ์€ ๋ ˆ์ด์–ด์— ์œ„์น˜ํ•œ ๋‹ค๋ฅธ ์Šฌ๋ผ์ด์Šค๋งŒ ์ž„ํฌํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
193+
194+
์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
195+
196+
1. **์š”์ฒญ ์‹œ๋งˆ๋‹ค ํ† ํฐ ์ˆ˜๋™ ์ „๋‹ฌ**
197+
์ด ๋ฐฉ๋ฒ•์€ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ๋ฒˆ๊ฑฐ๋กญ๊ณ  ํƒ€์ž… ์•ˆ์ „์„ฑ์ด ๋ณด์žฅ๋˜์ง€ ์•Š์œผ๋ฉด ์‹ค์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค. ๋˜ํ•œ Shared์˜ API ํด๋ผ์ด์–ธํŠธ์— ๋ฏธ๋“ค์›จ์–ด ํŒจํ„ด์„ ์ ์šฉํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
198+
2. **์•ฑ ์ „์—ญ์—์„œ ๊ธ€๋กœ๋ฒŒ ์Šคํ† ์–ด๋กœ ํ† ํฐ ๊ด€๋ฆฌ**
199+
ํ† ํฐ์„ context๋‚˜ `localStorage`์— ์ €์žฅํ•˜๊ณ , `shared/api`์— ํ† ํฐ ์ ‘๊ทผ ํ‚ค๋ฅผ ๋ณด๊ด€ํ•ฉ๋‹ˆ๋‹ค. ํ† ํฐ์˜ ๋ฐ˜์‘ํ˜• ์ €์žฅ์†Œ๋Š” User ์—”ํ„ฐํ‹ฐ์—์„œ ๋‚ด๋ณด๋‚ด๋ฉฐ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ context Provider๋Š” App ๋ ˆ์ด์–ด์—์„œ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ API ํด๋ผ์ด์–ธํŠธ ์„ค๊ณ„๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“ค์ง€๋งŒ, ์ƒ์œ„ ๋ ˆ์ด์–ด์— context ์ œ๊ณต์ด ํ•„์š”ํ•˜๋‹ค๋Š” ์•”๋ฌต์ ์ธ ์˜์กด์„ฑ์„ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ context๋‚˜ `localStorage`๊ฐ€ ์ œ๋Œ€๋กœ ์„ค์ •๋˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ, ์œ ์šฉํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
200+
3. **ํ† ํฐ ๋ณ€๊ฒฝ ์‹œ API ํด๋ผ์ด์–ธํŠธ ์—…๋ฐ์ดํŠธ**
201+
๋ฐ˜์‘ํ˜• ์Šคํ† ์–ด๋ฅผ ํ™œ์šฉํ•ด ์—”ํ‹ฐํ‹ฐ์˜ ์Šคํ† ์–ด๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค API ํด๋ผ์ด์–ธํŠธ์˜ ํ† ํฐ ์Šคํ† ์–ด๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ตฌ๋…(subscribe)์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์ƒ์œ„ ๊ณ„์ธต์— ์•”๋ฌต์ ์ธ ์˜์กด์„ฑ์„ ๋งŒ๋“ ๋‹ค๋Š” ์ ์—์„œ๋Š” ์ด์ „ ํ•ด๊ฒฐ์ฑ…๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ, ์ด ๋ฐฉ๋ฒ•์€ ๋” "๋ช…๋ นํ˜•(push)" ์ ‘๊ทผ์ด๊ณ , ์ด์ „ ๋ฐฉ๋ฒ•์€ ๋” "์„ ์–ธํ˜•(pull)" ์ ‘๊ทผ์ž…๋‹ˆ๋‹ค.
202+
203+
์—”ํ‹ฐํ‹ฐ์˜ `model`์— ํ† ํฐ์„ ์ €์žฅํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ฉด, ํ† ํฐ ๊ด€๋ฆฌ์™€ ๊ด€๋ จ๋œ ๋” ๋งŽ์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, `model` ์„ธ๊ทธ๋จผํŠธ์— ํ† ํฐ ๋งŒ๋ฃŒ ์‹œ ๊ฐฑ์‹ ํ•˜๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜, ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ํ† ํฐ์„ ๋ฌดํšจํ™”ํ•˜๋Š” ๋กœ์ง์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
204+
๋ฐฑ์—”๋“œ์— ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” User ์—”ํ‹ฐํ‹ฐ์˜ api ์„ธ๊ทธ๋จผํŠธ๋‚˜ `shared/api`๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
205+
206+
### Pages/Widgets์— ์ €์žฅํ•˜๊ธฐ (๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ)
207+
208+
์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์—ญ์— ์ ์šฉ๋˜๋Š” ์ƒํƒœ(์˜ˆ: ์•ก์„ธ์Šค ํ† ํฐ)๋ฅผ ํŽ˜์ด์ง€๋‚˜ ์œ„์ ฏ์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์€ ๊ถŒ์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์˜ `model` ์„ธ๊ทธ๋จผํŠธ์— ํ† ํฐ ์Šคํ† ์–ด๋ฅผ ๋ฐฐ์น˜ํ•˜๋Š” ๋Œ€์‹ , ์ด ์•„ํ‹ฐํด์—์„œ ์ œ์‹œํ•œ ์ฒ˜์Œ ๋‘ ํ•ด๊ฒฐ์ฑ…์ธ Shared๋‚˜ Entities๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.
209+
210+
## ๋กœ๊ทธ์•„์›ƒ ๋ฐ ํ† ํฐ ๋ฌดํšจํ™”
211+
212+
๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์ด์ง€๋งŒ, ์ด๋ฅผ ์œ„ํ•œ ๋ณ„๋„์˜ ํŽ˜์ด์ง€๋Š” ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ ๋ฐฑ์—”๋“œ์— ์ธ์ฆ๋œ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ํ† ํฐ ์Šคํ† ์–ด๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ž‘์—…์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.
213+
214+
๋ชจ๋“  ์š”์ฒญ์„ `shared/api`์— ๋ณด๊ด€ํ–ˆ๋‹ค๋ฉด, ๋กœ๊ทธ์ธ ํ•จ์ˆ˜ ๊ทผ์ฒ˜์— ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ ํ•จ์ˆ˜๋ฅผ ๋‘๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ, ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์ด ์žˆ๋Š” ์œ„์น˜ ๊ทผ์ฒ˜์— ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ ํ•จ์ˆ˜๋ฅผ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ชจ๋“  ํŽ˜์ด์ง€์— ๋‚˜ํƒ€๋‚˜๋Š” ํ—ค๋” ์œ„์ ฏ์— ๋กœ๊ทธ์•„์›ƒ ๋งํฌ๊ฐ€ ์žˆ๋‹ค๋ฉด, ํ•ด๋‹น ์š”์ฒญ์„ ๊ทธ ์œ„์ ฏ์˜ `api` ์„ธ๊ทธ๋จผํŠธ์— ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
215+
216+
ํ† ํฐ ์Šคํ† ์–ด์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๋Š” ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์ด ์œ„์น˜ํ•œ ๊ณณ(์˜ˆ: ํ—ค๋” ์œ„์ ฏ)์—์„œ ํŠธ๋ฆฌ๊ฑฐ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์š”์ฒญ๊ณผ ์Šคํ† ์–ด ์—…๋ฐ์ดํŠธ๋ฅผ ํ•ด๋‹น ์œ„์ ฏ์˜ `model` ์„ธ๊ทธ๋จผํŠธ์—์„œ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
217+
218+
### ์ž๋™ ๋กœ๊ทธ์•„์›ƒ
219+
220+
๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ ์‹คํŒจ๋‚˜ ๋กœ๊ทธ์ธ ํ† ํฐ ๊ฐฑ์‹  ์‹คํŒจ ์‹œ๋ฅผ ๋Œ€๋น„ํ•ด ์•ˆ์ „์žฅ์น˜๋ฅผ ๋งˆ๋ จํ•˜๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ ํ† ํฐ ์Šคํ† ์–ด๋ฅผ ๋น„์›Œ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ† ํฐ์„ Entities์— ์ €์žฅํ•˜๋Š” ๊ฒฝ์šฐ, ์ด ๋กœ์ง์€ `model` ์„ธ๊ทธ๋จผํŠธ์— ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ† ํฐ์„ Shared์— ์ €์žฅํ•˜๋Š” ๊ฒฝ์šฐ, ์ด ๋กœ์ง์„ `shared/api`์— ํฌํ•จํ•˜๋ฉด ์„ธ๊ทธ๋จผํŠธ๊ฐ€ ๋„ˆ๋ฌด ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ† ํฐ ๊ด€๋ฆฌ ๋กœ์ง์„ ๋ณ„๋„์˜ ์„ธ๊ทธ๋จผํŠธ(์˜ˆ: `shared/auth`)๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ๋„ ๊ณ ๋ คํ•ด๋ณผ ๋งŒํ•ฉ๋‹ˆ๋‹ค.
221+
222+
[tutorial-authentication]: /docs/get-started/tutorial#authentication
223+
[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers
224+
[ext-remix]: https://remix.run
225+
[ext-zod]: https://zod.dev

0 commit comments

Comments
ย (0)