Base app architecture:

    Route groups for customer, staff and owner.
* Reusable design system with around 20 UI components.
* Complete Prisma schema.
* Authentication with email/password and Google.
* Role and permission model.
* Protected routes.
* Clean separation between features, services, components and shared utilities.
This commit is contained in:
Stefan Lazic committed 2026-08-02 17:47:23 +01:00
1 parent 468d163299
commit 090646fdfd
201 files changed
+31984

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
import { PrismaAdapter } from "@auth/prisma-adapter";
import bcrypt from "bcryptjs";
import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";
import Google from "next-auth/providers/google";
import { authConfig } from "@/auth.config";
import { prisma } from "@/lib/db/prisma";
import { signInSchema } from "@/features/auth/schemas";
export const { handlers, auth, signIn, signOut } = NextAuth({
...authConfig,
// `@auth/prisma-adapter`'s published types still import `PrismaClient`
// from the legacy `@prisma/client` path; Prisma 7's `prisma-client`
// generator no longer populates that path (see prisma/schema.prisma).
// The adapter only calls plain `prisma.<model>.<method>()` at runtime,
// so this is a type-only mismatch, not a behavioural one — narrowed
// here instead of silencing it project-wide.
adapter: PrismaAdapter(prisma as Parameters<typeof PrismaAdapter>[0]),
providers: [
Google,
Credentials({
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
authorize: async (raw) => {
const parsed = signInSchema.safeParse(raw);
if (!parsed.success) return null;
const { email, password } = parsed.data;
const user = await prisma.user.findUnique({ where: { email } });
if (!user?.passwordHash) return null;
const valid = await bcrypt.compare(password, user.passwordHash);
if (!valid) return null;
return { id: user.id, email: user.email, name: user.name, image: user.image };
},
}),
],
callbacks: {
async jwt({ token, user }) {
if (user?.id) {
token.id = user.id;
}
return token;
},
async session({ session, token }) {
if (session.user && typeof token.id === "string") {
session.user.id = token.id;
}
return session;
},
},
});