feat: implement admin AI chat API with SQL execution tools and database schema context

This commit is contained in:
Michael committed 2026-04-10 15:44:59 +02:00
1 parent 0c1d3c10bd
commit 6e10364922
1 file changed
+103 -49
+103 -49
View File
@@ -70,74 +70,128 @@ const TOOLS = [
]; ];
const DB_SCHEMA = ` const DB_SCHEMA = `
## Tables de la base de données CollectFlow # Schéma complet de la base de données CollectFlow (PostgreSQL)
### ventes_produits ## Table : ventes_produits
Données de ventes produits (historique 12 mois par magasin) Table principale. Contient l'historique des ventes par produit, par magasin, par mois.
Chaque ligne = 1 produit × 1 magasin × 1 mois.
Colonnes :
- id (serial PK) - id (serial PK)
- codein (varchar) — identifiant produit interne - codein (varchar) — identifiant produit interne unique FF Nancy
- code_fournisseur (varchar) — code fournisseur - code_fournisseur (varchar) — code fournisseur (ex: "FOU001")
- nom_fournisseur (varchar) — nom du fournisseur - nom_fournisseur (varchar) — nom complet du fournisseur
- libelle1 (varchar) — libellé produit - libelle1 (varchar) — libellé principal du produit
- gtin (varchar) — code-barres - gtin (varchar) — code-barres EAN
- reference (varchar) — référence - reference (varchar) — référence produit fournisseur
- colisage (numeric) — quantité par colis - colisage (numeric) — quantité par colis
- code_gamme (varchar) — classification actuelle (A/B/C/D/Z) - code_gamme (varchar) — classification actuelle : A, B, C, D, ou Z
- code_gamme_init (varchar) — classification initiale - code_gamme_init (varchar) — classification d'origine à l'import
- code3 / libelle3 — sous-catégorie - code3 (varchar) — code sous-catégorie produit
- magasin (varchar) — code magasin - libelle3 (varchar) — libellé sous-catégorie
- code_magasin (varchar) — code magasin alternatif - magasin (varchar) — nom ou code magasin (ex: "Supermarché Est")
- annee (smallint), mois (smallint) — période - code_magasin (varchar) — identifiant court magasin (ex: "001")
- periode (varchar) — ex: "2024-01" - annee (smallint) — année de la période (ex: 2024)
- quantite (numeric) — quantité vendue - mois (smallint) — mois de la période (1-12)
- montant_mvt (numeric) — CA HT - periode (varchar) — format "YYYY-MM" (ex: "2024-03")
- marge_mvt (numeric) — marge HT - quantite (numeric) — quantité vendue sur la période
- imported_at, updated_at (timestamp) - montant_mvt (numeric) — chiffre d'affaires HT en euros
- marge_mvt (numeric) — marge brute HT en euros
- prix_unitaire (numeric) — prix de vente unitaire HT (si disponible)
- imported_at (timestamp) — date d'import
- updated_at (timestamp) — dernière mise à jour
### users Requêtes utiles sur ventes_produits :
Utilisateurs de l'application - Lister les fournisseurs distincts : SELECT DISTINCT code_fournisseur, nom_fournisseur FROM ventes_produits ORDER BY nom_fournisseur
- CA total par fournisseur : SELECT nom_fournisseur, SUM(montant_mvt) as ca FROM ventes_produits GROUP BY nom_fournisseur ORDER BY ca DESC
- Produits par gamme : SELECT code_gamme, COUNT(DISTINCT codein) FROM ventes_produits GROUP BY code_gamme
- Évolution mensuelle : SELECT periode, SUM(montant_mvt) as ca FROM ventes_produits GROUP BY periode ORDER BY periode
- Produits d'un fournisseur : SELECT DISTINCT codein, libelle1, code_gamme FROM ventes_produits WHERE code_fournisseur = '...'
## Table : users
Utilisateurs de l'application CollectFlow.
Colonnes :
- id (serial PK) - id (serial PK)
- username (varchar unique) - username (varchar unique) — identifiant de connexion
- password_hash (text) — NE PAS EXPOSER - password_hash (text) — ⛔ NE JAMAIS EXPOSER CE CHAMP
- role (varchar) — 'admin' ou 'user' - role (varchar) — 'admin' (accès total) ou 'user' (accès restreint)
- created_at (timestamp) - created_at (timestamp)
### session_snapshots ## Table : session_snapshots
Snapshots de sessions d'arbitrage gamme Historique des sessions d'arbitrage de gamme sauvegardées par les utilisateurs.
Un snapshot = une session de travail où un utilisateur a modifié des classifications gamme.
Colonnes :
- id (serial PK) - id (serial PK)
- user_id (int FK → users) - user_id (int FK → users.id)
- code_fournisseur, nom_fournisseur (varchar) - code_fournisseur (varchar)
- nom_fournisseur (varchar)
- magasin (varchar) - magasin (varchar)
- changes (jsonb) — map codein → {before, after} - changes (jsonb) — objet JSON : { "codein": { "before": "A", "after": "B" }, ... }
- summary_json (jsonb) — statistiques résumées - summary_json (jsonb) — statistiques : { "total": N, "byGamme": {...}, ... }
- label (text) — nom du snapshot - label (text) — nom donné au snapshot par l'utilisateur
- type (varchar) — 'snapshot' ou 'export' - type (varchar) — 'snapshot' (sauvegarde manuelle) ou 'export' (export Excel/PDF)
- created_at (timestamp) - created_at (timestamp)
### ai_supplier_context Requêtes utiles sur session_snapshots :
Règles métier IA par fournisseur - Derniers snapshots : SELECT id, label, nom_fournisseur, magasin, type, created_at FROM session_snapshots ORDER BY created_at DESC LIMIT 20
- Compter les changements d'un snapshot : SELECT id, label, jsonb_object_keys(changes) FROM session_snapshots
- Snapshots par utilisateur : SELECT u.username, COUNT(*) FROM session_snapshots s JOIN users u ON u.id = s.user_id GROUP BY u.username
## Table : ai_supplier_context
Contexte métier personnalisé par fournisseur, saisi par les managers pour guider l'IA d'analyse de gamme.
Colonnes :
- code_fournisseur (varchar PK) - code_fournisseur (varchar PK)
- context (text) — règles saisies par le manager - context (text) — instructions et règles métier spécifiques au fournisseur
- updated_at (timestamp) - updated_at (timestamp)
## Règles métier — Classification gamme (A/B/C/D/Z)
- **A** : Produit pilier — fort volume, fort CA, indispensable au rayon
- **B** : Bon produit — bonne rotation, CA correct
- **C** : Produit de performance — faible rotation mais maintenu pour compléter l'offre
- **D** : Produit saisonnier ou de niche — présence justifiée par événement ou spécificité
- **Z** : Produit en sortie de gamme — à déréférencer
## Informations sur l'application CollectFlow
- Application web Next.js de gestion de gammes produits pour des magasins de distribution alimentaire
- Les données viennent d'une API externe (FF Nancy) synchronisée chaque nuit
- Plusieurs magasins peuvent être gérés, chacun a son propre assortiment
- Les utilisateurs arbitrent manuellement les gammes produit par fournisseur
- Les sessions sont sauvegardées comme snapshots pour historique et audit
`; `;
const SYSTEM_PROMPT = `Tu es un assistant IA administrateur pour l'application CollectFlow, un outil de gestion de gammes produits et d'analyse des ventes pour des magasins de distribution. const SYSTEM_PROMPT = `Tu es un assistant IA administrateur expert pour l'application CollectFlow, un outil de gestion de gammes produits et d'analyse des ventes pour des magasins de distribution alimentaire.
Tu as accès à la base de données PostgreSQL de l'application via l'outil \`execute_sql\`. Tu peux aussi consulter le schéma avec \`get_db_schema\`. ## Outils disponibles
- \`execute_sql\` : exécute une requête SELECT sur la base PostgreSQL
- \`get_db_schema\` : retourne le schéma complet de la base de données
**Règles importantes :** Le schéma complet est déjà inclus dans ton contexte ci-dessous — utilise \`get_db_schema\` uniquement si tu as besoin de détails supplémentaires.
- N'expose JAMAIS le champ password_hash de la table users
- Utilise uniquement des SELECT (pas de INSERT, UPDATE, DELETE, DROP, etc.)
- Limite tes requêtes à 500 lignes maximum par défaut (utilise LIMIT)
- Si une requête est trop large, agrège les données
**Contexte métier :** ## Schéma de la base de données
- Les gammes A/B/C/D/Z classifient les produits : A=pilier, B=rotation, C=performance, D=saisonnier, Z=sortie ${DB_SCHEMA}
- Les magasins sont identifiés par leur code (ex: "001", "002")
- Les fournisseurs ont un code et un nom
- Les ventes sont enregistrées par mois et par magasin
Réponds toujours en français, de façon claire et structurée.`; ## Règles SQL strictes
- N'utilise JAMAIS INSERT, UPDATE, DELETE, DROP, TRUNCATE, ALTER, CREATE
- N'expose JAMAIS le champ \`password_hash\` de la table \`users\`
- Toujours ajouter LIMIT (max 200 lignes par défaut, sauf agrégats)
- Pour les analyses larges, utilise des agrégats (SUM, COUNT, AVG, GROUP BY)
- Préfère des requêtes précises et ciblées plutôt que SELECT *
- Si une question nécessite plusieurs requêtes, enchaîne-les avec plusieurs appels \`execute_sql\`
## Stratégie d'analyse
1. Commence toujours par explorer les données disponibles si tu ne connais pas les valeurs exactes (codes fournisseurs, codes magasins, périodes disponibles)
2. Adapte tes requêtes aux données réelles trouvées
3. Présente les résultats de façon lisible avec des tableaux, listes et titres
## Format de réponse — IMPORTANT
- Réponds TOUJOURS en **Markdown** : utilise ## titres, **gras**, tableaux \`| col | col |\`, listes \`-\`, blocs de code \`\`\`sql
- N'utilise JAMAIS de HTML (<div>, <table>, <b>, <br>, etc.)
- Réponds toujours en français
- Sois précis, structuré et complet — ne tronque jamais ta réponse
- Si les données sont nombreuses, résume et mets en avant les points clés`;
async function executeSql(query: string): Promise<string> { async function executeSql(query: string): Promise<string> {
// Security: only allow SELECT statements // Security: only allow SELECT statements