From 8bb341ea27ff6fc6c3b8def89863b9c485ad77a6 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 2 Jun 2026 22:29:30 +0300 Subject: [PATCH] Default active organization on session create Returning members were sent to onboarding on every sign-in because the new session had no activeOrganizationId. Add a session.create `before` hook that defaults it to the user's first clinic membership, so sign-in lands straight in the app. Co-Authored-By: Claude Opus 4.8 --- backend/src/auth.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/backend/src/auth.ts b/backend/src/auth.ts index 0e1d0b4..aa11eaa 100644 --- a/backend/src/auth.ts +++ b/backend/src/auth.ts @@ -1,6 +1,7 @@ import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { organization } from "better-auth/plugins"; +import { eq } from "drizzle-orm"; import { db } from "./db/index.js"; import * as authSchema from "./db/schema/auth.js"; @@ -103,6 +104,20 @@ export const auth = betterAuth({ databaseHooks: { session: { create: { + before: async (session) => { + // Default the active organization to the user's first clinic so + // returning members skip onboarding on sign-in. + const rows = await db + .select({ organizationId: authSchema.member.organizationId }) + .from(authSchema.member) + .where(eq(authSchema.member.userId, session.userId)) + .limit(1); + const organizationId = rows[0]?.organizationId; + if (organizationId) { + return { data: { ...session, activeOrganizationId: organizationId } }; + } + return undefined; + }, after: async (session) => { // Lightweight audit trail; swap console for a real sink in prod. console.info(