diff --git a/apps/hub/app/(auth)/login/_components/Login.tsx b/apps/hub/app/(auth)/login/_components/Login.tsx index 204e18df..aded2c2a 100644 --- a/apps/hub/app/(auth)/login/_components/Login.tsx +++ b/apps/hub/app/(auth)/login/_components/Login.tsx @@ -10,7 +10,9 @@ export const Login = () => { password: z.string().min(6), }); - const form = useForm({ + type schemaType = z.infer; + + const form = useForm({ resolver: zodResolver(schema), }); console.log(form.formState.errors); diff --git a/apps/hub/app/(auth)/logout/page.tsx b/apps/hub/app/(auth)/logout/page.tsx new file mode 100644 index 00000000..7b0cbbe4 --- /dev/null +++ b/apps/hub/app/(auth)/logout/page.tsx @@ -0,0 +1,16 @@ +'use client'; +import { signOut } from 'next-auth/react'; +import { useEffect } from 'react'; + +export default () => { + useEffect(() => { + signOut({ + callbackUrl: '/login', + }); + }, []); + return ( +
+

logging out...

+
+ ); +}; diff --git a/apps/hub/app/(auth)/register/_components/Register.tsx b/apps/hub/app/(auth)/register/_components/Register.tsx new file mode 100644 index 00000000..e32b815a --- /dev/null +++ b/apps/hub/app/(auth)/register/_components/Register.tsx @@ -0,0 +1,211 @@ +'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import { register } from '../action'; +import { signIn } from 'next-auth/react'; +import Link from 'next/link'; +import { useState } from 'react'; +import clsx, { ClassValue } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export const Register = () => { + const schema = z + .object({ + email: z.string().email({ + message: 'Please enter a valid email', + }), + firstname: z.string().min(2).max(30), + lastname: z.string().min(2).max(30), + password: z.string().min(6), + passwordConfirm: z.string().min(6), + }) + .superRefine(({ password, passwordConfirm }, ctx) => { + if (password !== passwordConfirm) { + ctx.addIssue({ + code: 'custom', + message: 'Die Passwörter stimmen nicht überein', + path: ['confirmPassword'], + }); + } + }); + + type IFormInput = z.infer; + + const [isLoading, setIsLoading] = useState(false); + + const cn = (...inputs: ClassValue[]) => { + return twMerge(clsx(inputs)); + }; + + const form = useForm({ + resolver: zodResolver(schema), + defaultValues: { + email: '', + password: '', + passwordConfirm: '', + }, + }); + console.log(form.formState.errors); + return ( +
{ + setIsLoading(true); + const values = form.getValues(); + const user = await register({ + email: form.getValues('email'), + password: form.getValues('password'), + firstname: form.getValues('firstname'), + lastname: form.getValues('lastname'), + }); + await signIn('credentials', { + redirect: false, + email: user.email, + password: values.password, + }); + setIsLoading(false); + })} + > +

Registrierung

+ + Zurück zum{' '} + + Login + + +
+ +

+ {typeof form.formState.errors.firstname?.message === 'string' + ? form.formState.errors.firstname.message + : ''} +

+ +

+ {typeof form.formState.errors.lastname?.message === 'string' + ? form.formState.errors.lastname.message + : ''} +

+
Account
+ + +

+ {typeof form.formState.errors.email?.message === 'string' + ? form.formState.errors.email.message + : ''} +

+ +

+ {typeof form.formState.errors.password?.message === 'string' + ? form.formState.errors.password.message + : ''} +

+ +

+ {typeof form.formState.errors.passwordConfirm?.message === 'string' + ? form.formState.errors.passwordConfirm.message + : ''} +

+
+ +
+
+
+ ); +}; diff --git a/apps/hub/app/(auth)/register/action.ts b/apps/hub/app/(auth)/register/action.ts new file mode 100644 index 00000000..805831fb --- /dev/null +++ b/apps/hub/app/(auth)/register/action.ts @@ -0,0 +1,17 @@ +'use server'; +import { prisma, Prisma } from '@repo/db'; +import bcrypt from 'bcryptjs'; + +export const register = async ({ + password, + ...user +}: Prisma.UserCreateInput) => { + const hashedPassword = await bcrypt.hash(password, 15); + const newUser = prisma.user.create({ + data: { + ...user, + password: hashedPassword, + }, + }); + return newUser; +}; diff --git a/apps/hub/app/(auth)/register/page.tsx b/apps/hub/app/(auth)/register/page.tsx new file mode 100644 index 00000000..fc233e56 --- /dev/null +++ b/apps/hub/app/(auth)/register/page.tsx @@ -0,0 +1,24 @@ +import { Register } from './_components/Register'; + +export default () => { + return ( + <> +
+
+
+
+
+ +
+
+
+
+ + ); +}; diff --git a/apps/hub/app/_components/ui/FormTextInput.tsx b/apps/hub/app/_components/ui/FormTextInput.tsx new file mode 100644 index 00000000..05436bbf --- /dev/null +++ b/apps/hub/app/_components/ui/FormTextInput.tsx @@ -0,0 +1,24 @@ +import { DetailedHTMLProps, InputHTMLAttributes, ReactNode } from 'react'; + +interface FormTextInputProps extends InputHTMLAttributes { + error: any; + Svg: ReactNode; + children?: ReactNode; +} + +export const FormTextInput = ({ + error, + Svg, + children, + ...props +}: FormTextInputProps) => { + return ( + <> + +

{error}

+ + ); +}; diff --git a/apps/hub/app/api/auth/[...nextauth]/auth.ts b/apps/hub/app/api/auth/[...nextauth]/auth.ts index c4724aaf..8d5c2de4 100644 --- a/apps/hub/app/api/auth/[...nextauth]/auth.ts +++ b/apps/hub/app/api/auth/[...nextauth]/auth.ts @@ -1,10 +1,11 @@ -import NextAuth, { AuthOptions } from 'next-auth'; +import { AuthOptions } from 'next-auth'; import { PrismaAdapter } from '@next-auth/prisma-adapter'; import Credentials from 'next-auth/providers/credentials'; -import { prisma } from '@repo/db'; +import { PrismaClient } from '@prisma/client'; import bcrypt from 'bcryptjs'; +const prisma = new PrismaClient(); -export const options = { +export const options: AuthOptions = { providers: [ Credentials({ credentials: { @@ -18,6 +19,7 @@ export const options = { where: { email: credentials.email }, }); if (bcrypt.compareSync(credentials.password, user.password)) { + console.log('User found and password correct', user); return user; } return null; @@ -32,6 +34,7 @@ export const options = { strategy: 'jwt', maxAge: 30 * 24 * 60 * 60, }, + adapter: PrismaAdapter(prisma), events: { async signIn(message) { @@ -44,6 +47,24 @@ export const options = { console.log('User created!', { message }); }, }, + callbacks: { + jwt: async ({ token, user }) => { + if (user) { + token.uid = user; + } + + return token; + }, + session: async ({ session, token }: any) => { + // here we put session.useData and put inside it whatever you want to be in the session + // here try to console.log(token) and see what it will have + // sometimes the user get stored in token.uid.userData + // sometimes the user data get stored in just token.uid + session.userData = token.uid.userData; + + return session; + }, + }, pages: { signIn: '/login', signOut: '/logout', diff --git a/apps/hub/app/page.tsx b/apps/hub/app/page.tsx index 1b1ccfe9..005f2119 100644 --- a/apps/hub/app/page.tsx +++ b/apps/hub/app/page.tsx @@ -1,13 +1,19 @@ 'use client'; import { useSession } from 'next-auth/react'; +import { useEffect } from 'react'; export default function Home() { - const { data: session, status } = useSession(); + const { data: session, status, update } = useSession(); console.log(session, status); + useEffect(() => { + update(); + }, []); return (

Hub

+ {!session &&

Not signed in

} + {session?.user?.firstname &&

Hi, {session?.user?.firstname}

}
); } diff --git a/apps/hub/package.json b/apps/hub/package.json index 77d7c5c6..c1262ab1 100644 --- a/apps/hub/package.json +++ b/apps/hub/package.json @@ -13,11 +13,15 @@ "@next-auth/prisma-adapter": "^1.0.7", "@repo/ui": "*", "bcryptjs": "^2.4.3", + "clsx": "^2.1.1", + "lodash": "^4.17.21", + "lucide-react": "^0.474.0", "next": "15.1.4", "next-auth": "^4.24.11", "react": "^19.0.0", "react-dom": "^19.0.0", "react-hook-form": "^7.54.2", + "tailwind-merge": "^2.6.0", "zod": "^3.24.1" }, "devDependencies": { @@ -26,6 +30,7 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "daisyui": "^4.12.23", "eslint": "^9", "eslint-config-next": "15.1.4", "postcss": "^8", diff --git a/apps/hub/tailwind.config.ts b/apps/hub/tailwind.config.ts index 1362b882..d4947001 100644 --- a/apps/hub/tailwind.config.ts +++ b/apps/hub/tailwind.config.ts @@ -1,18 +1,18 @@ -import type { Config } from "tailwindcss"; +import type { Config } from 'tailwindcss'; export default { content: [ - "./pages/**/*.{js,ts,jsx,tsx,mdx}", - "./components/**/*.{js,ts,jsx,tsx,mdx}", - "./app/**/*.{js,ts,jsx,tsx,mdx}", + './pages/**/*.{js,ts,jsx,tsx,mdx}', + './components/**/*.{js,ts,jsx,tsx,mdx}', + './app/**/*.{js,ts,jsx,tsx,mdx}', ], theme: { extend: { colors: { - background: "var(--background)", - foreground: "var(--foreground)", + background: 'var(--background)', + foreground: 'var(--foreground)', }, }, }, - plugins: [], + plugins: [require('daisyui')], } satisfies Config; diff --git a/apps/hub/types/next-auth.d.ts b/apps/hub/types/next-auth.d.ts new file mode 100644 index 00000000..b3d42874 --- /dev/null +++ b/apps/hub/types/next-auth.d.ts @@ -0,0 +1,20 @@ +import NextAuth from 'next-auth'; +import { User } from '@repo/db'; + +declare module 'next-auth' { + /** + * Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context + */ + interface Session { + user: User; + } + type User = User; +} + +declare module 'next-auth/jwt' { + interface JWT { + firstname: string; + lastname: string; + email: string; + } +} diff --git a/package-lock.json b/package-lock.json index de5edcc9..306995ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,11 +42,15 @@ "@next-auth/prisma-adapter": "^1.0.7", "@repo/ui": "*", "bcryptjs": "^2.4.3", + "clsx": "^2.1.1", + "lodash": "^4.17.21", + "lucide-react": "^0.474.0", "next": "15.1.4", "next-auth": "^4.24.11", "react": "^19.0.0", "react-dom": "^19.0.0", "react-hook-form": "^7.54.2", + "tailwind-merge": "^2.6.0", "zod": "^3.24.1" }, "devDependencies": { @@ -55,6 +59,7 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "daisyui": "^4.12.23", "eslint": "^9", "eslint-config-next": "15.1.4", "postcss": "^8", @@ -2256,6 +2261,14 @@ "node": ">=0.8" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -2376,6 +2389,16 @@ "node": ">= 8" } }, + "node_modules/css-selector-tokenizer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", + "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -2394,6 +2417,34 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "dev": true }, + "node_modules/culori": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz", + "integrity": "sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/daisyui": { + "version": "4.12.23", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.23.tgz", + "integrity": "sha512-EM38duvxutJ5PD65lO/AFMpcw+9qEy6XAZrTpzp7WyaPeO/l+F/Qiq0ECHHmFNcFXh5aVoALY4MGrrxtCiaQCQ==", + "dev": true, + "dependencies": { + "css-selector-tokenizer": "^0.8", + "culori": "^3", + "picocolors": "^1", + "postcss-js": "^4" + }, + "engines": { + "node": ">=16.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/daisyui" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -3619,6 +3670,12 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, "node_modules/fastq": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", @@ -5217,8 +5274,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.get": { "version": "4.4.2", @@ -5280,6 +5336,14 @@ "node": ">=12" } }, + "node_modules/lucide-react": { + "version": "0.474.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.474.0.tgz", + "integrity": "sha512-CmghgHkh0OJNmxGKWc0qfPJCYHASPMVSyGY8fj3xgk4v84ItqDg64JNKFZn5hC6E0vHi6gxnbCgwhyVB09wQtA==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -7516,6 +7580,15 @@ "upper-case": "^1.1.1" } }, + "node_modules/tailwind-merge": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", + "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "3.4.17", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", diff --git a/packages/database/prisma/migrations/20250126233728_dev/migration.sql b/packages/database/prisma/migrations/20250126233728_dev/migration.sql new file mode 100644 index 00000000..f30ffbe9 --- /dev/null +++ b/packages/database/prisma/migrations/20250126233728_dev/migration.sql @@ -0,0 +1,20 @@ +/* + Warnings: + + - You are about to drop the `accounts` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `sessions` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `users` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `verification_requests` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropTable +DROP TABLE "accounts"; + +-- DropTable +DROP TABLE "sessions"; + +-- DropTable +DROP TABLE "users"; + +-- DropTable +DROP TABLE "verification_requests"; diff --git a/packages/database/prisma/migrations/20250126234611_added_user/migration.sql b/packages/database/prisma/migrations/20250126234611_added_user/migration.sql new file mode 100644 index 00000000..0f811e7b --- /dev/null +++ b/packages/database/prisma/migrations/20250126234611_added_user/migration.sql @@ -0,0 +1,80 @@ +-- CreateTable +CREATE TABLE "sessions" ( + "id" SERIAL NOT NULL, + "user_id" INTEGER NOT NULL, + "expires" TIMESTAMP(3) NOT NULL, + "session_token" TEXT NOT NULL, + "access_token" TEXT NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "sessions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "users" ( + "id" TEXT NOT NULL, + "firstname" TEXT NOT NULL, + "lastname" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password" TEXT NOT NULL, + "email_verified" TIMESTAMP(3), + "image" TEXT, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "users_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "verification_requests" ( + "id" SERIAL NOT NULL, + "identifier" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expires" TIMESTAMP(3) NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "verification_requests_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "accounts" ( + "id" SERIAL NOT NULL, + "compound_id" TEXT NOT NULL, + "user_id" INTEGER NOT NULL, + "provider_type" TEXT NOT NULL, + "provider_id" TEXT NOT NULL, + "provider_account_id" TEXT NOT NULL, + "refresh_token" TEXT, + "access_token" TEXT, + "access_token_expires" TIMESTAMP(3), + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "accounts_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "sessions_session_token_key" ON "sessions"("session_token"); + +-- CreateIndex +CREATE UNIQUE INDEX "sessions_access_token_key" ON "sessions"("access_token"); + +-- CreateIndex +CREATE UNIQUE INDEX "users_email_key" ON "users"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "verification_requests_token_key" ON "verification_requests"("token"); + +-- CreateIndex +CREATE UNIQUE INDEX "accounts_compound_id_key" ON "accounts"("compound_id"); + +-- CreateIndex +CREATE INDEX "providerAccountId" ON "accounts"("provider_account_id"); + +-- CreateIndex +CREATE INDEX "providerId" ON "accounts"("provider_id"); + +-- CreateIndex +CREATE INDEX "userId" ON "accounts"("user_id"); diff --git a/packages/database/prisma/schema.prisma b/packages/database/prisma/schema.prisma deleted file mode 100644 index 87c160ac..00000000 --- a/packages/database/prisma/schema.prisma +++ /dev/null @@ -1,71 +0,0 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? -// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init - -generator client { - provider = "prisma-client-js" - output = "../generated/client" -} - -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") -} - -model Account { - id Int @id @default(autoincrement()) - compoundId String @unique @map(name: "compound_id") - userId Int @map(name: "user_id") - providerType String @map(name: "provider_type") - providerId String @map(name: "provider_id") - providerAccountId String @map(name: "provider_account_id") - refreshToken String? @map(name: "refresh_token") - accessToken String? @map(name: "access_token") - accessTokenExpires DateTime? @map(name: "access_token_expires") - createdAt DateTime @default(now()) @map(name: "created_at") - updatedAt DateTime @default(now()) @map(name: "updated_at") - - @@index([providerAccountId], name: "providerAccountId") - @@index([providerId], name: "providerId") - @@index([userId], name: "userId") - @@map(name: "accounts") -} - -model Session { - id Int @id @default(autoincrement()) - userId Int @map(name: "user_id") - expires DateTime - sessionToken String @unique @map(name: "session_token") - accessToken String @unique @map(name: "access_token") - createdAt DateTime @default(now()) @map(name: "created_at") - updatedAt DateTime @default(now()) @map(name: "updated_at") - - @@map(name: "sessions") -} - -model User { - id String @id @default(uuid()) - firstname String - lastname String - email String @unique - password String - emailVerified DateTime? @map(name: "email_verified") - image String? - createdAt DateTime @default(now()) @map(name: "created_at") - updatedAt DateTime @default(now()) @map(name: "updated_at") - - @@map(name: "users") -} - -model VerificationRequest { - id Int @id @default(autoincrement()) - identifier String - token String @unique - expires DateTime - createdAt DateTime @default(now()) @map(name: "created_at") - updatedAt DateTime @default(now()) @map(name: "updated_at") - - @@map(name: "verification_requests") -} diff --git a/packages/database/prisma/schema/auth.prisma b/packages/database/prisma/schema/auth.prisma new file mode 100644 index 00000000..ccd6fc73 --- /dev/null +++ b/packages/database/prisma/schema/auth.prisma @@ -0,0 +1,36 @@ +model Session { + id Int @id @default(autoincrement()) + userId Int @map(name: "user_id") + expires DateTime + sessionToken String @unique @map(name: "session_token") + accessToken String @unique @map(name: "access_token") + createdAt DateTime @default(now()) @map(name: "created_at") + updatedAt DateTime @default(now()) @map(name: "updated_at") + + @@map(name: "sessions") +} + +model User { + id String @id @default(uuid()) + firstname String + lastname String + email String @unique + password String + emailVerified DateTime? @map(name: "email_verified") + image String? + createdAt DateTime @default(now()) @map(name: "created_at") + updatedAt DateTime @default(now()) @map(name: "updated_at") + + @@map(name: "users") +} + +model VerificationRequest { + id Int @id @default(autoincrement()) + identifier String + token String @unique + expires DateTime + createdAt DateTime @default(now()) @map(name: "created_at") + updatedAt DateTime @default(now()) @map(name: "updated_at") + + @@map(name: "verification_requests") +} diff --git a/packages/database/prisma/schema/schema.prisma b/packages/database/prisma/schema/schema.prisma new file mode 100644 index 00000000..7df96a9e --- /dev/null +++ b/packages/database/prisma/schema/schema.prisma @@ -0,0 +1,15 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + previewFeatures = ["prismaSchemaFolder"] +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} diff --git a/packages/database/prisma/schema/user.prisma b/packages/database/prisma/schema/user.prisma new file mode 100644 index 00000000..e652702e --- /dev/null +++ b/packages/database/prisma/schema/user.prisma @@ -0,0 +1,18 @@ +model Account { + id Int @id @default(autoincrement()) + compoundId String @unique @map(name: "compound_id") + userId Int @map(name: "user_id") + providerType String @map(name: "provider_type") + providerId String @map(name: "provider_id") + providerAccountId String @map(name: "provider_account_id") + refreshToken String? @map(name: "refresh_token") + accessToken String? @map(name: "access_token") + accessTokenExpires DateTime? @map(name: "access_token_expires") + createdAt DateTime @default(now()) @map(name: "created_at") + updatedAt DateTime @default(now()) @map(name: "updated_at") + + @@index([providerAccountId], name: "providerAccountId") + @@index([providerId], name: "providerId") + @@index([userId], name: "userId") + @@map(name: "accounts") +}