|
| 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