Skip to content

๐Ÿง‘โ€๐Ÿซ 5์ฃผ์ฐจ ๋ฉ˜ํ† ๋ง

KimYujeong edited this page Dec 21, 2023 · 3 revisions

๋ฉ˜ํ† ๋ง ์‚ฌ์ „์ค€๋น„

์ง„ํ–‰ ์ƒํ™ฉ

FE

  • ์ˆ˜๋งŽ์€ ๋ฒ„๊ทธ ํ”ฝ์Šค
  • ๋ฆฌํŒฉํ† ๋ง
    • ์ปดํฌ๋„ŒํŠธ ์žฌํ™œ์šฉ
    • hook โ†’ module
  • socket event๋“ค์„ npm ๋ฐฐํฌํ•ด์„œ back/front ๊ณต์œ ํ•ด์„œ ์“ฐ๋Š” ์‹œ๋„

BE

  • ๋ฒ„๊ทธ ํ”ฝ์Šค ing..
    • ๋„์ปค, ๊นƒํ—™ ์•ก์…˜ ๋“ฑ๋“ฑ
  • ๋ฆฌํŒฉํ† ๋ง
    • ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋กœ๊น… ์ฒ˜๋ฆฌ + ํ˜ธ์ŠคํŠธ ์„œ๋ฒ„์— ๋กœ๊ทธ ์Œ“์ด๋„๋ก ๊ตฌํ˜„
    • DTO๋‚˜ Entity ์ƒ์„ฑ ์‹œ static ๋ฉ”์„œ๋“œ ํ™œ์šฉํ•˜๋„๋ก ์ˆ˜์ •
    • Swagger API ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ โ‡’ ์ปค์Šคํ…€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ƒ์„ฑํ•˜์—ฌ ์ •๋ฆฌ
    • ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์ •๋ฆฌ โ‡’ ๋ฐฑ์—”๋“œ ๋ฐฐํฌ ํŒŒ์ผ ๋ฐฑ์—”๋“œ ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด๋ถ€๋กœ ์ง‘์–ด๋„ฃ์Œ
  • graceful shutdown

๋ฉ˜ํ† ๋ง

โœ”๏ธย ์•„์  ๋‹ค ๋ฐ ์งˆ๋ฌธ

๋ฉ˜ํ† ๊ฐ€ ๋ฏธ๋ฆฌ ์•„์  ๋‹ค์™€ ์งˆ๋ฌธ์„ ๋ณด๊ณ  ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์‚ฌ์ „์— ์ค€๋น„ํ•˜์—ฌ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ™‹โ€โ™€๏ธ FE

์งˆ๋ฌธ 1๏ธโƒฃ setState๋กœ ๋ฐ”๋€ ์ƒํƒœ๋ฅผ ํ˜„์žฌ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜์ง„ ๋ชปํ•ด์„œ ๋ฏธ๋ž˜์— ์ƒํƒœ๊ฐ€ ๋ฐ”๋€” ๋•Œ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๋„๋ก ํ–ˆ๋Š”๋ฐ ์ข‹์€ ๋ฐฉ๋ฒ•์ผ๊นŒ์š”?

// useBlocker.tsx
export function useBlocker({ when, onConfirm, onCancel }: useBlockerParams) {
  const [blockedGoBack, setBlockedGoBack] = useState<boolean>(true);
  const [afterRunCallbacks, setAfterRunCallbacks] = useState<(() => void)[]>([]);

  const { openExitPopup } = useExitPopup();

  // true๋ฅผ ๋ฆฌํ„ดํ•  ๊ฒฝ์šฐ ํŽ˜์ด์ง€ ์ด๋™์ด ๋ง‰ํž˜
  // false๋ฅผ ๋ฆฌํ„ดํ•  ๊ฒฝ์šฐ ํŽ˜์ด์ง€ ์ด๋™์ด ๊ฐ€๋Šฅ
  reactRouterUserBlocker(args => {
    if (!blockedGoBack) {
      return false;
    }

    if (when({ ...args })) {
      openExitPopup({
        onConfirm: () => {
          unblockGoBack(() => {
            onConfirm?.();
          });
        },
        onCancel: ({ close }) => {
          onCancel?.();
          close();
        },
      });
      return true;
    }

    return false;
  });

  // blockedGoBack์ด ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ afterRunCallbacks ๋‚ด์šฉ์„ ๋ชจ๋‘ ์‹คํ–‰ํ•ด์คŒ
  useEffect(() => {
    if (!blockedGoBack) {
      afterRunCallbacks.forEach(callback => {
        callback();
      });
      setAfterRunCallbacks([]);
    }
  }, [blockedGoBack]);

  const unblockGoBack = (afterRunCallback: () => void) => {
    setBlockedGoBack(false);
    setAfterRunCallbacks(prev => [...prev, afterRunCallback]);
  };

  return { blockedGoBack, unblockGoBack };
}
// unblockGoBack ์‚ฌ์šฉ
const { unblockGoBack } = useBlocker({...});

unblockGoBack(()=> {
  // ํŽ˜์ด์ง€ ์ด๋™ ๋ง‰๊ธฐ๋ฅผ ํ•ด์ œํ•˜๋ฉด์„œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์‹คํ–‰
});

์งˆ๋ฌธ 2๏ธโƒฃ ์˜ค๋ฒ„๋ ˆ์ด์˜ ํ™•์ธ ํ˜น์€ ์ทจ์†Œ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ๋‹ซ์„์ง€ ํŒ๋‹จ์„ ์™ธ๋ถ€์—์„œ ํ•ด์คฌ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ฝœ๋ฐฑํ•จ์ˆ˜์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด์คฌ๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋Š”๊ฒŒ ์ œ์ผ ์ข‹์€ ๋ฐฉ๋ฒ•์ผ๊นŒ์š”?

// Popup.tsx
export default function Popup({ onCancel, onConfirm, children }: PopupProps) {
  ...
  return (
    ...
    <Button onClick={onCancel}> ์ทจ์†Œํ•˜๊ธฐ </Button>
    <Button onClick={onConfirm}> ํ™•์ธํ•˜๊ธฐ </Button>
    ...
  );
}
// PasswordPopup.tsx
export default function PasswordPopup({ onCancel, defaultValue, onSubmit }: PasswordPopupProps) {
  ...
  return (
    <Popup
      onCancel={onCancel}
      onConfirm={passwordSubmit}
    >
    ...
    </Popup>
  );
}
// usePasswordPopup.tsx
export function usePasswordPopup() {
  const { open } = useOverlay();

  const openPasswordPopup = ({ host, onSubmit, onClose }: openPasswordPopupParams) => {

    open(({ close }) => (
      <PasswordPopup
        onCancel={() => onClose?.({ close })}
        onSubmit={ password => {
          onSubmit?.({ password, close });
        }}
      />
    ));
  };

  return { openPasswordPopup };
}
// usePasswordPopup ์‚ฌ์šฉ
const { openPasswordPopup } = usePasswordPopup();

const createRoom = ({ roomName, onSuccess, onClose }: createRoomParams) => {
    openPasswordPopup({
      onClose: () => onClose?.({ close }),
      onSubmit: ({ password, close }) => {
        socketManager.emit('createRoom', roomName, password);
        socketManager.on('roomCreated', () => onSuccess?.({ password, close }));
      },
    });
  };
// createRoom ์‚ฌ์šฉ
createRoom({
  roomName: roomName as string,
  onSuccess: ({ close }) => {
    navigate('setting');
    close();
    enableSideBar();
  },
  onClose: ({ close }) => {
    close();
    navigate('/');
  },
});

์งˆ๋ฌธ 3๏ธโƒฃ socket event type๋“ค์„ npm package๋กœ ๋ฐฐํฌํ•ด์„œ back/front ๊ณต์œ ํ•ด์„œ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ด๋ดค๋Š”๋ฐ, ์ด๊ฒŒ ์ข‹์€ ๋ฐฉ๋ฒ•์ผ๊นŒ์š”?

export type AIServerEvent = "tarotCard" | "chatEnd" | "streamStart" | "streaming" | "streamEnd";
export type AIClientEvent = "message" | "tarotRead";

๐Ÿ™‹โ€โ™€๏ธ BE

์งˆ๋ฌธ 1๏ธโƒฃ ๋„์ปค๊ฐ€ ์ด์ „ ์ž‘์—… ๋‚ด์—ญ์„ ๊ธฐ์ค€์œผ๋กœ ๋ฐฐํฌํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿ˜ฑ

์ด๋ฒˆ ์ฃผ์— ๋„์ปค๊ฐ€ ์ด์ „ ๋ฒ„์ „์œผ๋กœ ๋นŒ๋“œ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ๋ง์”€๋“œ๋ ธ๋Š”๋ฐ, ํ™•์ธ ๊ฒฐ๊ณผ docker compose๋Š” docker์™€ ๋‹ฌ๋ฆฌ -t ์˜ต์…˜์ด ์—†๋‹ค๋Š” ๊ฑธ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋งค๋ฒˆ latest ํƒœ๊ทธ๊ฐ€ ๋ถ™๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ์˜ค๋ฒ„๋ผ์ด๋“œ๋„ ์•ˆ๋ผ์„œ ์ฒ˜์Œ ์ด๋ฏธ์ง€๊ฐ€ ๊ณ„์† ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€ ํƒœ๊ทธ์— ๊นƒํ—™ ํ•ด์‹œ๋ฅผ ๋‹ฌ์•„ ๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ฐ”๊ฟจ๋Š”๋ฐ ์—ฌ์ „ํžˆ ์ด์ „ ๋ฒ„์ „์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋ธ”๋ฃจ ๋ฒ„์ „
    • was : ${DOCKER_USERNAME}/magicconch:was-blue-${GITHUB_SHA}
    • signal : ${DOCKER_USERNAME}/magicconch:signal-blue-${GITHUB_SHA}
  • ๊ทธ๋ฆฐ ๋ฒ„์ „
    • was : ${DOCKER_USERNAME}/magicconch:was-green-${GITHUB_SHA}
    • signal : ${DOCKER_USERNAME}/magicconch:signal-green-${GITHUB_SHA}

์•„๋ž˜๋Š” docker images ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.

REPOSITORY             TAG                                                     IMAGE ID       CREATED        SIZE
kimyu0218/magicconch   signal-blue-07fa3c66521a83d8f746fbf54fbbd34c15153ded    69f2ce6851a8   2 hours ago    1.32GB
kimyu0218/magicconch   signal-blue-2f4b385b048a0b1e26d486c56eb6c2e98020c422    69f2ce6851a8   2 hours ago    1.32GB
kimyu0218/magicconch   signal-blue-cff42b4c955b4ef80fe99a460ed75e6156dee104    69f2ce6851a8   2 hours ago    1.32GB
kimyu0218/magicconch   signal-green-cff42b4c955b4ef80fe99a460ed75e6156dee104   69f2ce6851a8   2 hours ago    1.32GB
kimyu0218/magicconch   signal-green-e4edd3dbd33462cf9b45eb3dd8e8cbd8863836af   69f2ce6851a8   2 hours ago    1.32GB
kimyu0218/magicconch   was-blue-07fa3c66521a83d8f746fbf54fbbd34c15153ded       560d5152aec7   2 hours ago    1.43GB
kimyu0218/magicconch   was-blue-2f4b385b048a0b1e26d486c56eb6c2e98020c422       560d5152aec7   2 hours ago    1.43GB
kimyu0218/magicconch   was-blue-cff42b4c955b4ef80fe99a460ed75e6156dee104       560d5152aec7   2 hours ago    1.43GB
kimyu0218/magicconch   was-green-cff42b4c955b4ef80fe99a460ed75e6156dee104      560d5152aec7   2 hours ago    1.43GB
kimyu0218/magicconch   was-green-e4edd3dbd33462cf9b45eb3dd8e8cbd8863836af      560d5152aec7   2 hours ago    1.43GB

โœ”๏ธย ๋ฉ˜ํ† ๋ง ๋‚ด์šฉ

๋ฉ˜ํ† ๋ง ์‹œ๊ฐ„์— ๋‚˜๋ˆˆ ์ด์•ผ๊ธฐ๋ฅผ ๊ธฐ๋กํ•ด๋ณด์„ธ์š”.

  • ๋””์ž์ธ ํŒจํ„ด ๊ตณ์ด ์ฑ…์œผ๋กœ ๊ณต๋ถ€ํ•  ํ•„์š”์—†๋‹ค.

    • ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜๊ฐ™์€ ์ฑ…์„ ์ถ”์ฒœํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ง์ ‘ ๊ฒฝํ—˜ ํ•ด๋ณด๋Š”๊ฒŒ ์™€๋‹ฟ์Œ
    • ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ์งœ๊ณ  ๊ด€๋ฆฌ ํ•ด๋ณด๋ฉด์„œ ๊ณ ํ†ต์„ ๋Š๋ผ๋ฉด์„œ ํŒจํ„ด์ด ์™€๋‹ฟ๋Š”๋‹ค ๐Ÿ˜ฑ
  • ๋ชจ๋ฐ”์ผ ์›น ๋ถ€๋ถ„ ์„ ํƒ๊ณผ ์ง‘์ค‘์ด ํ•„์š”ํ•˜๋‹ค.

  • ๋’ค๋กœ ๊ฐ€๊ธฐ โ†’ ๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ 5์—๋Š” ์žˆ๊ณ  6์—๋Š” ์—†์Œ

    • before unload
    • useBlocker : ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง์ด ํ•„์š”ํ•ด๋ณด์ž„. ๋„ˆ๋ฌด ๋ณต์žกํ•จ
  • ์ฝœ๋ฐฑ์„ ๋„˜๊ฒจ์„œ ํ•˜๋Š”๊ฒŒ ๋ฌด๋‚œํ•œ ๋ฐฉ๋ฒ•

    • ์ฝœ๋ฐฑ์— ์ธ์ž๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ๊ฒƒ์€ ์กฐ๊ธˆ ๊ทธ๋ ‡๋‹ค. onClose์— close๋ฅผ ๋„˜๊ธฐ๋Š” ๊ฒƒ ์–ด์ƒ‰ํ•˜๋‹ค.
    • ๋˜ ํ•˜๋‚˜์˜ ๋ž˜ํ•‘ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
    • ์ƒํƒœ์— ๋Œ€ํ•ด์„œ ์™ธ๋ถ€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ฃผ์ž…์„ ํ•ด์ฃผ๋Š” ๊ฒŒ ๋‚ซ๋‹ค. ์ฃผ์ž… ๋ฐฉํ–ฅ์ด ์–‘๋ฐฉํ–ฅ์ด ๋˜๋ฒ„๋ฆฌ๋ฉด ํž˜๋“ค์–ด์ง„๋‹ค.
    • open close๋ฅผ ์ƒ์œ„์—์„œ ๊ด€๋ฆฌํ•˜๋„๋ก..
  • rootRouter ํŒŒ์ผ ์ด๋ฆ„์ด ์•„์‰ฝ๋‹ค.

  • useTOLD

    • ์ด๋ฆ„์„ ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค. ๋‹ค๋ฅธ ์„œ๋น„์Šค ์“ฐ๋ฉด ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค.
    • ๋ช…์‚ฌ๋‚˜ ํŠน์ • ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ์ง€์นญํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ๋’คํ†ต์ˆ˜ ๋งž๋Š”๋‹ค.
  • store/query โ†’ get~ (X) use~

    • query ์ด๋ฆ„์ด๋ฉด, ๊ด€๋ จ ์ƒํƒœ๊ฐ’๋„ ๊ฐ™์ด ๋ฐ˜ํ™˜?
  • types ํ•œ ๊ณณ์— ๋ชจ์•„๋‘๋ฉด ์ข‹๋‹ค โ‡’ types ํด๋” ์•ˆ์—

  • Socket ๋ถ€๋ถ„ ์‹ฑ๊ธ€ํ†ค์ด ์•„๋‹Œ๊ฒƒ๊ฐ™๋‹ค.

  • ์ปค์Šคํ…€ํ›…์„ ์—ฌ๋Ÿฌ๊ฐœ ์“ฐ๊ณ , depth๊ฐ€ ๊นŠ์œผ๋ฉด ๋‚˜์ค‘์— ์˜คํžˆ๋ ค ์ฝ”๋“œ๊ฐ€ ์ฝ๊ธฐ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ๋‹ค.

    • ์˜คํžˆ๋ ค ํ•œ๊ณณ์— ๋ชจ์—ฌ์žˆ๋Š”๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ฝ๊ธฐ ์‰ฌ์šธ์ง€๋„?
  • ์ปค์Šคํ…€ ํ›… ์‚ฌ์šฉํ•˜๋ฉด ๋ฆฌํ„ด ๊ฐ’์ด ํ•ด๋‹น ์ด๋ฆ„๊ฐ’์ด๋ฉด ์ข‹๊ฒ ๋‹ค.

    • ex) useSubmit ์ด๋ฉด submit์ด ๋ฆฌํ„ด๊ฐ’!

โœ”๏ธย ์ฒดํฌ๋ฆฌ์ŠคํŠธ

์ด๋ฒˆ์ฃผ์— ์šฐ๋ฆฌ ํŒ€์ด ๋˜๊ณ  ์‹ถ์€ ๋ชจ์Šต์„ ์ƒ์ƒํ•˜๋ฉฐ ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ด๋ด๋„ ์ข‹์Šต๋‹ˆ๋‹ค. ๋ฉ˜ํ† ๊ฐ€ ๋ณด๊ธฐ์— ์šฐ๋ฆฌ ํŒ€์€ ์–ด๋–ค์ง€ ์˜๊ฒฌ์„ ๊ตฌํ•ด๋ณด์„ธ์š”.

  • ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜์ค€์œผ๋กœ ์ฃผ์š” ๊ธฐ๋Šฅ์ด ๊ฐœ๋ฐœ๋˜์—ˆ๋‹ค.
  • GitHub ์ €์žฅ์†Œ๋งŒ ๋ด๋„ ํ”„๋กœ์ ํŠธ ๊ฐœ์š”, ๊ธฐ์ˆ ์  ๋„์ „, ๊ตฌํ˜„ ๊ณผ์ •์„ ๋ˆ„๊ตฌ๋‚˜ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
  • ๋‚˜์™€ ์šฐ๋ฆฌ ํŒ€์˜ ๊ธฐ์ˆ ์ ์ธ ์ž๋ž‘ ๊ฑฐ๋ฆฌ๋‚˜ ๊ฐ•์ ์ด ๋ฌด์—‡์ธ์ง€ ๊ทธ ์ด์œ ์™€ ํ•จ๊ป˜ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • 6์ฃผ์ฐจ์— ๋ฆฌํŒฉํ† ๋ง ๋˜๋Š” ๊ฐœ์„ ํ•  ์˜์—ญ์ด ๋ฌด์—‡์ธ์ง€ ์ธ์ง€ํ•˜๊ณ  ์žˆ๋‹ค.

๐Ÿ’ฆ ์šฐ๋‹นํƒ•ํƒ• ์ด์Šˆ ํ•ด๊ฒฐ๊ธฐ

BE

FE

FE/BE

๐Ÿง‘โ€๐Ÿซ ๋ฉ˜ํ† ๋ง ์ผ์ง€

๐Ÿ“ข ํšŒ์˜๋ก

๐Ÿ’ฌ ์Šคํฌ๋Ÿผ

๐Ÿ’ญ ํŒ€ ํšŒ๊ณ 

๐Ÿ’ญ ๊ฐœ์ธ ํšŒ๊ณ 

๐Ÿƒ Ongoing Project

Clone this wiki locally