강원도지사
article thumbnail

 

 

https://supabase.com/

 

Supabase | The Open Source Firebase Alternative

Build production-grade applications with a Postgres database, Authentication, instant APIs, Realtime, Functions, Storage and Vector embeddings. Start for free.

supabase.com

https://orm.drizzle.team/

 

Drizzle ORM - next gen TypeScript ORM.

Drizzle ORM is a lightweight and performant TypeScript ORM with developer experience in mind.

orm.drizzle.team

https://authjs.dev/getting-started/adapters

 

 

최종 파일구조는 다음과 같다

현재 최종 파일 구조

 

 

1. 올가니제이션을 만든다

2. 프로젝트를 만든다

 

3. drizzle에 들어가서 상단 documentation을 클릭한다

 

4. 좌측 Get Started를 누른 후 supabase를 누른다

 

5.순서대로 따라한다.

5-1. Step1은 프로젝트 안 cmd에 그대로 따라했다. yarn으로

5-2. 일단 step3로 넘어가서 첫번째 코드는 오류가 나서 두번째 if you need~ 문장 아래의 코드를 넣어서 수정했다.

(/db/index.ts도 만듦)

// /db/index.ts

import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'


    const client = postgres(process.env.DATABASE_URL!)
    const db = drizzle({ client });

export {db};

 

5-3. step 5로 넘어가 루트에 drizzle.config.ts를 만들고 아래 코드를 삽입했다

import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  out: './drizzle',
  schema: './src/db/schema.ts',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});

 

 

6. Auth.js로 들어가서 install 해준다

yarn add next-auth@beta
npx auth secret

 

npx auth secret을 하면 env.local이 생기는데 그 안의 코드를 env로 옮긴다

 

7. src/db/schema.ts를 만들고, src/db/auth.ts를 만들어 다음 코드를 넣는다

"use server"

import {NextAuthOptions} from "@/db/options"
import NextAuth from "next-auth"

export const {handlers, signIn, signOut, auth} = NextAuth(NextAuthOptions);

 

8. src/app/API/[...nextauth]/route.ts에 다음 코드를 넣는다

import { handlers } from "@/action/auth";
export const {GET, POST} = handlers;

 

9. /src/middleware.ts 파일에 원래 있던 내용을 삭제하고 아래 코드를 넣는다

export {auth as middleware} from "@/action/auth";

 

 

10. 다음을 설치한다(터미널에서)

yarn add drizzle-orm @/auth/drizzle-adapter
yarn add drizzle-kit --dev

 

 

11. https://authjs.dev/getting-started/adapters/drizzle#schemas 여기에 들어가서 

 

이 코드를 복사해준다. 나는 아래와 같이 좀 수정했다.

import {
  boolean,
  timestamp,
  pgTable,
  text,
  primaryKey,
  integer,
} from "drizzle-orm/pg-core";
// import postgres from "postgres";
// import { drizzle } from "drizzle-orm/postgres-js";
// import type { AdapterAccountType } from "next-auth/adapters";

// const connectionString = "postgres://postgres:postgres@localhost:5432/drizzle";
// const pool = postgres(connectionString, { max: 1 });

// export const db = drizzle(pool);

export const users = pgTable("user", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => crypto.randomUUID()),
  name: text("name"),
  email: text("email").unique(),
  emailVerified: timestamp("emailVerified", { mode: "date" }),
  image: text("image"),
});

export const accounts = pgTable(
  "account",
  {
    userId: text("userId")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    type: text("type").$type<AdapterAccountType>().notNull(),
    provider: text("provider").notNull(),
    providerAccountId: text("providerAccountId").notNull(),
    refresh_token: text("refresh_token"),
    access_token: text("access_token"),
    expires_at: integer("expires_at"),
    token_type: text("token_type"),
    scope: text("scope"),
    id_token: text("id_token"),
    session_state: text("session_state"),
  },
  (account) => [
    {
      compoundKey: primaryKey({
        columns: [account.provider, account.providerAccountId],
      }),
    },
  ]
);

export const sessions = pgTable("session", {
  sessionToken: text("sessionToken").primaryKey(),
  userId: text("userId")
    .notNull()
    .references(() => users.id, { onDelete: "cascade" }),
  expires: timestamp("expires", { mode: "date" }).notNull(),
});

export const verificationTokens = pgTable(
  "verificationToken",
  {
    identifier: text("identifier").notNull(),
    token: text("token").notNull(),
    expires: timestamp("expires", { mode: "date" }).notNull(),
  },
  (verificationToken) => [
    {
      compositePk: primaryKey({
        columns: [verificationToken.identifier, verificationToken.token],
      }),
    },
  ]
);

export const authenticators = pgTable(
  "authenticator",
  {
    credentialID: text("credentialID").notNull().unique(),
    userId: text("userId")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    providerAccountId: text("providerAccountId").notNull(),
    credentialPublicKey: text("credentialPublicKey").notNull(),
    counter: integer("counter").notNull(),
    credentialDeviceType: text("credentialDeviceType").notNull(),
    credentialBackedUp: boolean("credentialBackedUp").notNull(),
    transports: text("transports"),
  },
  (authenticator) => [
    {
      compositePK: primaryKey({
        columns: [authenticator.userId, authenticator.credentialID],
      }),
    },
  ]
);

 

 

12. options.ts파일로 가서 아래와 같이 수정합니다

import { NextAuthConfig } from "next-auth";
import { DrizzleAdapter } from "@auth/drizzle-adapter";
import Credentials from "next-auth/providers/credentials";
import { db } from ".";

export const NextAuthOptions: NextAuthConfig = {
  adapter: DrizzleAdapter(db),
  providers: [
    Credentials({
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {

      }
    })
  ],
};

 

 

13.schema.ts의 users를 입맛에 맞게 바꿔줍니다. 

 

14. package.json의 "scripts":{}안에 아래 코드를 추가했습니다

  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "db:generate": "drizzle-kit generate",  //추가
    "db:migrate": "drizzle-kit migrate",//추가
    "db:push": "drizzle-kit push",//추가
    "db:studio": "drizzle-kit studio",//추가
    "db:full": "drizzle-kit full",//추가
    "db:check": "drizzle-kit check"//추가
  },

 

15. yarn db:push를 하면 schema에 있는게 그대로 db에 올라간다.

 

만약 supabase를 안쓴다면 yarn db:studio를 하면 아래와 같이 나오는데 왜 값이 안나오는지는 잘 모르겠다(선생님이 안알려주심 ㅠㅠ)

 

 

16. /scr/action/auth.ts를 만들고 아래와 같은 코드를 삽입했다.

 

import { error } from "console";
import {eq} from "drizzle-orm"
import {z} from "zod"

const signInSchema = z.object({
  email: z.string().email(),
  password : z.string.min(8),
});

export type TSignInActionParams = z.infer<typeof signInSchema>;

export const signInAction = async(data: TSignInActionParams) =>{
  const {email, password} = signInSchema.parse(data);
  const user = await db.query.users.findFirst({
    where: eq(users.email, email),
  });
  if(!user){
    return{error: "유저를 찾을 수 없습니다", data:null};
  }
  if(user.password !== password){
    return{error:"일치하지 않는 비밀번호입니다", data:null}
  }
  return{success: "유저 로그인했습니다", data:"user"}
};

 

 

17. /src/db/index.ts 로 돌아와 코드를 아래처럼 수정했다

import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import * as schema from "./schema"


    const client = postgres(process.env.DATABASE_URL!)
    const db = drizzle(client, { schema });

export {db};

 

 

18. /src/action/auth.ts

//yarn add drizzle-zod

import { eq } from "drizzle-orm";
import { users } from "@/db/schema";
import { z } from "zod";
import { db } from "@/db";

const signInSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
});

export type TSignInActionParams = z.infer<typeof signInSchema>;

export const signInAction = async (data: TSignInActionParams) => {
  const { email, password } = signInSchema.parse(data);

  const user = await db.query.users.findFirst({
    where: eq(users.email, email),
  });

  if (!user) {
    return { error: "유저를 찾을 수 없습니다", data: null };
  }
};

export const signUpAction;

export const signUpSchema = createInsertSchema(users)
  .omit({
    id: true,
  })
  .extend({
    email: z.string().email(),
    password: z.string().min(8),
  });

export type TSignInActionParams = z.infer<typeof signUpSchema>;

export const signUpAction = async (data:TSignInActionParams) => {
  const {email, password} = signUpSchema.parse(data);
  const user = await db.insert(users).values({email, password}),returning();
  return {success:"유저 회원가입 완료",data: user[0]};
};

 

 

 

profile

강원도지사

@박강원입니다

노력하여 끊임없이 발전하는 사람이 되겠습니다!