Compare commits

..

2 Commits

Author SHA1 Message Date
Luca Sacchi Ricciardi
92217897ca fix: standardize project name to LogWhispererAI (no space)
- Replace all occurrences of 'LogWhisperer AI' with 'LogWhispererAI'
- Fix 47 instances across 30 files including:
  - Documentation (README, PRD, specs, docs)
  - Frontend components (Footer, Navbar, Hero, etc.)
  - Backend files (Dockerfile, server.js)
  - Workflow files (n8n, bash scripts)
  - Configuration files (AGENTS.md, LICENSE)

Ensures consistent branding across the entire codebase.
2026-04-03 17:07:35 +02:00
Luca Sacchi Ricciardi
8eb7dfb00e feat: add fake-backend mock API server for frontend development
Create mock backend to simulate AI responses for UI development:

Backend Implementation:
- tools/fake-backend/server.js: Express server with CORS
- POST /api/analyze: Accepts log, returns mock AI analysis with 1.5s delay
- GET /health: Health check endpoint
- Pattern matching for different log types (PostgreSQL, Nginx, Node.js, Disk)
- Error handling: 400 for empty payload, 500 for server errors
- Mock responses for common errors (OOM, 502, connection refused, disk full)

Container Setup:
- Dockerfile: Node.js 20 Alpine container
- docker-compose.yml: Added fake-backend service on port 3000
- Health checks for both frontend and backend services
- Environment variable VITE_API_URL for frontend

Frontend Integration:
- InteractiveDemo.tsx: Replaced static data with real fetch() calls
- API_URL configurable via env var (default: http://localhost:3000)
- Error handling with user-friendly messages
- Shows backend URL in demo section
- Maintains loading states and UI feedback

Documentation:
- docs/tools_fake_backend.md: Complete usage guide
- README.md: Updated with tools/fake-backend structure and usage

Development Workflow:
1. docker compose up -d (starts both frontend and backend)
2. Frontend calls http://fake-backend:3000/api/analyze
3. Backend returns realistic mock responses
4. No OpenRouter API costs during development

Safety First:
- No real API calls during development
- Isolated mock logic in dedicated tool
- Easy switch to real backend by changing URL
- CORS enabled only for development

Refs: Sprint 4 preparation, API development workflow
2026-04-03 16:57:14 +02:00
34 changed files with 1531 additions and 125 deletions

View File

@@ -1,4 +1,4 @@
# LogWhisperer AI - Environment Variables
# LogWhispererAI - Environment Variables
# Telegram Bot Configuration
# Ottieni questi valori seguendo le istruzioni in docs/telegram_setup.md

View File

@@ -7,7 +7,7 @@ read: true
@n8n-specialist
Sei un esperto di automazione n8n. Il tuo compito è interfacciare LogWhisperer AI con l'istanza Docker su 192.168.254.12.
Sei un esperto di automazione n8n. Il tuo compito è interfacciare LogWhispererAI con l'istanza Docker su 192.168.254.12.
Focus Operativo

View File

@@ -1,4 +1,4 @@
# LogWhisperer AI - Agent Rules
# LogWhispererAI - Agent Rules
Regole operative per gli agenti AI che collaborano su questo progetto.

View File

@@ -20,11 +20,11 @@ Nessuna Modifica: È vietato modificare, alterare, adattare, tradurre, decompila
Uso Non Autorizzato: È vietato vendere, noleggiare, dare in locazione, concedere in licenza o utilizzare il software per scopi commerciali senza una licenza specifica rilasciata dall'autore.
Tutela del Marchio: I nomi "LogWhisperer AI", "Sacchi's Server Sentinel" e il "Metodo Sacchi" sono marchi e metodologie di proprietà dell'autore.
Tutela del Marchio: I nomi "LogWhispererAI", "Sacchi's Server Sentinel" e il "Metodo Sacchi" sono marchi e metodologie di proprietà dell'autore.
Legge Applicabile e Foro Competente
Il presente accordo è regolato dalla legge italiana. Per qualsiasi controversia derivante dall'interpretazione, esecuzione o risoluzione della presente licenza e per ogni disputa relativa al progetto "LogWhisperer AI", sarà competente in via esclusiva il Foro di Milano, Italia.
Il presente accordo è regolato dalla legge italiana. Per qualsiasi controversia derivante dall'interpretazione, esecuzione o risoluzione della presente licenza e per ogni disputa relativa al progetto "LogWhispererAI", sarà competente in via esclusiva il Foro di Milano, Italia.
Contatti

View File

@@ -10,7 +10,7 @@
🎯 Visione del Progetto
LogWhisperer AI trasforma i log di sistema e database spesso incomprensibili in alert azionabili descritti in "plain language". È pensato per piccole web agency e freelance che gestiscono infrastrutture (AWS, DigitalOcean, VPS) senza avere un sistemista senior dedicato.
LogWhispererAI trasforma i log di sistema e database spesso incomprensibili in alert azionabili descritti in "plain language". È pensato per piccole web agency e freelance che gestiscono infrastrutture (AWS, DigitalOcean, VPS) senza avere un sistemista senior dedicato.
## 🚀 Stato di Sviluppo
@@ -237,6 +237,11 @@ LogWhispererAI/
├── tests/
│ ├── __init__.py
│ └── test_logwhisperer.py # Test suite Python
├── tools/
│ └── fake-backend/ # Mock API server per sviluppo frontend
│ ├── server.js # Server Express mock
│ ├── Dockerfile # Containerizzazione
│ └── README.md # Documentazione tool
└── .opencode/
├── opencode.json # Configurazione MCP servers
├── agents/ # Configurazioni agenti individuali
@@ -256,6 +261,31 @@ LogWhispererAI/
└── context7_documentation_retrivial/
```
## 🛠️ Tools di Sviluppo
### Fake Backend (Mock API)
Per sviluppare e testare il frontend senza dipendere dal backend reale:
```bash
# Avvia il mock API server
cd tools/fake-backend
npm install
node server.js
# Oppure con Docker
docker compose up fake-backend -d
```
**Endpoint:** `http://localhost:3000/api/analyze`
Simula le risposte AI con delay di 1.5s. Utile per:
- Sviluppo UI offline
- Testing senza costi API
- Demo senza dipendenze esterne
Vedi `docs/tools_fake_backend.md` per documentazione completa.
## ⚖️ Licenza e Note Legali
Questo software è **proprietà riservata** di Luca Sacchi Ricciardi.

View File

@@ -1,6 +1,7 @@
# Docker Compose - LogWhisperer AI Development Environment
# Docker Compose - LogWhispererAI Development Environment
# Usage: docker compose up -d
# Access: http://localhost:5173
# Access Frontend: http://localhost:5173
# Access Fake Backend API: http://localhost:3000
services:
frontend:
@@ -18,8 +19,11 @@ services:
environment:
- NODE_ENV=development
- CHOKIDAR_USEPOLLING=true
- VITE_API_URL=http://fake-backend:3000
# Ensure container restarts on failure
restart: unless-stopped
depends_on:
- fake-backend
# Health check to verify the service is running
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:5173"]
@@ -28,6 +32,25 @@ services:
retries: 3
start_period: 40s
fake-backend:
build:
context: ./tools/fake-backend
dockerfile: Dockerfile
container_name: logwhisperer-fake-backend
ports:
- "3000:3000"
environment:
- PORT=3000
- DELAY_MS=1500
- NODE_ENV=production
restart: unless-stopped
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => r.statusCode === 200 ? process.exit(0) : process.exit(1))"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s
volumes:
node_modules:
driver: local

View File

@@ -1,6 +1,6 @@
# LogWhisperer AI - Agent Staff Catalog
# LogWhispererAI - Agent Staff Catalog
Catalogo completo degli agenti AI specializzati che collaborano sul progetto LogWhisperer AI.
Catalogo completo degli agenti AI specializzati che collaborano sul progetto LogWhispererAI.
---
@@ -211,7 +211,7 @@ Mantiene aggiornata la documentazione e il changelog.
Esperto in automazione e orchestrazione n8n.
**Responsabilità:**
- Interfacciare LogWhisperer AI con l'istanza Docker su 192.168.254.12
- Interfacciare LogWhispererAI con l'istanza Docker su 192.168.254.12
- Configurazione e testing dei Webhook di ricezione log
- Monitorare esecuzioni per garantire applicazione "Metodo Sacchi" nei prompt LLM
- Troubleshooting della connessione tra script Bash locale e API n8n

View File

@@ -1,4 +1,4 @@
Ottimo progetto. Per trasformare **LogWhisperer AI** in un prodotto reale in 4 giorni usando **OpenCode.ai**, dobbiamo configurare l'ambiente in modo che l'agente non si limiti a scrivere codice, ma agisca come un vero team di sviluppo (Tech Lead + Developer + QA).
Ottimo progetto. Per trasformare **LogWhispererAI** in un prodotto reale in 4 giorni usando **OpenCode.ai**, dobbiamo configurare l'ambiente in modo che l'agente non si limiti a scrivere codice, ma agisca come un vero team di sviluppo (Tech Lead + Developer + QA).
Ecco come configurare OpenCode.ai seguendo la tua metodologia **Spec-Driven**, **TDD** e il **Metodo Sacchi**.

View File

@@ -1,6 +1,6 @@
# Piano d'Azione per lo Sviluppo della Landing Page
**Obiettivo:** Creare una landing page di alta qualità che comunichi efficacemente l'UVP di LogWhisperer AI e converta i visitatori in utenti attivi.
**Obiettivo:** Creare una landing page di alta qualità che comunichi efficacemente l'UVP di LogWhispererAI e converta i visitatori in utenti attivi.
## 🎯 UVP da Comunicare
> *"Il DevOps tascabile che traduce i crash del tuo server e ti dice l'esatto comando per risolverli"*

View File

@@ -1,6 +1,6 @@
# Git History - LogWhisperer AI
# Git History - LogWhispererAI
**Repository:** LogWhisperer AI
**Repository:** LogWhispererAI
**Branch Principale:** `main`
**Ultimo Aggiornamento:** 2026-04-02
**Commit Corrente:** `88cfe9a`
@@ -18,7 +18,7 @@
## Panoramica
Questo documento traccia la storia dei commit del progetto LogWhisperer AI. Viene aggiornato periodicamente per riflettere l'evoluzione del codebase.
Questo documento traccia la storia dei commit del progetto LogWhispererAI. Viene aggiornato periodicamente per riflettere l'evoluzione del codebase.
### Convenzioni di Commit

View File

@@ -1,5 +1,5 @@
# Product Requirements Document (PRD) - MVP
## Progetto: LogWhisperer AI (aka Sacchi's Server Sentinel)
## Progetto: LogWhispererAI (aka Sacchi's Server Sentinel)
**Status:** 🟢 MVP Active Development - Sprint 1 Completed
**Last Updated:** 2026-04-02

View File

@@ -4,7 +4,7 @@ Here is the English translation:
**PROMPT TO INSERT INTO THE AI:**
*"Act as a Tech Lead and Project Manager expert in Lean Startup and Micro-SaaS methodologies. I have provided you with the Product Requirements Document (PRD) for the 'LogWhisperer AI' project.
*"Act as a Tech Lead and Project Manager expert in Lean Startup and Micro-SaaS methodologies. I have provided you with the Product Requirements Document (PRD) for the 'LogWhispererAI' project.
Our goal is to launch this MVP to market in just 4 days ('fail fast, fail cheap' approach) using No-Code/Low-Code logic wherever possible to save time.
Your task is to analyze the PRD and generate a development strategy ('Spec-driven development') structured as follows:*

View File

@@ -1,5 +1,5 @@
# Project Review - Sprint 1
## LogWhisperer AI - Log Ingestion
## LogWhispererAI - Log Ingestion
**Data Review:** 2026-04-02
**Sprint:** 1 - Log Ingestion Script
@@ -430,7 +430,7 @@ Tutti i deliverable dello Sprint 1 sono stati prodotti e verificati con successo
---
**Review Condotta da:** Agent Staff LogWhisperer AI
**Review Condotta da:** Agent Staff LogWhispererAI
**Data:** 2026-04-02
**Prossima Review:** Post-Sprint 2

View File

@@ -1,6 +1,6 @@
# Roadmap & Suggerimenti di Sviluppo
> **Documento Living** - Questo file raccoglie idee, suggerimenti e potenziali nuove funzionalità per LogWhisperer AI.
> **Documento Living** - Questo file raccoglie idee, suggerimenti e potenziali nuove funzionalità per LogWhispererAI.
>
> Ultimo aggiornamento: 2026-04-03
@@ -289,4 +289,4 @@ Hai un'idea? Aggiungila a questo documento seguendo il formato:
---
*Documento mantenuto dal team LogWhisperer AI*
*Documento mantenuto dal team LogWhispererAI*

View File

@@ -1,4 +1,4 @@
# 🤖 Staff di Agenti AI - LogWhisperer AI
# 🤖 Staff di Agenti AI - LogWhispererAI
Questo documento definisce i ruoli, le responsabilità e le configurazioni per i sotto-agenti da utilizzare in OpenCode.ai per garantire un workflow "Spec-Driven" e "Safety First".

View File

@@ -10,7 +10,7 @@
## 1. Overview
### 1.1 Scopo
L'AI Processing Pipeline è il cuore intelligente di LogWhisperer AI. Trasforma log grezzi di sistema in insight azionabili utilizzando OpenRouter per accedere a modelli AI (GPT-4o-mini) con fallback automatico e costi ottimizzati.
L'AI Processing Pipeline è il cuore intelligente di LogWhispererAI. Trasforma log grezzi di sistema in insight azionabili utilizzando OpenRouter per accedere a modelli AI (GPT-4o-mini) con fallback automatico e costi ottimizzati.
### 1.2 Flusso Dati
@@ -56,7 +56,7 @@ Il prompt di sistema incorpora esplicitamente i tre pilastri del Metodo Sacchi:
### 2.2 System Prompt Completo
```javascript
const SYSTEM_PROMPT = `Sei LogWhisperer AI, un assistente DevOps esperto specializzato nell'analisi di log di sistema.
const SYSTEM_PROMPT = `Sei LogWhispererAI, un assistente DevOps esperto specializzato nell'analisi di log di sistema.
## MISSIONE
Analizza i log ricevuti e fornisci insight azionabili in italiano, semplice e chiaro.
@@ -305,7 +305,7 @@ const SITE_URL = process.env.OPENROUTER_SITE_URL || 'https://logwhisperer.ai';
const APP_NAME = process.env.OPENROUTER_APP_NAME || 'LogWhispererAI';
// System Prompt (incollare qui il SYSTEM_PROMPT completo)
const SYSTEM_PROMPT = `Sei LogWhisperer AI...`;
const SYSTEM_PROMPT = `Sei LogWhispererAI...`;
// Input dal nodo precedente
const inputData = $input.first().json;

View File

@@ -1,6 +1,6 @@
# Sprint 1 Verification Report
**Progetto:** LogWhisperer AI
**Progetto:** LogWhispererAI
**Sprint:** 1 - Log Ingestion Script
**Data Verifica:** 2026-04-02
**Verificatore:** OpenCode Agent
@@ -38,7 +38,7 @@
## 1. Overview
Questo documento certifica il completamento dello Sprint 1 del progetto LogWhisperer AI. Lo sprint aveva come obiettivo la creazione di uno script Bash per l'ingestion dei log di sistema, seguendo la metodologia TDD (Test-Driven Development) e il Metodo Sacchi.
Questo documento certifica il completamento dello Sprint 1 del progetto LogWhispererAI. Lo sprint aveva come obiettivo la creazione di uno script Bash per l'ingestion dei log di sistema, seguendo la metodologia TDD (Test-Driven Development) e il Metodo Sacchi.
---

192
docs/tools_fake_backend.md Normal file
View File

@@ -0,0 +1,192 @@
# Fake Backend Tool
> **Strumento di sviluppo per simulare risposte API AI**
>
> Scopo: Permettere lo sviluppo e il testing del frontend senza dipendere dal backend reale o dalle API di OpenRouter.
---
## 📋 Descrizione
Il `fake-backend` è un server Node.js/Express che simula le risposte dell'API di LogWhispererAI. È progettato per:
- **Sviluppo UI**: Testare l'interfaccia utente con risposte realistiche
- **Demo offline**: Mostrare il prodotto senza connessione internet
- **Testing**: Validare il flusso frontend senza costi API
- **Onboarding**: Permettere ai nuovi sviluppatori di lavorare subito
---
## 🚀 Endpoint API
### POST /api/analyze
Analizza un log e restituisce una risposta AI simulata.
**Request:**
```http
POST http://localhost:3000/api/analyze
Content-Type: application/json
{
"log": "FATAL: database system is out of memory"
}
```
**Response (dopo 1.5s delay):**
```json
{
"success": true,
"analysis": {
"title": "PostgreSQL Out of Memory",
"description": "Il database ha esaurito la memoria disponibile...",
"command": "ps aux | grep postgres | head -5 && free -h",
"isSafe": true,
"note": "Verifica processi Postgres e memoria disponibile."
},
"timestamp": "2026-04-03T10:30:00.000Z"
}
```
**Errori gestiti:**
- `400 Bad Request`: Payload vuoto o malformato
- `500 Internal Error`: Errore server generico
---
## 🛠️ Setup
### Prerequisiti
- Node.js 18+
- npm 9+
### Installazione
```bash
# Entra nella directory
cd tools/fake-backend
# Installa dipendenze
npm install
# Avvia il server
node server.js
```
Il server sarà disponibile su `http://localhost:3000`
---
## 🐳 Docker
Per avviare il fake backend con Docker:
```bash
# Dalla root del progetto
docker compose up fake-backend -d
```
Il servizio sarà esposto sulla porta 3000.
---
## 🔧 Configurazione
Variabili ambiente (opzionali):
```bash
PORT=3000 # Porta server (default: 3000)
DELAY_MS=1500 # Delay simulazione AI (default: 1500ms)
```
---
## 📁 Struttura
```
tools/fake-backend/
├── server.js # Server Express principale
├── package.json # Dipendenze npm
├── Dockerfile # Containerizzazione
└── README.md # Questo file
```
---
## 🔒 Sicurezza
⚠️ **ATTENZIONE**: Questo è uno strumento di sviluppo. NON usarlo in produzione:
- Nessuna autenticazione implementata
- Risposte statiche predefinite
- Nessuna validazione input avanzata
- CORS abilitato per tutte le origini
---
## 🧪 Test Manuale
```bash
# Test endpoint analyze
curl -X POST http://localhost:3000/api/analyze \
-H "Content-Type: application/json" \
-d '{"log": "Error: Connection refused"}'
```
---
## 📝 Note per Sviluppatori
### Aggiungere nuove risposte mock
Modifica l'oggetto `MOCK_RESPONSES` in `server.js`:
```javascript
const MOCK_RESPONSES = {
'errore-specifico': {
title: 'Titolo Problema',
description: 'Descrizione...',
command: 'comando-da-eseguire',
isSafe: true,
note: 'Nota aggiuntiva'
}
};
```
### Pattern matching
Il server cerca keyword nel log e restituisce la risposta appropriata:
- "memory" / "oom" → PostgreSQL OOM
- "connection refused" / "502" → Nginx/Connection error
- Default → Risposta generica
---
## 🤝 Integrazione Frontend
Per usare il fake backend dal frontend React:
```typescript
const analyzeLog = async (log: string) => {
const response = await fetch('http://localhost:3000/api/analyze', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ log })
});
return response.json();
};
```
---
## 🔄 Passaggio a Backend Reale
Quando il backend reale è pronto:
1. Aggiorna l'URL in `InteractiveDemo.tsx`
2. Aggiungi autenticazione (JWT/API Key)
3. Rimuovi CORS permissivo
4. Implementa rate limiting
---
*Strumento creato seguendo il principio "Safety First" del Metodo Sacchi*

View File

@@ -1,4 +1,4 @@
# Dockerfile.dev - Development container for LogWhisperer AI Frontend
# Dockerfile.dev - Development container for LogWhispererAI Frontend
# Optimized for Node.js with Hot Module Replacement (HMR)
FROM node:20-alpine

View File

@@ -53,7 +53,7 @@ export const Footer: React.FC = () => {
<div className="flex items-center gap-2 mb-4">
<span className="text-2xl">🌌</span>
<span className="text-xl font-bold text-white tracking-tight">
LogWhisperer AI
LogWhispererAI
</span>
</div>
<p className="text-slate-400 text-sm leading-relaxed mb-6">
@@ -226,7 +226,7 @@ export const Footer: React.FC = () => {
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div className="flex flex-col sm:flex-row items-center justify-between gap-4">
<p className="text-slate-500 text-sm">
© {currentYear} LogWhisperer AI. Tutti i diritti riservati.
© {currentYear} LogWhispererAI. Tutti i diritti riservati.
</p>
<p className="text-slate-600 text-xs">
Made with by Luca Sacchi Ricciardi

View File

@@ -12,7 +12,7 @@ export const Navbar: React.FC<NavbarProps> = ({ onCtaClick }) => {
<div className="flex items-center gap-2">
<span className="text-2xl">🌌</span>
<span className="text-xl font-bold text-slate-900 tracking-tight">
LogWhisperer AI
LogWhispererAI
</span>
</div>
@@ -20,7 +20,7 @@ export const Navbar: React.FC<NavbarProps> = ({ onCtaClick }) => {
<button
onClick={onCtaClick}
className="px-5 py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold rounded-lg transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 text-sm sm:text-base"
aria-label="Inizia gratis con LogWhisperer AI"
aria-label="Inizia gratis con LogWhispererAI"
>
Inizia Gratis
</button>

View File

@@ -49,7 +49,7 @@ export const Hero: React.FC<HeroProps> = ({
<button
onClick={onSecondaryCtaClick}
className="w-full sm:w-auto px-8 py-4 bg-white hover:bg-slate-50 text-slate-700 font-semibold rounded-xl border-2 border-slate-200 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 text-lg"
aria-label="Guarda la demo di LogWhisperer AI"
aria-label="Guarda la demo di LogWhispererAI"
>
Guarda la Demo
</button>

View File

@@ -1,85 +1,34 @@
import React, { useState } from 'react';
import { Terminal, Copy, Check, Loader2, AlertCircle, Activity } from 'lucide-react';
import { Terminal, Copy, Check, Loader2, AlertCircle, Activity, Server, Globe, Code } from 'lucide-react';
// Mock data for demo logs
// Demo log presets - only the content, not the analysis
const DEMO_LOGS = [
{
id: 'postgres-oom',
label: 'PostgreSQL OOM',
icon: <Database className="w-4 h-4" />,
icon: Server,
logContent: `FATAL: database system is out of memory
DETAIL: Failed on request of size 8192
HINT: Check memory usage and limits
CONTEXT: automatic vacuum of table "public.events"`,
analysis: {
title: 'PostgreSQL Out of Memory',
description: 'Il database ha esaurito la memoria disponibile durante un\'operazione di vacuum automatico su una tabella molto grande.',
command: 'ps aux | grep postgres | head -5 && free -h',
isSafe: true,
note: 'Verifica processi Postgres e memoria disponibile. Se necessario, aumenta work_mem o shared_buffers.',
},
},
{
id: 'nginx-502',
label: 'Nginx 502 Bad Gateway',
icon: <Globe className="w-4 h-4" />,
icon: Globe,
logContent: `2024/01/15 14:32:15 [error] 1234#1234: *56789 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.100, server: api.example.com, upstream: "127.0.0.1:3000"`,
analysis: {
title: 'Nginx 502 - Backend Non Raggiungibile',
description: 'Nginx non riesce a connettersi al backend sulla porta 3000. Probabilmente il servizio è down.',
command: 'sudo systemctl status app-service && netstat -tlnp | grep 3000',
isSafe: true,
note: 'Verifica stato del servizio backend. Se stopped, avvia con: sudo systemctl start app-service',
},
},
{
id: 'node-exception',
label: 'Node.js Exception',
icon: <Code className="w-4 h-4" />,
icon: Code,
logContent: `Error: connect ECONNREFUSED 127.0.0.1:5432
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16)
at emitErrorNT (internal/streams/destroy.js:92:8)
at processTicksAndRejections (internal/process/task_queues.js:80:21)`,
analysis: {
title: 'Node.js - Connessione Database Rifiutata',
description: 'L\'applicazione Node non riesce a connettersi al database PostgreSQL sulla porta 5432.',
command: 'sudo systemctl status postgresql && sudo netstat -tlnp | grep 5432',
isSafe: true,
note: 'Verifica che PostgreSQL sia in esecuzione. Se down, avvia con: sudo systemctl start postgresql',
},
},
];
// Icon components
function Database(props: React.SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<ellipse cx="12" cy="5" rx="9" ry="3" />
<path d="M3 5V19A9 3 0 0 0 21 19V5" />
<path d="M3 12A9 3 0 0 0 21 12" />
</svg>
);
}
function Globe(props: React.SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" />
<line x1="2" y1="12" x2="22" y2="12" />
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
</svg>
);
}
function Code(props: React.SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polyline points="16 18 22 12 16 6" />
<polyline points="8 6 2 12 8 18" />
</svg>
);
}
interface LogAnalysis {
title: string;
description: string;
@@ -88,26 +37,60 @@ interface LogAnalysis {
note: string;
}
interface ApiResponse {
success: boolean;
analysis: LogAnalysis & { originalLog?: string };
meta?: {
processingTime: string;
model: string;
timestamp: string;
};
error?: string;
message?: string;
}
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000';
export const InteractiveDemo: React.FC = () => {
const [selectedLog, setSelectedLog] = useState<string | null>(null);
const [isAnalyzing, setIsAnalyzing] = useState(false);
const [analysis, setAnalysis] = useState<LogAnalysis | null>(null);
const [copied, setCopied] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleLogSelect = async (logId: string) => {
const logData = DEMO_LOGS.find((l) => l.id === logId);
if (!logData) return;
const handleLogSelect = (logId: string) => {
setSelectedLog(logId);
setIsAnalyzing(true);
setAnalysis(null);
setCopied(false);
setError(null);
// Simulate AI analysis delay
setTimeout(() => {
const log = DEMO_LOGS.find((l) => l.id === logId);
if (log) {
setAnalysis(log.analysis);
try {
// Real API call to fake-backend
const response = await fetch(`${API_URL}/api/analyze`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ log: logData.logContent }),
});
const data: ApiResponse = await response.json();
if (!response.ok || !data.success) {
throw new Error(data.message || `HTTP error! status: ${response.status}`);
}
setAnalysis(data.analysis);
} catch (err) {
console.error('API Error:', err);
setError(err instanceof Error ? err.message : 'Errore durante l\'analisi. Verifica che il backend sia attivo.');
} finally {
setIsAnalyzing(false);
}
}, 1500);
};
const handleCopyCommand = () => {
@@ -119,6 +102,7 @@ export const InteractiveDemo: React.FC = () => {
};
const selectedLogData = DEMO_LOGS.find((l) => l.id === selectedLog);
const SelectedIcon = selectedLogData?.icon || Terminal;
return (
<section id="demo-interattiva" className="w-full py-24 lg:py-32 bg-white" aria-labelledby="demo-heading">
@@ -131,6 +115,9 @@ export const InteractiveDemo: React.FC = () => {
<p className="text-lg text-slate-600 max-w-2xl mx-auto">
Seleziona un log di esempio e vedi come l'AI lo trasforma in un comando risolutivo in pochi secondi.
</p>
<p className="text-sm text-slate-500 mt-2">
Backend: <code className="bg-slate-100 px-2 py-1 rounded">{API_URL}</code>
</p>
</div>
{/* Two Column Layout */}
@@ -154,7 +141,9 @@ export const InteractiveDemo: React.FC = () => {
<div className="p-4 border-b border-slate-700">
<p className="text-slate-400 text-sm mb-3">Seleziona un log di esempio:</p>
<div className="flex flex-wrap gap-2">
{DEMO_LOGS.map((log) => (
{DEMO_LOGS.map((log) => {
const IconComponent = log.icon;
return (
<button
key={log.id}
onClick={() => handleLogSelect(log.id)}
@@ -166,10 +155,11 @@ export const InteractiveDemo: React.FC = () => {
} disabled:opacity-50 disabled:cursor-not-allowed`}
aria-pressed={selectedLog === log.id}
>
{log.icon}
<IconComponent className="w-4 h-4" />
{log.label}
</button>
))}
);
})}
</div>
</div>
@@ -197,7 +187,7 @@ export const InteractiveDemo: React.FC = () => {
aria-live="polite"
aria-atomic="true"
>
{!selectedLog && !isAnalyzing && !analysis && (
{!selectedLog && !isAnalyzing && !analysis && !error && (
<div className="h-full flex flex-col items-center justify-center text-center text-slate-400">
<Activity className="w-16 h-16 mb-4 opacity-50" aria-hidden="true" />
<p className="text-lg">L'output dell'analisi apparirà qui</p>
@@ -218,12 +208,24 @@ export const InteractiveDemo: React.FC = () => {
</div>
)}
{analysis && !isAnalyzing && (
{error && !isAnalyzing && (
<div className="h-full flex flex-col items-center justify-center text-center">
<AlertCircle className="w-16 h-16 mb-4 text-red-500" aria-hidden="true" />
<p className="text-lg font-medium text-red-700 mb-2">Errore</p>
<p className="text-sm text-slate-600 mb-4">{error}</p>
<p className="text-xs text-slate-500">
Assicurati che il fake-backend sia in esecuzione:<br />
<code className="bg-slate-200 px-2 py-1 rounded">docker compose up fake-backend -d</code>
</p>
</div>
)}
{analysis && !isAnalyzing && !error && (
<div className="space-y-6">
{/* Analysis Header */}
<div className="flex items-start gap-3">
<div className="w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center flex-shrink-0">
<AlertCircle className="w-5 h-5 text-indigo-600" aria-hidden="true" />
<SelectedIcon className="w-5 h-5 text-indigo-600" aria-hidden="true" />
</div>
<div>
<h3 className="text-xl font-bold text-slate-900">{analysis.title}</h3>

View File

@@ -94,7 +94,7 @@ export const OnboardingWizard: React.FC<OnboardingWizardProps> = ({ onComplete }
Inizia in 3 semplici passi
</h2>
<p className="text-lg text-slate-600 max-w-2xl mx-auto">
Configura LogWhisperer AI sul tuo server in meno di 5 minuti.
Configura LogWhispererAI sul tuo server in meno di 5 minuti.
</p>
</div>
@@ -145,7 +145,7 @@ export const OnboardingWizard: React.FC<OnboardingWizardProps> = ({ onComplete }
<Rocket className="w-10 h-10 text-indigo-600" aria-hidden="true" />
</div>
<h3 className="text-2xl font-bold text-slate-900 mb-4">
Benvenuto su LogWhisperer AI
Benvenuto su LogWhispererAI
</h3>
<p className="text-slate-600 mb-6 max-w-lg mx-auto">
Il tuo assistente DevOps personale che monitora i log del server

View File

@@ -75,7 +75,7 @@ export const ProblemSolution: React.FC = () => {
🌌
</div>
<div>
<div className="font-semibold text-slate-900">LogWhisperer AI</div>
<div className="font-semibold text-slate-900">LogWhispererAI</div>
<div className="text-xs text-slate-500">Ora</div>
</div>
</div>

33
tools/fake-backend/.gitignore vendored Normal file
View File

@@ -0,0 +1,33 @@
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage/
# Logs
logs
*.log
# Environment variables
.env
.env.local
.env.*.local
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db

View File

@@ -0,0 +1,31 @@
# Dockerfile for Fake Backend
# Development mock API server for LogWhispererAI
FROM node:20-alpine
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy server code
COPY server.js ./
# Expose port 3000
EXPOSE 3000
# Set environment variables
ENV PORT=3000
ENV DELAY_MS=1500
ENV NODE_ENV=production
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => r.statusCode === 200 ? process.exit(0) : process.exit(1))"
# Start server
CMD ["node", "server.js"]

854
tools/fake-backend/package-lock.json generated Normal file
View File

@@ -0,0 +1,854 @@
{
"name": "fake-backend",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "fake-backend",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"cors": "^2.8.6",
"express": "^5.2.1"
}
},
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
"license": "MIT",
"dependencies": {
"mime-types": "^3.0.0",
"negotiator": "^1.0.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/body-parser": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
"integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
"license": "MIT",
"dependencies": {
"bytes": "^3.1.2",
"content-type": "^1.0.5",
"debug": "^4.4.3",
"http-errors": "^2.0.0",
"iconv-lite": "^0.7.0",
"on-finished": "^2.4.1",
"qs": "^6.14.1",
"raw-body": "^3.0.1",
"type-is": "^2.0.1"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/content-disposition": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
"integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie-signature": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
"license": "MIT",
"engines": {
"node": ">=6.6.0"
}
},
"node_modules/cors": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
"integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"license": "MIT"
},
"node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"license": "MIT",
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.1",
"content-disposition": "^1.0.0",
"content-type": "^1.0.5",
"cookie": "^0.7.1",
"cookie-signature": "^1.2.1",
"debug": "^4.4.0",
"depd": "^2.0.0",
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"etag": "^1.8.1",
"finalhandler": "^2.1.0",
"fresh": "^2.0.0",
"http-errors": "^2.0.0",
"merge-descriptors": "^2.0.0",
"mime-types": "^3.0.0",
"on-finished": "^2.4.1",
"once": "^1.4.0",
"parseurl": "^1.3.3",
"proxy-addr": "^2.0.7",
"qs": "^6.14.0",
"range-parser": "^1.2.1",
"router": "^2.2.0",
"send": "^1.1.0",
"serve-static": "^2.2.0",
"statuses": "^2.0.1",
"type-is": "^2.0.1",
"vary": "^1.1.2"
},
"engines": {
"node": ">= 18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/finalhandler": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
"integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.0",
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"on-finished": "^2.4.1",
"parseurl": "^1.3.3",
"statuses": "^2.0.1"
},
"engines": {
"node": ">= 18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/fresh": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/http-errors": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
"license": "MIT",
"dependencies": {
"depd": "~2.0.0",
"inherits": "~2.0.4",
"setprototypeof": "~1.2.0",
"statuses": "~2.0.2",
"toidentifier": "~1.0.1"
},
"engines": {
"node": ">= 0.8"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/iconv-lite": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/is-promise": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/media-typer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/merge-descriptors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
"license": "MIT",
"dependencies": {
"mime-db": "^1.54.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/negotiator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"license": "ISC",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/path-to-regexp": {
"version": "8.4.2",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
"integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"license": "MIT",
"dependencies": {
"forwarded": "0.2.0",
"ipaddr.js": "1.9.1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/qs": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
"integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/raw-body": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
"license": "MIT",
"dependencies": {
"bytes": "~3.1.2",
"http-errors": "~2.0.1",
"iconv-lite": "~0.7.0",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.0",
"depd": "^2.0.0",
"is-promise": "^4.0.0",
"parseurl": "^1.3.3",
"path-to-regexp": "^8.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/send": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
"integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.3",
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"etag": "^1.8.1",
"fresh": "^2.0.0",
"http-errors": "^2.0.1",
"mime-types": "^3.0.2",
"ms": "^2.1.3",
"on-finished": "^2.4.1",
"range-parser": "^1.2.1",
"statuses": "^2.0.2"
},
"engines": {
"node": ">= 18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/serve-static": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
"integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
"license": "MIT",
"dependencies": {
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"parseurl": "^1.3.3",
"send": "^1.2.0"
},
"engines": {
"node": ">= 18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
"node_modules/side-channel": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3",
"side-channel-list": "^1.0.0",
"side-channel-map": "^1.0.1",
"side-channel-weakmap": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-list": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-map": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-weakmap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3",
"side-channel-map": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/statuses": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"license": "MIT",
"engines": {
"node": ">=0.6"
}
},
"node_modules/type-is": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
"license": "MIT",
"dependencies": {
"content-type": "^1.0.5",
"media-typer": "^1.1.0",
"mime-types": "^3.0.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"license": "ISC"
}
}
}

View File

@@ -0,0 +1,17 @@
{
"name": "fake-backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"cors": "^2.8.6",
"express": "^5.2.1"
}
}

View File

@@ -0,0 +1,224 @@
/**
* Fake Backend Server for LogWhispererAI
*
* Simulates AI analysis responses for frontend development
* without requiring real backend or OpenRouter API calls.
*
* @author LogWhispererAI Team
* @version 1.0.0
*/
const express = require('express');
const cors = require('cors');
const app = express();
const PORT = process.env.PORT || 3000;
const DELAY_MS = parseInt(process.env.DELAY_MS) || 1500;
// Enable CORS for all origins (development only!)
app.use(cors({
origin: '*',
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type']
}));
// Parse JSON bodies
app.use(express.json());
// Mock responses database
const MOCK_RESPONSES = {
// PostgreSQL errors
'memory': {
title: 'PostgreSQL Out of Memory',
description: 'Il database ha esaurito la memoria disponibile. Questo è spesso causato da query troppo pesanti o da un numero eccessivo di connessioni.',
command: 'ps aux | grep postgres | head -5 && free -h',
isSafe: true,
note: 'Verifica processi Postgres e memoria disponibile. Se necessario, riavvia il servizio con: sudo systemctl restart postgresql'
},
'oom': {
title: 'PostgreSQL Out of Memory',
description: 'Out Of Memory error rilevato. Il sistema ha esaurito la RAM disponibile.',
command: 'free -h && ps aux --sort=-%mem | head -10',
isSafe: true,
note: 'Identifica i processi che consumano più memoria e considera di aumentare la RAM o ottimizzare le query.'
},
// Nginx/Connection errors
'connection refused': {
title: 'Connessione al Backend Rifiutata',
description: 'Il reverse proxy (Nginx) non riesce a connettersi al backend. Il servizio potrebbe essere down.',
command: 'sudo systemctl status app-service && netstat -tlnp | grep 3000',
isSafe: true,
note: 'Verifica che il servizio backend sia in esecuzione. Se stopped, avvia con: sudo systemctl start app-service'
},
'502': {
title: 'Nginx 502 Bad Gateway',
description: 'Nginx riceve errore dal server upstream. Il backend non risponde correttamente.',
command: 'sudo systemctl status backend && tail -n 50 /var/log/backend/error.log',
isSafe: true,
note: 'Controlla i log del backend per errori specifici. Potrebbe essere necessario un riavvio.'
},
// Node.js errors
'econnrefused': {
title: 'Node.js - Connessione Database Rifiutata',
description: 'L\'applicazione Node non riesce a connettersi al database PostgreSQL sulla porta 5432.',
command: 'sudo systemctl status postgresql && sudo netstat -tlnp | grep 5432',
isSafe: true,
note: 'Verifica che PostgreSQL sia in esecuzione. Se down, avvia con: sudo systemctl start postgresql'
},
'exception': {
title: 'Node.js Exception',
description: 'Eccezione non gestita nell\'applicazione Node.js. Potrebbe essere un errore di connessione o configurazione.',
command: 'pm2 logs app --lines 50',
isSafe: true,
note: 'Controlla i log dell\'applicazione per l\'errore completo. Usa pm2 restart app se necessario.'
},
// Disk errors
'disk': {
title: 'Spazio su Disco Esaurito',
description: 'Il filesystem ha raggiunto il 100% di utilizzo. Nessuna scrittura possibile.',
command: 'df -h && du -sh /var/log/* | sort -hr | head -10',
isSafe: true,
note: 'Identifica quali directory occupano più spazio. Pulisci log vecchi con: sudo find /var/log -name "*.log" -mtime +7 -delete'
},
'no space': {
title: 'Spazio su Disco Esaurito',
description: 'Spazio insufficiente sul disco. Impossibile scrivere nuovi dati.',
command: 'df -h && du -sh /tmp /var/log /var/cache',
isSafe: true,
note: 'Libera spazio eliminando file temporanei o log vecchi.'
}
};
// Default response for unknown errors
const DEFAULT_RESPONSE = {
title: 'Errore di Sistema',
description: 'È stato rilevato un errore nel log. L\'analisi suggerisce di verificare lo stato dei servizi e le risorse di sistema.',
command: 'sudo systemctl status && df -h && free -h',
isSafe: true,
note: 'Esegui il comando sopra per verificare lo stato generale del sistema. Se il problema persiste, controlla i log specifici del servizio.'
};
/**
* Find matching mock response based on log content
* @param {string} logContent - The log content to analyze
* @returns {object} - Matching response or default
*/
function findMockResponse(logContent) {
const logLower = logContent.toLowerCase();
for (const [keyword, response] of Object.entries(MOCK_RESPONSES)) {
if (logLower.includes(keyword.toLowerCase())) {
return response;
}
}
return DEFAULT_RESPONSE;
}
/**
* POST /api/analyze
* Analyze log and return AI-like response
*/
app.post('/api/analyze', (req, res) => {
const { log } = req.body;
// Validate input
if (!log || typeof log !== 'string' || log.trim().length === 0) {
return res.status(400).json({
success: false,
error: 'Bad Request',
message: 'Il campo "log" è richiesto e non può essere vuoto',
timestamp: new Date().toISOString()
});
}
// Simulate AI processing delay
setTimeout(() => {
try {
const analysis = findMockResponse(log);
res.json({
success: true,
analysis: {
...analysis,
originalLog: log.substring(0, 500) // Include first 500 chars for reference
},
meta: {
processingTime: `${DELAY_MS}ms`,
model: 'fake-backend-mock-v1',
timestamp: new Date().toISOString()
}
});
} catch (error) {
console.error('Error processing request:', error);
res.status(500).json({
success: false,
error: 'Internal Server Error',
message: 'Errore durante l\'analisi del log',
timestamp: new Date().toISOString()
});
}
}, DELAY_MS);
});
/**
* GET /health
* Health check endpoint
*/
app.get('/health', (req, res) => {
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
version: '1.0.0'
});
});
/**
* GET /
* Root endpoint with API info
*/
app.get('/', (req, res) => {
res.json({
name: 'LogWhispererAI - Fake Backend',
version: '1.0.0',
description: 'Mock API server for frontend development',
endpoints: {
'POST /api/analyze': 'Analyze log and return AI-like response',
'GET /health': 'Health check endpoint'
},
documentation: 'See docs/tools_fake_backend.md'
});
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error('Unhandled error:', err);
res.status(500).json({
success: false,
error: 'Internal Server Error',
message: 'Errore imprevisto del server',
timestamp: new Date().toISOString()
});
});
// Start server
app.listen(PORT, () => {
console.log(`
╔══════════════════════════════════════════════════════════════╗
║ LogWhispererAI - Fake Backend Server ║
║ ║
║ 🚀 Server running on http://localhost:${PORT}
║ 📖 Documentation: docs/tools_fake_backend.md ║
║ ⏱️ Simulated delay: ${DELAY_MS}ms ║
║ ║
║ Endpoints: ║
║ POST /api/analyze - Analyze log and get mock AI response ║
║ GET /health - Health check ║
║ ║
║ Press Ctrl+C to stop ║
╚══════════════════════════════════════════════════════════════╝
`);
});
module.exports = app; // Export for testing

View File

@@ -1,4 +1,4 @@
# LogWhisperer AI - Workflow n8n
# LogWhispererAI - Workflow n8n
Workflow per l'ingestion sicura dei log con validazione HMAC-SHA256.

View File

@@ -131,7 +131,7 @@ cd /home/google/Sources/LucaSacchiNet/LogWhispererAI
# Output atteso:
# ==========================================
# LogWhisperer AI - Workflow Test Suite
# LogWhispererAI - Workflow Test Suite
# Target: http://192.168.254.12:5678
# ==========================================
#

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
#!/bin/bash
#
# LogWhisperer AI - Workflow Test Script
# LogWhispererAI - Workflow Test Script
# Verifica che il workflow n8n risponda correttamente
#
@@ -205,7 +205,7 @@ EOF
# Main
main() {
echo "=========================================="
echo "LogWhisperer AI - Workflow Test Suite"
echo "LogWhispererAI - Workflow Test Suite"
echo "Target: ${N8N_URL}"
echo "=========================================="
echo ""