Files
Nexus/apps/web/src/server/auth.ts
T
Hartmut ddec3a927a feat: timeline multi-select, demand popover, resource hover card, merged tooltips, dark mode fixes
Major timeline enhancements:
- Right-click drag multi-selection with floating action bar (batch delete/assign)
- DemandPopover for demand strip details (replaces broken "Loading" modal)
- ResourceHoverCard on name hover showing skills, rates, role, chapter
- Merged heatmap+vacation tooltips into unified TimelineTooltip component
- Fixed overbooking blink animation (date normalization, z-index ordering)
- Fixed dark mode sticky column bleed-through in project view
- System roles admin page, notification task management, performance review docs

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-18 23:43:51 +01:00

72 lines
1.8 KiB
TypeScript

import { prisma } from "@planarchy/db";
import NextAuth, { type NextAuthConfig } from "next-auth";
import Credentials from "next-auth/providers/credentials";
import { verify } from "@node-rs/argon2";
import { z } from "zod";
const LoginSchema = z.object({
email: z.string().email(),
password: z.string().min(1),
});
const authConfig = {
providers: [
Credentials({
name: "credentials",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
const parsed = LoginSchema.safeParse(credentials);
if (!parsed.success) return null;
const { email, password } = parsed.data;
const user = await prisma.user.findUnique({ where: { email } });
if (!user?.passwordHash) return null;
const isValid = await verify(user.passwordHash, password);
if (!isValid) return null;
// Track last login time
await prisma.user.update({
where: { id: user.id },
data: { lastLoginAt: new Date() },
});
return {
id: user.id,
email: user.email,
name: user.name,
role: user.systemRole,
};
},
}),
],
callbacks: {
async session({ session, token }) {
if (token.sub) {
session.user.id = token.sub;
}
if (token.role) {
(session.user as typeof session.user & { role: string }).role = token.role as string;
}
return session;
},
async jwt({ token, user }) {
if (user) {
token.role = (user as typeof user & { role: string }).role;
}
return token;
},
},
pages: {
signIn: "/auth/signin",
},
session: {
strategy: "jwt",
},
} satisfies NextAuthConfig;
export const { handlers, auth } = NextAuth(authConfig);