바이트의 기술적 측면

⚠️⚠️ 프로젝트는 더 이상 유지 관리되거나 호스팅되지 않습니다. 코드는 Github에서 사용할 수 있습니다.

If you are unaware of Bytes then check out this blog that I wrote:
Bytes - A Platform to share bite-sized learnings!



이 블로그에서는 Bytes의 데이터베이스 모델링인 기술 스택을 선택하기로 한 결정에 대해 이야기하겠습니다.


목차



  • Tech Stack
  • NextJS
  • HarperDB
  • TailwindCSS
  • Firebase ( Storage and Authentication )


  • Database Modelling

  • Schemas
  • User Schema
  • Post Schema
  • Tag Schema
  • Post_Tag Schema


  • Relationships
  • User <-> Post
  • Post <-> Tags


  • Protecting Routes
  • Socials



  • 기술 스택


  • 넥스트제이에스
  • 하퍼DB
  • TailwindCSS
  • 중포 기지

  • NextJS


  • NextJS는 SSR 지원 및 Pages 지원을 즉시 제공하기 때문에 NextJS를 선택했습니다.

  • 하퍼DB


  • Bytes는 HashNode-HarperDB 해커톤의 일부로 만들어지므로 HarperDB는 Database for Bytes 역할을 합니다.
  • SQL 방식 또는 NoSQL 방식으로 쿼리하는 기능을 사용하면 작업이 매우 쉬워집니다.

  • TailwindCSS


  • 블로그에서 항상 Tailwind를 칭찬합니다. 모든 유틸리티 클래스로 CSS를 작성하는 것이 더 쉽습니다
  • .
  • Dark/Light 테마도 지원합니다.

  • Firebase(저장 및 인증)


  • 바이트 이미지는 Firebase 저장소에서 처리됩니다.
  • 업로드된 이미지의 모든 URL이 Harper에 저장됩니다
  • .
  • 인증은 사용자 세션도 정상적으로 처리하므로 Firebase 인증을 사용하여 구현됩니다.



  • 데이터베이스 모델링


  • 이것은 저에게 데이터베이스 작업의 재미있는 부분입니다. 이 섹션에서는 테이블의 스키마와 해당 관계를 공유합니다.
  • 모델과 해당 관계를 정규화하도록 노력했습니다.

  • 스키마



    사용자 스키마




    export type UserSchema = {
      uid: string;
      email: string;
      name: string;
      username: string;
      verified: boolean;
      __createdtime__?: string;
      __updatedtime__?: string;
    };
    


    사후 스키마




    export type PostSchema = {
      pid: string;
      images: Array<string>;
      slug: string;
      title: string;
      uid: string;
      reactions: number;
      __createdtime__?: string;
      __updatedtime__?: string;
    };
    


    태그 스키마




    export type TagType = {
      tid: string;
      name: string;
      color: string;
      image?: string;
      slug?: string;
      __createdtime__?: string;
      __updatedtime__?: string;
    };
    


    Post_Tag 스키마




    export type Post_Tag_Type = {
      pid: string;
      ptid: string;
      tid: string;
      __createdtime__?: string;
      __updatedtime__?: string;
    };
    


    관계



    사용자 <-> 게시물


  • 이 관계는 일대다입니다
  • .
  • 따라서 포스트 스키마는 외래 키, 즉 사용자의 uuid를 uid로 갖게 됩니다.
  • 사용자 게시물을 가져오려면 여기uid에서 사용자와 게시물을 내부 조인하기만 하면 됩니다.

  • -- Gets all the Posts of a User
    SELECT p.*,u.name,u.username FROM bytes.post AS p INNER JOIN bytes.user AS u ON u.uid=p.uid WHERE u.username='${username}'
    


    게시 <-> 태그


  • 게시물 및 태그와의 관계는 다대다입니다.
  • 하나의 게시물에 많은 태그가 있을 수 있고 하나의 태그에 게시물이 있을 수 있음
  • N:M 관계를 구현하는 다양한 방법을 보여주는 놀라운 기사를 찾았습니다.
  • Tags: Database schemas

  • 이를 바탕으로 Post_Tag라는 별도의 테이블을 만들어
    게시물 ID를 pid로, 태그 ID를 tid로 지정
  • 이제 모든 태그가 포함된 게시물을 가져오려면 다음 SQL 쿼리를 작성합니다.

  • -- Gets all Tags for a Post
    SELECT t.* FROM bytes.post_tag AS pt INNER JOIN bytes.tag AS t ON pt.tid=t.tid WHERE pt.pid='${post.pid}'
    



    -- Get all Posts of a Tag
    SELECT p.*,u.name,u.username FROM bytes.post_tag AS pt INNER JOIN bytes.post AS p ON pt.pid=p.pid INNER JOIN bytes.user AS u ON p.uid = u.uid WHERE pt.tid='${tag.tid}'
    
    



    경로 보호


  • 현재 Bytes에는 다음 경로가 있습니다.
  • /
  • /업로드
  • /로그인
  • /프로필/:id/
  • /byte/:id/
  • /tag/:id/


  • 이 경로 중 /upload 경로가 보호되며 사용자가 로그인한 경우에만 액세스할 수 있습니다.
  • 그렇게 하기 위해 사용자를 확인하는 사용자 지정 후크를 만들었습니다.
  • 사용자가 로그인한 경우 사용자가 "/login"으로 리디렉션하도록 허용합니다.

  • // useRequireLogin.tsx
    const router = useRouter();
    
    const { user, setUser } = useContext(UserContext);
    const [loading, setLoading] = useState(false);
    
    useEffect(() => {
      setLoading(true);
      firebase.auth().onAuthStateChanged(async (user) => {
        if (user) {
          const authUser = await getAuthUserFromHarper(user.uid);
          setUser({ ...authUser, isLoggedIn: true });
          setLoading(false);
          router.push(to);
        } else {
          setUser({});
          setLoading(false);
          router.push("/login");
        }
      });
    }, []);
    
    return { user, loading };
    
    // ------------------------
    // Using in the Upload Page
    // /pages/upload.tsx
    // ------------------------
    
    const { user, loading } = useRequireLogin({ to: "/upload" });
    
    if (loading || !user.isLoggedIn) return null;
    



    이 블로그가 마음에 들었고 여기에서 무언가를 배웠기를 바랍니다.
    아직 Bytes에 추가하고 있는 몇 가지 개선 사항과 기능이 있습니다.

    소셜



    내 트위터에서 나를 팔로우할 수 있습니다.

    좋은 웹페이지 즐겨찾기