feat(admin-auth): add first-start onboarding flow and dev db reset command

This commit is contained in:
2026-02-10 18:14:47 +01:00
parent 411861419f
commit 7b665ae633
18 changed files with 485 additions and 152 deletions

View File

@@ -1,28 +1,106 @@
import { authRouteHandlers, ensureAuthBootstrap } from "@/lib/auth/server"
import {
authRouteHandlers,
canUserSelfRegister,
ensureSupportUserBootstrap,
hasOwnerUser,
promoteFirstRegisteredUserToOwner,
} from "@/lib/auth/server"
export const runtime = "nodejs"
type AuthPostResponse = {
user?: {
id?: string
role?: string
}
message?: string
}
function jsonResponse(payload: unknown, status: number): Response {
return Response.json(payload, { status })
}
async function handleSignUpPost(request: Request): Promise<Response> {
await ensureSupportUserBootstrap()
const hadOwnerBeforeSignUp = await hasOwnerUser()
const registrationEnabled = await canUserSelfRegister()
if (!registrationEnabled) {
return jsonResponse(
{
message: "Registration is currently disabled.",
},
403,
)
}
const response = await authRouteHandlers.POST(request)
if (!response.ok) {
return response
}
const payload = (await response
.clone()
.json()
.catch(() => null)) as AuthPostResponse | null
const userId = payload?.user?.id
if (!userId) {
return response
}
if (hadOwnerBeforeSignUp || !payload?.user) {
return response
}
const promoted = await promoteFirstRegisteredUserToOwner(userId)
if (!promoted) {
return jsonResponse(
{
message: "Initial owner registration window has just closed. Please sign in instead.",
},
409,
)
}
payload.user.role = "owner"
return new Response(JSON.stringify(payload), {
status: response.status,
headers: response.headers,
})
}
export async function GET(request: Request): Promise<Response> {
await ensureAuthBootstrap()
await ensureSupportUserBootstrap()
return authRouteHandlers.GET(request)
}
export async function POST(request: Request): Promise<Response> {
await ensureAuthBootstrap()
const pathname = new URL(request.url).pathname
if (pathname.endsWith("/sign-up/email")) {
return handleSignUpPost(request)
}
await ensureSupportUserBootstrap()
return authRouteHandlers.POST(request)
}
export async function PATCH(request: Request): Promise<Response> {
await ensureAuthBootstrap()
await ensureSupportUserBootstrap()
return authRouteHandlers.PATCH(request)
}
export async function PUT(request: Request): Promise<Response> {
await ensureAuthBootstrap()
await ensureSupportUserBootstrap()
return authRouteHandlers.PUT(request)
}
export async function DELETE(request: Request): Promise<Response> {
await ensureAuthBootstrap()
await ensureSupportUserBootstrap()
return authRouteHandlers.DELETE(request)
}