feat: Init project with frontend and rudimentary authentication

This commit is contained in:
2025-02-07 15:44:04 +01:00
commit 84e701131f
20 changed files with 7054 additions and 0 deletions

58
.gitignore vendored Normal file
View File

@@ -0,0 +1,58 @@
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist
# Node dependencies
node_modules
# Logs
logs
*.log
# Misc
.DS_Store
.fleet
sqlite.db
# Local env files
.env
.env.*
!.env.example
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### VS Code ###
.vscode/
### Kotlin ###
.kotlin

1
legalconsenthub/.npmrc Normal file
View File

@@ -0,0 +1 @@
shamefully-hoist=true

1
legalconsenthub/.nvmrc Normal file
View File

@@ -0,0 +1 @@
22

23
legalconsenthub/README.md Normal file
View File

@@ -0,0 +1,23 @@
# Legal Consent Hub
## Setup
1. Create `.env` file with these variables:
```
BETTER_AUTH_URL=http://localhost:3000
BETTER_AUTH_SECRET=YOUR_SECRET
```
2. Generate database schema: `npx @better-auth/cli generate`
3. Migrate schema: `npx @better-auth/cli migrate`
## Common errors
### better-auth/cli generate
```
Couldn't read your auth config. Error: Could not locate the bindings file. Tried:
```
**Solution:** I was able to resolve by running npx node-gyp rebuild in 'node_modules/better-sqlite3'
https://github.com/WiseLibs/better-sqlite3/issues/1320
https://github.com/WiseLibs/better-sqlite3/issues/146

6
legalconsenthub/app.vue Normal file
View File

@@ -0,0 +1,6 @@
<template>
<NuxtLoadingIndicator />
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>

View File

@@ -0,0 +1,7 @@
create table "better_auth_user" ("id" text not null primary key, "name" text not null, "email" text not null unique, "emailVerified" integer not null, "image" text, "createdAt" date not null, "updatedAt" date not null);
create table "better_auth_session" ("id" text not null primary key, "expiresAt" date not null, "token" text not null unique, "createdAt" date not null, "updatedAt" date not null, "ipAddress" text, "userAgent" text, "userId" text not null references "better_auth_user" ("id"));
create table "better_auth_account" ("id" text not null primary key, "accountId" text not null, "providerId" text not null, "userId" text not null references "better_auth_user" ("id"), "accessToken" text, "refreshToken" text, "idToken" text, "accessTokenExpiresAt" date, "refreshTokenExpiresAt" date, "scope" text, "password" text, "createdAt" date not null, "updatedAt" date not null);
create table "better_auth_verification" ("id" text not null primary key, "identifier" text not null, "value" text not null, "expiresAt" date not null, "createdAt" date, "updatedAt" date)

View File

@@ -0,0 +1,77 @@
<template>
<div class="form-container">
<h2>Login</h2>
<form @submit.prevent="handleLogin">
<div class="form-group">
<label for="email-login">Email:</label>
<input type="email" id="email-login" v-model="email" required />
</div>
<div class="form-group">
<label for="password-login">Passwort:</label>
<input type="password" id="password-login" v-model="password" required />
</div>
<button type="submit">Login</button>
</form>
</div>
</template>
<script setup>
import { ref } from 'vue';
const email = ref('');
const password = ref('');
const handleLogin = () => {
if (!email.value || !password.value) {
alert('Bitte alle Felder ausfüllen');
return;
}
authClient.signIn.email({
email: email.value,
password: password.value
}, {
onRequest: (ctx) => {
console.log("Sending login request", ctx)
},
onSuccess: (ctx) => {
console.log("Successfully logged in!")
},
onError: (ctx) => {
console.log(ctx.error.message);
},
});
};
</script>
<style scoped>
.form-container {
max-width: 300px;
margin: auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
background: #f9f9f9;
}
.form-group {
margin-bottom: 10px;
}
input {
width: 100%;
padding: 8px;
margin-top: 4px;
}
button {
width: 100%;
padding: 10px;
background: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
</style>

View File

@@ -0,0 +1,94 @@
<template>
<div class="form-container">
<h2>Registrieren</h2>
<form @submit.prevent="handleRegister">
<div class="form-group">
<label for="username">Benutzername:</label>
<input type="text" id="username" v-model="username" required />
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" v-model="email" required />
</div>
<div class="form-group">
<label for="password">Passwort:</label>
<input type="password" id="password" v-model="password" required />
</div>
<div class="form-group">
<label for="confirmPassword">Passwort bestätigen:</label>
<input type="password" id="confirmPassword" v-model="confirmPassword" required />
</div>
<button type="submit">Registrieren</button>
</form>
</div>
</template>
<script setup>
import { ref } from 'vue';
const username = ref('');
const email = ref('');
const password = ref('');
const confirmPassword = ref('');
const handleRegister = () => {
if (!username.value || !email.value || !password.value || !confirmPassword.value) {
alert('Bitte alle Felder ausfüllen');
return;
}
if (password.value !== confirmPassword.value) {
alert('Passwörter stimmen nicht überein');
return;
}
authClient.signUp.email({
email: email.value,
password: password.value,
name: username.value
}, {
onRequest: (ctx) => {
console.log("Sending register request", ctx)
},
onSuccess: (ctx) => {
console.log("Successfully registered!")
},
onError: (ctx) => {
console.log(ctx.error.message);
},
});
};
</script>
<style scoped>
.form-container {
max-width: 300px;
margin: auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
background: #f9f9f9;
}
.form-group {
margin-bottom: 10px;
}
input {
width: 100%;
padding: 8px;
margin-top: 4px;
}
button {
width: 100%;
padding: 10px;
background: #28a745;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background: #218838;
}
</style>

View File

@@ -0,0 +1,6 @@
<template>
<slot/>
</template>
<script setup lang="ts">
</script>

View File

@@ -0,0 +1,4 @@
export default defineNuxtConfig({
devtools: { enabled: true },
compatibilityDate: '2024-11-01'
})

View File

@@ -0,0 +1,23 @@
{
"name": "legalconsenthub",
"private": true,
"type": "module",
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare",
"fix:bettersqlite": "cd node_modules/better-sqlite3 && npx node-gyp rebuild && cd ../.."
},
"dependencies": {
"better-auth": "^1.1.16",
"better-sqlite3": "^11.8.1",
"nuxt": "^3.15.4",
"vue": "latest",
"vue-router": "latest"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.12"
}
}

View File

@@ -0,0 +1,16 @@
<template>
<div>
<pre>{{ session }}</pre>
<h1>{{ session.data ? "Du bist eingeloggt" : "Nicht eingeloggt"}}</h1>
<button v-if="session?.data" @click="authClient.signOut()">
Sign out
</button>
</div>
<Register />
<Login />
</template>
<script setup lang="ts">
const session = authClient.useSession()
</script>

6708
legalconsenthub/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,6 @@
import { auth } from "../../utils/auth";
import {H3Event} from "h3";
export default defineEventHandler((event: H3Event) => {
return auth.handler(toWebRequest(event));
});

View File

@@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}

View File

@@ -0,0 +1,11 @@
import { betterAuth } from "better-auth";
import Database from "better-sqlite3";
export const auth = betterAuth({
database: new Database("./sqlite.db"),
emailAndPassword: { enabled: true, autoSignIn: false },
user: { modelName: "better_auth_user" },
session: { modelName: "better_auth_session" },
account: { modelName: "better_auth_account" },
verification: { modelName: "better_auth_verification" },
});

View File

@@ -0,0 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}

View File

@@ -0,0 +1,5 @@
import { createAuthClient } from "better-auth/vue";
export const authClient = createAuthClient({
baseURL: "http://localhost:3000",
});