diff --git a/.env.local b/.env.local
new file mode 100644
index 0000000..30790fe
--- /dev/null
+++ b/.env.local
@@ -0,0 +1,6 @@
+AUTH_KEYCLOAK_ID=verity_client
+AUTH_KEYCLOAK_SECRET=veritysecret
+AUTH_KEYCLOAK_ISSUER=http://localhost:8080/realms/verity
+AUTH_SECRET=authsecret
+
+DATABASE_URL=postgresql://verity:verity@localhost:5432/verity
diff --git a/README.md b/README.md
index 9406186..7b8a470 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,58 @@
Verity is a service that allows you to create new versions of various applications and connect them
to each other. Manage your applications easily and efficiently.
+
+## Local Development
+
+### Prerequisites
+
+- [Docker](https://www.docker.com/)
+- [Docker Compose](https://docs.docker.com/compose/)
+- [Node.js LTS](https://nodejs.org/en/)
+
+### Getting Started
+
+1. Clone the repository:
+
+```bash
+git clone git@github.com:platacard/verity.git
+```
+
+or
+
+```bash
+git clone https://github.com/platacard/verity.git
+```
+
+2. Change to the project directory:
+
+```bash
+cd verity
+```
+
+3. Start the development environment:
+
+```bash
+docker-compose up -d
+```
+
+4. Install the dependencies:
+
+```bash
+npm install
+```
+
+5. Start the development server:
+
+```bash
+npm start
+```
+
+6. Open your browser and navigate to [http://localhost:3000](http://localhost:3000).
+
+7. Login with the following credentials:
+
+- **Username:** verity
+- **Password:** verity
+
+8. You're all set! 🚀
diff --git a/apps/web/app/api/auth/[...nextauth]/route.ts b/apps/web/app/api/auth/[...nextauth]/route.ts
new file mode 100644
index 0000000..6dd17dd
--- /dev/null
+++ b/apps/web/app/api/auth/[...nextauth]/route.ts
@@ -0,0 +1,3 @@
+import { handlers } from '@verity/auth/server';
+
+export const { GET, POST } = handlers;
diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx
index 59d3022..f118968 100644
--- a/apps/web/app/page.tsx
+++ b/apps/web/app/page.tsx
@@ -1,11 +1,18 @@
import Link from 'next/link';
+import { redirect } from 'next/navigation';
import { MountainIcon } from 'lucide-react';
+import { auth } from '@verity/auth/server';
import { Button } from '@verity/ui/button';
import { Input } from '@verity/ui/input';
-export default function Component() {
+export default async function Component() {
+ const session = await auth();
+ if (!session) {
+ redirect('/api/auth/signin');
+ }
+
return (
diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts
new file mode 100644
index 0000000..f1b7c2c
--- /dev/null
+++ b/apps/web/middleware.ts
@@ -0,0 +1,10 @@
+import NextAuth from 'next-auth';
+import Keycloak from 'next-auth/providers/keycloak';
+
+export const middleware = NextAuth({
+ providers: [Keycloak],
+}).auth;
+
+export const config = {
+ matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
+};
diff --git a/apps/web/project.json b/apps/web/project.json
index 9e8f5ac..3992130 100644
--- a/apps/web/project.json
+++ b/apps/web/project.json
@@ -5,5 +5,9 @@
"projectType": "application",
"tags": [],
"// targets": "to see all targets run: nx show project web --web",
- "targets": {}
+ "targets": {
+ "dev": {
+ "dependsOn": ["verity:prisma:migrate:dev"]
+ }
+ }
}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..88edf30
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,63 @@
+version: '3.8'
+
+services:
+ keycloakdb:
+ image: postgres:latest
+ container_name: postgres
+ environment:
+ POSTGRES_DB: keycloak
+ POSTGRES_USER: keycloak
+ POSTGRES_PASSWORD: keycloak
+ volumes:
+ - keycloakdb_data:/var/lib/postgresql/data
+ networks:
+ - keycloak-network
+
+ keycloak:
+ image: quay.io/keycloak/keycloak:latest
+ container_name: keycloak
+ command:
+ - start-dev
+ - -Dkeycloak.migration.action=import
+ - -Dkeycloak.migration.provider=singleFile
+ - -Dkeycloak.migration.file=/opt/keycloak/data/import/realm-export.json
+ - -Dkeycloak.migration.strategy=IGNORE_EXISTING
+ environment:
+ DB_VENDOR: POSTGRES
+ DB_ADDR: keycloakdb
+ DB_DATABASE: keycloak
+ DB_USER: keycloak
+ DB_PASSWORD: keycloak
+ KEYCLOAK_ADMIN: admin
+ KEYCLOAK_ADMIN_PASSWORD: admin
+ KEYCLOAK_IMPORT: /opt/keycloak/data/import/realm-export.json
+ volumes:
+ - ./realm-export.json:/opt/keycloak/data/import/realm-export.json
+ ports:
+ - 8080:8080
+ depends_on:
+ - keycloakdb
+ networks:
+ - keycloak-network
+
+ verity_db:
+ image: postgres:latest
+ container_name: verity_db
+ environment:
+ POSTGRES_DB: verity
+ POSTGRES_USER: verity
+ POSTGRES_PASSWORD: verity
+ volumes:
+ - verity_db_data:/var/lib/postgresql/data
+ networks:
+ - keycloak-network
+ ports:
+ - 5432:5432
+
+networks:
+ keycloak-network:
+ driver: bridge
+
+volumes:
+ keycloakdb_data:
+ verity_db_data:
diff --git a/libs/auth/.eslintrc.json b/libs/auth/.eslintrc.json
new file mode 100644
index 0000000..a39ac5d
--- /dev/null
+++ b/libs/auth/.eslintrc.json
@@ -0,0 +1,18 @@
+{
+ "extends": ["plugin:@nx/react", "../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.ts", "*.tsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.js", "*.jsx"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/libs/auth/README.md b/libs/auth/README.md
new file mode 100644
index 0000000..910a0e9
--- /dev/null
+++ b/libs/auth/README.md
@@ -0,0 +1,7 @@
+# auth
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test auth` to execute the unit tests via [Jest](https://jestjs.io).
diff --git a/libs/auth/project.json b/libs/auth/project.json
new file mode 100644
index 0000000..06f038a
--- /dev/null
+++ b/libs/auth/project.json
@@ -0,0 +1,9 @@
+{
+ "name": "auth",
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "libs/auth/src",
+ "projectType": "library",
+ "tags": [],
+ "// targets": "to see all targets run: nx show project auth --web",
+ "targets": {}
+}
diff --git a/libs/auth/src/index.ts b/libs/auth/src/index.ts
new file mode 100644
index 0000000..e13d2ba
--- /dev/null
+++ b/libs/auth/src/index.ts
@@ -0,0 +1 @@
+export { signIn, signOut } from 'next-auth/react';
diff --git a/libs/auth/src/lib/auth.ts b/libs/auth/src/lib/auth.ts
new file mode 100644
index 0000000..fd8ab72
--- /dev/null
+++ b/libs/auth/src/lib/auth.ts
@@ -0,0 +1,13 @@
+import NextAuth from 'next-auth';
+import Keycloak from 'next-auth/providers/keycloak';
+
+import { PrismaAdapter } from '@auth/prisma-adapter';
+import { PrismaClient } from '@prisma/client';
+
+const prisma = new PrismaClient();
+
+export const { handlers, signIn, signOut, auth } = NextAuth({
+ adapter: PrismaAdapter(prisma),
+ providers: [Keycloak],
+ session: { strategy: 'jwt' },
+});
diff --git a/libs/auth/src/server.ts b/libs/auth/src/server.ts
new file mode 100644
index 0000000..de7e0fb
--- /dev/null
+++ b/libs/auth/src/server.ts
@@ -0,0 +1,3 @@
+import 'server-only';
+
+export * from './lib/auth';
diff --git a/libs/auth/tsconfig.json b/libs/auth/tsconfig.json
new file mode 100644
index 0000000..95cfeb2
--- /dev/null
+++ b/libs/auth/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "allowJs": false,
+ "esModuleInterop": false,
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.lib.json"
+ }
+ ],
+ "extends": "../../tsconfig.base.json"
+}
diff --git a/libs/auth/tsconfig.lib.json b/libs/auth/tsconfig.lib.json
new file mode 100644
index 0000000..08e579b
--- /dev/null
+++ b/libs/auth/tsconfig.lib.json
@@ -0,0 +1,25 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "types": [
+ "node",
+ "@nx/react/typings/cssmodule.d.ts",
+ "@nx/react/typings/image.d.ts",
+ "next",
+ "@nx/next/typings/image.d.ts"
+ ]
+ },
+ "exclude": [
+ "jest.config.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.tsx",
+ "src/**/*.test.tsx",
+ "src/**/*.spec.js",
+ "src/**/*.test.js",
+ "src/**/*.spec.jsx",
+ "src/**/*.test.jsx"
+ ],
+ "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
+}
diff --git a/package-lock.json b/package-lock.json
index ec24d10..2685acf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,10 @@
"version": "0.0.0",
"license": "MIT",
"dependencies": {
+ "@auth/prisma-adapter": "^2.1.0",
"@hookform/resolvers": "^3.4.2",
+ "@prisma/adapter-pg": "^5.14.0",
+ "@prisma/client": "^5.14.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-aspect-ratio": "^1.0.3",
@@ -45,12 +48,15 @@
"input-otp": "^1.2.4",
"lucide-react": "^0.381.0",
"next": "14.2.3",
+ "next-auth": "^5.0.0-beta.18",
"next-themes": "^0.3.0",
+ "pg": "^8.11.5",
"react": "18.3.1",
"react-day-picker": "^8.10.1",
"react-dom": "18.3.1",
"react-hook-form": "^7.51.5",
"react-resizable-panels": "^2.0.19",
+ "server-only": "^0.0.1",
"sonner": "^1.4.41",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
@@ -82,6 +88,7 @@
"@testing-library/react": "^15.0.7",
"@types/jest": "^29.4.0",
"@types/node": "18.16.9",
+ "@types/pg": "^8.11.6",
"@types/react": "18.3.1",
"@types/react-dom": "18.3.0",
"@typescript-eslint/eslint-plugin": "^7.3.0",
@@ -105,6 +112,7 @@
"prettier": "^3.2.5",
"prettier-plugin-packagejson": "^2.5.0",
"prettier-plugin-tailwindcss": "^0.6.0",
+ "prisma": "^5.14.0",
"tailwindcss": "3.4.3",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
@@ -141,6 +149,47 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@auth/core": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.31.0.tgz",
+ "integrity": "sha512-UKk3psvA1cRbk4/c9CkpWB8mdWrkKvzw0DmEYRsWolUQytQ2cRqx+hYuV6ZCsngw/xbj9hpmkZmAZEyq2g4fMg==",
+ "dependencies": {
+ "@panva/hkdf": "^1.1.1",
+ "@types/cookie": "0.6.0",
+ "cookie": "0.6.0",
+ "jose": "^5.1.3",
+ "oauth4webapi": "^2.4.0",
+ "preact": "10.11.3",
+ "preact-render-to-string": "5.2.3"
+ },
+ "peerDependencies": {
+ "@simplewebauthn/browser": "^9.0.1",
+ "@simplewebauthn/server": "^9.0.2",
+ "nodemailer": "^6.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@simplewebauthn/browser": {
+ "optional": true
+ },
+ "@simplewebauthn/server": {
+ "optional": true
+ },
+ "nodemailer": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@auth/prisma-adapter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@auth/prisma-adapter/-/prisma-adapter-2.1.0.tgz",
+ "integrity": "sha512-x1gYsi8xCFdxpEM6pxhh7OTV+VHB3PgID2L18y8F1kXu+PbcEWt4VZSQ8zk6dI/4YRStcuwQdHe7neCpczr0mg==",
+ "dependencies": {
+ "@auth/core": "0.31.0"
+ },
+ "peerDependencies": {
+ "@prisma/client": ">=2.26.0 || >=3 || >=4 || >=5"
+ }
+ },
"node_modules/@babel/code-frame": {
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz",
@@ -4816,6 +4865,14 @@
"yargs-parser": "21.1.1"
}
},
+ "node_modules/@panva/hkdf": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.1.1.tgz",
+ "integrity": "sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/@phenomnomnominal/tsquery": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-5.0.1.tgz",
@@ -4864,6 +4921,87 @@
"node": ">=16"
}
},
+ "node_modules/@prisma/adapter-pg": {
+ "version": "5.14.0",
+ "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-5.14.0.tgz",
+ "integrity": "sha512-AcV1DKY4ps3zvBIKolCzmBD+resdG4oH14I0iG3SntMjjnCbC/COefIInSV038c8g20RoHJO7fPyf1WPKicRgQ==",
+ "dependencies": {
+ "@prisma/driver-adapter-utils": "5.14.0",
+ "postgres-array": "3.0.2"
+ },
+ "peerDependencies": {
+ "pg": "^8.11.3"
+ }
+ },
+ "node_modules/@prisma/client": {
+ "version": "5.14.0",
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.14.0.tgz",
+ "integrity": "sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==",
+ "hasInstallScript": true,
+ "engines": {
+ "node": ">=16.13"
+ },
+ "peerDependencies": {
+ "prisma": "*"
+ },
+ "peerDependenciesMeta": {
+ "prisma": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@prisma/debug": {
+ "version": "5.14.0",
+ "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.14.0.tgz",
+ "integrity": "sha512-iq56qBZuFfX3fCxoxT8gBX33lQzomBU0qIUaEj1RebsKVz1ob/BVH1XSBwwwvRVtZEV1b7Fxx2eVu34Ge/mg3w=="
+ },
+ "node_modules/@prisma/driver-adapter-utils": {
+ "version": "5.14.0",
+ "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-5.14.0.tgz",
+ "integrity": "sha512-EyAfdKjk0M7CaA7BfiwDTPLs7udOwt+RUnyWIPSg7uBEFp2GS/l9Ig7CCgMZFcBFc62v0c6Z/R3WFuQ+bNxfnA==",
+ "dependencies": {
+ "@prisma/debug": "5.14.0"
+ }
+ },
+ "node_modules/@prisma/engines": {
+ "version": "5.14.0",
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.14.0.tgz",
+ "integrity": "sha512-lgxkKZ6IEygVcw6IZZUlPIfLQ9hjSYAtHjZ5r64sCLDgVzsPFCi2XBBJgzPMkOQ5RHzUD4E/dVdpn9+ez8tk1A==",
+ "devOptional": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "@prisma/debug": "5.14.0",
+ "@prisma/engines-version": "5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48",
+ "@prisma/fetch-engine": "5.14.0",
+ "@prisma/get-platform": "5.14.0"
+ }
+ },
+ "node_modules/@prisma/engines-version": {
+ "version": "5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48",
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48.tgz",
+ "integrity": "sha512-ip6pNkRo1UxWv+6toxNcYvItNYaqQjXdFNGJ+Nuk2eYtRoEdoF13wxo7/jsClJFFenMPVNVqXQDV0oveXnR1cA==",
+ "devOptional": true
+ },
+ "node_modules/@prisma/fetch-engine": {
+ "version": "5.14.0",
+ "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.14.0.tgz",
+ "integrity": "sha512-VrheA9y9DMURK5vu8OJoOgQpxOhas3qF0IBHJ8G/0X44k82kc8E0w98HCn2nhnbOOMwbWsJWXfLC2/F8n5u0gQ==",
+ "devOptional": true,
+ "dependencies": {
+ "@prisma/debug": "5.14.0",
+ "@prisma/engines-version": "5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48",
+ "@prisma/get-platform": "5.14.0"
+ }
+ },
+ "node_modules/@prisma/get-platform": {
+ "version": "5.14.0",
+ "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.14.0.tgz",
+ "integrity": "sha512-/yAyBvcEjRv41ynZrhdrPtHgk47xLRRq/o5eWGcUpBJ1YrUZTYB8EoPiopnP7iQrMATK8stXQdPOoVlrzuTQZw==",
+ "devOptional": true,
+ "dependencies": {
+ "@prisma/debug": "5.14.0"
+ }
+ },
"node_modules/@radix-ui/number": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
@@ -7080,6 +7218,11 @@
"@types/node": "*"
}
},
+ "node_modules/@types/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
+ },
"node_modules/@types/eslint": {
"version": "8.56.10",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
@@ -7265,6 +7408,65 @@
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
"dev": true
},
+ "node_modules/@types/pg": {
+ "version": "8.11.6",
+ "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.6.tgz",
+ "integrity": "sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "pg-protocol": "*",
+ "pg-types": "^4.0.1"
+ }
+ },
+ "node_modules/@types/pg/node_modules/pg-types": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz",
+ "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==",
+ "dev": true,
+ "dependencies": {
+ "pg-int8": "1.0.1",
+ "pg-numeric": "1.0.2",
+ "postgres-array": "~3.0.1",
+ "postgres-bytea": "~3.0.0",
+ "postgres-date": "~2.1.0",
+ "postgres-interval": "^3.0.0",
+ "postgres-range": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@types/pg/node_modules/postgres-bytea": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz",
+ "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==",
+ "dev": true,
+ "dependencies": {
+ "obuf": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@types/pg/node_modules/postgres-date": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz",
+ "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@types/pg/node_modules/postgres-interval": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz",
+ "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/@types/prop-types": {
"version": "15.7.12",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
@@ -9917,7 +10119,6 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
- "dev": true,
"engines": {
"node": ">= 0.6"
}
@@ -16012,6 +16213,14 @@
"jiti": "bin/jiti.js"
}
},
+ "node_modules/jose": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-5.3.0.tgz",
+ "integrity": "sha512-IChe9AtAE79ru084ow8jzkN2lNrG3Ntfiv65Cvj9uOCE2m5LNsdHG+9EbxWxAoWRF9TgDOqLN5jm08++owDVRg==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -17430,6 +17639,32 @@
}
}
},
+ "node_modules/next-auth": {
+ "version": "5.0.0-beta.18",
+ "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-5.0.0-beta.18.tgz",
+ "integrity": "sha512-x55L8wZb8PcPGCYA3e/l9tdpd7YL3FDuhas4W8pxq3PjrWJ9OoDxNN0otK9axJamJBbBgjfzTJjVQB6hXoe0ZQ==",
+ "dependencies": {
+ "@auth/core": "0.31.0"
+ },
+ "peerDependencies": {
+ "@simplewebauthn/browser": "^9.0.1",
+ "@simplewebauthn/server": "^9.0.2",
+ "next": "^14",
+ "nodemailer": "^6.6.5",
+ "react": "^18.2.0"
+ },
+ "peerDependenciesMeta": {
+ "@simplewebauthn/browser": {
+ "optional": true
+ },
+ "@simplewebauthn/server": {
+ "optional": true
+ },
+ "nodemailer": {
+ "optional": true
+ }
+ }
+ },
"node_modules/next-themes": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz",
@@ -17696,6 +17931,14 @@
}
}
},
+ "node_modules/oauth4webapi": {
+ "version": "2.10.4",
+ "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.10.4.tgz",
+ "integrity": "sha512-DSoj8QoChzOCQlJkRmYxAJCIpnXFW32R0Uq7avyghIeB6iJq0XAblOD7pcq3mx4WEBDwMuKr0Y1qveCBleG2Xw==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -18187,6 +18430,104 @@
"url": "https://github.com/sponsors/Borewit"
}
},
+ "node_modules/pg": {
+ "version": "8.11.5",
+ "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.5.tgz",
+ "integrity": "sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==",
+ "dependencies": {
+ "pg-connection-string": "^2.6.4",
+ "pg-pool": "^3.6.2",
+ "pg-protocol": "^1.6.1",
+ "pg-types": "^2.1.0",
+ "pgpass": "1.x"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ },
+ "optionalDependencies": {
+ "pg-cloudflare": "^1.1.1"
+ },
+ "peerDependencies": {
+ "pg-native": ">=3.0.1"
+ },
+ "peerDependenciesMeta": {
+ "pg-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pg-cloudflare": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz",
+ "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==",
+ "optional": true
+ },
+ "node_modules/pg-connection-string": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz",
+ "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA=="
+ },
+ "node_modules/pg-int8": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
+ "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/pg-numeric": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz",
+ "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pg-pool": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz",
+ "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==",
+ "peerDependencies": {
+ "pg": ">=8.0"
+ }
+ },
+ "node_modules/pg-protocol": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz",
+ "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg=="
+ },
+ "node_modules/pg-types": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
+ "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
+ "dependencies": {
+ "pg-int8": "1.0.1",
+ "postgres-array": "~2.0.0",
+ "postgres-bytea": "~1.0.0",
+ "postgres-date": "~1.0.4",
+ "postgres-interval": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pg-types/node_modules/postgres-array": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
+ "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pgpass": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
+ "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
+ "dependencies": {
+ "split2": "^4.1.0"
+ }
+ },
"node_modules/picocolors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
@@ -18984,6 +19325,72 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
+ "node_modules/postgres-array": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz",
+ "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/postgres-bytea": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
+ "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-date": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
+ "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-interval": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
+ "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
+ "dependencies": {
+ "xtend": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-range": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz",
+ "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==",
+ "dev": true
+ },
+ "node_modules/preact": {
+ "version": "10.11.3",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz",
+ "integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/preact-render-to-string": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz",
+ "integrity": "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==",
+ "dependencies": {
+ "pretty-format": "^3.8.0"
+ },
+ "peerDependencies": {
+ "preact": ">=10"
+ }
+ },
+ "node_modules/preact-render-to-string/node_modules/pretty-format": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
+ "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -19126,6 +19533,22 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/prisma": {
+ "version": "5.14.0",
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.14.0.tgz",
+ "integrity": "sha512-gCNZco7y5XtjrnQYeDJTiVZmT/ncqCr5RY1/Cf8X2wgLRmyh9ayPAGBNziI4qEE4S6SxCH5omQLVo9lmURaJ/Q==",
+ "devOptional": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "@prisma/engines": "5.14.0"
+ },
+ "bin": {
+ "prisma": "build/index.js"
+ },
+ "engines": {
+ "node": ">=16.13"
+ }
+ },
"node_modules/proc-log": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz",
@@ -20236,6 +20659,11 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/server-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz",
+ "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA=="
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -20637,7 +21065,6 @@
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
- "dev": true,
"engines": {
"node": ">= 10.x"
}
@@ -22889,6 +23316,14 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
},
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/package.json b/package.json
index b61b1c2..08d175f 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,10 @@
"start": "nx dev web"
},
"dependencies": {
+ "@auth/prisma-adapter": "^2.1.0",
"@hookform/resolvers": "^3.4.2",
+ "@prisma/adapter-pg": "^5.14.0",
+ "@prisma/client": "^5.14.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-aspect-ratio": "^1.0.3",
@@ -44,12 +47,15 @@
"input-otp": "^1.2.4",
"lucide-react": "^0.381.0",
"next": "14.2.3",
+ "next-auth": "^5.0.0-beta.18",
"next-themes": "^0.3.0",
+ "pg": "^8.11.5",
"react": "18.3.1",
"react-day-picker": "^8.10.1",
"react-dom": "18.3.1",
"react-hook-form": "^7.51.5",
"react-resizable-panels": "^2.0.19",
+ "server-only": "^0.0.1",
"sonner": "^1.4.41",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
@@ -81,6 +87,7 @@
"@testing-library/react": "^15.0.7",
"@types/jest": "^29.4.0",
"@types/node": "18.16.9",
+ "@types/pg": "^8.11.6",
"@types/react": "18.3.1",
"@types/react-dom": "18.3.0",
"@typescript-eslint/eslint-plugin": "^7.3.0",
@@ -104,6 +111,7 @@
"prettier": "^3.2.5",
"prettier-plugin-packagejson": "^2.5.0",
"prettier-plugin-tailwindcss": "^0.6.0",
+ "prisma": "^5.14.0",
"tailwindcss": "3.4.3",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
diff --git a/prisma/migrations/20240531202421_auth/migration.sql b/prisma/migrations/20240531202421_auth/migration.sql
new file mode 100644
index 0000000..62283b4
--- /dev/null
+++ b/prisma/migrations/20240531202421_auth/migration.sql
@@ -0,0 +1,81 @@
+-- CreateTable
+CREATE TABLE "User" (
+ "id" TEXT NOT NULL,
+ "name" TEXT,
+ "email" TEXT NOT NULL,
+ "emailVerified" TIMESTAMP(3),
+ "image" TEXT,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "User_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateTable
+CREATE TABLE "Account" (
+ "userId" TEXT NOT NULL,
+ "type" TEXT NOT NULL,
+ "provider" TEXT NOT NULL,
+ "providerAccountId" TEXT NOT NULL,
+ "refresh_token" TEXT,
+ "access_token" TEXT,
+ "expires_at" INTEGER,
+ "token_type" TEXT,
+ "scope" TEXT,
+ "id_token" TEXT,
+ "session_state" TEXT,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "Account_pkey" PRIMARY KEY ("provider","providerAccountId")
+);
+
+-- CreateTable
+CREATE TABLE "Session" (
+ "sessionToken" TEXT NOT NULL,
+ "userId" TEXT NOT NULL,
+ "expires" TIMESTAMP(3) NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "VerificationToken" (
+ "identifier" TEXT NOT NULL,
+ "token" TEXT NOT NULL,
+ "expires" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "VerificationToken_pkey" PRIMARY KEY ("identifier","token")
+);
+
+-- CreateTable
+CREATE TABLE "Authenticator" (
+ "credentialID" TEXT NOT NULL,
+ "userId" TEXT NOT NULL,
+ "providerAccountId" TEXT NOT NULL,
+ "credentialPublicKey" TEXT NOT NULL,
+ "counter" INTEGER NOT NULL,
+ "credentialDeviceType" TEXT NOT NULL,
+ "credentialBackedUp" BOOLEAN NOT NULL,
+ "transports" TEXT,
+
+ CONSTRAINT "Authenticator_pkey" PRIMARY KEY ("userId","credentialID")
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Authenticator_credentialID_key" ON "Authenticator"("credentialID");
+
+-- AddForeignKey
+ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "Authenticator" ADD CONSTRAINT "Authenticator_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml
new file mode 100644
index 0000000..fbffa92
--- /dev/null
+++ b/prisma/migrations/migration_lock.toml
@@ -0,0 +1,3 @@
+# Please do not edit this file manually
+# It should be added in your version-control system (i.e. Git)
+provider = "postgresql"
\ No newline at end of file
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
new file mode 100644
index 0000000..329b3b4
--- /dev/null
+++ b/prisma/schema.prisma
@@ -0,0 +1,78 @@
+datasource db {
+ provider = "postgresql"
+ url = env("DATABASE_URL")
+}
+
+generator client {
+ provider = "prisma-client-js"
+}
+
+model User {
+ id String @id @default(cuid())
+ name String?
+ email String @unique
+ emailVerified DateTime?
+ image String?
+ accounts Account[]
+ sessions Session[]
+ // Optional for WebAuthn support
+ Authenticator Authenticator[]
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+
+model Account {
+ userId String
+ type String
+ provider String
+ providerAccountId String
+ refresh_token String?
+ access_token String?
+ expires_at Int?
+ token_type String?
+ scope String?
+ id_token String?
+ session_state String?
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ @@id([provider, providerAccountId])
+}
+
+model Session {
+ sessionToken String @unique
+ userId String
+ expires DateTime
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+
+model VerificationToken {
+ identifier String
+ token String
+ expires DateTime
+
+ @@id([identifier, token])
+}
+
+// Optional for WebAuthn support
+model Authenticator {
+ credentialID String @unique
+ userId String
+ providerAccountId String
+ credentialPublicKey String
+ counter Int
+ credentialDeviceType String
+ credentialBackedUp Boolean
+ transports String?
+
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ @@id([userId, credentialID])
+}
diff --git a/project.json b/project.json
index 0623223..48ea0be 100644
--- a/project.json
+++ b/project.json
@@ -2,5 +2,12 @@
"name": "verity",
"$schema": "./node_modules/nx/schemas/project-schema.json",
"tags": [],
- "targets": {}
+ "targets": {
+ "prisma:migrate:dev": {
+ "command": "npx prisma migrate dev"
+ },
+ "prisma:generate": {
+ "command": "npx prisma generate"
+ }
+ }
}
diff --git a/realm-export.json b/realm-export.json
new file mode 100644
index 0000000..47a6380
--- /dev/null
+++ b/realm-export.json
@@ -0,0 +1,31 @@
+{
+ "id": "verity",
+ "realm": "verity",
+ "enabled": true,
+ "clients": [
+ {
+ "clientId": "verity_client",
+ "secret": "veritysecret",
+ "enabled": true,
+ "protocol": "openid-connect",
+ "redirectUris": ["http://localhost:3000/*"]
+ }
+ ],
+ "users": [
+ {
+ "username": "verity",
+ "enabled": true,
+ "emailVerified": true,
+ "firstName": "Rootus",
+ "lastName": "Adminus",
+ "email": "verity@mail.com",
+ "credentials": [
+ {
+ "type": "password",
+ "value": "verity"
+ }
+ ],
+ "realmRoles": ["ADMIN"]
+ }
+ ]
+}
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 75007dc..669fee5 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -15,6 +15,8 @@
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {
+ "@verity/auth": ["libs/auth/src/index.ts"],
+ "@verity/auth/server": ["libs/auth/src/server.ts"],
"@verity/ui": ["libs/ui/src/index.ts"],
"@verity/ui/*": ["libs/ui/src/lib/*"],
"@verity/ui/server": ["libs/ui/src/server.ts"],