feat: add admin dashboard and core API routes with Docker configuration

This commit is contained in:
2026-10-29 19:46:37 +01:00
parent 2fdabe1dfd
commit 4f4856d9dc
89 changed files with 1984 additions and 1034 deletions

View File

@@ -1,17 +1,37 @@
import { NextRequest, NextResponse } from 'next/server';
import prisma from '../../../../../lib/prisma';
import { getAuthUser } from '@/lib/auth-utils';
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const authUser = await getAuthUser(request);
if (!authUser) {
return NextResponse.json({ error: 'Authentification requise' }, { status: 401 });
}
const { id } = await params;
if (!id) {
return NextResponse.json({ error: 'ID Business requis' }, { status: 400 });
}
// Verify ownership or ADMIN role
const business = await prisma.business.findUnique({
where: { id },
select: { id: true, ownerId: true }
});
if (!business) {
return NextResponse.json({ error: 'Entreprise non trouvée' }, { status: 404 });
}
if (business.ownerId !== authUser.id && authUser.role !== 'ADMIN') {
return NextResponse.json({ error: 'Accès non autorisé' }, { status: 403 });
}
// 1. Get total views from AnalyticsEvent
const totalViews = await prisma.analyticsEvent.count({
where: {

View File

@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from 'next/server';
import { isIP } from 'node:net';
import prisma from '@/lib/prisma';
import { getGeoInfo } from '@/lib/geo';
@@ -7,14 +8,15 @@ export async function POST(request: NextRequest) {
const body = await request.json();
const { type, path, label, value, metadata } = body;
if (!type || !path) {
if (!type || !path || typeof type !== 'string' || typeof path !== 'string') {
return NextResponse.json({ error: 'Type et Path requis' }, { status: 400 });
}
// Extract detailed info from headers
const userAgent = request.headers.get('user-agent') || '';
const referrer = request.headers.get('referer') || '';
const ip = request.headers.get('x-forwarded-for')?.split(',')[0] || '127.0.0.1';
const userAgent = (request.headers.get('user-agent') || '').slice(0, 500);
const referrer = (request.headers.get('referer') || '').slice(0, 500);
const rawForwardedIp = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || '127.0.0.1';
const ip = isIP(rawForwardedIp) !== 0 ? rawForwardedIp : '127.0.0.1';
// Basic User-Agent parsing
const isMobile = /mobile/i.test(userAgent);
@@ -33,22 +35,22 @@ export async function POST(request: NextRequest) {
else if (/iphone|ipad/i.test(userAgent)) os = 'iOS';
// Simple Country detection
const { country, city } = await getGeoInfo(ip, request.headers);
const { country } = await getGeoInfo(ip, request.headers);
const event = await prisma.analyticsEvent.create({
data: {
type,
path,
label: label || null,
value: value || null,
metadata: metadata || {},
type: type.slice(0, 100),
path: path.slice(0, 500),
label: typeof label === 'string' ? label.slice(0, 200) : null,
value: typeof value === 'number' ? value : null,
metadata: metadata && typeof metadata === 'object' ? metadata : {},
ip,
country,
browser,
os,
device,
referrer,
userId: metadata?.userId || null,
userId: typeof metadata?.userId === 'string' ? metadata.userId : null,
},
});