Aperçu
BlunxAI transforme votre base de données en un collaborateur agentique : vos utilisateurs posent des questions en langage naturel et reçoivent des réponses, des graphiques, des tableaux et des insights automatiques — directement dans votre application.
Le principe
BlunxAI n'est pas une plateforme externe vers laquelle vous exporteriez vos données : c'est un SDK que vous embarquez dans votre infrastructure. Le SQL est exécuté localement, en lecture seule, et le système multi-agents est piloté par le serveur Blunx (le point d'entrée cloud /api/v1/*).
Architecture
Ce que vous devez retenir
- Lecture seule stricte : seuls des SELECT / WITH sont exécutés, à plusieurs niveaux de garde-fous (voir Sécurité).
- Backend-agnostique : le Web SDK n'attend qu'un contrat REST /api/blunx/*. Les packages Laravel et Node.js l'implémentent aujourd'hui ; les SDK Django, Go, Spring Boot suivront sans rien changer côté front.
- Un serveur, plusieurs clés : le SDK backend s'authentifie auprès du serveur Blunx avec une clé d'application (X-Blunx-Key) et une clé LLM (X-Blunx-LLM-Key).
- Votre BDD, vos règles : MySQL, MariaDB, PostgreSQL, SQLite et SQL Server sont pris en charge ; vous contrôlez les accès par rôle (RBAC).
Allez à la section Démarrage rapide : installation de bout en bout, avec des onglets par langage backend.
Démarrage rapide
Installez Blunx dans votre application en ~10 minutes. Choisissez votre backend (Laravel ou Node.js) : le schéma est identique, seul le SDK change. Chaque étape est minimale — les détails sont dans les guides.
Ce que vous allez faire : 1 · récupérer vos clés → 2 · installer le SDK → 3 · configurer le .env → 4 · connecter Blunx et exclure les tables sensibles → 5 · générer le schéma de votre base → 6 · intégrer l'interface (Web SDK) dans vos pages. Une fois en place, Blunx transforme les questions de vos utilisateurs en SQL en lecture seule sur votre base : il ne modifie jamais vos données.
Prérequis
| Prérequis | Détail |
|---|---|
| Application | Laravel 9-12 (PHP 8.1+) ou Node.js 18+ (Express, Fastify, Koa, NestJS, HTTP natif) |
| Base de données | MySQL, MariaDB, PostgreSQL, SQLite ou SQL Server (celle de votre app) |
| Compte Blunx | Une application créée sur le dashboard → votre clé d'application |
| Fournisseur LLM | Un compte avec clé API (OpenAI, Claude, Gemini, Ollama, Groq, DeepSeek…) |
1 · Récupérer vos clés
Regroupez ces 4 informations — vous en aurez besoin à l'étape 3 :
| À récupérer | Variable | Exemple |
|---|---|---|
| Clé d'application | BLUNX_API_KEY | blunx_app_live_xxxx |
| Clé LLM | BLUNX_LLM_API_KEY | sk-xxxxxxxxxxxx |
| Endpoint LLM | BLUNX_LLM_ENDPOINT | https://api.openai.com/v1 |
| Modèle | BLUNX_LLM_MODEL | gpt-4o |
Ollama fonctionne en local, sans compte : endpoint http://localhost:11434/v1, modèle llama3.1. Voir Fournisseurs LLM.
Installer le package
composer require blunx/ai
php artisan vendor:publish --tag=blunx-config
Provider en auto-discovery, aucune migration à publier.
Renseigner votre .env
Ajoutez vos 4 clés de l'étape 1 :
BLUNX_API_KEY=blunx_app_live_xxxxxxxxxxxx
BLUNX_LLM_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
BLUNX_LLM_ENDPOINT=https://api.openai.com/v1
BLUNX_LLM_MODEL=gpt-4o
Puis : php artisan config:clear. La connexion BDD par défaut de votre app est utilisée automatiquement.
Exclure les tables à ignorer
À l'init, Blunx scanne toutes les tables de votre base. Les tables techniques de Laravel (migrations, jobs, sessions, cache…) et les tables internes blunx_* sont déjà exclues par défaut. Ajoutez vos tables sensibles ou sans intérêt à la clé excluded_tables du fichier publié config/blunx.php (étape 2) :
// Déjà exclus par défaut : migrations, failed_jobs, cache, jobs, sessions,
// password_reset_tokens, personal_access_tokens… + toutes les tables blunx_*
'excluded_tables' => [
'admin_logs', 'notifications', 'settings', 'audit_trail', // ▶ vos tables
],
Puis videz le cache de configuration pour que blunx:init relise le fichier : php artisan config:clear.
Une table exclue n'est jamais scannée ni proposée à l'assistant. Une table interdite (forbidden_tables, fichier blunx_access.php) reste dans le schéma mais est bloquée selon le rôle. Détail dans Configuration.
Générer et verrouiller le schéma
php artisan blunx:init # scanne la base → storage/app/blunx_schema.json
php artisan blunx:setup # verrouille le schéma + crée les 8 tables
blunx:init appelle le serveur Blunx pour enrichir les descriptions : la clé LLM doit être valide.
Ajouter getUserRoleName() au modèle User
Pour appliquer vos règles d'accès (RBAC), Blunx appelle automatiquement Auth::user()?->getUserRoleName() à chaque requête. Vous devez donc ajouter une méthode nommée exactement getUserRoleName() à votre modèle User — ce n'est pas une alternative : c'est cette méthode que Blunx va réellement exécuter.
public function getUserRoleName(): ?string
{
return $this->role->name ?? null;
}
Elle doit retourner le libellé du rôle de l'utilisateur connecté (une chaîne, ex. 'admin', 'vendeur'), ou null s'il n'a pas de rôle. L'exemple ci-dessus suppose une relation role et une colonne name sur votre table roles. Si votre schéma diffère (colonne role directe, table roles avec libelle…), adaptez uniquement l'intérieur de la méthode — gardez le même nom et le même type de retour.
Intégrer le Web SDK
Collez ce snippet à l'endroit où vous voulez que l'assistant Blunx apparaisse. Deux cas possibles :
- Sur une page entière — créez une vue dédiée (ex. resources/views/blunx.blade.php) avec un conteneur plein écran (height:100vh) : c'est exactement l'exemple ci-dessous.
- Dans une page existante — ajoutez simplement le <div id="blunx"> (avec la hauteur de votre choix, ex. height:600px) à l'emplacement voulu, et la même balise <script> à la fin du <body>. Rien d'autre à changer.
<div id="blunx" style="height:100vh;"></div>
<script src="https://cdn.jsdelivr.net/npm/@blunx/web-sdk/dist/blunx-loader.min.js"
data-container="#blunx"
data-view="auto"></script>
data-container="#blunx" indique au SDK le div dans lequel se monter ; data-view="auto" laisse le SDK choisir la vue. L'API /api/blunx/* est servie par votre Laravel (même origine) : data-api-base-url reste vide. La session est envoyée automatiquement.
Installer le package
npm install blunx-ai
Le .env est chargé automatiquement (dotenv). Aucune migration à publier.
Renseigner votre .env
Ajoutez vos 4 clés de l'étape 1 plus votre base de données (ligne BLUNX_DB_URL). Cette ligne est lue par la CLI (étape 6) et par votre application (étape 4) :
BLUNX_API_KEY=blunx_app_live_xxxxxxxxxxxx
BLUNX_LLM_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
BLUNX_LLM_ENDPOINT=https://api.openai.com/v1
BLUNX_LLM_MODEL=gpt-4o
# Votre base (ADAPTEZ) — mysql://user:motdepasse@hote:port/base
BLUNX_DB_URL=mysql://root:secret@127.0.0.1:3306/ma_base
Autres bases supportées : postgres://…, sqlite:///chemin/vers/base.sqlite, sqlsrv://….
Initialiser Blunx dans votre serveur
Deux situations possibles — choisissez celle qui vous correspond :
Cas A — Vous avez déjà un serveur Express (le plus courant)
Pas besoin de créer de fichier ni de toucher à votre point d'entrée. Ajoutez simplement ces 3 blocs dans votre code serveur existant :
const { Blunx, blunxExpress } = require('blunx-ai'); // 1. import
// 2. Runtime Blunx — clés (BLUNX_API_KEY, BLUNX_LLM_*) et base (BLUNX_DB_URL)
// lues dans le .env. Les 2 hooks ci-dessous sont OBLIGATOIRES :
const blunx = Blunx.init({
getUserRole: (userId) => null, // TODO : retournez le libellé du rôle (ex. 'admin')
getUser: (userId) => null, // TODO : retournez { name, email } ou null
});
// 3. Montez le routeur Blunx APRÈS votre middleware d'authentification
// (celui-ci doit avoir rempli req.user avant)
app.use('/api/blunx', blunxExpress(blunx));
Implémentation typique à adapter (ici une table users) :
getUserRole: (userId) => users[userId]?.role ?? null,
getUser: (userId) => {
const u = users[userId];
return u ? { name: u.name, email: u.email } : null;
},
Cas B — Vous partez de zéro (aucun serveur existant)
Créez un fichier app.js complet (Express). Adaptez les 2 endroits marqués ADAPTEZ puis lancez node app.js : le fichier gère l'auth, monte Blunx et démarre le serveur.
const express = require('express'); // framework HTTP
const { Blunx, blunxExpress } = require('blunx-ai'); // SDK Blunx
const app = express();
app.use(express.json()); // lit le body JSON
// ── Utilisateurs de démo (ADAPTEZ : venez de votre table users) ──
const USERS = {
1: { name: 'Amir', email: 'amir@x.com', role: 'admin' },
2: { name: 'Sarah', email: 'sarah@x.com', role: 'vendeur' },
};
// ── Authentification (ADAPTEZ : Passport, JWT, session…) ──
// Blunx renvoie 401 si req.user est absent : votre middleware d'auth
// doit s'exécuter AVANT le routeur Blunx et remplir req.user.
app.use((req, res, next) => {
req.user = USERS[1]; // démo : l'utilisateur 1 est connecté
next();
});
// ── Runtime Blunx (clés + BDD lues dans le .env) ──
const blunx = Blunx.init({
getUserRole: (userId) => USERS[userId]?.role ?? null,
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
// ── Routeur Blunx monté APRÈS l'auth ──
app.use('/api/blunx', blunxExpress(blunx));
// ── Démarrage ──
app.listen(3000, () => console.log('Blunx prêt sur http://localhost:3000'));
Autres frameworks (Fastify, Koa, NestJS, HTTP natif) : fichiers complets dans Backend Node.js.
Option (avancé) — Gérer la configuration dans des fichiers TypeScript
Vous n'en avez pas besoin pour démarrer : le .env suffit. Cette option ne remplace pas l'intégration ci-dessus — elle change uniquement la source de la configuration : au lieu de tout passer à Blunx.init(), vous chargez 2 fichiers TypeScript versionnables (équivalent de vendor:publish). Les hooks et le montage du routeur restent identiques :
cp node_modules/blunx-ai/config/blunx.config.ts ./config/blunx.config.ts
cp node_modules/blunx-ai/config/blunx-access.config.ts ./config/blunx-access.config.ts
import blunxConfig from './config/blunx.config'; // ta copie éditée
import blunxAccessConfig from './config/blunx-access.config'; // tes règles RBAC
const blunx = Blunx.init({
...blunxConfig, // serverUrl, apiKey, llm, currency, locale…
access: blunxAccessConfig, // règles RBAC
// hooks identiques à ceux du Cas A / B ci-dessus (USERS) :
getUserRole: (userId) => USERS[userId]?.role ?? null,
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
Deux fichiers pour deux rôles : blunx.config.ts = configuration générale du runtime (clés, serveur, LLM, devise, langue) ; blunx-access.config.ts = vos règles d'accès RBAC. Détail dans Configuration.
Exclure les tables à ignorer
À l'init, Blunx scanne toutes les tables de votre base. Par défaut, seules les tables internes blunx_* sont ignorées. Ajoutez vos tables techniques (migrations, sessions…) et sensibles (logs, notifications, réglages…) à l'option excludedTables, en éditant le fichier config/blunx.config.ts chargé dans Blunx.init() :
export default {
// Tables internes blunx_* déjà ignorées par défaut.
// ▶ Ajoutez vos tables techniques / sensibles à ne pas scanner :
excludedTables: ['migrations', 'sessions', 'log_errors', 'admin_logs', 'notifications'],
};
Une table exclue n'est jamais scannée ni proposée à l'assistant. Une table interdite (forbidden_tables, fichier blunx-access.config.ts) reste dans le schéma mais est bloquée selon le rôle. Détail dans Configuration.
Générer et verrouiller le schéma
npx blunx-ai init # scanne la base → storage/app/blunx_schema.json
npx blunx-ai setup # verrouille le schéma + crée les 8 tables
Lancez depuis la racine de votre projet : la CLI lit le .env pour construire sa connexion.
Intégrer le Web SDK
<div id="blunx" style="height:100vh;"></div>
<script src="https://cdn.jsdelivr.net/npm/@blunx/web-sdk/dist/blunx-loader.min.js"
data-container="#blunx"
data-view="auto"></script>
L'API /api/blunx/* est servie par votre app Node (même origine) : data-api-base-url reste vide.
Vérifier que tout fonctionne
Connectez-vous avec un utilisateur de votre application et ouvrez la page. Posez une question (ex. « Quel est le nombre total de clients ? ») : le cockpit affiche le pipeline puis le résultat.
C'est presque toujours les clés BLUNX_API_KEY / BLUNX_LLM_API_KEY ou une configuration LLM incomplète. Voir Erreurs & dépannage.
Pour aller plus loin (BDD, jobs, auth, RBAC…) : Backend Laravel ou Backend Node.js.
Compatibilité
Les versions et environnements pris en charge, par brique de l'intégration. Les SDK backend : Laravel et Node.js sont disponibles, les autres suivent.
Bases de données
Blunx fonctionne avec la connexion de votre application et exécute le SQL en lecture seule. Les bases suivantes sont prises en charge par le SDK Laravel et par le serveur Blunx :
| Base de données | Valeur db_connection | Notes |
|---|---|---|
| MySQL | mysql | Défaut |
| MariaDB | mariadb | Traité comme MySQL côté SDK |
| PostgreSQL | pgsql | Scan limité au schéma BLUNX_PGSQL_SCHEMA (défaut public) |
| SQLite | sqlite | Fichier local |
| SQL Server | sqlsrv | Driver sqlsrv / sqlserver |
Backend (SDK serveur)
| Technologie | Statut | Notes |
|---|---|---|
| Laravel (package blunx/ai) | ● Disponible | Laravel 9 à 12 (testé sous 12), PHP 8.1+ |
| Node.js (package blunx-ai) | ● Disponible | Node.js 18+, npm, même contrat /api/blunx/* |
| Django (Python) | ● Bientôt | Même contrat /api/blunx/* |
| Go | ● Bientôt | Même contrat /api/blunx/* |
| Spring Boot (Java) | ● Bientôt | Même contrat /api/blunx/* |
Front-end (Web SDK @blunx/web-sdk)
| Technologie | Méthode | Contrainte |
|---|---|---|
| HTML pur / PHP / Laravel Blade | <script> + loader (auto-update) | Aucune |
| React (Vite, CRA, Next.js) | npm install + init()/destroy() | Next.js : côté client uniquement ('use client' / dynamic(…, {ssr:false})) |
| Vue 3 (Vite, Nuxt) | npm install + init()/destroy() | Appeler init() dans onMounted |
| Angular | npm install + init()/destroy() | Appeler init() dans ngAfterViewInit |
| Svelte / SvelteKit | npm install + init()/destroy() | Chargement côté client uniquement |
| Widget isolé (iframe) | Page hôte qui embarque le SDK | Isolation maximale recommandée |
Fournisseurs LLM
Le driver openai est un adaptateur compatible OpenAI : il fonctionne avec la quasi-totalité des fournisseurs propriétaires ET open-source. Voir Fournisseurs LLM pour le détail.
| Driver | Fournisseurs |
|---|---|
| openai | OpenAI, Azure OpenAI, Ollama (local), Groq, DeepSeek, Mistral, Together, Fireworks, OpenRouter, vLLM, LM Studio, llama.cpp… |
| anthropic | Anthropic Claude (format natif /v1/messages) |
| gemini | Google Gemini (format natif generateContent) |
Navigateurs & environnements
| Élément | Prise en charge |
|---|---|
| Navigateurs | Chrome, Edge, Firefox, Safari (ES2019+, pas d'IE) |
| Bundlers | Vite, webpack, esbuild, Rollup (module ESM) |
| SSR | Non supporté nativement — à exécuter côté client uniquement |
| CDN | jsDelivr (loader + bundle), unpkg |
Backend Laravel
Le package blunx/ai sert le contrat /api/blunx/* attendu par le Web SDK, exécute le SQL en lecture seule sur votre base et proxie vers le serveur Blunx. Prérequis : Laravel 9 à 12 (testé sous 12), PHP 8.1+.
Installation
composer require blunx/ai
php artisan vendor:publish --tag=blunx-config
- Provider en auto-discovery — aucune déclaration manuelle.
- Aucune migration à publier : les 8 tables Blunx sont créées par blunx:setup.
Configuration
Deux fichiers publiés dans config/ : blunx.php (lu depuis vos variables BLUNX_*) et blunx_access.php (règles RBAC). La référence complète des variables est dans Configuration.
Le package appelle Auth::user()?->getUserRoleName() à chaque requête pour résoudre les règles d'accès. Cette méthode doit donc exister avec ce nom exact sur votre modèle User et retourner le libellé du rôle de l'utilisateur (une chaîne, ou null s'il n'a pas de rôle). L'exemple ci-dessous suppose une relation role avec une colonne name — si votre schéma diffère, adaptez l'intérieur de la méthode mais gardez le nom et le type de retour :
public function getUserRoleName(): ?string
{
return $this->role->name ?? null;
}
Commandes artisan
| Commande | Rôle |
|---|---|
| blunx:init | Scanne la base et génère storage/app/blunx_schema.json (enrichi via le serveur Blunx). |
| blunx:edit | Édition manuelle des descriptions ou ré-indexation après évolution de la base. |
| blunx:setup | Verrouille le schéma et crée les 8 tables Blunx (idempotent). |
| blunx:feedback | Révise les retours utilisateurs non résolus. |
| blunx:run-insights | Exécute immédiatement les insights « dus » (next_run_at dépassé), avec retry — équivalent du scheduler horaire déclenché manuellement. En cas d'échec après les retries, le job re-tente dans 30 min. |
Workflow : blunx:init → (optionnel) blunx:edit → blunx:setup. Relancez blunx:edit après chaque évolution de votre base.
Tables créées
Toutes ont un id auto-incrémenté + un uuid unique (routes liées par uuid) :
| Table | Rôle |
|---|---|
| blunx_conversations | Conversations de chat |
| blunx_messages | Messages (user|assistant) |
| blunx_feedbacks | Retours utilisateurs |
| blunx_dashboards | Dashboards |
| blunx_dashboard_widgets | Widgets (chart|table) + reference_queries |
| blunx_insights | Insights + report_pdf |
| blunx_widget_insight_settings | Réglages d'insights par widget |
| blunx_cache | Cache (dont schema_id 48 h) |
Authentification & routes
Toutes les routes /api/blunx/* sont dans le groupe de middleware blunx = session + auth (utilisateur connecté exigé, sans CSRF) + throttle:60,1. Rien à configurer : une requête non authentifiée est bloquée par le framework (401/redirection).
La vue email référence route('blunx.dashboard', …). Cette route n'est pas définie par le package : définissez-la dans votre application.
File d'attente & insights
- GenerateWidgetInsightJob : ShouldQueue, tries=5, timeout=200 — exécute le widget, génère le rapport PDF et l'email.
- BlunxInsightMail : email coloré selon la sévérité, PDF en pièce jointe.
- Planification : toutes les heures pour les réglages « dus » ; un nouveau réglage est exécuté immédiatement.
- Échec après retries (ex. appel serveur en erreur) : le job n'avance pas vers le prochain créneau — il re-tente dans 30 min (next_run_at = maintenant + 30 min, last_run_at inchangé tant que le job n'a pas abouti).
- En local : php artisan queue:work --once (ou QUEUE_CONNECTION=sync en dev).
Le guide d'intégration pas à pas est dans Démarrage rapide. La référence des endpoints dans Contrat API, les erreurs dans Erreurs & dépannage.
Backend Node.js
Le package blunx-ai sert le contrat /api/blunx/* attendu par le Web SDK, exécute le SQL en lecture seule sur votre base et proxie vers le serveur Blunx. Prérequis : Node.js 18+, framework agnostique (Express, Fastify, Koa, NestJS ou HTTP natif).
Installation
npm install blunx-ai
- Le .env est chargé automatiquement (dotenv) — aucune publication de config obligatoire.
- Aucune migration à publier : les 8 tables Blunx sont créées par blunx-ai setup.
Initialisation
Créez le runtime Blunx une seule fois avec vos hooks d'authentification. La priorité de configuration : option de Blunx.init() > variable BLUNX_* > défaut (voir Configuration).
La connexion à votre base se fournit de 3 façons (du plus simple au plus intégré) :
| Méthode | Comment | Quand l'utiliser |
|---|---|---|
| BLUNX_DB_URL dans le .env (recommandé) | Une URL de connexion, lue par la CLI et le runtime | La majorité des cas — une seule config pour tout. |
| database: { client, connection } | Config de connexion passée à Blunx.init() | Quand la CLI n'est pas utilisée (runtime seul). |
| knex: instanceKnex | Votre instance knex existante | Votre app utilise déjà knex — on la réutilise. |
const { Blunx } = require('blunx-ai');
// Clés (BLUNX_API_KEY, BLUNX_LLM_*) et base (BLUNX_DB_URL) lues dans le .env.
// Exemple de résolution des utilisateurs (ADAPTEZ : venez de votre base) :
const USERS = {
1: { name: 'Amir', email: 'amir@x.com', role: 'admin' },
2: { name: 'Sarah', email: 'sarah@x.com', role: 'vendeur' },
};
const blunx = Blunx.init({
// Résout le rôle de l'utilisateur (RBAC) — équivaut getUserRoleName() de Laravel
getUserRole: (userId) => USERS[userId]?.role ?? null,
// Résout {name, email} pour /api/blunx/user — équivaut Auth::user() de Laravel
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
Option (avancé) — publier et charger les fichiers de config
Vous n'en avez pas besoin pour démarrer : le .env suffit. Cette option ne remplace pas l'initialisation ci-dessus — elle change seulement la source de la configuration. Utilisez-la si vous voulez versionner vos réglages et vos règles RBAC dans des fichiers TypeScript plutôt que dans le .env. Copiez les 2 templates (aucune dépendance), éditez-les, puis chargez-les dans Blunx.init() :
cp node_modules/blunx-ai/config/blunx.config.ts ./config/blunx.config.ts
cp node_modules/blunx-ai/config/blunx-access.config.ts ./config/blunx-access.config.ts
import blunxConfig from './config/blunx.config'; // ta copie éditée
import blunxAccessConfig from './config/blunx-access.config'; // tes règles RBAC
const blunx = Blunx.init({
...blunxConfig, // serverUrl, apiKey, llm, currency, locale…
access: blunxAccessConfig, // règles RBAC
// hooks identiques à ci-dessus (USERS) :
getUserRole: (userId) => USERS[userId]?.role ?? null,
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
La base se passe par BLUNX_DB_URL (.env) ou l'option database. Détail des règles RBAC dans Configuration.
Commandes (CLI blunx-ai)
| Commande | Rôle |
|---|---|
| npx blunx-ai init | Scanne la base et génère storage/app/blunx_schema.json (enrichi via le serveur Blunx). |
| npx blunx-ai edit | Édition manuelle des descriptions ou ré-indexation après évolution de la base. |
| npx blunx-ai setup | Verrouille le schéma et crée les 8 tables Blunx (idempotent). |
| npx blunx-ai feedback | Révise les retours utilisateurs non résolus. |
| npx blunx-ai run-insights | Exécute maintenant les insights « dus » (équivalent du scheduler horaire). En cas d'échec après les retries, le job re-tente dans 30 min. |
Workflow : blunx-ai init → (optionnel) blunx-ai edit → blunx-ai setup. La CLI construit sa propre connexion depuis le .env (BLUNX_DB_URL ou BLUNX_DB_*) — lancez-la depuis la racine de votre projet.
Tables créées
Identiques au package Laravel : blunx_conversations, blunx_messages, blunx_feedbacks, blunx_dashboards, blunx_dashboard_widgets, blunx_insights, blunx_widget_insight_settings, blunx_cache (toutes avec id + uuid unique).
Authentification & routes
Le package protège lui-même les routes : sans utilisateur authentifié (req.user / ctx.state.user absent), il renvoie 401 {"message":"Unauthenticated."} — équivalent du middleware auth du groupe blunx de Laravel. Aucun garde requireAuth à ajouter.
const express = require('express');
const { Blunx, blunxExpress } = require('blunx-ai');
const app = express();
app.use(express.json());
// Utilisateurs de démo (ADAPTEZ : venez de votre base)
const USERS = {
1: { name: 'Amir', email: 'amir@x.com', role: 'admin' },
2: { name: 'Sarah', email: 'sarah@x.com', role: 'vendeur' },
};
// 1. Authentification : votre middleware d'auth (Passport, JWT, session…)
// remplit req.user. Exemple de démo :
app.use((req, res, next) => {
req.user = USERS[1];
next();
});
const blunx = Blunx.init({
getUserRole: (userId) => USERS[userId]?.role ?? null,
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
// 2. Blunx monté APRÈS : il vérifie req.user et renvoie 401 s'il est absent
app.use('/api/blunx', blunxExpress(blunx));
app.listen(3000);
Blunx lit req.user.id (filtrage user_id), req.user.name/email (endpoint /user) et optionnellement req.user.getUserRoleName() (sinon votre hook getUserRole est appelé). Autres adaptateurs : blunxFastify, blunxKoa, createBlunxNestController, blunxNodeHttp.
Laravel applique throttle:60,1. En Node, ajoutez votre rate limiter sur le routeur Blunx (ex. express-rate-limit). Ne compressez pas le flux /stream (SSE).
Planification des insights
- Scheduler (node-cron) : toutes les heures, trouve les réglages « dus » et exécute GenerateWidgetInsightJob. Activé par défaut (enableScheduler: true), désactivable via Blunx.init({ enableScheduler: false }).
- npx blunx-ai run-insights : exécution manuelle immédiate.
- Échec après retries (ex. appel serveur en erreur) : le job n'avance pas vers le prochain créneau — il re-tente dans 30 min (next_run_at = maintenant + 30 min, last_run_at inchangé tant que le job n'a pas abouti).
- sendInsightMail (nodemailer) : email coloré selon la sévérité, PDF en pièce jointe (généré par InsightPdfGenerator — rendu 100 % JS, aucun navigateur).
En Laravel c'est la route blunx.dashboard ; en Node, fournissez le hook dashboardUrl: (uuid) => '…' à Blunx.init(). Pour le PDF, aucun navigateur ni chemin à configurer : rendu HTML→PDF via Puppeteer (Chromium embarqué, pas de Chrome installé sur la machine), comme dompdf côté PHP.
Exemples complets par framework
Chaque exemple est un fichier complet et copiable : utilisateurs de démo, authentification, runtime et démarrage. Remplacez les blocs marqués ADAPTEZ (base, auth, rôles) par vos vraies données. Clés + BDD dans le .env.
const express = require('express'); // framework HTTP
const { Blunx, blunxExpress } = require('blunx-ai'); // SDK Blunx
const app = express();
app.use(express.json()); // lit le body JSON
// ── Utilisateurs de démo (ADAPTEZ : venez de votre table users) ──
const USERS = {
1: { name: 'Amir', email: 'amir@x.com', role: 'admin' },
2: { name: 'Sarah', email: 'sarah@x.com', role: 'vendeur' },
};
// ── Authentification (ADAPTEZ : Passport, JWT, session…) ──
app.use((req, res, next) => {
req.user = USERS[1]; // démo : l'utilisateur 1 est connecté
next();
});
// ── Runtime Blunx (clés + BDD depuis le .env) ──
const blunx = Blunx.init({
getUserRole: (userId) => USERS[userId]?.role ?? null,
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
// ── Routeur Blunx monté APRÈS l'auth ──
app.use('/api/blunx', blunxExpress(blunx));
app.listen(3000, () => console.log('Blunx prêt sur http://localhost:3000'));
const fastify = require('fastify');
const { Blunx, blunxFastify } = require('blunx-ai');
const app = fastify();
// Utilisateurs de démo (ADAPTEZ)
const USERS = {
1: { name: 'Amir', email: 'amir@x.com', role: 'admin' },
2: { name: 'Sarah', email: 'sarah@x.com', role: 'vendeur' },
};
// Authentification (ADAPTEZ) : remplit req.user avant le routeur Blunx
app.addHook('onRequest', (req, reply, done) => {
req.user = USERS[1];
done();
});
// Runtime Blunx (clés + BDD depuis le .env)
const blunx = Blunx.init({
getUserRole: (userId) => USERS[userId]?.role ?? null,
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
// Montage du routeur Blunx
blunxFastify(app, blunx);
app.listen({ port: 3000 }).then(() => console.log('Blunx prêt sur http://localhost:3000'));
const Koa = require('koa');
const bodyParser = require('koa-bodyparser'); // requis : lit le body JSON
const { Blunx, blunxKoa } = require('blunx-ai');
const app = new Koa();
app.use(bodyParser());
// Utilisateurs de démo (ADAPTEZ)
const USERS = {
1: { name: 'Amir', email: 'amir@x.com', role: 'admin' },
2: { name: 'Sarah', email: 'sarah@x.com', role: 'vendeur' },
};
// Authentification (ADAPTEZ) : remplit ctx.state.user avant le routeur Blunx
app.use(async (ctx, next) => {
ctx.state.user = USERS[1];
await next();
});
// Runtime Blunx (clés + BDD depuis le .env)
const blunx = Blunx.init({
getUserRole: (userId) => USERS[userId]?.role ?? null,
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
// Montage du routeur Blunx
app.use(blunxKoa(blunx));
app.listen(3000, () => console.log('Blunx prêt sur http://localhost:3000'));
import { Module } from '@nestjs/common';
import { Blunx, createBlunxNestController } from 'blunx-ai';
// Utilisateurs de démo (ADAPTEZ)
const USERS: Record<number, any> = {
1: { name: 'Amir', email: 'amir@x.com', role: 'admin' },
2: { name: 'Sarah', email: 'sarah@x.com', role: 'vendeur' },
};
// Runtime Blunx (clés + BDD depuis le .env)
const blunx = Blunx.init({
getUserRole: (userId: any) => USERS[userId]?.role ?? null,
getUser: (userId: any) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
// Contrôleur Blunx (votre guard d'auth Nest doit remplir req.user — ADAPTEZ)
const BlunxController = createBlunxNestController(blunx);
@Module({ controllers: [BlunxController] })
export class BlunxModule {}
const http = require('http');
const { Blunx, blunxNodeHttp } = require('blunx-ai');
// Utilisateurs de démo (ADAPTEZ)
const USERS = {
1: { name: 'Amir', email: 'amir@x.com', role: 'admin' },
2: { name: 'Sarah', email: 'sarah@x.com', role: 'vendeur' },
};
// Runtime Blunx (clés + BDD depuis le .env)
const blunx = Blunx.init({
getUserRole: (userId) => USERS[userId]?.role ?? null,
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
http.createServer((req, res) => {
// Authentification (ADAPTEZ) : remplit req.user avant le routeur Blunx
req.user = USERS[1];
if (blunxNodeHttp(blunx, req, res)) return; // requête gérée par Blunx
res.writeHead(404).end();
}).listen(3000, () => console.log('Blunx prêt sur http://localhost:3000'));
Le guide d'intégration pas à pas est dans Démarrage rapide. La référence des endpoints dans Contrat API, les erreurs dans Erreurs & dépannage.
Web SDK
Le Web SDK (@blunx/web-sdk) est une application front autonome et embarquable : cockpit de chat + canvas, dashboards et insights. Il se monte dans un simple conteneur DOM. L'intégration est identique quel que soit votre backend (Laravel, Node.js…).
Formats de distribution
| Fichier | Format | Usage |
|---|---|---|
| dist/blunx-loader.min.js | IIFE | <script> simple, auto-update (toujours la dernière version) |
| dist/blunx.min.js | IIFE | <script> direct → window.Blunx |
| dist/blunx.esm.js | ESM | npm install @blunx/web-sdk → import { init } |
La langue est récupérée depuis /api/blunx/user (champ locale). Ne passez pas locale à l'initialisation : la valeur serveur fait foi.
Intégration par framework
Le SDK se monte dans un simple <div>. Deux intégrations possibles : sur une page entière (conteneur plein écran, ex. height:100vh) ou dans une page existante (placez le div à l'emplacement voulu, avec la hauteur de votre choix, et la balise <script> à la fin du <body>). Dans les deux cas, le snippet est le même — seul change le conteneur.
Loader (recommandé, mise à jour automatique) :
<div id="blunx" style="height:100vh;"></div>
<script src="https://cdn.jsdelivr.net/npm/@blunx/web-sdk/dist/blunx-loader.min.js"
data-container="#blunx"
data-view="auto"></script>
Bundle direct (version épinglée) :
<div id="blunx" style="height:100vh;"></div>
<script src="https://cdn.jsdelivr.net/npm/@blunx/web-sdk/dist/blunx.min.js"></script>
<script>
Blunx.init({ container: '#blunx', view: 'auto' })
.then(function (info) { console.log('[Blunx] prêt', info); })
.catch(function (err) { console.error('[Blunx] échec', err); });
</script>
L'API étant servie par votre backend (même origine), apiBaseUrl reste vide. Le cookie de session est envoyé automatiquement.
npm install @blunx/web-sdk
import { useEffect } from 'react';
import { init, destroy, navigate } from '@blunx/web-sdk';
export default function App() {
useEffect(() => {
let mounted = true;
init({
container: '#blunx',
apiBaseUrl: '', // cross-origin — vide en même origine
view: 'auto',
onReady: (info) => console.log('[React] Blunx prêt', info),
onError: (err) => console.error('[React] Blunx erreur', err),
})
.then((info) => { if (mounted) console.log('[React] monté', info); })
.catch((err) => console.error('[React] init échouée', err));
return () => { mounted = false; destroy(); }; // démontage (StrictMode-safe)
}, []);
return (
<div className="host">
<header className="host-top">
<strong>React hôte</strong>
<span>SDK monté dans <code>#blunx</code></span>
</header>
<div id="blunx" className="blunx-zone" />
</div>
);
}
Le SDK touche window/document à l'évaluation : côté client uniquement. En App Router, on l'importe donc dynamiquement dans un useEffect (composant 'use client').
'use client';
import { useEffect, useRef } from 'react';
export default function Home() {
const apiRef = useRef(null);
useEffect(() => {
let mounted = true;
import('@blunx/web-sdk')
.then(({ init, destroy, navigate }) => {
apiRef.current = { destroy, navigate };
return init({
container: '#blunx',
apiBaseUrl: '', // cross-origin — vide en même origine
view: 'auto',
onReady: (info) => console.log('[Next] Blunx prêt', info),
onError: (err) => console.error('[Next] Blunx erreur', err),
});
})
.then((info) => { if (mounted) console.log('[Next] monté', info); })
.catch((err) => console.error('[Next] init échouée', err));
return () => { mounted = false; apiRef.current?.destroy?.(); };
}, []);
return (
<main className="host">
<header className="host-top">
<strong>Next.js hôte</strong>
<span>SDK importé dynamiquement (SSR-safe)</span>
</header>
<div id="blunx" className="blunx-zone" />
</main>
);
}
npm install @blunx/web-sdk
<script setup>
import { onMounted, onUnmounted } from 'vue';
import { init, destroy, navigate } from '@blunx/web-sdk';
onMounted(async () => {
try {
const info = await init({
container: '#blunx',
apiBaseUrl: '', // cross-origin — vide en même origine
view: 'auto',
onReady: (i) => console.log('[Vue] Blunx prêt', i),
onError: (e) => console.error('[Vue] Blunx erreur', e),
});
console.log('[Vue] monté', info);
} catch (e) {
console.error('[Vue] init échouée', e);
}
});
onUnmounted(() => {
destroy(); // démonte le SDK quand le composant est retiré
});
</script>
<template>
<div class="host">
<header class="host-top">
<strong>Vue 3 hôte</strong>
<span>SDK monté dans <code>#blunx</code></span>
</header>
<div id="blunx" class="blunx-zone" />
</div>
</template>
import { Component, OnInit, OnDestroy } from '@angular/core';
import { init, destroy, navigate } from '@blunx/web-sdk';
@Component({
selector: 'app-root',
standalone: true,
template: `
<div class="host">
<header class="host-top">
<strong>Angular hôte</strong>
<span>SDK monté dans <code>#blunx</code></span>
</header>
<div id="blunx" class="blunx-zone"></div>
</div>
`,
})
export class AppComponent implements OnInit, OnDestroy {
async ngOnInit(): Promise<void> {
try {
const info = await init({
container: '#blunx',
apiBaseUrl: '', // cross-origin — vide en même origine
view: 'auto',
onReady: (i) => console.log('[Angular] Blunx prêt', i),
onError: (e) => console.error('[Angular] Blunx erreur', e),
});
console.log('[Angular] monté', info);
} catch (e) {
console.error('[Angular] init échouée', e);
}
}
ngOnDestroy(): void {
destroy(); // démonte le SDK quand le composant est détruit
}
}
<script>
import { onMount, onDestroy } from 'svelte';
import { init, destroy, navigate } from '@blunx/web-sdk';
onMount(async () => {
try {
const info = await init({
container: '#blunx',
apiBaseUrl: '', // cross-origin — vide en même origine
view: 'auto',
onReady: (i) => console.log('[Svelte] Blunx prêt', i),
onError: (e) => console.error('[Svelte] Blunx erreur', e),
});
console.log('[Svelte] monté', info);
} catch (e) {
console.error('[Svelte] init échouée', e);
}
});
onDestroy(() => {
destroy(); // démonte le SDK quand le composant est détruit
});
</script>
<div class="host">
<header class="host-top">
<strong>Svelte hôte</strong>
<span>SDK monté dans <code>#blunx</code></span>
</header>
<div id="blunx" class="blunx-zone"></div>
</div>
API publique & options
import { init, destroy, navigate, version } from '@blunx/web-sdk';
init(options) // → Promise<{ view: 'cockpit'|'dashboard', version }>
destroy() // démonte et nettoie le listener hashchange + le contenu du conteneur
navigate(path) // navigation interne, ex. navigate('/dashboard/abc-123') → '#/dashboard/abc-123'
version // string, ex. "0.1.0"
| Option | Type | Défaut | Description |
|---|---|---|---|
| container | string | HTMLElement | '#blunx' | Sélecteur / élément dans lequel monter l'application |
| apiBaseUrl | string | '' | Base de l'API (vide = même origine, recommandé) |
| view | 'auto' | 'cockpit' | 'dashboard' | 'auto' | Vue initiale ('auto' suit le hash de l'URL) |
| dashboardUuid | string | null | null | UUID du dashboard si view: 'dashboard' |
| onReady | function | null | Appelé après le premier montage : (info) => {} |
| onError | function | null | Appelé si init() échoue (conteneur, routage). La promesse rejette aussi. |
Via script-tag, les options se passent en attributs data-* : data-container, data-api-base-url, data-view, data-dashboard-uuid.
Pièges & bonnes pratiques
Le sélecteur doit exister au moment de init(), et le conteneur doit avoir une hauteur (height:100vh ou 70vh), sinon le rendu peut être écrasé.
Le module accède à window/document à l'évaluation : importez-le uniquement côté client ('use client' ou ssr: false).
Le SDK réagit à tout hashchange. Si votre app utilise déjà le hash pour son routage, il peut y avoir conflit.
En cross-origin (apiBaseUrl sur un autre domaine), le fetch de /api/blunx/stream n'envoie pas credentials. Préférez une configuration même origine.
Si la page hôte a déjà jQuery/Bootstrap/DataTables/ECharts, le SDK les réutilise. Une version incompatible (ex. Bootstrap 4) dégrade silencieusement certains composants.
Configuration
Cette page est la référence complète : toutes les variables d'environnement, toutes les options de Blunx.init() et les règles d'accès RBAC. Dans la majorité des cas, le .env suffit.
Les 3 façons de configurer
| Méthode | Laravel | Node.js | Quand l'utiliser |
|---|---|---|---|
| .env (recommandé) | Chargé par Laravel | Chargé automatiquement (dotenv) | La quasi-totalité des cas : clés, LLM, BDD. |
| config/blunx.php ↔ Blunx.init() | config/blunx.php | options de Blunx.init({...}) | Pour forcer une valeur (monnaie, exclusions…) ou passer les règles RBAC. |
| Règles RBAC | config/blunx_access.php | init({ access }) | Uniquement par fichier/option — aucune variable d'env. |
Laravel : php artisan config:clear. Node : rien à faire (le .env est relu à chaque démarrage).
Variables d'environnement
Colonne Alternative : clé blunx.* (Laravel) / option init() (Node).
| Variable | Défaut | Rôle | Alternative (Laravel → Node) |
|---|---|---|---|
| BLUNX_SERVER_URL | https://blunxai.com | URL du serveur Blunx (/api/v1/*) | server_url → serverUrl |
| BLUNX_REQUEST_TIMEOUT | 600 | Timeout (s) de chaque requête vers le Hub (SSE chat + JSON) — 0 = aucun (une question lourde qui fait réfléchir le LLM n'est jamais coupée) | request_timeout → requestTimeout |
| BLUNX_API_KEY | — | Clé d'application → X-Blunx-Key | api_key → apiKey |
| BLUNX_LLM_API_KEY | — | Clé LLM → X-Blunx-LLM-Key | llm_api_key → llmApiKey |
| BLUNX_LLM_DRIVER | openai | openai (compatible : Ollama, Groq, DeepSeek…) | gemini | anthropic | llm.driver → llm.driver |
| BLUNX_LLM_ENDPOINT | — | Endpoint de votre fournisseur | llm.endpoint → llm.endpoint |
| BLUNX_LLM_MODEL | — | Modèle utilisé par l'IA | llm.model → llm.model |
| BLUNX_LLM_SUPPORTS_JSON_FORMAT | true | Le modèle gère response_format: json_object ? (false sur modèles locaux anciens) | llm.supports_json_format → llm.supportsJsonFormat |
| BLUNX_DB_CONNECTION | mysql | Dialecte SQL envoyé au serveur Blunx (la connexion locale réelle vient de votre app) | db_connection → dbConnection |
| BLUNX_DB_URL | — | URL de connexion (DSN) : remplace la connexion par défaut, SSL possible | db_url → databaseUrl |
| BLUNX_READONLY_DB_USERNAME / PASSWORD | — | Rôle BDD lecture seule (optionnel — voir modes de connexion) | readonly_db → readonlyDb |
| BLUNX_PGSQL_SCHEMA | public | Schéma PostgreSQL scanné | pgsql_schema → pgsqlSchema |
| BLUNX_CURRENCY_CODE / SYMBOL / LOCALE | EUR / € / fr_FR | Format d'affichage des montants | currency.* → currency.* |
| BLUNX_LOCALE | fr | Langue des prompts, messages et vues | locale → locale |
| BLUNX_SCHEMA_PATH | storage/app/blunx_schema.json | Chemin du fichier de schéma | — → schemaPath |
Les tables exclues du scan (excluded_tables en Laravel, excludedTables en Node) et les règles RBAC (access) n'ont pas de variable d'env : elles se passent par option/fichier (voir les sections ci-dessous).
BLUNX_API_KEY, BLUNX_LLM_API_KEY, BLUNX_LLM_ENDPOINT et BLUNX_LLM_MODEL. Tout le reste a une valeur par défaut utilisable.
Blunx.init() — toutes les options (Node.js)
Référence complète de ce que vous pouvez passer à Blunx.init(). Priorité : option > variable d'env > défaut. Le template TypeScript config/blunx.config.ts (exporté, sans dépendance) utilise ces clés en camelCase ; les clés snake_case (server_url, api_key, db_url…) sont aussi acceptées (miroir de config/blunx.php).
| Option | Type | Défaut | Env | Description |
|---|---|---|---|---|
| enabled | boolean | true | — | Active / désactive le SDK |
| serverUrl | string | https://blunxai.com | BLUNX_SERVER_URL | URL du Hub Blunx (/api/v1/*) |
| requestTimeout | number | 600 | BLUNX_REQUEST_TIMEOUT | Timeout (s) de chaque requête vers le Hub (SSE + JSON) — 0 = aucun timeout |
| apiKey | string | null | null | BLUNX_API_KEY | Clé d'application → en-tête X-Blunx-Key |
| llmApiKey | string | null | null | BLUNX_LLM_API_KEY | Clé LLM → en-tête X-Blunx-LLM-Key |
| dbConnection | string | null | null | BLUNX_DB_CONNECTION | Dialecte SQL envoyé au Hub (mysql, pgsql…) — ≠ connexion locale |
| databaseUrl | string | null | null | BLUNX_DB_URL | URL de connexion BDD (DSN) — prioritaire (mysql://, postgres://, sqlite://…) |
| readonlyDb | { username, password } | { null, null } | BLUNX_READONLY_DB_* | Rôle BDD lecture seule (optionnel) |
| pgsqlSchema | string | public | BLUNX_PGSQL_SCHEMA | Schéma PostgreSQL scanné par init/edit |
| llm | { driver, endpoint, model, supportsJsonFormat } | openai / null / null / true | BLUNX_LLM_* | Config LLM relayée au Hub (les clés restent en en-tête) |
| users | { userTable, primaryKey } | users / id | — | Table et clé des utilisateurs de l'hôte |
| currency | { code, symbol, locale } | EUR / € / fr_FR | BLUNX_CURRENCY_* | Format d'affichage des montants |
| excludedTables | string[] | blunx_* (8) | — | Tables ignorées au scan de schéma (voir la section dédiée plus bas) |
| locale | string | fr | BLUNX_LOCALE | Langue des messages et vues |
| tables | { conversations, messages, feedbacks, dashboards, widgets, insights, insightSettings, cache } | blunx_* | — | Noms de tables Blunx personnalisés |
| schemaPath | string | storage/app/blunx_schema.json | BLUNX_SCHEMA_PATH | Chemin du fichier de schéma |
| access | AccessConfig | défaut | — | Règles RBAC (voir ci-dessous) |
| knex | instance | — | — | Instance knex de l'hôte (connexion principale) |
| readonlyKnex | instance | — | — | Instance knex lecture seule |
| database | { client, connection, useNullAsDefault, pool } | — | — | Config de connexion knex (si pas d'instance) |
| getUserRole | (userId) => string | null | — | — | Résout le rôle de l'utilisateur — équivaut getUserRoleName() |
| getUser | (userId) => { name, email } | null | — | — | Résout name/email pour /api/blunx/user — équivaut Auth::user() |
| dashboardUrl | (uuid) => string | — | — | URL du dashboard (lien « Voir le dashboard » des emails) |
| MailOptions | — | — | SMTP des emails : host, port, secure, user, pass, from, transport (nodemailer) | |
| enableScheduler | boolean | true | — | Active le scheduler horaire des insights |
- apiKey / llmApiKey ne sont jamais envoyées dans le body (en-têtes uniquement).
- dbConnection ≠ connexion locale : c'est le dialecte envoyé au Hub. La vraie connexion vient de databaseUrl, database ou knex.
- readonlyDb : si username est vide, Blunx retombe sur la connexion par défaut (défense en profondeur).
Charger les fichiers de config (Node.js)
Exemple complet : on publie config/blunx.config.ts + config/blunx-access.config.ts (templates TypeScript, aucune dépendance), on les charge, et on ajoute la base + les hooks :
import blunxConfig from './config/blunx.config'; // ta copie éditée
import blunxAccessConfig from './config/blunx-access.config'; // tes règles RBAC
const blunx = Blunx.init({
...blunxConfig, // serverUrl, apiKey, llm, currency, locale…
access: blunxAccessConfig, // règles RBAC
// BDD : via BLUNX_DB_URL dans le .env (recommandé), ou :
// database: { client: 'mysql2', connection: { host, user, password, database } },
getUserRole: (userId) => USERS[userId]?.role ?? null,
getUser: (userId) => {
const u = USERS[userId];
return u ? { name: u.name, email: u.email } : null;
},
});
Règles d'accès RBAC (access)
Approche NÉGATIVE : on définit ce que l'utilisateur N'A PAS le droit de voir. En Laravel : config/blunx_access.php. En Node : option access de Blunx.init() (fichier config/blunx-access.config.ts). Aucune variable d'env.
Trois niveaux de restriction par rôle :
| Niveau | Type | Rôle |
|---|---|---|
| forbidden_tables | string[] | Tables entièrement interdites au rôle |
| forbidden_columns | { table: string[] } | Colonnes interdites par table ("*" = toutes les tables) |
| row_level | { table: { column, value } } | Filtrage automatique des lignes (ex. WHERE user_id = X) |
Exemple complet (fichier config/blunx-access.config.ts) :
export default {
"vendeur": {
"forbidden_tables": ["salaires", "comptabilite"],
"forbidden_columns": {
"users": ["salaire", "numero_secu", "adresse_complete"],
"*": ["mot_de_passe", "token_api"]
},
"row_level": {
"orders": { "column": "user_id", "value": "USER_ID" },
"products": { "column": "vendor_id", "value": "USER_ID" }
}
},
"admin": { "forbidden_tables": [], "forbidden_columns": [], "row_level": {} },
"default": { "forbidden_tables": ["users"], "forbidden_columns": {}, "row_level": {} },
"enabled": true
}
- USER_ID : placeholder remplacé par l'ID de l'utilisateur connecté.
- Le SDK fusionne default + les règles du rôle (fusion récursive, comme array_replace_recursive).
- Si aucun rôle n'est résolu → null → erreur SSE Access rules not resolved.
- enabled : active/désactive tout le système de permissions.
Tables exclues du scan (excluded_tables / excludedTables)
À la génération du schéma (blunx:init / npx blunx-ai init), Blunx scanne toutes les tables de votre base et les rend interrogeables par l'assistant. Listez ici les tables techniques, sensibles ou sans intérêt qui ne doivent jamais apparaître dans le schéma. Aucune variable d'env : la liste se déclare par fichier/option.
| Laravel | Node.js | |
|---|---|---|
| Où | config/blunx.php → 'excluded_tables' | config/blunx.config.ts → excludedTables |
| Défaut | Tables techniques Laravel (migrations, jobs, sessions…) + blunx_* | Tables internes blunx_* uniquement |
| Quand c'est lu | Au blunx:init / blunx:edit | Au init / edit (runtime chargé) |
'excluded_tables' => [
// Déjà exclus par défaut : migrations, failed_jobs, cache, jobs, sessions,
// password_reset_tokens, personal_access_tokens… + les tables internes blunx_*
'admin_logs', 'notifications', 'settings', 'audit_trail', // ▶ vos tables
],
export default {
// ...
// Tables internes blunx_* déjà ignorées par défaut.
// ▶ Ajoutez vos tables techniques / sensibles à ne pas scanner :
excludedTables: ['migrations', 'sessions', 'log_errors', 'admin_logs', 'notifications'],
};
Une table exclue n'est jamais scannée : elle n'existe pas pour Blunx (ni dans le schéma, ni proposée à l'assistant). Une table interdite (forbidden_tables, RBAC) reste dans le schéma mais son accès est bloqué selon le rôle de l'utilisateur. Modifiez la liste avant init ; après coup, relancez blunx:edit / npx blunx-ai edit pour retirer une table déjà scannée.
Un .env complet prêt à copier
# --- Serveur Blunx ---
BLUNX_SERVER_URL=https://blunxai.com
# Timeout (s) de chaque requête vers le Hub — 600 (10 min) par défaut ; 0 = aucun
BLUNX_REQUEST_TIMEOUT=600
BLUNX_API_KEY=blunx_app_live_xxxxxxxxxxxx
# --- Fournisseur LLM (OpenAI dans cet exemple) ---
BLUNX_LLM_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
BLUNX_LLM_DRIVER=openai
BLUNX_LLM_ENDPOINT=https://api.openai.com/v1
BLUNX_LLM_MODEL=gpt-4o
BLUNX_LLM_SUPPORTS_JSON_FORMAT=true
# --- Base de données ---
BLUNX_DB_CONNECTION=mysql
# BLUNX_DB_URL=postgres://user:pass@host:5432/db?sslmode=require # alternative : URL de connexion (DSN)
# BLUNX_READONLY_DB_USERNAME=blunx_readonly # optionnel (voir modes de connexion)
# BLUNX_READONLY_DB_PASSWORD=secret
# BLUNX_PGSQL_SCHEMA=public # PostgreSQL uniquement
# --- Affichage & langue ---
BLUNX_CURRENCY_CODE=EUR
BLUNX_CURRENCY_SYMBOL=€
BLUNX_CURRENCY_LOCALE=fr_FR
BLUNX_LOCALE=fr
Les 3 modes de connexion à la base de données
Blunx exécute le SQL sur votre base. Trois notions complémentaires — à ne pas confondre :
| Mode | Variable | Ce que c'est | Quand l'utiliser |
|---|---|---|---|
| 1 · Connexion par défaut de l'app | BLUNX_DB_CONNECTION | La connexion que votre application utilise déjà (connexion Laravel par défaut, ou instance/config knex passée à Blunx.init()). | Cas le plus courant : Blunx réutilise la base de votre app telle quelle. |
| 2 · URL de connexion (DSN) | BLUNX_DB_URL | Une URL complète (hôte, port, base, user, mot de passe, SSL) qui remplace la connexion par défaut. | Bases cloud (Neon, Railway, Heroku…) ou cibler une autre base sans toucher à la config de l'app. |
| 3 · Rôle lecture seule | BLUNX_READONLY_DB_* | Un override de credentials appliqué par-dessus le mode 1 ou 2 pour forcer l'exécution en lecture seule. | Verrou de sécurité : la connexion porte le rôle principal mais Blunx ne doit jamais écrire. |
BLUNX_DB_URL prime sur la connexion par défaut (mode 2 > mode 1). Le rôle lecture seule (mode 3) est ensuite appliqué par-dessus, SSL conservé. Si l'URL contient déjà un rôle read-only, le mode 3 est inutile : laissez-le vide.
Contrat API
Deux familles d'endpoints : le Web SDK ne connaît que les endpoints locaux /api/blunx/* servis par votre SDK backend ; celui-ci proxie vers le serveur Blunx /api/v1/*.
Endpoints locaux (/api/blunx/*)
Session + auth, sans CSRF, throttle 60:1. Réponses enveloppées dans { "data": … }, sauf /user (objet direct).
| Méthode | Chemin | Rôle |
|---|---|---|
| GET | /api/blunx/user | Utilisateur connecté (champ locale) |
| GET · POST | /api/blunx/conversations | Lister / créer une conversation |
| DELETE | /api/blunx/conversations/{uuid} | Supprimer une conversation |
| GET | /api/blunx/conversations/{uuid}/messages | Messages d'une conversation |
| POST | /api/blunx/messages | Sauvegarder un message (crée la conversation si conversation_uuid nul) |
| DELETE | /api/blunx/messages/{uuid} | Supprimer un message |
| POST | /api/blunx/feedback | Retour utilisateur |
| GET · POST | /api/blunx/dashboards | Lister / créer un dashboard |
| GET · DELETE | /api/blunx/dashboards/{uuid} | Afficher / supprimer un dashboard |
| POST | /api/blunx/widgets | Créer un widget |
| PATCH · DELETE | /api/blunx/widgets/{uuid} | Modifier / supprimer un widget |
| POST | /api/blunx/widgets/{uuid}/execute | Exécuter un widget |
| GET | /api/blunx/insights/{dashUuid} | Insights d'un dashboard |
| GET | /api/blunx/insights/{dashUuid}/settings | Réglages d'insights |
| POST | /api/blunx/insights/{uuid}/mark-read | Marquer un insight lu |
| DELETE | /api/blunx/insights/{uuid} | Supprimer un insight |
| GET | /api/blunx/insights/{uuid}/download | Télécharger le rapport PDF |
| POST | /api/blunx/insight-settings | Créer / mettre à jour un réglage d'insight |
| DELETE | /api/blunx/insights/jobs/{widgetUuid} | Annuler un job d'insight planifié |
| POST | /api/blunx/execute-sql | Exécuter une requête stockée sur un message |
| POST | /api/blunx/stream | Chat SSE : pipeline multi-agents en streaming |
Endpoints du serveur Blunx (/api/v1/*)
Middlewares : ValidateBlunxKey (X-Blunx-Key) puis RequireLLMConfig (X-Blunx-LLM-Key + bloc llm dans le body).
| Endpoint | Méthode | Format réponse |
|---|---|---|
| /api/v1/chat/queries | POST | SSE |
| /api/v1/chat/validate | POST | SSE |
| /api/v1/chat/synthesize | POST | SSE |
| /api/v1/insights/analyze | POST | JSON |
| /api/v1/insights/report | POST | JSON |
| /api/v1/schema/enrich | POST | JSON |
| /api/v1/reference/generate | POST | JSON |
En-têtes communs
X-Blunx-Key: blunx_app_live_xxxxxxx # clé d'application (requis)
X-Blunx-LLM-Key: sk-xxxxxxxxxxxxxxxx # clé du fournisseur LLM (requis)
Content-Type: application/json
Accept: text/event-stream | application/json
Payload de base
Chaque appel au serveur Blunx transporte la connexion BDD et la configuration LLM. Les clés passent par les en-têtes, jamais dans le body (pas de fuite dans les logs).
{
"db_connection": "mysql",
"locale": "fr",
"currency": { "code": "XOF", "symbol": "FCFA", "locale": "fr_FR" },
"llm": {
"driver": "openai",
"endpoint": "https://api.openai.com/v1",
"model": "gpt-4o",
"supports_json_format": true
}
}
Chat — POST /api/v1/chat/queries
Requête :
{
"question": "Quel est le chiffre d'affaires par région ?",
"conversation_history": [ { "role": "user", "content": "…" } ],
"access_rules": { "forbidden_tables": [], "forbidden_columns": [], "row_level": [] },
"schema": "… schéma complet en JSON string (ou schema_id) …",
"schema_id": "uuid-optionnel",
"db_connection": "mysql",
"locale": "fr",
"currency": { "code": "XOF", "symbol": "FCFA", "locale": "fr_FR" },
"llm": { "driver": "openai", "endpoint": "…", "model": "…", "supports_json_format": true }
}
Réponse SSE — événement result :
{
"needs_data": true,
"needs_clarification": false,
"normalized_question": "…",
"intent": "…",
"queries": [ { "sql": "SELECT …", "ui_hint": "chart", "chart_type": "bar" } ],
"warnings": [],
"filtered_schema_id": "uuid"
}
Cas terminaux : needs_clarification (+ clarification_question), needs_data=false, access_denied (+ message, forbidden_info).
Chat — validate & synthesize
Validate : {normalized_question, intent, execution_results, filtered_schema_id, access_rules, locale, db_connection, llm} → {queries[], warnings[]} (SQL corrigés).
Synthesize : {normalized_question, execution_results, conversation_history, needs_data, locale, currency, llm} → réponse structurée :
{
"title": "Chiffre d'affaires par région",
"layout": [
{ "type": "paragraph", "content": "… HTML Bootstrap 5 …" },
{ "type": "chart", "chart_type": "bar", "title": "…", "label_column": "…",
"data_columns": ["…"], "comment": "…", "sql_query": "…" },
{ "type": "table", "title": "…", "comment": "…", "sql_query": "…" }
],
"Resume": "… résumé markdown …"
}
Si needs_data=false : { "Resume": "…", "is_conversational": true }.
Insights, schéma & références
- Analyze : {widget_title, sql_query, current_meta, previous_meta?, metric_weights?, locale, currency, llm} → {type, severity, message, meta}.
- Report : {insight_result, current_meta, previous_meta?, last_insight?, widget_title, dashboard_name, report_frequency, locale, currency, llm} → {html}.
- Schema enrich : {columns, locale, llm} → {columns} avec descriptions.
- Reference generate : {widget_sql, widget_title?, numeric_columns[], access_rules?, db_connection, locale, llm} → {queries}.
Flux SSE — événements
event: step
data: {"step":1,"status":"running","duration":1}
event: result
data: { …resultat… }
event: done
data: {"result":{ "title":"…", "Resume":"…", "layout":[…] }, "message_uuid":"…"}
event: error
data: {"message":"…"}
| Événement | Signification |
|---|---|
| step | Progression (étapes 1 à 6 : Analyse, Planification, Collecte, Exécution, Validation, Synthèse) |
| result | Résultat intermédiaire (ex. requêtes générées) |
| done | Fin : réponse finale + message_uuid |
| error | Erreur ({message, code, fields, plan, limit, used}) |
Content-Type: text/event-stream; charset=UTF-8, Cache-Control: no-cache, no-store, X-Accel-Buffering: no. Ne bufferisez pas la réponse.
Sécurité & accès
Blunx applique une défense en profondeur sur plusieurs niveaux pour garantir que vos données ne sont jamais modifiées ni exposées au-delà de ce que vous autorisez.
1. Lecture seule stricte (SqlGuard)
Chaque requête SQL est validée localement avant exécution. Les règles sont multiples :
- La requête doit commencer par SELECT ou WITH (CTE).
- Mots-clés dangereux interdits : INSERT, UPDATE, DELETE, DROP, ALTER, CREATE, TRUNCATE, GRANT, REVOKE, EXEC, VACUUM, LOCK, COPY, etc.
- Fonctions dangereuses interdites : pg_sleep, pg_read_file, lo_import, dblink, pg_execute_server_program, set_config, etc.
- SELECT … INTO interdit.
- Un sanitize() retire les littéraux chaîne et les commentaires avant analyse (évite les faux positifs sur les valeurs).
invalid statement type: INSERT (only SELECT allowed)
forbidden keyword found: DROP
forbidden function call found: pg_sleep
SELECT ... INTO is forbidden ...
Même si une requête était altérée entre la génération et l'exécution, l'agent d'exécution (DataExecutorAgent) re-valide et saute toute requête non-SELECT.
2. Connexion BDD en lecture seule dédiée
C'est le verrou de sécurité principal. Si BLUNX_READONLY_DB_USERNAME est renseigné, le package crée une connexion blunx_readonly (même driver/hôte/base, identifiants dédiés) utilisée pour toutes les exécutions. En base, accordez à ce rôle uniquement GRANT SELECT, USAGE :
-- MySQL
CREATE USER 'blunx_readonly'@'%' IDENTIFIED BY 'mot_de_passe_fort';
GRANT SELECT ON votre_base.* TO 'blunx_readonly'@'%';
-- PostgreSQL
CREATE ROLE blunx_readonly LOGIN PASSWORD 'mot_de_passe_fort';
GRANT CONNECT ON DATABASE votre_base TO blunx_readonly;
GRANT USAGE ON SCHEMA public TO blunx_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO blunx_readonly;
Créez toujours un rôle BDD en lecture seule. Sans cela, le package utilise la connexion principale de Laravel — les garde-fous SqlGuard restent actifs, mais un rôle dédié ajoute une protection au niveau de la base elle-même.
3. Règles d'accès par rôle (RBAC)
Le fichier config/blunx_access.php définit, par rôle, les tables et colonnes interdites et le filtrage par ligne. Voir la section Configuration pour la syntaxe complète. Le rôle provient de getUserRoleName() sur votre modèle User.
- Tables interdites : jamais scannées ni exposées au LLM.
- Colonnes interdites : masquées (motif '*' = toutes les tables).
- Filtrage par ligne : le placeholder USER_ID est remplacé par l'ID de l'utilisateur connecté (ex. un vendeur ne voit que orders.user_id = lui-même).
4. Authentification
| Contexte | Mécanisme |
|---|---|
| Web SDK → package Laravel | Cookie de session Laravel (middleware auth du groupe blunx) |
| Web SDK → package Node.js | Utilisateur authentifié de l'app hôte (req.user / ctx.state.user) — le routeur renvoie 401 s'il est absent |
| SDK backend → Serveur Blunx | En-têtes X-Blunx-Key (clé app) + X-Blunx-LLM-Key (clé LLM) |
En cross-origin, le backend doit accepter credentials: include (Access-Control-Allow-Credentials + origine explicite, pas *) et les en-têtes Accept, Content-Type, X-Requested-With (préflight CORS).
5. Autres protections
- Rate limiting : 60 requêtes/min/IP sur le groupe local /api/blunx/* (throttle Laravel ; en Node, ajoutez votre rate limiter, ex. express-rate-limit), sauf webhook Stripe (non concerné ici).
- Validation SQL : double vérification (client + serveur), une requête non-SELECT n'est jamais exécutée.
- Schéma PostgreSQL : le scan ne touche que le schéma configuré (BLUNX_PGSQL_SCHEMA), jamais les autres.
- CSRF : le groupe blunx reproduit web sans CSRF (l'auth par session suffit pour cette API AJAX).
Fournisseurs LLM
Choisissez votre fournisseur via le driver et l'endpoint. L'adaptateur openai est « compatible OpenAI » : il fonctionne avec la quasi-totalité des fournisseurs, propriétaires comme open-source.
L'adaptateur openai ne fait aucune hypothèse sur l'hôte : il POSTe exactement à l'URL fournie dans llm.endpoint, au format standard chat/completions. C'est un adaptateur « compatible OpenAI », pas « OpenAI uniquement ». Or la quasi-totalité des fournisseurs actuels — propriétaires ET open-source — exposent cette API compatible.
Tableau des fournisseurs
| Fournisseur | Driver | Endpoint (à mettre dans BLUNX_LLM_ENDPOINT) |
|---|---|---|
| OpenAI | openai | https://api.openai.com/v1 |
| Azure OpenAI | openai | https://{ressource}.openai.azure.com/openai/v1 |
| Ollama (local) | openai | http://localhost:11434/v1 |
| Groq | openai | https://api.groq.com/openai/v1 |
| DeepSeek | openai | https://api.deepseek.com/v1 |
| Mistral | openai | https://api.mistral.ai/v1 |
| Together, Fireworks, OpenRouter… | openai | URL compatible OpenAI du fournisseur |
| vLLM, LM Studio, llama.cpp | openai | URL locale / self-hosted (ex. http://localhost:8000/v1) |
| Anthropic Claude | anthropic | https://api.anthropic.com/v1/messages (format natif) |
| Google Gemini | gemini | https://generativelanguage.googleapis.com (format natif generateContent) |
Configurer un fournisseur
Exemple : DeepSeek (API compatible OpenAI)
BLUNX_LLM_DRIVER=openai
BLUNX_LLM_ENDPOINT=https://api.deepseek.com/v1
BLUNX_LLM_MODEL=deepseek-chat
BLUNX_LLM_API_KEY=sk-xxxxxxxxxxxx
BLUNX_LLM_SUPPORTS_JSON_FORMAT=true
Exemple : Ollama en local (zéro dépendance cloud)
BLUNX_LLM_DRIVER=openai
BLUNX_LLM_ENDPOINT=http://localhost:11434/v1
BLUNX_LLM_MODEL=llama3.1
BLUNX_LLM_API_KEY=ollama # valeur non utilisée, peut rester vide
BLUNX_LLM_SUPPORTS_JSON_FORMAT=true
Exemple : Groq
BLUNX_LLM_DRIVER=openai
BLUNX_LLM_ENDPOINT=https://api.groq.com/openai/v1
BLUNX_LLM_MODEL=llama-3.3-70b-versatile
BLUNX_LLM_API_KEY=gsk_xxxxxxxxxxxx
BLUNX_LLM_SUPPORTS_JSON_FORMAT=true
Détail des drivers
| Driver | Format | Remarques |
|---|---|---|
| openai | POST {endpoint}/chat/completions | Compatible OpenAI + tous les fournisseurs cités ci-dessus. endpoint peut inclure ou non le suffixe /chat/completions. |
| anthropic | POST /v1/messages (format natif) | Anthropic Claude. Endpoint natif, headers Anthropic. |
| gemini | generateContent (format natif) | Google Gemini. Endpoint natif Google. |
supports_json_format
Indique si le modèle gère le mode response_format: json_object. Les modèles modernes (GPT-4o, DeepSeek, Groq…) le supportent (true) ; certains modèles locaux plus anciens non. Si le modèle ne le supporte pas, mettez false pour que le pipeline demande le JSON en langage naturel plutôt qu'en mode structuré.
Pour un usage en production, préférez un modèle fiable en sortie JSON (supports_json_format=true) et un endpoint à faible latence. Le pipeline gère un retry automatique en cas de réponse LLM vide ou d'échec transitoire.
Erreurs & dépannage
Organisé par niveau : serveur Blunx (HTTP), backend (Laravel / Node), SSE et Web SDK. Cherchez d'abord le code HTTP, puis le niveau concerné.
1 · Codes HTTP du serveur Blunx
Communs aux deux backends — renvoyés par le hub /api/v1/* :
| Code | Signification | Déclencheur / action |
|---|---|---|
| 400 | Bad Request | JSON invalide. Vérifiez le corps de la requête. |
| 401 | Unauthorized | Clé manquante/invalide (missing_key / invalid_key). Vérifiez BLUNX_API_KEY. |
| 402 | Payment Required | Abonnement inactif/expiré (billing_inactive). Consultez votre facturation. |
| 403 | Forbidden | Application suspendue/inactive (frozen). Contactez le support. |
| 404 | Not Found | SCHEMA_NOT_FOUND → le package vide le cache et réessaie sans schema_id. |
| 413 | Payload Too Large | Body trop volumineux. Réduisez le schéma envoyé. |
| 422 | Unprocessable Entity | Validation / config LLM manquante (missing_llm_config, invalid_llm_driver). |
| 429 | Too Many Requests | Quota dépassé (plan, limit, used). Attendez ou augmentez votre plan. |
| 500 | Internal Server Error | Erreur LLM côté serveur Blunx. Réessayez, vérifiez votre clé LLM. |
2 · Backend
Les deux SDK lèvent une exception avec un message humain (le message du serveur prime s'il existe) :
Mapping du BlunxApiClient (PHP) :
401 => "Invalid or expired API key"
402 => "Billing inactive. Please check your subscription."
403 => "Application suspended. Contact support."
429 => "Quota exceeded. Please wait before retrying."
422 => "LLM configuration missing. Check your settings."
default => "AI service error. Please try again later."
Le BlunxError (JS) porte un message et un statusCode — même mapping que Laravel :
try {
await blunx.api.someCall();
} catch (e) {
if (e instanceof BlunxError) {
console.error(e.statusCode, e.message); // ex. 401 "Invalid or expired API key"
}
}
3 · Erreurs SSE
- Événement error : {message, code, fields, plan, limit, used}.
- HTTP ≥ 400 : extraction de message / error / detail.
- Erreur réseau : cURL error: … (PHP) / fetch failed (Node).
- SCHEMA_NOT_FOUND : retry automatique sans schema_id.
4 · Erreurs du Web SDK
| Cas | Comportement |
|---|---|
| Conteneur introuvable | init() rejette : [Blunx] Conteneur introuvable : "#blunx" |
| view:'dashboard' sans UUID | [Blunx] Vue dashboard sans UUID. |
| Réponse HTTP non-OK (API) | Erreur HTTP {status}: {statusText} (ou message du body) |
| Échec stream | Server error (HTTP {status}) / Unknown error / Connection failed |
| Dépendance CDN en échec | console.warn non bloquant |
5 · Erreurs fréquentes à l'intégration
| Symptôme | Cause probable | Solution |
|---|---|---|
| 401 au premier appel | Clé BLUNX_API_KEY manquante/invalide | Vérifiez le .env et config:clear (Laravel). |
| 422 / missing_llm_config | LLM incomplet (endpoint, modèle, clé) | Complétez les 4 variables LLM (voir Configuration). |
| 401 sur /api/blunx/* (Node) | req.user non rempli | Votre middleware d'auth doit s'exécuter avant blunxExpress. |
| Listes vides en réponse | Requête non authentifiée (Node) ou user_id absent | Authentifiez l'utilisateur avant le routeur Blunx. |
| SCHEMA_NOT_FOUND | Schéma non envoyé au hub | Relancez blunx:init / blunx-ai init. |
Versions & mises à jour
Politique de versioning du Web SDK et mise à jour du SDK backend.
Politique de versioning
Le Web SDK suit le versioning sémantique (MAJEUR.MINEUR.CORRECTIF) :
- Correctif : bugfix sans rupture (aucune action requise).
- Mineur : nouvelle fonctionnalité rétro-compatible.
- Majeur : rupture (API publique, contrat REST, navigation).
Mises à jour du Web SDK
| Mode d'intégration | Comportement de mise à jour |
|---|---|
| Loader auto-update (blunx-loader.min.js) | Résout ./blunx.min.js relatif à lui-même : servi depuis jsDelivr « latest », il est toujours à la même version que le loader. Aucune action requise de votre part. |
| Bundle direct (blunx.min.js) | Vous épinglez la version. Pour mettre à jour, changez l'URL ou ajoutez ?v=. |
| npm (@blunx/web-sdk) | Épinglez la version (^0.1.0) et exécutez npm update. |
Sur CDN, le loader ajoute ?v={version} (le CDN purge au release). En local/auto-hébergé, il ajoute un horodatage : vous servez toujours le dernier build sans vider le cache navigateur.
Changelog du Web SDK
| Version | Date | Points clés |
|---|---|---|
| 0.1.0 | 7 août 2026 | Refonte en projet autonome ; API publique init/destroy/navigate/version ; routage par hash ; build esbuild 3 cibles ; loader auto-update ; dépendances auto-injectées ; CSS + logo embarqués ; config par options ; traductions embarquées ; isolation CSS .blunx-root ; démo PHP mock complète. |
Package Laravel
- Mettez à jour avec composer update blunx/ai.
- Vérifiez la version : composer show blunx/ai.
- Après mise à jour majeure, revérifiez config/blunx.php publié (le fichier publié n'est pas écrasé automatiquement).
Après une mise à jour majeure, comparez config/blunx.php avec la version publiée du package (vendor/blunx/ai/config/blunx.php) et reportez les nouvelles clés si nécessaire.
Support
Un problème non résolu par cette documentation ? L'équipe Blunx vous répond sous 24 h.
| Canal | Détail |
|---|---|
| Formulaire de contact | /contact — sujet « Intégration technique » recommandé pour les questions d'implémentation |
| Retours produit | Le module feedback de l'application (thumbs + commentaire) remonte directement à l'équipe |
| Signalement de bug | Décrivez : version SDK (info.version), version Laravel/PHP, étapes de reproduction, code d'erreur HTTP/SSE |
Joignez systématiquement : le message d'erreur exact (code HTTP + body), votre bloc llm (sans la clé), le résultat de composer show blunx/ai et, si pertinent, les logs de votre file d'attente.
Licence : MIT — © 2026 BlunxAI. Package Laravel : blunx/ai · Web SDK : @blunx/web-sdk.