mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-21 14:08:08 +02:00
feat: add settings page for database, OpenRouter, score, theme, and display density configurations.
This commit is contained in:
1 parent
359d196c4d
commit
cfd079fbf5
7 files changed
+41
-28
No files matched your search
@@ -9,8 +9,6 @@ import { useDbSettingsStore } from "@/features/settings/store/use-db-settings-st
|
|||||||
import { testDatabaseConnection, saveDatabaseSettings, getSavedDatabaseConfig } from "@/features/settings/actions";
|
import { testDatabaseConnection, saveDatabaseSettings, getSavedDatabaseConfig } from "@/features/settings/actions";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { UserManagement } from "@/features/admin/components/user-management";
|
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; }
|
interface OpenRouterModel { id: string; name: string; free: boolean; }
|
||||||
|
|
||||||
|
|||||||
@@ -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 :
|
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.
|
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).
|
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).
|
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. 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).
|
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 OU sa rentabilité brute.
|
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.
|
Ta réponse doit être courte, directe et sans complaisance.
|
||||||
Format impératif : "[Recommandation]: [Justification courte]"`;
|
Format impératif : "[Recommandation]: [Justification courte]"`;
|
||||||
@@ -38,8 +38,10 @@ Benchmarks Rayon ("${p.libelleNiveau2}") :
|
|||||||
Rayon : ${p.libelleNiveau2 || "Non classé"}
|
Rayon : ${p.libelleNiveau2 || "Non classé"}
|
||||||
Gamme actuelle : ${p.codeGamme ?? "Non définie"}
|
Gamme actuelle : ${p.codeGamme ?? "Non définie"}
|
||||||
${volumeInfo}${benchmarks}
|
${volumeInfo}${benchmarks}
|
||||||
Indicateurs Clés :
|
Indicateurs de Performance :
|
||||||
- Marge : ${p.tauxMarge.toFixed(1)}%
|
- 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}
|
- Historique mensuel (Pondéré) : ${monthlySummary}
|
||||||
|
|
||||||
Quelle est ta recommandation (A, C ou Z) et pourquoi ?`;
|
Quelle est ta recommandation (A, C ou Z) et pourquoi ?`;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ export interface ProductAnalysisInput {
|
|||||||
storeCount: number;
|
storeCount: number;
|
||||||
sales12m: Record<string, number>;
|
sales12m: Record<string, number>;
|
||||||
codeGamme: string | null;
|
codeGamme: string | null;
|
||||||
|
score: number;
|
||||||
|
regularityScore: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AnalysisResult {
|
export interface AnalysisResult {
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ export function BulkAiAnalyzer() {
|
|||||||
Object.entries(r.sales12m || {}).map(([month, val]) => [month, val * weight])
|
Object.entries(r.sales12m || {}).map(([month, val]) => [month, val * weight])
|
||||||
),
|
),
|
||||||
codeGamme: r.codeGamme || null,
|
codeGamme: r.codeGamme || null,
|
||||||
|
score: r.score || 0,
|
||||||
|
regularityScore: Object.values(r.sales12m || {}).filter(v => v > 0).length,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
+2
-20
@@ -5,8 +5,10 @@ import { users } from "@/db/schema";
|
|||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { verifyPassword } from "@/features/auth/logic/auth-logic";
|
import { verifyPassword } from "@/features/auth/logic/auth-logic";
|
||||||
import { ensureAdminExists } from "@/features/auth/logic/seed-admin";
|
import { ensureAdminExists } from "@/features/auth/logic/seed-admin";
|
||||||
|
import { authConfig } from "./auth.config";
|
||||||
|
|
||||||
export const { handlers, auth, signIn, signOut } = NextAuth({
|
export const { handlers, auth, signIn, signOut } = NextAuth({
|
||||||
|
...authConfig,
|
||||||
providers: [
|
providers: [
|
||||||
Credentials({
|
Credentials({
|
||||||
name: "Credentials",
|
name: "Credentials",
|
||||||
@@ -15,7 +17,6 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
|
|||||||
password: { label: "Mot de passe", type: "password" }
|
password: { label: "Mot de passe", type: "password" }
|
||||||
},
|
},
|
||||||
async authorize(credentials) {
|
async authorize(credentials) {
|
||||||
// S'assure que le compte admin par défaut existe
|
|
||||||
await ensureAdminExists();
|
await ensureAdminExists();
|
||||||
|
|
||||||
if (!credentials?.username || !credentials?.password) return null;
|
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",
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
+4
-1
@@ -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";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
const { auth } = NextAuth(authConfig);
|
||||||
|
|
||||||
export default auth((req) => {
|
export default auth((req) => {
|
||||||
const isLoggedIn = !!req.auth;
|
const isLoggedIn = !!req.auth;
|
||||||
const { nextUrl } = req;
|
const { nextUrl } = req;
|
||||||
|
|||||||
Reference in new issue
Block a user