feat: mvp

This commit is contained in:
2025-11-26 21:48:06 +01:00
commit c1521af887
57 changed files with 8140 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';
import { env } from '$env/dynamic/private';
import { building } from '$app/environment';
if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set');
const client = building ? postgres() : postgres(env.DATABASE_URL);
export const db = drizzle(client, { schema, casing: 'snake_case' });

View File

@@ -0,0 +1,49 @@
import { relations, sql } from 'drizzle-orm';
import { integer, pgTable, real, text, uuid } from 'drizzle-orm/pg-core';
import { users } from './user';
export const aktis = pgTable('akti', {
id: uuid()
.default(sql`gen_random_uuid()`)
.primaryKey(),
title: text().notNull(),
summary: text().notNull(),
body: text().notNull(),
author: text('user_id')
.notNull()
.references(() => users.id),
version: integer('version').notNull().default(1)
});
export const ratings = pgTable('rating', {
id: uuid()
.default(sql`gen_random_uuid()`)
.primaryKey(),
aktiId: uuid()
.notNull()
.references(() => aktis.id, { onDelete: 'cascade' }),
userId: text()
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
rating: real().notNull(),
comment: text(),
aktiVersion: integer('akti_version').notNull()
});
export const aktisRelations = relations(aktis, ({ one }) => ({
author: one(users, {
fields: [aktis.author],
references: [users.id]
})
}));
export const ratingsRelations = relations(ratings, ({ one }) => ({
akti: one(aktis, {
fields: [ratings.aktiId],
references: [aktis.id]
}),
user: one(users, {
fields: [ratings.userId],
references: [users.id]
})
}));

View File

@@ -0,0 +1,76 @@
import { boolean, integer, pgTable, primaryKey, text, timestamp } from 'drizzle-orm/pg-core';
import type { AdapterAccountType } from '@auth/core/adapters';
import { users } from './user';
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]
})
}
]
);

View File

@@ -0,0 +1,3 @@
export * from './auth.ts';
export * from './user.ts';
export * from './akti.ts';

View File

@@ -0,0 +1,11 @@
import { pgTable, text, timestamp } from 'drizzle-orm/pg-core';
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')
});