chore: seminarhof customer project

This commit is contained in:
e2e
2026-06-22 09:44:35 +02:00
commit c3035e16ec
161 changed files with 18517 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
import type { Kysely } from 'kysely'
import type { DB } from '../types/db.types.js'
/**
* Ensures a login-capable client user exists for a client org, idempotently.
*
* Finds or creates a `user` row (role `client`) keyed by lower-cased email,
* then ensures a `client_member` row links that user to the client as `organiser`.
*
* Reuse-by-email is intentional: one person who organises for several clients
* gets one login with multiple `client_member` rows.
* Returns the resolved `userId`.
*/
export async function provisionClientLogin(
kysely: Kysely<DB>,
{ clientId, email, name }: { clientId: string; email: string; name: string | null },
): Promise<string> {
const normalisedEmail = email.toLowerCase()
const existing = await kysely
.selectFrom('user')
.where('email', '=', normalisedEmail)
.select('id')
.executeTakeFirst()
const id = existing?.id ?? crypto.randomUUID()
if (!existing) {
const now = new Date().toISOString()
await kysely
.insertInto('user')
.values({
id,
email: normalisedEmail,
name: name ?? normalisedEmail,
emailVerified: 0,
createdAt: now,
updatedAt: now,
role: 'client',
locale: 'de',
} as any)
.execute()
}
await kysely
.insertInto('clientMember')
.values({ clientId, userId: id, role: 'organiser' })
.onConflict((oc) => oc.columns(['clientId', 'userId']).doNothing())
.execute()
return id
}