From cfd079fbf5e6493dd1e38b8f523a6b3b69d4a026 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Feb 2026 14:16:49 +0100 Subject: [PATCH] feat: add settings page for database, OpenRouter, score, theme, and display density configurations. --- src/app/(dashboard)/settings/page.tsx | 2 -- .../ai-copilot/business/analysis-engine.ts | 12 ++++++---- .../ai-copilot/models/ai-analysis.types.ts | 2 ++ .../grid/components/bulk-ai-analyzer.tsx | 2 ++ src/lib/auth.config.ts | 24 +++++++++++++++++++ src/lib/auth.ts | 22 ++--------------- src/middleware.ts | 5 +++- 7 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 src/lib/auth.config.ts diff --git a/src/app/(dashboard)/settings/page.tsx b/src/app/(dashboard)/settings/page.tsx index 01029f3..7756641 100644 --- a/src/app/(dashboard)/settings/page.tsx +++ b/src/app/(dashboard)/settings/page.tsx @@ -9,8 +9,6 @@ import { useDbSettingsStore } from "@/features/settings/store/use-db-settings-st import { testDatabaseConnection, saveDatabaseSettings, getSavedDatabaseConfig } from "@/features/settings/actions"; import { useEffect } from "react"; import { UserManagement } from "@/features/admin/components/user-management"; -import { auth } from "@/lib/auth"; -import { redirect } from "next/navigation"; interface OpenRouterModel { id: string; name: string; free: boolean; } diff --git a/src/features/ai-copilot/business/analysis-engine.ts b/src/features/ai-copilot/business/analysis-engine.ts index 340fa64..7cdffce 100644 --- a/src/features/ai-copilot/business/analysis-engine.ts +++ b/src/features/ai-copilot/business/analysis-engine.ts @@ -12,9 +12,9 @@ En analysant les données de ventes fournies, génère une recommandation de gam Critères de pondération et Règles Métier Strictes : 1. Normalisation Totale (Base 2 magasins) : TOUTES les statistiques fournies sont PONDÉRÉES par 2 si le produit n'est au catalogue que de 1 magasin. 2. Segmentation par Rayon (Univers) : Privilégie la comparaison "Intra-Rayon". Un produit doit être performant par rapport aux standards de son propre Rayon (Niveau 2). -3. Seuil "Permanent" (A) : Pour être A, un produit doit avoir un volume PONDÉRÉ significatif (ex: > 30-50 unités/an). -4. Seuil "Sortie" (Z) : Un produit avec moins de 10 unités pondérées par an et un CA faible est un candidat à la sortie (Z). -5. Équilibre : Un produit "A" doit justifier sa place par son flux OU sa rentabilité brute. +3. Score de Performance Global (0-10) : Un score > 7 est un indicateur fort pour "Permanent" (A). Un score < 3 est un indicateur fort pour "Sortie" (Z). +4. Régularité des Ventes (0-12 mois) : Un produit avec une vente régulière (> 8 mois/an) est un candidat idéal pour "Permanent" (A). Une régularité faible (< 3 mois) couplée à un volume total faible indique une "Sortie" (Z). +5. Équilibre : Un produit "A" doit justifier sa place par son flux, sa rentabilité brute OU son score global. Ta réponse doit être courte, directe et sans complaisance. Format impératif : "[Recommandation]: [Justification courte]"`; @@ -38,8 +38,10 @@ Benchmarks Rayon ("${p.libelleNiveau2}") : Rayon : ${p.libelleNiveau2 || "Non classé"} Gamme actuelle : ${p.codeGamme ?? "Non définie"} ${volumeInfo}${benchmarks} -Indicateurs Clés : -- Marge : ${p.tauxMarge.toFixed(1)}% +Indicateurs de Performance : +- Score Global App : ${p.score.toFixed(1)}/10 +- Régularité des ventes : ${p.regularityScore}/12 mois +- Marge brute : ${p.tauxMarge.toFixed(1)}% - Historique mensuel (Pondéré) : ${monthlySummary} Quelle est ta recommandation (A, C ou Z) et pourquoi ?`; diff --git a/src/features/ai-copilot/models/ai-analysis.types.ts b/src/features/ai-copilot/models/ai-analysis.types.ts index 6139a39..5e043b1 100644 --- a/src/features/ai-copilot/models/ai-analysis.types.ts +++ b/src/features/ai-copilot/models/ai-analysis.types.ts @@ -15,6 +15,8 @@ export interface ProductAnalysisInput { storeCount: number; sales12m: Record; codeGamme: string | null; + score: number; + regularityScore: number; } export interface AnalysisResult { diff --git a/src/features/grid/components/bulk-ai-analyzer.tsx b/src/features/grid/components/bulk-ai-analyzer.tsx index 1c4553b..99399a3 100644 --- a/src/features/grid/components/bulk-ai-analyzer.tsx +++ b/src/features/grid/components/bulk-ai-analyzer.tsx @@ -80,6 +80,8 @@ export function BulkAiAnalyzer() { Object.entries(r.sales12m || {}).map(([month, val]) => [month, val * weight]) ), codeGamme: r.codeGamme || null, + score: r.score || 0, + regularityScore: Object.values(r.sales12m || {}).filter(v => v > 0).length, }; }); diff --git a/src/lib/auth.config.ts b/src/lib/auth.config.ts new file mode 100644 index 0000000..35703da --- /dev/null +++ b/src/lib/auth.config.ts @@ -0,0 +1,24 @@ +import type { NextAuthConfig } from "next-auth"; + +export const authConfig = { + pages: { + signIn: "/login", + }, + callbacks: { + async jwt({ token, user }) { + if (user) { + token.role = (user as any).role; + token.id = user.id; + } + return token; + }, + async session({ session, token }) { + if (session.user) { + (session.user as any).role = token.role as string; + (session.user as any).id = token.id as string; + } + return session; + }, + }, + providers: [], // Les providers seront ajoutés dans auth.ts +} satisfies NextAuthConfig; diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 52345c7..a27d542 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -5,8 +5,10 @@ import { users } from "@/db/schema"; import { eq } from "drizzle-orm"; import { verifyPassword } from "@/features/auth/logic/auth-logic"; import { ensureAdminExists } from "@/features/auth/logic/seed-admin"; +import { authConfig } from "./auth.config"; export const { handlers, auth, signIn, signOut } = NextAuth({ + ...authConfig, providers: [ Credentials({ name: "Credentials", @@ -15,7 +17,6 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ password: { label: "Mot de passe", type: "password" } }, async authorize(credentials) { - // S'assure que le compte admin par défaut existe await ensureAdminExists(); if (!credentials?.username || !credentials?.password) return null; @@ -42,23 +43,4 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ } }) ], - callbacks: { - async jwt({ token, user }) { - if (user) { - token.role = (user as any).role; - token.id = user.id; - } - return token; - }, - async session({ session, token }) { - if (session.user) { - (session.user as any).role = token.role as string; - (session.user as any).id = token.id as string; - } - return session; - }, - }, - pages: { - signIn: "/login", - } }); diff --git a/src/middleware.ts b/src/middleware.ts index 8ba6e04..b637b75 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,6 +1,9 @@ -import { auth } from "@/lib/auth"; +import NextAuth from "next-auth"; +import { authConfig } from "@/lib/auth.config"; import { NextResponse } from "next/server"; +const { auth } = NextAuth(authConfig); + export default auth((req) => { const isLoggedIn = !!req.auth; const { nextUrl } = req;