Careeroza
Data Access Layer Pattern
Auth + Data + DTO in One Place
The Next.js team recommends a Data Access Layer (DAL): every data function checks the user, fetches, and returns a DTO (only safe fields). Then even if a component forgets a check, sensitive data cannot leak.
// lib/dal/orders.ts
import 'server-only';
import { cache } from 'react';
import { auth } from '@/auth';
import { prisma } from '@/lib/prisma';
export const verifySession = cache(async () => {
const session = await auth();
if (!session?.user) throw new Error('Unauthorized');
return session.user;
});
export async function getMyOrder(orderId: string) {
const user = await verifySession();
const order = await prisma.order.findUnique({ where: { id: orderId }, include: { items: true } });
if (!order || (order.userId !== user.id && user.role !== 'admin')) return null;
return toOrderDto(order);
}DTO Mapping
Example
The database row has internal fields (cost price, fraud score, payment ids). The DTO exposes only what the page shows:
type OrderRow = {
id: string; userId: string; status: 'PAID' | 'SHIPPED';
totalPaise: number; costPaise: number; fraudScore: number;
razorpayPaymentId: string; createdAt: Date;
items: { name: string; qty: number; pricePaise: number }[];
};
type OrderDto = { id: string; status: string; total: string; placedOn: string; items: string[] };
const rupees = (paise: number) => '₹' + (paise / 100).toLocaleString('en-IN', { minimumFractionDigits: 2 });
function toOrderDto(o: OrderRow): OrderDto {
return {
id: o.id,
status: o.status,
total: rupees(o.totalPaise),
placedOn: o.createdAt.toISOString().slice(0, 10),
items: o.items.map((i) => i.qty + ' x ' + i.name + ' @ ' + rupees(i.pricePaise)),
};
}
const row: OrderRow = {
id: 'ORD-1001', userId: 'u1', status: 'SHIPPED', totalPaise: 1879800, costPaise: 1500000, fraudScore: 0.02,
razorpayPaymentId: 'pay_N1x2y3', createdAt: new Date('2026-01-15T10:00:00Z'),
items: [{ name: 'Redmi Note 14', qty: 1, pricePaise: 1799900 }, { name: 'Phone Case', qty: 1, pricePaise: 79900 }],
};
console.log(toOrderDto(row));Output
{
id: 'ORD-1001',
status: 'SHIPPED',
total: '₹18,798.00',
placedOn: '2026-01-15',
items: [ '1 x Redmi Note 14 @ ₹17,999.00', '1 x Phone Case @ ₹799.00' ]
}Tainting (Extra Safety)
React has an experimental taintUniqueValue / taintObjectReference API that throws if a marked object or value (like an API key or full user row) is ever passed to a Client Component. Enable it with experimental.taint in next.config.ts. The DAL + DTO pattern is the main defence; tainting is a safety net.