Authentication
๋ณดํต ์ธ์ฆ์ ์ธ ๊ฐ์ง ์ฃผ์ ๋จ๊ณ๋ก ์ด๋ฃจ์ด์ง๋๋ค:
- ์ฌ์ฉ์๋ก๋ถํฐ ๋ก๊ทธ์ธ ์ ๋ณด(์์ด๋, ๋น๋ฐ๋ฒํธ ๋ฑ)์ ์์งํฉ๋๋ค.
- ๋ฐฑ์๋ ์๋ฒ๋ก ํด๋น ๋ก๊ทธ์ธ ์ ๋ณด์ ์ ์กํฉ๋๋ค.
- ์ธ์ฆ ํ ๋ฐ๊ธ๋ฐ์ ํ ํฐ์ ์ ์ฅํ์ฌ ์ดํ ์์ฒญ์ ์ฌ์ฉํฉ๋๋ค.
์ฌ์ฉ์ ๋ก๊ทธ์ธ ์ ๋ณด ์์ง ๋ฐฉ๋ฒโ
์ฑ์์ ์ฌ์ฉ์๋ก๋ถํฐ ๋ก๊ทธ์ธ ์ ๋ณด๋ฅผ ์์งํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด๊ฒ ์ต๋๋ค. ๋ง์ฝ์ OAuth๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, OAuth ์ ๊ณต์์ ๋ก๊ทธ์ธ ํ์ด์ง๋ฅผ ์ฌ์ฉํ์ฌ 3๋จ๊ณ๋ก ๋ฐ๋ก ๋์ด๊ฐ ์ ์์ต๋๋ค.
์ ์ฉ ๋ก๊ทธ์ธ ํ์ด์ง ๋ง๋ค๊ธฐโ
์น์ฌ์ดํธ์์ ์ฌ์ฉ์ ์ด๋ฆ๊ณผ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ๋ ฅํ๋ ๋ก๊ทธ์ธ ํ์ด์ง๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ ๋๋ค. ์ด๋ฌํ ํ์ด์ง๋ค์ ๊ตฌ์กฐ๊ฐ ๋จ์ํ์ฌ ๋ณ๋์ ๋ณต์กํ ๋ถํด ์์ ์ด ํ์ํ์ง ์์ต๋๋ค. ๋ค๋ง, ๋ก๊ทธ์ธ๊ณผ ํ์๊ฐ์ ์์์ ์ธํ์ด ๋น์ทํ๊ธฐ ๋๋ฌธ์, ๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋ ์์์ ํ๋์ ํ์ด์ง์์ ํตํฉํ์ฌ ์ ๊ณตํ๊ธฐ๋ ํฉ๋๋ค.
- ๐ pages
- ๐ login
- ๐ ui
- ๐ LoginPage.tsx (or your framework's component file format)
- ๐ RegisterPage.tsx
- ๐ index.ts
- ๐ ui
- other pagesโฆ
- ๐ login
๋ก๊ทธ์ธ๊ณผ ํ์๊ฐ์ ์ปดํฌ๋ํธ๋ฅผ ๋ณ๋๋ก ๋ง๋ค๊ณ , ํ์์ ๋ฐ๋ผ index ํ์ผ์์ export ํ ์ ์์ต๋๋ค. ์ด ์ปดํฌ๋ํธ๋ค์ ์ฌ์ฉ์๋ก๋ถํฐ ๋ก๊ทธ์ธ ์ ๋ณด์ ์ ๋ ฅ๋ฐ๋ ํผ์ ํฌํจํฉ๋๋ค.
๋ก๊ทธ์ธ ๋ค์ด์ผ๋ก๊ทธ ๋ง๋ค๊ธฐโ
์ฑ์ ์ด๋์๋ ์ฌ์ฉํ ์ ์๋ ๋ก๊ทธ์ธ ๋ค์ด์ผ๋ก๊ทธ๊ฐ ํ์ํ๋ค๋ฉด, ์ด ๋ค์ด์ผ๋ก๊ทธ๋ฅผ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์์ ฏ์ผ๋ก ๋ง๋๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ถํ์ํ ์ธ๋ถํ๋ฅผ ํผํ๋ฉด์๋ ์ด๋ค ํ์ด์ง์์๋ ์ฝ๊ฒ ๋ก๊ทธ์ธ ๋ค์ด์ผ๋ก๊ทธ๋ฅผ ๋์ธ ์ ์์ต๋๋ค.
- ๐ widgets
- ๐ login-dialog
- ๐ ui
- ๐ LoginDialog.tsx
- ๐ index.ts
- ๐ ui
- other widgetsโฆ
- ๐ login-dialog
๊ฐ์ด๋ ๋๋จธ์ง ๋ถ๋ถ์ ์ ์ฉ ํ์ด์ง ๋ฐฉ์์ ๋ํด ์ค๋ช ํ๊ณ ์์ง๋ง, ๋์ผํ ์์น์ ๋ก๊ทธ์ธ ๋ค์ด์ผ๋ก๊ทธ์๋ ์ ์ฉํ ์ ์์ต๋๋ค.
ํด๋ผ์ด์ธํธ ์ธก ๊ฒ์ฆโ
ํนํ ํ์๊ฐ์
์ ๊ฒฝ์ฐ, ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋ด์ฉ์ ๋ฌธ์ ๊ฐ ์์ ๋ ๋น ๋ฅด๊ฒ ํผ๋๋ฐฑ์ ์ ๊ณตํ๊ธฐ ์ํด ํด๋ผ์ด์ธํธ ์ธก ๊ฒ์ฆ์ ์ํํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ด๋ฅผ ์ํด ๋ก๊ทธ์ธ ํ์ด์ง์ model
์ธ๊ทธ๋จผํธ์์ ๊ฒ์ฆ ๋ก์ง์ ๊ตฌํํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด JS/TS์์๋ Zod์ ๊ฐ์ ์คํค๋ง ๊ฒ์ฆ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
import { z } from "zod";
export const registrationData = z.object({
email: z.string().email(),
password: z.string().min(6),
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
message: "๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค",
path: ["confirmPassword"],
});
๊ทธ๋ฐ ๋ค์, ui ์ธ๊ทธ๋จผํธ์์ ์ด ์คํค๋ง๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ ๋ ฅ์ ๊ฒ์ฆํ ์ ์์ต๋๋ค:
import { registrationData } from "../model/registration-schema";
function validate(formData: FormData) {
const data = Object.fromEntries(formData.entries());
try {
registrationData.parse(data);
} catch (error) {
// TODO: Show error message to the user
}
}
export function RegisterPage() {
return (
<form onSubmit={(e) => validate(new FormData(e.target))}>
<label htmlFor="email">์ด๋ฉ์ผ</label>
<input id="email" name="email" required />
<label htmlFor="password">๋น๋ฐ๋ฒํธ (์ต์ 6์)</label>
<input id="password" name="password" type="password" required />
<label htmlFor="confirmPassword">๋น๋ฐ๋ฒํธ ํ์ธ</label>
<input id="confirmPassword" name="confirmPassword" type="password" required />
</form>
)
}
๋ก๊ทธ์ธ ์ ๋ณด ์ ์ก ๋ฐฉ๋ฒโ
๋ก๊ทธ์ธ ์ ๋ณด๋ฅผ ๋ฐฑ์๋ ์๋ฒ๋ก ์ ์กํ๊ธฐ ์ํ ์์ฒญ ํจ์๋ฅผ ์์ฑํ์ธ์. ์ด ํจ์๋ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ฎคํ ์ด์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(์: TanStack Query)๋ฅผ ์ฌ์ฉํ์ฌ ํธ์ถํ ์ ์์ต๋๋ค.
์์ฒญ ํจ์ ์ ์ฅ ์์นโ
์ด ์์ฒญ ํจ์๋ฅผ ์ ์ฅํ ์ ์๋ ์์น๋ ํฌ๊ฒ ๋ ๊ฐ์ง์
๋๋ค: shared/api
๋๋ ํ์ด์ง์ api
์ธ๊ทธ๋จผํธ์
๋๋ค.
shared/api
์ ์ ์ฅํ๊ธฐโ
๋ชจ๋ API ์์ฒญ์ shared/api
์ ๋ชจ์์ ๊ด๋ฆฌํ๊ณ , ์๋ํฌ์ธํธ๋ณ๋ก ๊ทธ๋ฃนํํ๋ ์ ๊ทผ ๋ฐฉ์์
๋๋ค. ํ์ผ ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๐ shared
- ๐ api
- ๐ endpoints
- ๐ login.ts
- other endpoint functionsโฆ
- ๐ client.ts
- ๐ index.ts
- ๐ endpoints
- ๐ api
๐ client.ts
ํ์ผ์ ์์ฒญ์ ์ํํ๋ ์์ ํจ์(์: fetch()
)์ ๋ํ ๋ํผ๋ฅผ ํฌํจํฉ๋๋ค. ์ด ๋ํผ๋ ๋ฐฑ์๋์ ๊ธฐ๋ณธ URL ์ค์ , ํค๋ ์ค์ , ๋ฐ์ดํฐ ์ง๋ ฌํ ๋ฑ์ ์ฒ๋ฆฌํฉ๋๋ค.
import { POST } from "../client";
export function login({ email, password }: { email: string, password: string }) {
return POST("/login", { email, password });
}
export { login } from "./endpoints/login";
ํ์ด์ง์ api
์ธ๊ทธ๋จผํธ์ ์ ์ฅํ๊ธฐโ
๋ก๊ทธ์ธ ์์ฒญ์ด ํน์ ํ์ด์ง์๋ง ํ์ํ ๊ฒฝ์ฐ, ๋ก๊ทธ์ธ ํ์ด์ง์ api
์ธ๊ทธ๋จผํธ์ ํจ์๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค:
- ๐ pages
- ๐ login
- ๐ api
- ๐ login.ts
- ๐ ui
- ๐ LoginPage.tsx
- ๐ index.ts
- ๐ api
- other pagesโฆ
- ๐ login
import { POST } from "shared/api";
export function login({ email, password }: { email: string, password: string }) {
return POST("/login", { email, password });
}
์ด ํจ์๋ ํ์ด์ง์ ๊ณต๊ฐ API์์ ๋ด๋ณด๋ผ ํ์๊ฐ ์์ต๋๋ค. ๋ก๊ทธ์ธ ์์ฒญ์ด ๋ค๋ฅธ ๊ณณ์์ ํ์ํ ๊ฐ๋ฅ์ฑ์ด ๋ฎ๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ด์ค ์ธ์ฆ(2FA)โ
์ฑ์ด ์ด์ค ์ธ์ฆ(2FA)์ ์ง์ํ๋ ๊ฒฝ์ฐ, ์ฌ์ฉ์๊ฐ ์ผํ์ฉ ๋น๋ฐ๋ฒํธ(OTP)๋ฅผ ์
๋ ฅํ ์ ์๋ ๋ณ๋์ ํ์ด์ง๋ก ์ด๋ํด์ผ ํ ์ ์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก POST /login
์์ฒญ์ ์ฌ์ฉ์๊ฐ 2FA๋ฅผ ํ์ฑํํ์์ ๋ํ๋ด๋ ํ๋๊ทธ๊ฐ ํฌํจ๋ ์ฌ์ฉ์ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ํ๋๊ทธ๊ฐ ์ค์ ๋๋ฉด ์ฌ์ฉ์๋ฅผ 2FA ํ์ด์ง๋ก ๋ฆฌ๋๋ ์
ํด์ผ ํฉ๋๋ค.
2FA ํ์ด์ง๋ ๋ก๊ทธ์ธ๊ณผ ๋ฐ์ ํ๊ฒ ์ฐ๊ด๋์ด ์์ผ๋ฏ๋ก Pages ๋ ์ด์ด์ login
์ฌ๋ผ์ด์ค์ ํจ๊ป ์ ์ฅํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ด์ค ์ธ์ฆ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด์๋ login()
ํจ์์ ์ ์ฌํ ๋ ๋ค๋ฅธ ์์ฒญ ํจ์๊ฐ ํ์ํ ๊ฒ์
๋๋ค. ์ด๋ฌํ ํจ์๋ค์ Shared
๋ ๋ก๊ทธ์ธ ํ์ด์ง์ api
์ธ๊ทธ๋จผํธ์ ํจ๊ป ๋ฐฐ์นํ ์ ์์ต๋๋ค.
์ธ์ฆ๋ ์์ฒญ์ ํ ํฐ ์ ์ฅ ๋ฐฉ๋ฒโ
์ธ์ฆ ๋ฐฉ์์ด ๋ก๊ทธ์ธ/๋น๋ฐ๋ฒํธ, OAuth, 2๋จ๊ณ ์ธ์ฆ ๋ฑ ์ด๋ค ๊ฒ์ด๋ , ๊ฒฐ๊ตญ ํ ํฐ์ด ๋ฐ๊ธ๋ฉ๋๋ค. ์ด ํ ํฐ์ ์ดํ ์์ฒญ์์ ์ฌ์ฉ์ ์๋ณ์ ์ํด ์ ์ฅ๋์ด์ผ ํฉ๋๋ค.
์น ์ ํ๋ฆฌ์ผ์ด์
์์๋ ์ฟ ํค๋ฅผ ์ฌ์ฉํด ํ ํฐ์ ์ ์ฅํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ผ๋ฐ์ ์ด๊ณ ์ด์์ ์ธ ๋ฐฉ๋ฒ์
๋๋ค. ์ฟ ํค๋ฅผ ์ฌ์ฉํ๋ฉด ํ ํฐ์ ์๋์ผ๋ก ๊ด๋ฆฌํ ํ์๊ฐ ์์ผ๋ฉฐ, ๋ณต์กํ ์ฒ๋ฆฌ๋ฅผ ์ค์ผ ์ ์์ต๋๋ค. ๋ง์ฝ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง์ ์ง์ํ๋ ํ๋ ์์ํฌ(์: Remix)๋ฅผ ์ฌ์ฉ ์ค์ด๋ผ๋ฉด, ์๋ฒ ์ฌ์ด๋ ์ฟ ํค ์ธํ๋ผ๋ฅผ shared/api
์ ์ ์ฅํ๋ ๊ฒ์ด ์ข์ต๋๋ค. Remix๋ฅผ ์ฌ์ฉํ๋ ์์๋ ํํ ๋ฆฌ์ผ์ ์ธ์ฆ ์น์
์์ ํ์ธํ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ฟ ํค๋ฅผ ์ฌ์ฉํ ์ ์๋ ์ํฉ์์๋, ํ ํฐ์ ์ง์ ๊ด๋ฆฌํด์ผ ํฉ๋๋ค. ์ด ๊ฒฝ์ฐ, ํ ํฐ ๋ง๋ฃ ์ ๊ฐฑ์ ๋ก์ง์ ํจ๊ป ๊ตฌํํด์ผ ํ ์๋ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ, ํ ํฐ ๋ง๋ฃ ์ ๊ฐฑ์ ๋ก์ง์ ํจ๊ป ๊ตฌํํด์ผ ํฉ๋๋ค. FSD์์๋ ํ ํฐ์ ์ ์ฅํ ์ ์๋ ๋ค์ํ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
Shared์ ์ ์ฅํ๊ธฐโ
shared/api
์ ์ ์ฅํ๋ ์ ๊ทผ ๋ฐฉ์์ API ํด๋ผ์ด์ธํธ์ ์ ๋ง์๋จ์ด์ง๋๋ค. ์ธ์ฆ์ด ํ์ํ ๋ค๋ฅธ ์์ฒญ ํจ์์์ ์ด ํ ํฐ์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. API ํด๋ผ์ด์ธํธ์์ ๋ฐ์ํ ์คํ ์ด๋ ๋ชจ๋ ์์ค ๋ณ์๋ฅผ ์ฌ์ฉํด ํ ํฐ์ ์ ์ฅํ๊ณ , login()/logout()
ํจ์์์ ํด๋น ์ํ๋ฅผ ์
๋ฐ์ดํธํ ์ ์์ต๋๋ค.
ํ ํฐ ์๋ ๊ฐฑ์ ์ API ํด๋ผ์ด์ธํธ์์ ๋ฏธ๋ค์จ์ด ํํ๋ก ๊ตฌํํ ์ ์์ต๋๋ค. ๋ชจ๋ ์์ฒญ๋ง๋ค ์คํ๋๋ฉฐ, ์๋์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋์ํฉ๋๋ค:
- ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธํ๋ฉด ์ก์ธ์ค ํ ํฐ๊ณผ ๊ฐฑ์ ํ ํฐ์ ์ ์ฅํฉ๋๋ค.
- ์ธ์ฆ์ด ํ์ํ ์์ฒญ์ ์ํํฉ๋๋ค.
- ํ ํฐ์ด ๋ง๋ฃ๋์ด ์์ฒญ์ด ์คํจํ๋ฉด, ๊ฐฑ์ ํ ํฐ์ ์ฌ์ฉํด ์๋ก์ด ํ ํฐ์ ์์ฒญํ๊ณ ์ ์ฅํ ํ, ์๋ ์์ฒญ์ ๋ค์ ์๋ํฉ๋๋ค.
์ด ๋ฐฉ๋ฒ์ ๋จ์ ์ค ํ๋๋ ํ ํฐ ๊ด๋ฆฌ ๋ก์ง์ด ์์ฒญ ๋ก์ง๊ณผ ๊ฐ์ ์์น์ ์์ด, ๋ณต์กํด์ง ์ ์๋ค๋ ์ ์
๋๋ค. ๊ฐ๋จํ ๊ฒฝ์ฐ์๋ ๋ฌธ์ ๊ฐ ์๊ฒ ์ง๋ง, ํ ํฐ ๊ด๋ฆฌ ๋ก์ง์ด ๋ณต์กํ ๊ฒฝ์ฐ์๋ ์์ฒญ๊ณผ ๊ด๋ฆฌ ๋ก์ง์ ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์์ฒญ ๋ฐ API ํด๋ผ์ด์ธํธ๋ shared/api
์ ๋๊ณ , ํ ํฐ ๊ด๋ฆฌ ๋ก์ง์ shared/auth
์ ๋๋ ๋ฐฉ์์ผ๋ก ๋๋ ์ ์์ต๋๋ค.
๋ ๋ค๋ฅธ ๋จ์ ์ ๋ฐฑ์๋๊ฐ ํ ํฐ๊ณผ ํจ๊ป ํ์ฌ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ, ์ด ์ ๋ณด๋ฅผ ๋ณ๋๋ก ์ ์ฅํ๊ฑฐ๋ /me
๋๋ /users/current
์ ๊ฐ์ ์๋ํฌ์ธํธ์์ ๋ค์ ์์ฒญํด์ผ ํ๋ค๋ ์ ์
๋๋ค.
Entities์ ์ ์ฅํ๊ธฐโ
FSD ํ๋ก์ ํธ์์๋ ์ฌ์ฉ์ ์ํฐํฐ ๋๋ ํ์ฌ ์ฌ์ฉ์ ์ํฐํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ ๋๋ค. ๋ ์ํฐํฐ๋ ๊ฐ์ ๊ฒ์ ๊ฐ๋ฆฌํฌ ์๋ ์์ต๋๋ค.
ํ์ฌ ์ฌ์ฉ์๋ "viewer" ๋๋ "me"๋ผ๊ณ ๋ ํฉ๋๋ค. ์ด๋ ๊ถํ๊ณผ ๊ฐ์ธ ์ ๋ณด๋ฅผ ๊ฐ์ง ๋จ์ผ ์ธ์ฆ ์ฌ์ฉ์์ ๊ณต๊ฐ์ ์ผ๋ก ์ ๊ทผ ๊ฐ๋ฅํ ์ ๋ณด๋ก ๊ตฌ์ฑ๋ ๋ชจ๋ ์ฌ์ฉ์ ๋ชฉ๋ก์ ๊ตฌ๋ณํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
User ์ํฐํฐ์ ํ ํฐ์ ์ ์ฅํ๋ ค๋ฉด model
์ธ๊ทธ๋จผํธ์ ๋ฐ์ํ ์คํ ์ด๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค. ์ด ์คํ ์ด๋ ํ ํฐ๊ณผ ์ฌ์ฉ์ ๊ฐ์ฒด๋ฅผ ๋ชจ๋ ํฌํจํ ์ ์์ต๋๋ค.
API ํด๋ผ์ด์ธํธ๋ ์ผ๋ฐ์ ์ผ๋ก shared/api
์ ์๋๊ฑฐ๋ ์ํฐํฐ ์ ์ฒด์ ๋ถ์ฐ๋์ด ์์ต๋๋ค. ๋ฐ๋ผ์ ์ฃผ์ ๊ณผ์ ๋ ๋ ์ด์ด์ ์ํฌํธ ๊ท์น(import rule on layers)์ ์๋ฐํ์ง ์์ผ๋ฉด์ ๋ค๋ฅธ ์์ฒญ์์๋ ํ ํฐ์ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ ๊ฒ์
๋๋ค.
๋ ์ด์ด ๊ท์น: ์ฌ๋ผ์ด์ค์ ๋ชจ๋์ ์๊ธฐ๋ณด๋ค ๋ฎ์ ๋ ์ด์ด์ ์์นํ ๋ค๋ฅธ ์ฌ๋ผ์ด์ค๋ง ์ํฌํธํ ์ ์์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์์ฒญ ์๋ง๋ค ํ ํฐ ์๋ ์ ๋ฌ
์ด ๋ฐฉ๋ฒ์ ๊ฐ์ฅ ๊ฐ๋จํ์ง๋ง, ๋ฒ๊ฑฐ๋กญ๊ณ ํ์ ์์ ์ฑ์ด ๋ณด์ฅ๋์ง ์์ผ๋ฉด ์ค์๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ํฝ๋๋ค. ๋ํ Shared์ API ํด๋ผ์ด์ธํธ์ ๋ฏธ๋ค์จ์ด ํจํด์ ์ ์ฉํ๊ธฐ ์ด๋ ต์ต๋๋ค. - ์ฑ ์ ์ญ์์ ๊ธ๋ก๋ฒ ์คํ ์ด๋ก ํ ํฐ ๊ด๋ฆฌ
ํ ํฐ์ context๋localStorage
์ ์ ์ฅํ๊ณ ,shared/api
์ ํ ํฐ ์ ๊ทผ ํค๋ฅผ ๋ณด๊ดํฉ๋๋ค. ํ ํฐ์ ๋ฐ์ํ ์ ์ฅ์๋ User ์ํฐํฐ์์ ๋ด๋ณด๋ด๋ฉฐ, ํ์ํ ๊ฒฝ์ฐ context Provider๋ App ๋ ์ด์ด์์ ์ค์ ํฉ๋๋ค. ์ด ๋ฐฉ๋ฒ์ API ํด๋ผ์ด์ธํธ ์ค๊ณ๋ฅผ ์ ์ฐํ๊ฒ ๋ง๋ค์ง๋ง, ์์ ๋ ์ด์ด์ context ์ ๊ณต์ด ํ์ํ๋ค๋ ์๋ฌต์ ์ธ ์์กด์ฑ์ ๋ฐ์์ํต๋๋ค. ๋ฐ๋ผ์ context๋localStorage
๊ฐ ์ ๋๋ก ์ค์ ๋์ง ์์์ ๊ฒฝ์ฐ, ์ ์ฉํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ์ข์ต๋๋ค. - ํ ํฐ ๋ณ๊ฒฝ ์ API ํด๋ผ์ด์ธํธ ์
๋ฐ์ดํธ
๋ฐ์ํ ์คํ ์ด๋ฅผ ํ์ฉํด ์ํฐํฐ์ ์คํ ์ด๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค API ํด๋ผ์ด์ธํธ์ ํ ํฐ ์คํ ์ด๋ฅผ ์ ๋ฐ์ดํธํ๋ ๊ตฌ๋ (subscribe)์ ์์ฑํ ์ ์์ต๋๋ค. ์ด ๋ฐฉ๋ฒ์ ์์ ๊ณ์ธต์ ์๋ฌต์ ์ธ ์์กด์ฑ์ ๋ง๋ ๋ค๋ ์ ์์๋ ์ด์ ํด๊ฒฐ์ฑ ๊ณผ ๋น์ทํ์ง๋ง, ์ด ๋ฐฉ๋ฒ์ ๋ "๋ช ๋ นํ(push)" ์ ๊ทผ์ด๊ณ , ์ด์ ๋ฐฉ๋ฒ์ ๋ "์ ์ธํ(pull)" ์ ๊ทผ์ ๋๋ค.
์ํฐํฐ์ model
์ ํ ํฐ์ ์ ์ฅํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ฉด, ํ ํฐ ๊ด๋ฆฌ์ ๊ด๋ จ๋ ๋ ๋ง์ ๋น์ฆ๋์ค ๋ก์ง์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, model
์ธ๊ทธ๋จผํธ์ ํ ํฐ ๋ง๋ฃ ์ ๊ฐฑ์ ํ๋ ๋ก์ง์ ์ถ๊ฐํ๊ฑฐ๋, ์ผ์ ์๊ฐ์ด ์ง๋๋ฉด ํ ํฐ์ ๋ฌดํจํํ๋ ๋ก์ง์ ํฌํจํ ์ ์์ต๋๋ค.
๋ฐฑ์๋์ ์์ฒญ์ ๋ณด๋ด์ผ ํ๋ ๊ฒฝ์ฐ์๋ User ์ํฐํฐ์ api ์ธ๊ทธ๋จผํธ๋ shared/api
๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Pages/Widgets์ ์ ์ฅํ๊ธฐ (๊ถ์ฅํ์ง ์์)โ
์ ํ๋ฆฌ์ผ์ด์
์ ์ญ์ ์ ์ฉ๋๋ ์ํ(์: ์ก์ธ์ค ํ ํฐ)๋ฅผ ํ์ด์ง๋ ์์ ฏ์ ์ ์ฅํ๋ ๊ฒ์ ๊ถ์ฅ๋์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ก๊ทธ์ธ ํ์ด์ง์ model
์ธ๊ทธ๋จผํธ์ ํ ํฐ ์คํ ์ด๋ฅผ ๋ฐฐ์นํ๋ ๋์ , ์ด ์ํฐํด์์ ์ ์ํ ์ฒ์ ๋ ํด๊ฒฐ์ฑ
์ธ Shared๋ Entities๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ถ์ฅ๋ฉ๋๋ค.
๋ก๊ทธ์์ ๋ฐ ํ ํฐ ๋ฌดํจํโ
๋ก๊ทธ์์ ๊ธฐ๋ฅ์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ค์ํ ๊ธฐ๋ฅ์ด์ง๋ง, ์ด๋ฅผ ์ํ ๋ณ๋์ ํ์ด์ง๋ ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ ๋ฐฑ์๋์ ์ธ์ฆ๋ ์์ฒญ์ ๋ณด๋ด๊ณ , ํ ํฐ ์คํ ์ด๋ฅผ ์ ๋ฐ์ดํธํ๋ ์์ ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
๋ชจ๋ ์์ฒญ์ shared/api
์ ๋ณด๊ดํ๋ค๋ฉด, ๋ก๊ทธ์ธ ํจ์ ๊ทผ์ฒ์ ๋ก๊ทธ์์ ์์ฒญ ํจ์๋ฅผ ๋๋ ๊ฒ์ด ์ข์ต๋๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ, ๋ก๊ทธ์์ ๋ฒํผ์ด ์๋ ์์น ๊ทผ์ฒ์ ๋ก๊ทธ์์ ์์ฒญ ํจ์๋ฅผ ๋ฐฐ์นํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ชจ๋ ํ์ด์ง์ ๋ํ๋๋ ํค๋ ์์ ฏ์ ๋ก๊ทธ์์ ๋งํฌ๊ฐ ์๋ค๋ฉด, ํด๋น ์์ฒญ์ ๊ทธ ์์ ฏ์ api
์ธ๊ทธ๋จผํธ์ ๋ฐฐ์นํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
ํ ํฐ ์คํ ์ด์ ๋ํ ์
๋ฐ์ดํธ๋ ๋ก๊ทธ์์ ๋ฒํผ์ด ์์นํ ๊ณณ(์: ํค๋ ์์ ฏ)์์ ํธ๋ฆฌ๊ฑฐ๋์ด์ผ ํฉ๋๋ค. ์ด ์์ฒญ๊ณผ ์คํ ์ด ์
๋ฐ์ดํธ๋ฅผ ํด๋น ์์ ฏ์ model
์ธ๊ทธ๋จผํธ์์ ๊ฒฐํฉํ ์ ์์ต๋๋ค.
์๋ ๋ก๊ทธ์์โ
๋ก๊ทธ์์ ์์ฒญ ์คํจ๋ ๋ก๊ทธ์ธ ํ ํฐ ๊ฐฑ์ ์คํจ ์๋ฅผ ๋๋นํด ์์ ์ฅ์น๋ฅผ ๋ง๋ จํ๋ ๊ฒ๋ ์ค์ํฉ๋๋ค. ์ด ๋ ๊ฒฝ์ฐ ๋ชจ๋ ํ ํฐ ์คํ ์ด๋ฅผ ๋น์์ผ ํฉ๋๋ค. ํ ํฐ์ Entities์ ์ ์ฅํ๋ ๊ฒฝ์ฐ, ์ด ๋ก์ง์ model
์ธ๊ทธ๋จผํธ์ ๋ฐฐ์นํ ์ ์์ต๋๋ค. ํ ํฐ์ Shared์ ์ ์ฅํ๋ ๊ฒฝ์ฐ, ์ด ๋ก์ง์ shared/api
์ ํฌํจํ๋ฉด ์ธ๊ทธ๋จผํธ๊ฐ ๋๋ฌด ๋ณต์กํด์ง ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ํ ํฐ ๊ด๋ฆฌ ๋ก์ง์ ๋ณ๋์ ์ธ๊ทธ๋จผํธ(์: shared/auth
)๋ก ๋ถ๋ฆฌํ๋ ๊ฒ๋ ๊ณ ๋ คํด๋ณผ ๋งํฉ๋๋ค.