feat(auth): include subscription tier in token and session payload

- Adds subscription tier info to access/refresh tokens.
- Stores tier details in session Redis record.
- Returns tier data in login/register response.
- Uses default tier when user has none.
This commit is contained in:
Evandro Fonseca Junior committed 2025-11-07 21:03:19 -03:00
1 parent 7f42def478
commit d27526e026
20 files changed
+2133 -40

No files matched your search

+70 -6
View File
@@ -4,6 +4,7 @@
*/
import { prisma } from "../app";
import { getDefaultSubscriptionTier } from "./subscription-tiers";
import type { User } from "@prisma/client";
export interface CreateUserData {
@@ -21,6 +22,7 @@ export interface UpdateUserData {
last_name?: string;
phone?: string;
whatsapp_notifications?: boolean;
subscription_tier_id?: number | null;
}
/**
@@ -29,6 +31,7 @@ export interface UpdateUserData {
export async function createUser(
data: CreateUserData
): Promise<{ userId: number; username: string; email: string }> {
const defaultTier = await getDefaultSubscriptionTier();
const user = await prisma.user.create({
data: {
username: data.username,
@@ -38,6 +41,7 @@ export async function createUser(
last_name: data.last_name,
phone: data.phone || null,
cpf: data.cpf || null,
subscription_tier_id: defaultTier?.subscription_tier_id ?? undefined,
},
select: {
user_id: true,
@@ -56,10 +60,29 @@ export async function createUser(
/**
* Busca usuário por email (inclui password_hash para login)
*/
export async function getUserByEmail(email: string): Promise<User | null> {
return await prisma.user.findUnique({
type UserWithTier = User & {
subscription_tier?: {
subscription_tier_id: number;
name: string;
slug: string;
level: number;
} | null;
};
export async function getUserByEmail(email: string): Promise<UserWithTier | null> {
return (await prisma.user.findUnique({
where: { email },
});
include: {
subscription_tier: {
select: {
subscription_tier_id: true,
name: true,
slug: true,
level: true,
},
},
},
})) as UserWithTier | null;
}
/**
@@ -67,10 +90,20 @@ export async function getUserByEmail(email: string): Promise<User | null> {
*/
export async function getUserByUsername(
username: string
): Promise<User | null> {
return await prisma.user.findUnique({
): Promise<UserWithTier | null> {
return (await prisma.user.findUnique({
where: { username },
});
include: {
subscription_tier: {
select: {
subscription_tier_id: true,
name: true,
slug: true,
level: true,
},
},
},
})) as UserWithTier | null;
}
/**
@@ -92,6 +125,12 @@ type PublicUser = {
last_login: Date | null;
is_active: boolean;
is_verified: boolean;
subscription_tier?: {
subscription_tier_id: number;
name: string;
slug: string;
level: number;
} | null;
};
export async function getUserById(userId: number): Promise<PublicUser | null> {
@@ -113,6 +152,14 @@ export async function getUserById(userId: number): Promise<PublicUser | null> {
last_login: true,
is_active: true,
is_verified: true,
subscription_tier: {
select: {
subscription_tier_id: true,
name: true,
slug: true,
level: true,
},
},
},
}) as PublicUser | null;
}
@@ -144,6 +191,15 @@ export async function updateUser(
if (data.phone !== undefined) updateData.phone = data.phone || null;
if (data.whatsapp_notifications !== undefined)
updateData.whatsapp_notifications = data.whatsapp_notifications;
if (data.subscription_tier_id !== undefined) {
if (data.subscription_tier_id === null) {
updateData.subscription_tier = { disconnect: true };
} else {
updateData.subscription_tier = {
connect: { subscription_tier_id: data.subscription_tier_id },
};
}
}
const user = await prisma.user.update({
where: { user_id: userId },
@@ -164,6 +220,14 @@ export async function updateUser(
last_login: true,
is_active: true,
is_verified: true,
subscription_tier: {
select: {
subscription_tier_id: true,
name: true,
slug: true,
level: true,
},
},
},
});