☁️ TrubaxCloud Docs

Backend self-hosted stile Firebase. Auth, Database, Storage, Cloud Functions, Hosting, AI Services, Security Rules e App Android in un unico server Node.js.

Node.jsSQLiteREST API WebSDKReact Native SDKSSE Realtime Push NotificationsAPI KeysLLM LocaleVision AIWeb Search SmartDocument EngineDeep SearchRAG PDFVideo AIWebRTC TURN/STUNGeocodingGeofenceAttendanceNavigationUser ConsoleUser RulesApp AndroidProfile AvatarPush NotificationsDelete AccountHTTPS

📖 Introduzione

TrubaxCloud è un backend self-hosted che replica le funzionalità di Firebase: autenticazione JWT, database Firestore-like, storage file, cloud functions eseguibili via HTTP, hosting di webapp statiche e regole di sicurezza.
🔐

Authentication

JWT-based. Login, register, verifica email, reset password, sessioni persistenti.

🗃️

Firestore

Database documenti con collezioni, query, batch write e SSE realtime.

📦

Storage

Upload/download file per bucket. Base64 o binary. Metadata e statistiche.

⚡

Functions

Codice JS eseguito in sandbox isolato. fetch, env vars, async/await, Gemini AI.

🌐

Hosting

Deploy webapp statiche via file, ZIP o cartella. History e rollback istantaneo.

🔔

Messaging

Push notifications Web Push (VAPID) e polling mobile con topic e storico.

🔑

API Keys & AI

Chiavi API Firebase-style per LLM, Vision, TTS, STT e Web Search con permessi granulari.

👤

User Console

Ogni utente ha Firestore, Storage e Hosting isolati con console grafica.

🛡️

Security Rules

Regole di sicurezza JSON stile Firebase per proteggere DB e storage. Individuali per utente.

📱

App Android

Registra le tue app Android con package name e SHA-256. Associa API key per i servizi AI.

📷

Profilo & Avatar

Foto profilo, nome visualizzato, cambio password ed eliminazione account self-service. Avatar distribuito via SDK.

📦 Installare l'SDK

L'SDK Web è un singolo file JavaScript che funziona sia come script tag nel browser che come modulo Node.js/ES.

Browser (tag script)

html
<!-- Hosted direttamente su TrubaxCloud -->
<script src="http://localhost:4000/sdk/trubaxcloud.js"></script>
<script>
  const app = TrubaxCloud.initializeApp({
    url: 'http://localhost:4000'
  });
</script>

React Native / Node.js

Per React Native copia il file sdk/trubaxcloud.js nel tuo progetto come src/services/trubaxCloud.js oppure usa direttamente le API REST.
javascript
const TrubaxCloud = require('./trubaxcloud');
// oppure
import TrubaxCloud from './trubaxcloud';

const app = TrubaxCloud.initializeApp({
  url: 'http://10.0.2.2:4000' // emulatore Android
});

🚀 Quickstart

In 5 righe di codice hai autenticazione, lettura DB e chiamata a una Cloud Function.
javascript — completo
// 1. Inizializza
const app = TrubaxCloud.initializeApp({ url: 'http://localhost:4000' });

// 2. Login
const user = await app.auth.login('[email protected]', 'password123');

// 3. Leggi dal DB
const result = await app.db.collection('prodotti').doc('abc123').get();
console.log(result.doc);

// 4. Chiama una Cloud Function
const risposta = await app.functions.call('magic', { image: base64 });
console.log(risposta.analysis);

🔐 Authentication

Sistema JWT con sessioni persistenti, verifica email, reset password e listener di stato.

Registrazione e Login

Campi registrazione A differenza di Firebase, TrubaxCloud richiede username (unico), email, password e opzionalmente displayName.
// Registra nuovo utente (REST API)
const res = await fetch('/auth/register', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: 'mario_rossi',      // obbligatorio, unico
    email: '[email protected]',    // obbligatorio, unico
    password: 'password123',      // obbligatorio, min 6 caratteri
    displayName: 'Mario Rossi'    // opzionale
  })
});

// Login
const user = await app.auth.login('[email protected]', 'password');

// Logout
await app.auth.logout();

// Ascolta cambio stato auth (come Firebase)
const unsub = app.auth.onAuthStateChanged(user => {
  if (user) console.log('Loggato:', user.displayName);
  else console.log('Non autenticato');
});
unsub(); // rimuove listener

Metodi disponibili

MetodoRitornaDescrizione
auth.login(email, pass)Promise<User>Login, salva token in localStorage
auth.register(email, pass, name?)Promise<User>Registra e fa login automatico
auth.logout()Promise<void>Revoca token lato server
auth.getUser()Promise<User|null>Utente corrente dal server
auth.currentUserUser|nullUtente sincrono (può essere stale)
auth.onAuthStateChanged(cb)() => voidListener, ritorna funzione di cleanup
auth.updateProfile(data)Promise<User>Aggiorna displayName, avatar
auth.changePassword(old, new)PromiseCambio password autenticato
auth.uploadAvatar(file)PromiseUpload foto profilo (max 5MB)
auth.removeAvatar()PromiseRimuovi foto profilo
auth.deleteAccount(password)PromiseElimina account (irreversibile)

REST API diretta

POST /auth/register          { username, email, password, displayName? }
POST /auth/login             { email, password }  // email può essere anche username
POST /auth/logout            Authorization: Bearer <token>
GET  /auth/me                Authorization: Bearer <token>
PUT  /auth/me                { displayName } — aggiorna nome visualizzato
DELETE /auth/me              { password } — elimina il proprio account (irreversibile)
PUT  /auth/password           { currentPassword, newPassword }
POST /auth/me/avatar         multipart/form-data — upload foto profilo (max 5MB)
GET  /auth/avatar/:id         pubblica, cached 1h — scarica avatar utente
DELETE /auth/me/avatar        rimuovi foto profilo
POST /auth/verify             { token } — verifica token per app esterne
POST /auth/sdk/user           { appSecret, userId } — dati utente per app SDK
POST /auth/send-verification  invia email di verifica (auth)
POST /auth/verify-email       { token } — verifica email
POST /auth/reset-password     { token, newPassword } — reset password con token

🗃️ Firestore Database

Database documenti NoSQL con collezioni, documenti, query e aggiornamenti realtime via SSE. API identica a Firebase Firestore (semplificata).

CRUD documenti

const db = app.db;

// Scrivi documento
await db.collection('utenti').doc('user123').set({
  nome: 'Mario',
  eta: 30,
  createdAt: new Date().toISOString()
});

// Leggi documento
const { doc } = await db.collection('utenti').doc('user123').get();
console.log(doc.nome); // Mario

// Aggiorna (merge parziale)
await db.collection('utenti').doc('user123').update({ eta: 31 });

// Elimina
await db.collection('utenti').doc('user123').delete();

// Aggiungi con ID auto
await db.collection('log').add({ evento: 'login', timestamp: Date.now() });

Query su collezione

// Lista tutti i documenti
const { docs } = await db.collection('prodotti').get();

// Con limite
const { docs } = await db.collection('prodotti').get({ limit: 20 });

// Con filtro where (REST diretta)
GET /db/prodotti?where=[["prezzo",">","10"]]&orderBy=prezzo&order=asc&limit=50

Realtime onSnapshot

// Ascolta aggiornamenti in realtime (SSE)
const unsub = db.collection('messaggi').onSnapshot(payload => {
  console.log('Evento:', payload.type, payload.docId, payload.doc);
});

unsub(); // chiude la connessione SSE

Batch write

await db.batch([
  { type: 'set',    collection: 'items', id: 'a', data: { val: 1 } },
  { type: 'set',    collection: 'items', id: 'b', data: { val: 2 } },
  { type: 'delete', collection: 'items', id: 'c' },
]);

Admin Firestore API (Cross-User Access)

Solo Admin Questi endpoint richiedono privilegi admin (role='admin' o email in whitelist). Permettono di accedere ai dati di TUTTI gli utenti.
// Lista tutti i documenti di una collection cross-user
// Cerca in tutte le collection u_*_{collectionName}
GET /admin/firestore/:collection
// Risposta: { docs: [...], total: N }

// Leggi singolo documento (cerca in tutte le user collections)
GET /admin/firestore/:collection/:docId

// Aggiorna documento in qualsiasi user collection
PUT /admin/firestore/:collection/:docId
// Body: { campo: valore, ... }

// Elimina documento in qualsiasi user collection
DELETE /admin/firestore/:collection/:docId

// SSE Realtime: ascolta modifiche cross-user
GET /admin/firestore/:collection/_listen
// Eventi SSE: { event: 'added'|'modified'|'removed', doc: {...}, _sourceCollection: 'u_xxx_col' }

Esempio: Sistema Approvazione Operatori

// 1. Operatore crea richiesta (user-scoped)
POST /user/firestore/ideaia_operators/op_mario_rossi
{ email: '[email protected]', name: 'Mario Rossi', status: 'pending' }

// 2. Admin lista tutte le richieste pending
GET /admin/firestore/ideaia_operators
// Ritorna documenti da TUTTE le collection u_*_ideaia_operators

// 3. Admin approva operatore
PUT /admin/firestore/ideaia_operators/op_mario_rossi
{ status: 'approved', approvedBy: '[email protected]', approvedAt: '2026-05-04T...' }

// 4. Admin ascolta nuove richieste in realtime
const es = new EventSource('/admin/firestore/ideaia_operators/_listen?token=...');
es.onmessage = (e) => console.log(JSON.parse(e.data));

📦 Storage

Upload e download di file organizzati in bucket. Supporta binary, base64 e File/Blob del browser.
const storage = app.storage;

// Upload da input file del browser
const file = document.getElementById('fileInput').files[0];
await storage.ref('immagini', 'user123/avatar.jpg').upload(file, {
  contentType: 'image/jpeg'
});

// Ottieni URL di download
const url = storage.ref('immagini', 'user123/avatar.jpg').getDownloadURL();
// → http://localhost:4000/storage/immagini/user123/avatar.jpg

// Elimina file
await storage.ref('immagini', 'user123/avatar.jpg').delete();

// REST: Lista file in bucket
GET /storage-meta/immagini?prefix=user123/
Upload base64 via REST POST /storage/:bucket/:path con body { data: "<base64>", contentType: "image/jpeg" }

⚡ Cloud Functions

Funzioni JavaScript eseguite in un sandbox isolato (vm.runInContext). Supportano async/await, fetch verso API esterne, variabili d'ambiente e accesso a DB e Auth.

Creare una funzione (Admin Console)

Vai in Admin → Cloud Functions

Clicca "+ Nuova Funzione", scegli il tipo: HTTP (callable), Trigger (su evento DB/Auth/Storage) o Scheduled (periodica).

Scrivi il codice

Il codice è JavaScript normale con await. Usa context per leggere la request e response per rispondere.

Configura le Env Vars

Scroll in basso → pannello "🔑 Variabili d'Ambiente" → aggiungi le chiavi (es. GEMINI_API_KEY).

Testa con "▶️ Esegui Test"

Esegui la funzione dalla console e leggi i log in tempo reale.

API disponibili nel sandbox

// ── CONTEXT (request HTTP) ──
context.method    // GET, POST, PUT, DELETE
context.headers   // headers della richiesta
context.query     // query string params
context.body      // body JSON della richiesta
context.ip        // IP del chiamante

// ── RESPONSE ──
response.status = 200;
response.body = { messaggio: 'ok' };
response.headers['X-Custom'] = 'valore';
__result = { qualsiasi: 'oggetto' }; // per test console

// ── FETCH (API esterne) ──
const res = await fetch('https://api.esempio.com/data', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ chiave: 'valore' })
});
const data = await res.json();

// ── ENV VARS ──
const apiKey = env.get('GEMINI_API_KEY'); // da Admin → Env Vars

// ── DATABASE ──
const { doc } = await db.get('collezione', 'doc-id');
await db.set('collezione', 'doc-id', { campo: 'valore' });
const { docs } = await db.list('collezione', { limit: 10 });
await db.delete('collezione', 'doc-id');

// ── MESSAGING ──
await messaging.sendEmail('[email protected]', 'Oggetto', '<p>HTML</p>');

// ── BUFFER / BASE64 ──
const buf = Buffer.from(base64String, 'base64');
const b64 = buf.toString('base64');

Esempio: Funzione Gemini AI (MagicPics)

cloud function — tipo: HTTP, id: magic
const apiKey = env.get('GEMINI_API_KEY');
if (!apiKey) {
  response.status = 500;
  response.body = { error: 'GEMINI_API_KEY non configurata' };
  return;
}
const { image, mimeType } = context.body || {};
const geminiRes = await fetch(
  `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${apiKey}`,
  { method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ contents: [{ parts: [
      { text: 'Descrivi questa immagine in italiano' },
      { inline_data: { mime_type: mimeType, data: image } }
    ]}]})
  }
);
const result = await geminiRes.json();
const text = result.candidates?.[0]?.content?.parts?.[0]?.text;
response.status = 200;
response.body = { success: true, analysis: text };

Endpoint pubblica

// Chiama funzione HTTP pubblica
POST /fn/<id-funzione>
Content-Type: application/json
{ "campo": "valore" }

// Via SDK
const res = await app.functions.call('magic', { image: base64 });

🌐 Hosting

Deploy di webapp statiche (HTML/CSS/JS, React build, Vue dist, ecc.) con history dei deploy e rollback istantaneo. Ogni sito è servito a /sites/:slug/.

Metodi di deploy

3 modi per deployare 1. Admin Console (consigliato): trascina il file ZIP o seleziona la cartella
2. Script Node.js: leggi i file e chiama la REST API
3. curl / API: upload ZIP diretto via HTTP

1 — Deploy via Admin Console (drag & drop)

Apri Admin → Hosting

Clicca sul sito di destinazione oppure crea un nuovo sito con "+ Nuovo Sito".

Trascina il file ZIP o la cartella

Puoi trascinare un file .zip oppure selezionare una cartella intera con il pulsante "📁 Cartella".

Guarda il progresso

Il pannello mostra in tempo reale: Upload → Estrazione → Deploy → ✅ Live.

2 — Deploy via script (come deploy-landing.js)

javascript — deploy-script.js
const fs = require('fs');
const CLOUD_URL = 'http://localhost:4000';

// 1. Login admin
const { token } = await (await fetch(`${CLOUD_URL}/auth/login`, {
  method: 'POST', headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: '[email protected]', password: 'password' })
})).json();

// 2. Deploy file HTML singolo
await fetch(`${CLOUD_URL}/hosting/mio-sito/deploy`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    message: 'Deploy v1.0',
    files: [
      { path: 'index.html', content: fs.readFileSync('./dist/index.html', 'utf8') },
      { path: 'style.css',  content: fs.readFileSync('./dist/style.css', 'utf8') },
    ]
  })
});

3 — Deploy ZIP via curl

shell
# Zippa la cartella dist/
zip -r dist.zip dist/

# Ottieni il token
TOKEN=$(curl -s -X POST http://localhost:4000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"password"}' | jq -r .token)

# Deploy ZIP
curl -X POST http://localhost:4000/hosting/mio-sito/deploy-zip \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/zip" \
  -H "X-Deploy-Message: Deploy v1.0" \
  --data-binary @dist.zip
Nota sul prefisso ZIP Se il ZIP contiene una cartella radice (es. dist/), il sistema la strip automaticamente. I file vengono serviti dalla root del sito.

Rollback

// Via Admin Console: sezione "📋 Deploy History" → clicca "↩️ Rollback"
// Via API:
POST /hosting/:id/rollback
{ "deployId": "deploy_1700000000000" }

🔔 Messaging

Sistema di notifiche push e in-app. Invia notifiche a dispositivi registrati con Web Push (VAPID) o polling. Supporta topic per segmentare gli utenti.

Concetti chiave

📲

Subscription

I dispositivi si registrano con un endpoint push e i topic di interesse.

📤

Send

L'admin invia una notifica che viene salvata e pushata ai dispositivi.

🏷️

Topics

Segmenta le notifiche: all, updates, alerts, promo.

📡

Polling

Per mobile nativo, chiama /messaging/poll ogni 30s per ricevere le ultime notifiche.

Registrare un dispositivo

// Web Push — registra il service worker e invia la subscription
POST /messaging/subscribe
Authorization: Bearer <token>
{
  "subscription": { // PushSubscription dal browser
    "endpoint": "https://fcm.googleapis.com/...",
    "keys": { "auth": "...", "p256dh": "..." }
  },
  "topics": ["all", "updates"]
}

Polling (React Native / Mobile)

// Chiama ogni 30s per nuove notifiche
GET /messaging/poll?since=2025-01-01T00:00:00Z&topics=all,updates
Authorization: Bearer <token>

// Risposta
{
  "notifications": [
    { "id": "...", "title": "Update", "body": "Nuova versione!", "topic": "updates" }
  ]
}

Inviare notifica (Admin)

POST /messaging/send
Authorization: Bearer <admin-token>
{
  "title": "Aggiornamento v2.0",
  "body": "Nuove funzionalità disponibili!",
  "topic": "updates",
  "url": "https://tuodominio.com/changelog",
  "icon": "/favicon.ico"
}

// Risposta
{ "success": true, "push": { "sent": 12, "errors": 0 } }

SDK (esempio mobile)

// React Native — polling-based
const TrubaxMessaging = {
  async poll(since, topics = ['all']) {
    const qs = `since=${since}&topics=${topics.join(',')}`;
    const res = await fetch(`${CLOUD_URL}/messaging/poll?${qs}`, {
      headers: { Authorization: `Bearer ${token}` }
    });
    return res.json();
  }
};

🔑 API Keys & AI Services

Sistema di chiavi API stile Firebase per accedere ai servizi AI di TrubaxCloud: LLM locale (Ollama), Vision, TTS, STT e Web Search. Ogni chiave ha permessi granulari per servizio, scadenza configurabile e tracking utilizzo.

Concetti chiave

🔑

API Key

Formato tc_live_ + 48 hex chars. Univoca per utente. Gestibile da dashboard o admin.

⚙

Servizi

Ogni chiave abilita servizi specifici: LLM, Vision, TTS, STT, Web Search. Configurabili singolarmente.

⏰

Scadenza

Default: mai. Configurabile a 7, 30, 90, 365 giorni. Chiavi scadute rifiutate automaticamente.

📊

Tracking

Contatore utilizzi, ultimo uso, proprietario. Admin vede tutte le chiavi, utenti solo le proprie.

Autenticazione con API Key

http headers
// Metodo 1: Header x-api-key
x-api-key: tc_live_abc123def456...

// Metodo 2: Bearer token
Authorization: Bearer tc_live_abc123def456...

// Metodo 3: JWT utente (dalla dashboard)
Authorization: Bearer eyJhbGciOi...

Gestione chiavi (REST API)

// Genera nuova chiave (qualsiasi utente autenticato)
POST /api/keys/generate
Authorization: Bearer <token>
{
  "name": "Idea IA Produzione",
  "services": {              // opzionale, default: tutti abilitati
    "llm": true,
    "vision": true,
    "tts": false,
    "stt": false,
    "webSearch": true
  },
  "expiresAt": null          // null = mai, oppure ISO date string
}

// Risposta
{
  "success": true,
  "apiKey": {
    "id": "uuid-xxx",
    "key": "tc_live_abc123def456...",  // mostrata UNA VOLTA sola
    "name": "Idea IA Produzione",
    "services": { ... },
    "enabled": true,
    "expiresAt": null
  }
}

Endpoint gestione chiavi

EndpointMetodoDescrizione
POST /api/keys/generatePOSTGenera nuova chiave (auth utente)
GET /api/keys/listGETLista chiavi (admin: tutte, user: proprie)
GET /api/keys/reveal/:idGETRivela chiave completa (owner/admin)
PUT /api/keys/update/:idPUTAggiorna nome, servizi, scadenza
PUT /api/keys/toggle/:idPUTAbilita/disabilita chiave
DELETE /api/keys/client/:idDELETEElimina chiave (owner/admin)

Servizi AI disponibili

LLM Chat (testo)

POST /api/ai/chat
x-api-key: tc_live_xxx
{
  "messages": [
    { "role": "user", "content": "Cos'e un interruttore differenziale?" }
  ],
  "model": "qwen3:8b",           // opzionale, default: auto-fallback
  "temperature": 0.7,            // opzionale
  "maxTokens": 2048              // opzionale
}

// Modelli disponibili: llama3.1:8b (default), qwen2.5-coder:7b, qwen3:8b, deepseek-r1:8b
// Il sistema prova i modelli in sequenza fino a trovarne uno disponibile (fallback automatico)

Vision (analisi immagini)

POST /api/ai/vision
x-api-key: tc_live_xxx
{
  "image": "data:image/jpeg;base64,/9j/...",  // o URL http
  "prompt": "Descrivi questa immagine"       // opzionale
}

// Modello: minicpm-v (locale via Ollama)

Web Search Smart v4.0

Cache + DDG + SerpAPI La ricerca web usa un sistema a 3 livelli: 1) cache locale (7 giorni, istantanea) → 2) DuckDuckGo con rate-limit 5s → 3) SerpAPI fallback. Le query ripetute sono servite dalla cache a costo zero. Il campo source nella risposta indica quale livello ha servito la query.
GET /api/web-search?q=TrubaxCloud&max=8
x-api-key: tc_live_xxx

// Risposta
{
  "query": "TrubaxCloud",
  "results": [
    { "title": "...", "url": "https://...", "snippet": "..." }
  ],
  "count": 8,
  "source": "cache"    // "cache" | "ddg" | "serpapi" | "none"
}

// source: indica quale livello ha servito la query
//   "cache"   → risultato dalla cache locale (0ms, gratis)
//   "ddg"     → DuckDuckGo live (rate-limited 5s tra chiamate)
//   "serpapi" → SerpAPI fallback (quando DDG è bloccato)
//   "none"    → nessun risultato disponibile

Ricerca Immagini v4.0

Richiede SerpAPI — La ricerca immagini usa esclusivamente SerpAPI. Configura la chiave nel pannello admin Server.
GET /api/web-search?q=arduino+relay&type=images&max=6
x-api-key: tc_live_xxx

// Risposta
{
  "query": "arduino relay",
  "type": "images",
  "results": [
    {
      "title": "...",
      "url": "https://...full-image.jpg",
      "thumbnail": "https://...thumb.jpg",
      "source": "example.com",
      "width": 1200,
      "height": 800
    }
  ],
  "count": 6,
  "source": "serpapi"
}

Ricerca Video v4.0

GET /api/web-search?q=come+installare+differenziale&type=videos&max=6
x-api-key: tc_live_xxx

// Risposta
{
  "query": "come installare differenziale",
  "type": "videos",
  "results": [
    {
      "title": "...",
      "url": "https://youtube.com/...",
      "thumbnail": "https://...thumb.jpg",
      "duration": "12:34",
      "source": "youtube.com",
      "snippet": "..."
    }
  ],
  "count": 6,
  "source": "serpapi"
}
Parametro type Valori ammessi: web (default), images, videos. Se omesso, la ricerca è di tipo web. Immagini e video sono serviti solo tramite SerpAPI e cachati per 7 giorni come le ricerche web.

Estrazione Documenti v4.0

Formati supportati: PDF, DOCX, XLSX, PPTX, CSV, TXT, JSON, XML, HTML. Per immagini → usa Vision. Per ZIP/APK/binari → download con metadati archivio.
GET /api/extract?url=https://example.com/manual.pdf&chunk_size=3000&chunk=0
x-api-key: tc_live_xxx

// Risposta
{
  "url": "https://example.com/manual.pdf",
  "fileType": "pdf",
  "filename": "manual.pdf",
  "size": 2456789,
  "extractable": true,
  "totalChunks": 12,
  "totalLength": 35420,
  "chunks": ["...testo chunk 0...", "...chunk 1..."],
  "hasMore": true,         // usa ?chunk=N per i successivi
  "pages": 24,
  "info": { "Title": "...", "Author": "..." }
}

Download File v4.0

GET /api/download?url=https://example.com/firmware.zip
x-api-key: tc_live_xxx

// Risposta
{
  "success": true,
  "filename": "firmware.zip",
  "fileType": "zip",
  "size": 15000000,
  "downloadUrl": "/api/download/file/dl_17...",
  "archiveContents": [
    { "name": "readme.txt", "size": 1024 },
    { "name": "firmware.bin", "size": 14000000 }
  ]
}

Deep Search (Ricerca + Analisi) v4.0

Pipeline completa: Cerca sul web → scarica le fonti → estrae il contenuto (anche da PDF e documenti) → invia tutto al LLM per un'analisi mirata con citazioni dalle fonti. Timeout 4 minuti per analisi complesse. Fallback automatico se modello richiesto fallisce.
POST /api/web-search/deep
x-api-key: tc_live_xxx
{
  "query": "manuale inverter ABB ACS580",
  "maxSources": 3,       // max 5 fonti
  "model": "qwen3:8b"    // opzionale, usa default
}

// Risposta
{
  "query": "manuale inverter ABB ACS580",
  "answer": "Dall'analisi delle fonti trovate...",
  "model": "qwen3:8b",
  "sources": [{ "title": "...", "url": "..." }],
  "extractedContent": [{
    "url": "...", "fileType": "pdf",
    "pages": 120,
    "textPreview": "...primi 500 caratteri..."
  }],
  "sourcesCount": 3
}

Stato servizi

GET /api/ai/status

// Risposta
{
  "ollama": { "available": true, "models": [...] },
  "strategy": "local-only",
  "textModels": ["llama3.1:8b", "qwen2.5-coder:7b", "qwen3:8b", "deepseek-r1:8b"],
  "defaultModel": "llama3.1:8b",  // configurabile da admin
  "visionModel": "minicpm-v",
  "apiKeys": { "total": 5, "active": 4 }
}

Esempio completo: integrazione in app

javascript
const API_KEY = 'tc_live_abc123def456...';
const BASE_URL = 'https://ketadl-trubax.ddns.net';

// Chat con LLM locale
async function askAI(question) {
  const res = await fetch(`${BASE_URL}/api/ai/chat`, {
    method: 'POST',
    headers: {
      'x-api-key': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      messages: [{ role: 'user', content: question }]
    })
  });
  const data = await res.json();
  return data.message.content;
}

// Ricerca web
async function webSearch(query) {
  const res = await fetch(
    `${BASE_URL}/api/web-search?q=${encodeURIComponent(query)}`,
    { headers: { 'x-api-key': API_KEY } }
  );
  return (await res.json()).results;
}
Servizi TTS e STT I servizi Text-to-Speech e Speech-to-Text sono predisposti nel sistema di permessi delle chiavi API. Quando saranno attivati, basterà abilitarli sulla chiave esistente senza generarne una nuova.
Sicurezza La chiave API viene mostrata una sola volta al momento della generazione. Copiala subito. Non condividere mai le chiavi in repository pubblici. Usa variabili d'ambiente nelle tue app.

📋 TODO — Integrazione Idea IA (v10.0)

Il backend è predisposto per ricevere parametri dal frontend. Ogni app decide il proprio comportamento. Il server NON standardizza il tono o la modalità — è il frontend che sceglie.

🐛 Bug noti TTS/STT

  • TTS non risponde: la risposta testuale arriva in chat ma il TTS non parte. Verificare che la chiamata TTS parta DOPO che il testo completo è arrivato, non durante lo streaming.
  • STT riaggancia prima di completare: la chiamata vocale si chiude prima che il LLM finisca di rispondere. Il timeout della sessione vocale è probabilmente troppo basso — aumentare o legarlo alla lunghezza della risposta LLM.
  • Possibile causa: il flusso streaming SSE del LLM non segnala correttamente il completamento → TTS/STT non sa quando la risposta è finita.

🔬 Integrazione Deep Search

Quando l'utente chiede di cercare qualcosa su internet, Idea IA deve usare il nuovo endpoint:

  • POST /api/web-search/deep — Cerca → Scarica fonti (anche PDF!) → Estrae contenuto → LLM analizza tutto e risponde con citazioni
  • Parametri: { query, maxSources: 3, model: "auto" }
  • La risposta contiene answer (risposta LLM analizzata) + sources + extractedContent
  • Timeout: fino a 3 minuti per ricerche complesse — mostrare indicatore di caricamento

📄 Integrazione Estrazione Documenti

  • GET /api/extract?url=...&chunk_size=3000 — Quando l'utente incolla un URL di un documento
  • Supporta: PDF, DOCX, XLSX, PPTX, CSV, TXT, JSON, XML, HTML
  • Ritorna testo a chunks — navigabili con ?chunk=0, ?chunk=1, ecc.
  • Per documenti grandi: caricare chunk per chunk e passare ogni chunk al LLM per analisi progressiva
  • Per immagini: usa /api/ai/vision con il base64 restituito

⬇️ Integrazione Download File

  • GET /api/download?url=... — Quando l'utente chiede di scaricare un file (ZIP, APK, ROM, firmware, ecc.)
  • Il file viene salvato sul server in data/downloads/
  • Ritorna downloadUrl per il download + archiveContents per gli archivi
  • Per software Windows: suggerire i link di download diretto trovati nella ricerca
  • Pulizia automatica: file più vecchi di 24h vengono rimossi con DELETE /api/download/clean

👁️ Vision AI — Immagini + Video (v5.1)

  • POST /api/ai/vision — Analisi immagini con provider: "local" (minicpm-v) o "gemini" (Gemini Flash)
  • Parametri: { prompt, image (base64), provider: "local"|"gemini" }
  • POST /api/ai/vision/video — Analisi video (max 60s, max 50MB)
  • Parametri: { video (base64), prompt, provider: "local"|"gemini" }
  • Pipeline video: FFmpeg estrae 1 frame ogni 5s (max 12) → ogni frame analizzato con Vision → LLM genera riassunto
  • Risposta video: { frameDescriptions[], summary, visionModel, summaryModel, duration, framesAnalyzed }
  • Gemini Flash è molto più dettagliato di minicpm-v per analisi immagini — usare se disponibile
  • BUG NOTO: con provider locale, se si carica un'immagine in Idea IA senza passare image in base64, il modello risponde solo come LLM testo senza vedere l'immagine. Verificare che Idea IA invii il campo image correttamente!

🌐 Provider Gemini — Integrazione Idea IA

  • Quando l'utente seleziona Google come provider in Idea IA e carica un'immagine o video:
  • → Idea IA deve passare provider: "gemini" a /api/ai/vision o /api/ai/vision/video
  • → Il backend usa Gemini 2.0 Flash (gratuito, veloce, dettagliato)
  • → Richiede geminiApiKey configurata in server-config (già fatto)
  • Quando il provider è TrubaxCloud (locale), usa minicpm-v per Vision e qwen/llama per LLM
  • IMPORTANTE: Il video analysis usa sempre FFmpeg per estrarre frame — cambia solo chi analizza ogni frame (locale vs Gemini)

🎛️ Parametri Configurabili dal Frontend (v6.0)

Il backend accetta questi parametri — ogni frontend decide come usarli. Il server non impone comportamenti.

  • /api/ai/chat accetta: { messages, model, systemInstruction, temperature, maxTokens, modalita, format }
  • temperature: 0 = notaio preciso, 0.6 = tecnico colloquiale, 0.7 = conversazionale
  • maxTokens: 150 = risposta corta, 300 = media, 2048 = lunga
  • systemInstruction = prompt di sistema custom (es: "Sei un tecnico Idea Group con 20 anni di cantiere")
  • modalita = stringa libera (es: "Tecnico", "Notaio", "DDT") — il server la logga ma NON la interpreta
  • format: "json" = forza output JSON (utile per DDT, report strutturati)
  • Fallback automatico: se il modello specificato fallisce, il server prova gli altri in ordine

📚 RAG PDF — Lettura Manuali Intelligente (v6.0)

Per quando l'utente chiede info specifiche da un manuale PDF. Il server scarica, chunka, cerca, e risponde con citazione fonte.

  • POST /api/ai/rag-pdf — { pdf_url, domanda, temperature, max_tokens, systemInstruction, model, modalita }
  • Pipeline: Download PDF → Chunk 800 char con stima pagina → Ricerca keyword → Top 5 chunks → LLM estrae risposta
  • Risposta: { risposta, fonte: { file, pagine }, model, chunks_trovati, pagine_totali, raw_chunks }
  • Cache PDF: 1 ora, max 20 PDF in memoria — non riscarica se già letto
  • Default: temperature: 0, max_tokens: 300 — preciso come un notaio
  • Il frontend può cambiare il systemInstruction per decidere se risposta secca o discorsiva
  • Idea IA uso tipico: utente chiede "coppia serraggio AC Peimar" → frontend cerca PDF via /api/web-search con filetype:pdf → passa URL a /api/ai/rag-pdf
Esempio chiamata frontend:
fetch('/api/ai/rag-pdf', { method: 'POST', body: JSON.stringify({
  pdf_url: 'https://...manuale.pdf',
  domanda: 'coppia serraggio connettore AC',
  systemInstruction: 'Rispondi da tecnico, con dato e fonte.',
  temperature: 0, max_tokens: 200
}) })

💳 NOTE PER DOMANI IN UFFICIO — Idea IA (v10.1)

CONCETTO CHIAVE: Il server è un motore — il frontend è il pilota.

Il backend predispone temperature, max_tokens, systemInstruction, modalita, format, provider. Idea IA decide come usarli. Ogni app può avere il suo comportamento.

✅ RISOLTO IN v10.1: Profilo Utente & Avatar

Ogni utente ora ha foto profilo, nome visualizzato, cambio password ed eliminazione account self-service. Avatar distribuito automaticamente via SDK a tutte le app collegate.

Integrazione per Idea IA: Quando un utente accede, user.avatar è disponibile in /auth/verify e /auth/sdk/user. Mostrare avatar nell'header dell'app.

1. Bug Vision con provider locale: Idea IA non invia image base64 a /api/ai/vision. Controllare:

  • L'immagine va convertita in base64 puro (senza data:image/...;base64,)
  • Body: { image: base64, prompt: "...", provider: "local" o "gemini" }
  • La chiamata DEVE andare a /api/ai/vision, NON a /api/ai/chat

2. Sistema modalità (gestito dal FRONTEND):

  • Tecnico: systemInstruction: "Sei Idea IA, tecnico con 20 anni cantiere. Diretto, da collega.", temperature: 0.6, maxTokens: 2048
  • Notaio: systemInstruction: "Rispondi SOLO con il dato + fonte. Zero chiacchiere.", temperature: 0, maxTokens: 2048
  • DDT: systemInstruction: "Rispondi SOLO in JSON valido.", temperature: 0, format: "json", maxTokens: 2048
  • Il campo modalita va passato per logging/tracciabilità ma il server NON lo usa per decidere il comportamento
  • IMPORTANTE: maxTokens deve SEMPRE essere 2048 (o non passato) — mai valori bassi!

3. Doppia analisi Notaio+Tecnico (frontend):

  • Quando Idea IA rileva una domanda tecnica (regex: /coppia|serraggio|errore|manuale|PSI-|E\d{3}/i):
  • → Prima chiama /api/ai/rag-pdf con temperature: 0 per dato certificato
  • → Poi chiama /api/ai/chat con il dato come contesto + temperature: 0.6 per risposta umana
  • → Tutto gestito dal frontend, il server non sa nulla della doppia analisi

4. Video + Immagini + Provider:

  • Immagini → /api/ai/vision con provider: "local"|"gemini"
  • Video (max 1 min) → /api/ai/vision/video con provider: "local"|"gemini"
  • Con Gemini: risultati più dettagliati, col locale: funziona offline

5. Modelli LLM ora:

  • llama3.1:8b (DEFAULT) — 128K context, ideale per PDF lunghi. Gira sulla 1070
  • qwen2.5-coder:7b — Veloce, buono per codice
  • qwen3:8b — Thinking mode, LENTO su contesti grandi (timeout)
  • deepseek-r1:8b — Ragionamento, ma timeout su deep search
  • minicpm-v — Solo Vision (immagini/frame video)

6. Log IA: Tutte le interazioni AI vengono loggate in data/log_ia.json (user, domanda, risposta, model, modalita). Admin può vedere: GET /api/ai/log?limit=50

7. WebRTC TURN/STUN Server (NUOVO v7.0)

Server TURN/STUN integrato in TrubaxCloud, già attivo e configurato:

  • Porta: 3478 (UDP+TCP) — firewall Windows e router GIÀ configurati
  • Porte relay: 49152-49252 (100 porte)
  • Auto-start: si avvia con il server (data/turn-config.json → enabled: true)
  • Admin panel: bottoni Start/Stop/Test nel pannello AI di admin.html

Per Idea IA — integrazione videochiamate:

// 1. Ottieni credenziali TURN/STUN
const res = await fetch('/api/webrtc/credentials', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + token }
});
const { iceServers } = await res.json();

// 2. Crea connessione WebRTC
const pc = new RTCPeerConnection({ iceServers });

// 3. Aggiungi stream audio/video
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
stream.getTracks().forEach(track => pc.addTrack(track, stream));

Endpoints: POST /api/webrtc/credentials (credenziali ICE), GET /api/webrtc/status (stato), POST /api/webrtc/start|stop (admin), GET /api/webrtc/config / PUT /api/webrtc/config (config)

8. Riepilogo completo API TrubaxCloud per Claude/Idea IA

Queste sono le API che Idea IA può usare. Claude deve conoscerle tutte per configurare correttamente il frontend:

POST /api/ai/chatChat LLM — params: messages, model, systemInstruction, temperature, maxTokens, modalita, format
POST /api/ai/visionAnalisi immagine — params: image (base64), prompt, provider (local|gemini)
POST /api/ai/vision/videoAnalisi video — params: video (base64), prompt, provider (local|gemini)
POST /api/ai/rag-pdfEstrazione PDF — params: pdf_url, domanda, temperature, max_tokens, systemInstruction
GET /api/web-searchRicerca web — params: q, max, type (web|images|videos)
POST /api/web-search/deepDeep search + LLM — params: query, maxSources, type, model
GET /api/extractEstrai documenti — params: url, chunk_size, chunk
POST /api/webrtc/credentialsCredenziali ICE per WebRTC TURN/STUN
GET /api/ai/statusStato modelli + chiavi (defaultModel, textModels[], visionModels[])
GET /api/ai/logLog interazioni IA (admin) — params: limit
GET /api/geo/geocodeGeocoding — params: q, limit
GET /api/geo/reverseReverse geocoding — params: lat, lng
GET /api/geo/routePercorso stradale (OSRM) — params: lat1, lng1, lat2, lng2
GET /api/geo/navigateNavigazione turn-by-turn — params: lat1, lng1, lat2, lng2, destName — restituisce steps[], geometry GeoJSON
POST /api/geo/geofenceCheck geofence — body: { lat, lng, zoneId? }
POST /api/geo/attendance/fullPresenze completo — body: { lat, lng, vehicleId?, action? }
GET /api/geo/attendance/summaryRiepilogo giornata — params: user, date (YYYY-MM-DD)
GET/POST/PUT/DELETE /api/geo/zonesCRUD zone geofence (admin crea, tutti leggono)

Base URL: https://ketadl-trubax.ddns.net — Auth: Authorization: Bearer <token> oppure X-API-Key: <key>

9. GEO SERVICES & PRESENZE AUTOMATICHE (NUOVO v9.0)

Sistema completo per gestione presenze operai con geofencing automatico. Idea IA Mobile deve implementare questo.

FLUSSO PRESENZE OPERAIO:

  1. Mattina 07:30 — L'operaio apre l'app → GPS automatico → POST /api/geo/attendance/full { lat, lng } → server risponde CHECK_IN + zona
  2. Durante il giorno — L'app invia posizione ogni 5-10 min (background) → server logga e traccia se in cantiere/transito/sede
  3. Dopo le 16:30 — Il server marca automaticamente STRAORDINARIO con minuti extra. Nessuna azione richiesta dall'operaio
  4. Riconsegna mezzo — L'operaio arriva in sede col furgone → POST /api/geo/attendance/full { lat, lng, vehicleId: "FIAT-001", action: "vehicle_return" }
  5. Uscita sede — POST /api/geo/attendance/full { lat, lng, action: "sede_exit" } → si registra chi esce e quando (l'ultimo chiude!)
  6. Riepilogo — Il responsabile vede: GET /api/geo/attendance/[email protected]&date=2026-04-17

SETUP ZONE (da fare domani):

  • Il responsabile crea le zone dal pannello admin (bottone 🗺️ Zone) o via API: POST /api/geo/zones { name, lat, lng, radius, type, address }
  • Tipi: sede (ufficio), cantiere (sito lavoro), magazzino (deposito)
  • Raggio default 200m — aumentare per cantieri grandi (es. 500m)
  • Si può cercare l'indirizzo con GET /api/geo/geocode?q=Via Roma 1, Napoli per ottenere lat/lng

STIMA PERCORSO + CARBURANTE:

  • GET /api/geo/route?lat1=&lng1=&lat2=&lng2= → restituisce km, minuti, stima litri e costo (8L/100km, €1.85/L)
  • Provider: OSRM (gratuito), fallback su stima Haversine
  • L'endpoint /api/geo/attendance/full calcola automaticamente travelToSede se l'operaio non è in sede

TURNI:

  • Turno: 07:30 – 16:30, 1h pausa pranzo
  • Dopo 16:30 → workStatus: "STRAORDINARIO", overtimeMinutes: N
  • Prima 07:30 → workStatus: "PRE-TURNO"
  • Config turni in WORK_CONFIG nel server (modificabile)

10. RTX 5070 futuro: Con più VRAM → modelli Vision migliori (LLaVA-34B), LLM più grandi (llama3.1:70b), e minicpm-v sostituibile con modello più potente.

⚠️ REMINDER: Queste note sono temporanee per Claude/Idea IA. Verranno rimosse quando tutto sarà integrato e stabile.


📡 WebRTC TURN/STUN Server

TrubaxCloud include un server TURN/STUN integrato per WebRTC. Permette videochiamate, screen sharing e comunicazione peer-to-peer anche attraverso NAT e firewall aziendali. Il servizio genera credenziali temporanee HMAC (RFC 5389) con scadenza configurabile.
Come funziona
STUN = dice al client il suo IP pubblico (leggero, veloce, gratis).
TURN = fa da relay quando la connessione diretta P2P fallisce (NAT simmetrici, firewall). Più pesante ma essenziale per affidabilità.

Attivazione (Admin)

Il TURN/STUN è disabilitato di default. L'admin lo attiva da API o dal pannello:

Attivare TURN/STUN
// Attivare il server TURN/STUN
POST /api/webrtc/start
Authorization: Bearer <admin_token>

// Risposta
{ "success": true, "running": true }

// Disattivare
POST /api/webrtc/stop

Ottenere credenziali ICE (Client)

Ogni client autenticato (JWT o API Key) richiede credenziali temporanee per la connessione WebRTC:

POST /api/webrtc/credentials
// Richiesta
POST /api/webrtc/credentials
Authorization: Bearer <token> | X-API-Key: <api_key>

// Risposta
{
  "iceServers": [
    { "urls": ["stun:ketadl-trubax.ddns.net:3478"] },
    {
      "urls": [
        "turn:ketadl-trubax.ddns.net:3478?transport=udp",
        "turn:ketadl-trubax.ddns.net:3478?transport=tcp"
      ],
      "username": "1713398400:[email protected]",
      "credential": "base64_hmac_password"
    }
  ],
  "ttl": 86400,
  "provider": "trubaxcloud"
}

Uso nel frontend (React Native / Web)

JavaScript — WebRTC con credenziali TrubaxCloud
// 1. Ottieni credenziali dal server
const res = await fetch('/api/webrtc/credentials', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + token }
});
const { iceServers } = await res.json();

// 2. Crea connessione WebRTC con le credenziali
const pc = new RTCPeerConnection({ iceServers });

// 3. Usa normalmente (addTrack, createOffer, etc.)
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
stream.getTracks().forEach(track => pc.addTrack(track, stream));

API Admin

MetodoEndpointDescrizione
POST/api/webrtc/credentialsGenera credenziali ICE temporanee (auth richiesta)
GET/api/webrtc/statusStato del server TURN/STUN (auth richiesta)
GET/api/webrtc/configConfigurazione completa (solo admin)
PUT/api/webrtc/configModifica configurazione (porta, realm, TTL, ecc.)
POST/api/webrtc/startAvvia il server TURN/STUN
POST/api/webrtc/stopFerma il server TURN/STUN
POST/api/webrtc/rotate-secretRuota il secret HMAC (invalida tutte le credenziali)
GET/api/webrtc/usersLista utenti TURN attivi

Configurazione

PUT /api/webrtc/config — Parametri configurabili
{
  "enabled": true,          // attiva/disattiva
  "port": 3478,             // porta STUN/TURN (standard: 3478)
  "minPort": 49152,         // range porte relay
  "maxPort": 65535,
  "realm": "ketadl-trubax.ddns.net",
  "credentialTTL": 86400    // durata credenziali in secondi (default: 24h)
}
Porte e Firewall
Il server TURN usa la porta 3478 (UDP+TCP) per signaling e le porte 49152-49252 per relay. Assicurarsi che queste porte siano aperte nel firewall/router. La porta 3478 NON passa per Caddy — è un protocollo UDP/TCP diretto, non HTTP.
Sicurezza
Le credenziali TURN sono temporanee (HMAC-SHA1, scadenza configurabile). Il secret viene generato automaticamente al primo avvio e può essere ruotato dall'admin. Ogni utente riceve credenziali uniche.

📍 Geo Services & Attendance

Geocoding, reverse geocoding, distanze, percorsi con tempo/carburante, geofencing per zone cantiere/sede, e sistema presenze automatico con rilevamento straordinari. Usa Nominatim (OpenStreetMap) e OSRM — gratis, senza API key.

Endpoint API

MetodoEndpointDescrizione
GET/api/geo/geocode?q=&limit=Indirizzo → coordinate (lat/lng)
GET/api/geo/reverse?lat=&lng=Coordinate → indirizzo completo
GET/api/geo/distance?lat1=&lng1=&lat2=&lng2=Distanza Haversine tra 2 punti
GET/api/geo/route?lat1=&lng1=&lat2=&lng2=Percorso stradale: tempo, km, stima carburante (OSRM)
GET/api/geo/navigate?lat1=&lng1=&lat2=&lng2=&destName=Navigazione turn-by-turn con indicazioni stradali + geometria GeoJSON
GET/api/geo/timezone?lat=&lng=Fuso orario approssimato da coordinate
POST/api/geo/geofenceCheck se un punto è dentro una o più zone
POST/api/geo/attendanceCheck-in/out semplice (auto-detect zona)
POST/api/geo/attendance/fullPresenze completo: overtime, mezzo, stima ritorno sede
GET/api/geo/attendance/summary?user=&date=Riepilogo giornata operaio
GET/api/geo/zonesLista zone geofence
POST/api/geo/zonesCrea zona (admin): { name, lat, lng, radius, type, address }
PUT/api/geo/zones/:idModifica zona (admin)
DELETE/api/geo/zones/:idElimina zona (admin)
GET/api/geo/log?limit=&user=Log eventi geofence (admin)

Tipi di zona

🏢
sede
Sede aziendale. Registra arrivo/uscita e riconsegna mezzi.
🏗️
cantiere
Cantiere attivo. Auto check-in quando l'operaio è nel raggio.
📦
magazzino
Punto di ritiro/deposito materiali.

Sistema presenze automatico

Turno standard: 07:30 – 16:30 (1h pausa pranzo)
Dopo le 16:30 → evento marcato STRAORDINARIO con conteggio minuti extra
Prima delle 07:30 → marcato PRE-TURNO
Event types: SEDE_PRESENT, CANTIERE_PRESENT, IN_TRANSIT, VEHICLE_RETURN, SEDE_EXIT
Veicoli: passa vehicleId + action: "vehicle_return" quando un operaio riporta il mezzo in sede
Uscita sede: action: "sede_exit" per registrare chi esce ultimo (porta aperta!)
Provider gratuiti
Geocoding: Nominatim (OpenStreetMap) — nessuna API key. Routing: OSRM (Open Source Routing Machine) — nessuna API key. Carburante: stima 8L/100km a €1.85/L.

Navigazione Turn-by-Turn (v10.0)

L'endpoint /api/geo/navigate restituisce indicazioni stradali passo-passo con icone manovra, GeoJSON per disegnare il percorso su mappa, stima carburante e tempo.
Esempio risposta /api/geo/navigate
{
  "destination": "Cantiere Via Roma",
  "distance": { "km": 12.3, "text": "12.3km" },
  "duration": { "minutes": 18, "text": "18 min" },
  "fuelEstimate": { "liters": 1.0, "costEur": 1.85 },
  "steps": [
    { "step": 1, "icon": "🚗", "instruction": "🚗 Parti su Via Napoli", "distance": { "text": "200m" } },
    { "step": 2, "icon": "➡️", "instruction": "➡️ right su SS18", "distance": { "text": "5.2km" } },
    { "step": 3, "icon": "🏁", "instruction": "🏁 Arrivo a Via Roma", "distance": { "text": "50m" } }
  ],
  "geometry": { "type": "LineString", "coordinates": [[14.23, 40.83], ...] }
}
Navigatore in Idea IA Mobile
L'app mobile chiama /api/geo/navigate, riceve gli step, e può mostrare:
1. Lista indicazioni come Google Maps (icone manovra + strada + distanza)
2. Mappa con polyline usando la geometry GeoJSON (Leaflet/MapLibre)
3. Aggiornamento live: ricalcola ogni N secondi con nuova posizione GPS
Il server fornisce i dati — il frontend renderizza la UI navigatore.
Rate limit Nominatim
Nominatim ha un rate limit di 1 richiesta/secondo. Per uso intensivo (tracking real-time di molti operai), implementare una cache lato frontend o usare un'istanza Nominatim privata.

🆚 TrubaxCloud vs Google Firebase

Confronto funzionalità per funzionalità. TrubaxCloud è 100% self-hosted e gratuito.
FunzionalitàGoogle FirebaseTrubaxCloudStato
AuthenticationFirebase Auth (OAuth, email, phone)JWT Auth (email, password, verifica email, reset)✅ Parità
Firestore DatabaseCloud Firestore (NoSQL, realtime)SQLite Firestore-like (CRUD, SSE realtime)✅ Parità
StorageCloud Storage (GCS buckets)File Storage (upload, download, list, quota)✅ Parità
Cloud FunctionsCloud Functions (Node.js, Python)Cloud Functions (JS sandbox, HTTP trigger)✅ Parità
HostingFirebase Hosting (CDN global)Self-hosted (Caddy + sites)✅ Parità
Push NotificationsFirebase Cloud Messaging (FCM)Web Push (VAPID) + Mobile polling✅ Parità
Security RulesFirestore Security RulesCustom Security Rules per collection✅ Parità
AI/MLVertex AI, ML KitLLM locale (Ollama), Gemini, Vision, Video AI, RAG PDF, Deep Search✅ Superiore
GeocodingGoogle Maps Geocoding API ($$$)Nominatim (OpenStreetMap, GRATIS)✅ Parità
Directions/NavigationGoogle Maps Directions API ($$$)OSRM turn-by-turn (GRATIS)✅ Parità
GeofencingNon integrato (servizio separato)Geofence API + zone cantiere/sede✅ Superiore
Attendance/PresenzeNon disponibileAuto check-in/out, overtime, veicoli✅ Esclusivo
WebRTC TURN/STUNNon inclusoServer TURN/STUN integrato✅ Esclusivo
Web SearchNon disponibileDuckDuckGo scraper + Deep Search AI✅ Esclusivo
AnalyticsGoogle Analytics (completo)Stats base (utenti, storage, funzioni)⚠️ Base
Remote ConfigFirebase Remote Configserver-config endpoint⚠️ Base
CrashlyticsFirebase CrashlyticsNon disponibile❌ Manca
A/B TestingFirebase A/B TestingNon disponibile❌ Manca
Dynamic LinksFirebase Dynamic Links (deprecato)Non necessario➖ N/A
Costo$0.06/100K reads, $0.18/100K writes, Maps APIs $$$€0 — GRATIS per sempre✅ Imbattibile
Risultato: 15 a parità o superiore, 2 base, 2 mancanti
TrubaxCloud offre tutto ciò che serve per app aziendali. Le 2 funzionalità mancanti (Crashlytics, A/B Testing) sono di nicchia e non bloccanti. Per le app Idea IA, TrubaxCloud è superiore a Firebase grazie a AI integrata, Geo services gratuiti e sistema presenze.

👤 User Console API

Ogni utente registrato ha la propria console dove gestisce Firestore, Storage e Hosting isolati per account. I dati sono completamente separati da quelli degli altri utenti e da quelli globali del server.

Come funziona l'isolamento

ServizioNamespaceEsempio
Firestoreu_<uid>_<collection>Utente crea "prodotti" → salvato come u_abc123_prodotti
StorageBucket user_<uid>File caricati in user_abc123
HostingCampo owner = uidL'utente vede solo i siti dove owner = il suo ID

Endpoint User Console

── USER FIRESTORE ────────────────────────────────────
GET    /user/firestore                    lista collection utente
GET    /user/firestore/:col               documenti in collection
POST   /user/firestore/:col/:docId?       crea/aggiorna documento
PUT    /user/firestore/:col/:docId        aggiorna documento
DELETE /user/firestore/:col/:docId        elimina documento
DELETE /user/firestore/:col               elimina collection

── USER STORAGE ──────────────────────────────────────
GET    /user/storage                      lista file + stats
POST   /user/storage/upload               upload file (multipart)
GET    /user/storage/file/:path           download file
DELETE /user/storage/file/:path           elimina file

── USER HOSTING ──────────────────────────────────────
GET    /user/hosting                      lista siti utente
POST   /user/hosting                      crea sito
POST   /user/hosting/:id/deploy-zip       deploy ZIP
DELETE /user/hosting/:id                  elimina sito

── USER STATS ────────────────────────────────────────
GET    /user/stats                        statistiche utente
GET    /user/notifications                notifiche utente

Esempio: creare una collection e aggiungere un documento

// 1. Crea collection aggiungendo il primo doc
const res = await fetch('/user/firestore/prodotti', {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ nome: 'Widget', prezzo: 9.99 })
});
// Documento salvato in u_<tuo-uid>_prodotti

// 2. Lista tutti i tuoi documenti
const docs = await (await fetch('/user/firestore/prodotti', {
  headers: { Authorization: `Bearer ${token}` }
})).json();
Dashboard utente Vai a /dashboard.html per la console grafica completa con sidebar, CRUD Firestore, upload Storage, deploy Hosting e gestione profilo. Funziona identicamente alla Admin Console ma con dati isolati per il tuo account.

🛡️ Security Rules

Regole JSON stile Firebase per proteggere Firestore e Storage. Definisci chi può leggere/scrivere/eliminare ogni risorsa.

Struttura regole Firestore

json — admin → security rules → firestore
{
  "rules": {
    "collections": {
      "utenti": {
        "read":   "auth",        // solo utenti autenticati
        "write":  "owner",       // solo il proprietario del doc
        "delete": "admin"        // solo admin
      },
      "prodotti": {
        "read":   "public",      // chiunque
        "write":  "admin",
        "delete": "admin"
      },
      "magicpics_history": {
        "read":   "public",
        "write":  "public"       // scritto dalle Cloud Functions
      }
    },
    "default": {
      "read":  "auth",
      "write": "admin"
    }
  }
}

Valori permission

ValoreChi può accedere
publicChiunque, anche senza token
authQualsiasi utente autenticato con token valido
ownerSolo l'utente il cui UID corrisponde al campo userId del documento
adminSolo utenti con ruolo admin
false / denyNessuno (accesso negato)

Regole utente (per-user rules)

Ogni utente puo definire le proprie regole di sicurezza per le collezioni e lo storage nel proprio namespace. Le regole utente si applicano solo ai dati isolati (u_<uid>_*).
rest api — user rules
// Leggi le tue regole
GET /user/rules
Authorization: Bearer <token>

// Aggiorna regole Firestore
PUT /user/rules/firestore
Authorization: Bearer <token>
{ "rules": "{ \"rules\": { \"*\": { \".read\": \"auth != null\", \".write\": \"auth != null\" } } }" }

// Aggiorna regole Storage
PUT /user/rules/storage
Authorization: Bearer <token>
{ "rules": "{ \"rules\": { \"*\": { \".read\": true, \".write\": \"auth != null\" } } }" }
Dashboard utente Nella sezione Security Rules della dashboard utente puoi modificare graficamente le regole Firestore e Storage con un editor di testo e salvarle con un click.

📱 Registrazione App Android

Registra le tue app Android per collegare i servizi TrubaxCloud. Inserisci il package name e opzionalmente la SHA-256 del certificato di firma. Puoi associare un'API Key per accedere ai servizi AI dall'app.

Concetti chiave

📦

Package Name

Identificativo univoco dell'app (es. com.trubax.ideaia). Deve essere unico per utente.

🔑

SHA-256

Fingerprint del certificato di firma (opzionale). Serve per verificare l'identita dell'app.

🔗

API Key

Associa un'API key per abilitare i servizi AI (LLM, Vision, Web Search) dall'app.

⚙

Dashboard

Gestisci le tue app dalla sezione "App Android" nella console utente.

Registrare un'app (REST API)

// Registra una nuova app Android
POST /user/apps/android
Authorization: Bearer <token>
{
  "appName": "Idea IA",
  "packageName": "com.trubax.ideaia",
  "sha256": "AA:BB:CC:DD:..."   // opzionale
}

// Risposta
{
  "success": true,
  "app": {
    "id": "uuid-xxx",
    "packageName": "com.trubax.ideaia",
    "appName": "Idea IA",
    "sha256": "AA:BB:CC:DD:...",
    "platform": "android",
    "apiKeyId": null
  }
}

Endpoint App Android

EndpointMetodoDescrizione
POST /user/apps/androidPOSTRegistra nuova app (auth utente)
GET /user/appsGETLista app dell'utente
PUT /user/apps/:idPUTAggiorna nome, SHA-256 o API key associata
DELETE /user/apps/:idDELETEElimina app registrata
GET /admin/appsGETLista tutte le app (solo admin)

Ottenere la SHA-256

bash — terminale Android Studio
# Debug key
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android

# Release key
keytool -list -v -keystore <percorso-keystore> -alias <alias>

# Cerca la riga: SHA256: AA:BB:CC:DD:EE:FF:...

Integrazione nell'app Android

kotlin — TrubaxCloudService.kt
object TrubaxCloud {
    private const val BASE_URL = "https://ketadl-trubax.ddns.net/cloud"
    private const val API_KEY  = "tc_live_xxx..."

    suspend fun chat(prompt: String): String {
        val client = OkHttpClient()
        val json = """{"messages":[{"role":"user","content":"$prompt"}]}"""
        val body = json.toRequestBody("application/json".toMediaType())
        val request = Request.Builder()
            .url("$BASE_URL/api/ai/chat")
            .addHeader("x-api-key", API_KEY)
            .post(body).build()
        return client.newCall(request).execute().body!!.string()
    }
}
Indirizzo HTTPS L'indirizzo HTTPS per TrubaxCloud e: https://ketadl-trubax.ddns.net/cloud/
Le API sono accessibili a: https://ketadl-trubax.ddns.net/api/ai/chat, /api/web-search, ecc.
Per KetaDL Web: https://ketadl-trubax.ddns.net

📚 SDK Web — Riferimento completo

Tutti i metodi esposti dall'SDK JavaScript browser/Node (/sdk/trubaxcloud.js).

initializeApp(config)

const app = TrubaxCloud.initializeApp({
  url: 'http://localhost:4000'  // URL del tuo server TrubaxCloud
});
// app.auth — servizio autenticazione
// app.db   — servizio database
// app.storage — servizio storage
// app.functions — servizio cloud functions

📱 SDK React Native

Per React Native usa il modulo src/services/trubaxCloud.ts già creato nel progetto MagicPics e SpotifyX. Funziona identicamente ma usa 10.0.2.2:4000 per l'emulatore Android.
typescript — src/services/trubaxCloud.ts
const CLOUD_URL = __DEV__
  ? 'http://10.0.2.2:4000'   // emulatore Android
  : 'http://ketadl-trubax.ddns.net:4000'; // produzione

export const TrubaxFunctions = {
  async call(functionId: string, data: Record<string, unknown>) {
    const res = await fetch(`${CLOUD_URL}/fn/${functionId}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    });
    return res.json();
  }
};

🔌 REST API — Riferimento

Puoi usare TrubaxCloud senza SDK, chiamando direttamente gli endpoint HTTP.
── AUTH ────────────────────────────────────────────────
POST   /auth/register          { email, password, displayName? }
POST   /auth/login             { email, password }
POST   /auth/logout            Bearer token
GET    /auth/me                Bearer token
PUT    /auth/me                Bearer token + { displayName }
DELETE /auth/me                Bearer token + { password } elimina account
PUT    /auth/password          { currentPassword, newPassword }
POST   /auth/me/avatar         multipart upload foto profilo (max 5MB)
GET    /auth/avatar/:id        scarica avatar utente (pubblico, cached 1h)
DELETE /auth/me/avatar         rimuovi foto profilo
POST   /auth/verify            { token, appSecret? } → user info + avatar (per SDK)
POST   /auth/sdk/user          { appSecret, userId } → dati utente per app SDK
POST   /auth/send-verification  invia email di verifica (auth)
POST   /auth/verify-email       { token } — verifica email
GET    /auth/verify-email       ?token= — verifica via link email
POST   /auth/reset-password     { token, newPassword } — reset con token admin

── FIRESTORE ────────────────────────────────────────────
GET    /db/:collection                ?limit=&orderBy=&where=[]
GET    /db/:collection/:docId
PUT    /db/:collection/:docId         body = documento JSON
DELETE /db/:collection/:docId
POST   /db/_batch                     { ops: [{type,collection,id,data}] }
GET    /db/:collection/_listen        SSE stream

── STORAGE ──────────────────────────────────────────────
POST   /storage/:bucket/:path         { data: base64, contentType }
GET    /storage/:bucket/:path         → file binario
DELETE /storage/:bucket/:path
GET    /storage-meta/:bucket          ?prefix=

── CLOUD FUNCTIONS ──────────────────────────────────────
ALL    /fn/:id                        chiamata pubblica HTTP
GET    /functions                     lista (admin)
POST   /functions                     crea (admin)
PUT    /functions/:id                 aggiorna (admin)
DELETE /functions/:id                 elimina (admin)
POST   /functions/:id/execute         test (admin)
GET    /functions-env                 env vars (admin)
PUT    /functions-env/:key            imposta var (admin)
DELETE /functions-env/:key            elimina var (admin)

── HOSTING ──────────────────────────────────────────────
GET    /hosting                       lista siti (admin)
POST   /hosting                       crea sito (admin)
PUT    /hosting/:id                   aggiorna sito (admin)
DELETE /hosting/:id                   elimina sito (admin)
POST   /hosting/:id/deploy            deploy file JSON (admin)
POST   /hosting/:id/deploy-zip        deploy ZIP binario (admin)
POST   /hosting/:id/rollback          { deployId } (admin)
GET    /sites/:slug/                  sito live (pubblico)

── MESSAGING ────────────────────────────────────────────
POST   /messaging/subscribe           registra dispositivo push
GET    /messaging/poll                ?since=&topics=  (polling)
POST   /messaging/send                invia notifica (admin)
GET    /messaging/notifications       lista notifiche (admin)
DELETE /messaging/notifications/:id   elimina notifica (admin)
GET    /messaging/subscriptions       lista dispositivi (admin)
GET    /messaging/vapid-public-key   chiave pubblica VAPID
POST   /messaging/unsubscribe       rimuovi dispositivo
POST   /messaging/read/:id          segna notifica come letta

── API KEYS ─────────────────────────────────────────────
POST   /api/keys/generate         genera chiave (auth utente)
GET    /api/keys/list             lista chiavi (admin: tutte, user: proprie)
GET    /api/keys/reveal/:id       rivela chiave completa (owner/admin)
PUT    /api/keys/update/:id       aggiorna nome, servizi, scadenza
PUT    /api/keys/toggle/:id       abilita/disabilita chiave
DELETE /api/keys/client/:id       elimina chiave (owner/admin)

── AI SERVICES (richiede API Key o JWT) ──────────────────
POST   /api/ai/chat               LLM chat (Ollama locale, fallback automatico)
POST   /api/ai/vision             Vision (minicpm-v locale o Gemini 2.0 Flash)
POST   /api/ai/vision/video       Video AI (FFmpeg + Vision, max 60s)
POST   /api/ai/rag-pdf            RAG PDF (domanda su documento PDF)
GET    /api/ai/status             stato modelli + chiavi + defaultModel
GET    /api/ai/log?limit=50       log interazioni IA (admin)
GET    /api/web-search?q=&max=&type=  ricerca web/images/videos
GET    /api/web-scrape?url=       scraping contenuto HTML pagina

── DOCUMENT EXTRACTION & DOWNLOAD (v4.0) ────────────────
GET    /api/extract?url=&chunk_size=&chunk=  estrai testo (PDF/DOCX/XLSX/PPTX/CSV/TXT/HTML)
GET    /api/download?url=         scarica qualsiasi file (ZIP/APK/ROM/binari)
GET    /api/download/file/:name   serve file scaricato
GET    /api/download/list         lista file scaricati (admin)
DELETE /api/download/clean        pulisci download >24h (admin)
POST   /api/web-search/deep       { query, maxSources, type, model } ricerca+estrai+analisi LLM

── AI ADMIN (solo admin) ─────────────────────────────────
PUT    /api/ai/default-model      { model } imposta modello default
GET    /api/ai/default-model      leggi modello default + fallbackOrder
POST   /api/ai/test-model         { model, prompt } testa modello specifico
GET    /api/web-search/stats      statistiche cache (admin)
DELETE /api/web-search/cache      svuota cache ricerche (admin)

── YOUTUBE PROXY API (per SpotifyX) ──────────────────────
GET    /api/yt/search?q=           ricerca musica (Piped)
GET    /api/yt/streams/:videoId   streaming audio (Piped)
GET    /api/yt/trending           trending IT (Piped)

── ADMIN EMAIL & CONFIG (solo admin) ───────────────────
GET    /auth/admin/email-config   configurazione SMTP (pass mascherata)
PUT    /auth/admin/email-config   aggiorna configurazione SMTP
POST   /auth/admin/send-email    invia email generica (admin)

── SECURITY RULES ADMIN (solo admin) ──────────────────────
GET    /auth/admin/rules           regole globali
PUT    /auth/admin/rules/firestore   aggiorna regole Firestore globali
PUT    /auth/admin/rules/storage     aggiorna regole Storage globali

── ADMIN STATS EXTENDED (solo admin) ──────────────────────
GET    /auth/admin/full-stats      statistiche complete (auth + firestore + storage)
GET    /auth/admin/all-stats       statistiche complete (funzioni + hosting)

── WEBRTC TURN/STUN SERVER ────────────────────────────────
POST   /api/webrtc/credentials    credenziali ICE per WebRTC
GET    /api/webrtc/status         stato TURN/STUN
POST   /api/webrtc/start          avvia server TURN (admin)
POST   /api/webrtc/stop           ferma server TURN (admin)
GET    /api/webrtc/config         configurazione TURN
PUT    /api/webrtc/config         aggiorna configurazione TURN

── GEO SERVICES (geocoding, routing, geofence, presenze) ───
GET    /api/geo/geocode?q=&limit=  geocoding indirizzo
GET    /api/geo/reverse?lat=&lng=  reverse geocoding
GET    /api/geo/route?lat1=&lng1=&lat2=&lng2=  percorso stradale (OSRM)
GET    /api/geo/navigate?lat1=&lng1=&lat2=&lng2=&destName=  navigazione turn-by-turn
POST   /api/geo/geofence          check se punto dentro zona
POST   /api/geo/attendance/full  presenze complete (auto-detect)
GET    /api/geo/attendance/summary?user=&date=  riepilogo giornata
GET/POST/PUT/DELETE /api/geo/zones  CRUD zone geofence

── USER CONSOLE (scoped per utente) ──────────────────────
GET    /user/firestore                lista collection utente
GET    /user/firestore/:col           documenti collection
POST   /user/firestore/:col/:docId?  crea documento
PUT    /user/firestore/:col/:docId   aggiorna documento
DELETE /user/firestore/:col/:docId   elimina documento
DELETE /user/firestore/:col           elimina collection
GET    /user/storage                  lista file utente
POST   /user/storage/upload           upload file (multipart)
GET    /user/storage/file/:path       download file
DELETE /user/storage/file/:path       elimina file
GET    /user/hosting                  lista siti utente
POST   /user/hosting                  crea sito
POST   /user/hosting/:id/deploy-zip   deploy ZIP
DELETE /user/hosting/:id              elimina sito
GET    /user/stats                    statistiche utente
GET    /user/notifications            notifiche utente

── USER SECURITY RULES ──────────────────────────────────
GET    /user/rules                    leggi regole utente
PUT    /user/rules/firestore          aggiorna regole Firestore
PUT    /user/rules/storage            aggiorna regole Storage

── APP ANDROID ──────────────────────────────────────────
POST   /user/apps/android             registra app Android
GET    /user/apps                     lista app utente
PUT    /user/apps/:id                 aggiorna app
DELETE /user/apps/:id                 elimina app
GET    /auth/admin/android-apps      lista tutte le app (admin)

── ADMIN: GESTIONE UTENTI ───────────────────────────────
GET    /auth/admin/users              lista utenti
DELETE /auth/admin/users/:id          elimina utente
PUT    /auth/admin/users/:id/toggle   abilita/disabilita
PUT    /auth/admin/users/:id/role     { role: "admin"|"user" }
GET    /auth/admin/users/:id/data     dati utente (firestore/storage/hosting)
POST   /auth/admin/reset-password     { userId } → link reset

📷 Profilo & Avatar v10.1

Ogni utente può impostare una foto profilo (avatar) che viene automaticamente distribuita a tutte le app che usano TrubaxCloud come provider di autenticazione, esattamente come Google e i suoi servizi.

Come funziona

L'utente carica un'immagine (JPG, PNG, GIF, WebP, max 5MB) tramite la console o via API. L'immagine viene salvata in data/avatars/{userId}.ext ed è servita pubblicamente a /auth/avatar/{userId}. Quando uno sviluppatore integra l'accesso via TrubaxCloud, il campo user.avatar viene incluso automaticamente in POST /auth/verify e POST /auth/sdk/user.

Endpoints API

MetodoEndpointDescrizione
POST /auth/me/avatarmultipart avatarUpload foto profilo (max 5MB, JPG/PNG/GIF/WebP)
GET /auth/avatar/:idpublicScarica avatar utente (cacheable 1h, SVG default se assente)
DELETE /auth/me/avatarauthRimuovi foto profilo
PUT /auth/meauth { displayName }Aggiorna nome visualizzato
DELETE /auth/meauth { password }Elimina il proprio account (irreversibile)

Esempio: Upload avatar da frontend

javascript
const formData = new FormData();
formData.append('avatar', fileInput.files[0]);

const res = await fetch('/auth/me/avatar', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + token },
  body: formData
});
const data = await res.json();
// data.avatarUrl → "/auth/avatar/abc123"

Integrazione SDK — Avatar nelle tue app

javascript
// Quando un utente accede alla tua app tramite TrubaxCloud:
const res = await fetch('https://tuoserver.com/auth/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ token: userToken })
});
const { user } = await res.json();

// user.avatar → "/auth/avatar/abc123" (URL pubblica)
// user.displayName → "Mario Rossi"
// user.email → "[email protected]"

// Mostra avatar nell'app:
document.getElementById('userAvatar').src = serverUrl + user.avatar;

Eliminazione account (self-service)

⚠️ Azione irreversibile L'utente può eliminare il proprio account confermando la password. Vengono eliminati: dati utente, sessioni, avatar e tutte le app registrate. L'endpoint è DELETE /auth/me con body { "password": "..." }.

🔔 Push Notifications v10.0

TrubaxCloud supporta Web Push (VAPID) per notifiche in tempo reale nel browser e polling per app mobili. Le notifiche sono gestite tramite topic e hanno storico persistente.

Architettura

🌐

Web Push

Service Worker + VAPID. Funziona anche con browser chiuso. Richiede HTTPS.

📱

Mobile Polling

GET /messaging/poll per ricevere notifiche pendenti. Ideale per app React Native.

📋

Storico

Ultime 200 notifiche salvate. Mark-as-read per utente. Topic filtering.

🔑

VAPID

Chiavi generate automaticamente al primo avvio. Nessuna configurazione richiesta.

Endpoints

MetodoEndpointDescrizione
GET /messaging/vapid-public-keypublicOttieni VAPID public key per subscription
POST /messaging/subscribeauth { subscription, topics }Iscriviti a push notifications
POST /messaging/unsubscribeauth { endpoint }Disiscriviti
GET /messaging/pollauthRicevi notifiche pendenti (mobile SDK)
POST /messaging/read/:idauthSegna notifica come letta
POST /messaging/sendadmin { title, body, topic }Invia notifica (admin)

Esempio: Service Worker per Push

javascript — sw-push.js
// File statico servito dal server
self.addEventListener('push', function(e) {
  var d = { title: 'TrubaxCloud', body: 'Nuova notifica' };
  try { d = Object.assign(d, e.data.json()); } catch(x) {}
  e.waitUntil(self.registration.showNotification(d.title, {
    body: d.body, icon: d.icon || '/favicon.ico'
  }));
});

self.addEventListener('notificationclick', function(e) {
  e.notification.close();
  e.waitUntil(clients.openWindow(e.notification.data?.url || '/'));
});

Esempio: Subscribe da frontend

javascript
// 1. Registra service worker
const reg = await navigator.serviceWorker.register('sw-push.js');
await navigator.serviceWorker.ready;

// 2. Ottieni VAPID key
const vapid = await fetch('/messaging/vapid-public-key').then(r => r.json());

// 3. Subscribe
const sub = await reg.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: urlBase64ToUint8Array(vapid.publicKey)
});

// 4. Invia subscription al server
await fetch('/messaging/subscribe', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' },
  body: JSON.stringify({ subscription: sub.toJSON(), topics: ['all'] })
});
💡 Nota per HTTPS Le Web Push Notifications funzionano solo su HTTPS. In locale con localhost funzionano senza certificato. Per produzione, usa Caddy o Cloudflare Tunnel per HTTPS automatico. Il service worker deve essere registrato da un file statico (sw-push.js), NON da un blob URL.

📝 Note Ufficio — v10.3 23 Apr 2026

Aggiornamento piattaforma TrubaxCloud: filtri ricerca server-side (immagini/video/news), avatar dropdown unificato in tutti i servizi, link assoluti, DDG scraping per tipi multipli.

✅ Completato in v10.2

Caddy Routing — Servizi Web

Aggiunte e corrette route reverse proxy per /services/* e /search/* verso auth-service (:4000). Inclusi anche endpoint correlati come /api/tor-proxy, /api/ip-check e route ricerca per evitare fallback errato verso KetaDL.

Service Pages con path dedicati

Il server ora serve ufficialmente i servizi tramite /services/:name e la pagina ricerca tramite /search. I link interni dei servizi sono stati normalizzati su path assoluti (/search, /services/drive, /services/ai, /cloud/login.html, /cloud/dashboard.html) per funzionare correttamente quando la pagina è aperta da /services/*.

TrubaxSearch Web — redesign completo

search.html è stato riscritto in stile Google-like futuristico con navbar sticky, login/avatar in alto a destra, griglia servizi tipo app launcher, risultati con tab e ricerca collegata a /search/scrape.

Avatar distribuiti nei servizi

La foto profilo TrubaxCloud ora viene letta correttamente da /auth/me (response { user, apps }) e mostrata nei servizi principali. Allineati drive.html, mail.html, translate.html, photos.html, ai.html, maps.html, tor.html e notes.html.

Login redirect-aware

login.html supporta ora ?redirect=.... Se l'utente è già autenticato o completa il login, viene riportato direttamente al servizio richiesto invece di finire sempre nella dashboard.

KetaDL — login obbligatorio

Accesso TrubaxCloud reso obbligatorio per KetaDL web e mobile. Le API sensibili /api/extract, /api/mp3 e /api/mp4 richiedono autenticazione TrubaxCloud; il downloader web usa overlay/login gate e l'app mobile blocca l'uso finché non viene effettuato l'accesso.

TrubaxSearch Mobile

L'app mobile usa ora /search e i nuovi path /services/* invece di endpoint legacy. Migliorata la UI account con avatar reale o fallback iniziale in alto a destra.

Idea IA Mobile — fix integrazione profilo

Corretto il parsing del payload /auth/me nel SDK React Native. L'app Idea IA ora estrae correttamente data.user, permettendo propagazione coerente di user.avatar nei componenti header.

Profilo Utente & Avatar

Upload/download foto profilo per ogni utente. Servita pubblicamente su /auth/avatar/{id}. Integrata in header e sidebar di admin.html e dashboard.html. Avatar distribuita automaticamente via SDK a tutte le app collegate.

Settings Page — User Dashboard

Pagina impostazioni completa: upload foto, modifica nome, info account (ID, email verificata, date), cambio password con conferma, disconnessione sessioni, eliminazione account con conferma password (irreversibile).

Settings Page — Admin Console

Profilo admin con stesse funzionalità: avatar, nome, password. Sezione dedicata nella sidebar "Il mio Profilo".

Push Notifications Fix

Service Worker spostato da blob URL a file statico sw-push.js. Risolto errore "blob: URL protocol not supported" su HTTPS.

Android Apps — Endpoint Fix

Endpoints admin spostati da /admin/apps a /auth/admin/android-apps per compatibilità con Caddy proxy rules. Risolto 502 Bad Gateway.

Per-User Data Inspector

Modal e pannelli espandibili per ispezionare dati Firestore, Storage, Hosting, App Android e Security Rules di ogni utente dalla console admin.

✅ Completato in v10.3 23 Apr 2026

TrubaxSearch — Filtri tipo ricerca server-side

L'endpoint /search/scrape ora accetta il parametro type con valori web, images, videos, news. Per ogni tipo vengono usate le API JSON interne di DuckDuckGo (i.js, v.js, news.js) con estrazione automatica del token vqd. Fallback a SerpAPI per immagini e video se DDG fallisce. Nessun servizio AI esterno coinvolto.

TrubaxSearch Web — Tab filtri funzionanti

search.html ora include 6 tab filtri: Tutti, Immagini, Video, Notizie, Mappe, Shopping. I primi 4 passano il parametro type a /search/scrape. Tab Mappe reindirizza a TrubaxMaps con query. Tab Shopping reindirizza a DuckDuckGo Shopping. Renderer dedicati per immagini (griglia), video (card thumbnail+duration) e notizie (source+data).

Avatar dropdown unificato in tutti i servizi

In tutti gli 8 servizi web (ai.html, translate.html, photos.html, maps.html, tor.html, notes.html, mail.html, drive.html) il click sull'avatar ora apre un dropdown menu contestuale con: nome utente, link a Console TrubaxCloud, Impostazioni account, e Logout. Non naviga più direttamente alla dashboard.

Link navigazione assoluti in tutti i servizi

Tutti i link interni dei servizi web sono stati convertiti a path assoluti: /search, /services/drive, /services/ai, /services/maps, /services/translate, ecc. Anche i pulsanti di login usano /cloud/login.html?redirect=... per riportare l'utente al servizio dopo il login.

DDG Scraping — 3 nuove funzioni

Aggiunte searchDdgImages(), searchDdgVideos(), searchDdgNews() al server. Ognuna estrae il token vqd dalla pagina DDG, poi interroga le rispettive API JSON (/i.js, /v.js, /news.js). Rate limiting DDG condiviso tra tutte le funzioni (5s gap). Cache separata per tipo di ricerca.

TrubaxSearch Mobile — Avatar verificato

L'app mobile TrubaxSearch risolve correttamente avatar relativi (/auth/avatar/x → URL assoluto). Avatar visibile in topbar e nel menu modal. Quick links aggiornati con path assoluti (/search, /services/*).

Idea IA Mobile — Avatar verificato

L'SDK TrubaxCloud in Idea IA risolve avatar relativi in _notify(). Il componente Header riceve avatarUri={user?.avatar} e lo mostra correttamente in AIScreen, ChatsScreen e SettingsScreen. Nessuna modifica necessaria.

🔜 TODO per prossima sessione

Idee per v10.4+
  • Setup utente post-registrazione: wizard con campi dati personali (nome, cognome, data nascita, telefono, bio) salvati nel campo metadata del DB
  • SDK endpoint avatar: aggiungere /auth/sdk/user response con avatarUrl completo (host + path) per facilitare integrazione mobile
  • Dashboard avatar drag&drop: supporto drag&drop sulla zona avatar oltre al click
  • Admin: gestione avatar utenti: possibilità per admin di resettare avatar di qualsiasi utente
  • Crop/resize immagine: crop circolare client-side prima dell'upload + resize server-side a 256x256
  • Mail: aggiungere inbox badge globale, ricerca email e supporto allegati reali via storage

🏗️ Architettura Profilo

schema
── Database (auth.db) ───────────────────────────────
users.avatar      TEXT   →  "/auth/avatar/{userId}"
users.displayName TEXT   →  "Mario Rossi"
users.metadata    TEXT   →  '{"bio":"...","phone":"..."}'

── File System ──────────────────────────────────────
data/avatars/{userId}.jpg|png|gif|webp

── Endpoints ────────────────────────────────────────
POST   /auth/me/avatar      upload (multipart, max 5MB)
GET    /auth/avatar/:id     serve immagine (public, cached 1h)
DELETE /auth/me/avatar      rimuovi avatar
PUT    /auth/me             aggiorna displayName
DELETE /auth/me             elimina account (richiede password)

── SDK Integration ─────────────────────────────────
POST /auth/verify    → response.user.avatar
POST /auth/sdk/user  → response.user.avatar

⚠️ Codici di errore

StatusErroreCausa
401Token non validoToken scaduto o mancante nell'header
403Accesso negatoRuolo insufficiente o regola di sicurezza
404Non trovatoDocumento, sito o funzione non esistente
400Richiesta non validaCampi mancanti o formato errato
500Errore serverEccezione interna, vedi log server
502API esterna fallitaEs. Gemini API error (vedi error.message)

📁 TrubaxDrive

File manager stile Google Drive. Upload, download, organizzazione file con 2GB per utente.

Quota Storage

  • 2GB per utente (file Drive)
  • chat-images/ escluse dal limite (immagini Idea IA)
  • Upload max 50MB per file

API Endpoints

GET  /user/storage?type=drive     // Lista file (escludi chat-images)
POST /user/storage/upload          // Upload file (multipart)
GET  /user/storage/file/:path      // Download file
DELETE /user/storage/file/:path    // Elimina file

// Query params
?type=drive   → solo file Drive
?type=chat    → solo chat-images
?token=JWT    → auth via URL (per img tag)

✉️ TrubaxMail

Client email interno. Invia/ricevi tra utenti TrubaxCloud + SMTP esterno.

Funzionalità

  • Inbox, Sent, Drafts, Trash
  • Invio interno tra utenti TrubaxCloud
  • Invio esterno via SMTP (se configurato)
  • Starred, Read/Unread

API Endpoints

GET   /user/mail/:box              // box = inbox|sent|drafts|trash
POST  /user/mail/send              // { to, subject, body, html }
PATCH /user/mail/:box/:id          // { read, starred, _delete }

// Response GET
{ "mails": [...], "total": 42 }

// Response POST send
{ "success": true, "mail": {...}, "smtpSent": true|false }
⚠️ SMTP Config Per inviare email esterne, configura SMTP in Admin Console → Email Config.

🗺️ TrubaxMaps

Mappe e navigazione. Leaflet + OpenStreetMap + OSRM routing. Nessuna dipendenza Google.

Funzionalità

  • Ricerca luoghi (Nominatim geocoding)
  • Calcolo percorsi (OSRM routing)
  • Geolocalizzazione browser
  • Layer dark/light

API Esterne Usate

// Geocoding
https://nominatim.openstreetmap.org/search?q=...

// Routing
https://router.project-osrm.org/route/v1/driving/{lon1},{lat1};{lon2},{lat2}

🤖 TrubaxIA Chat

Chat IA locale. LLaMA, Qwen, DeepSeek via Ollama. Zero tracking, dati on-premise.

API Endpoint

POST /api/ai/chat
Authorization: Bearer {token}
Content-Type: application/json

{
  "messages": [{ "role": "user", "content": "Ciao" }],
  "model": "llama3.1:8b",
  "temperature": 0.7,
  "maxTokens": 2000
}

// Response
{ "response": "Ciao! Come posso aiutarti?" }

Modelli Disponibili

GET /api/ai/status   // Lista modelli installati

// Response
{ "textModels": ["llama3.1:8b", "qwen2.5:7b", ...] }

🌐 TrubaxTranslate

Traduttore IA. 12 lingue, traduzione contestuale via LLM locale.

Lingue Supportate

Italiano, English, Français, Español, Deutsch, Português, Русский, 中文, 日本語, العربية, 한국어 + rilevamento automatico.

Implementazione

Usa /api/ai/chat con prompt di traduzione. Cronologia salvata in localStorage.

📸 TrubaxPhotos

Galleria foto dal Drive. Lightbox, upload, navigazione tastiera.

Funzionalità

  • Griglia responsive
  • Lightbox con navigazione ←→
  • Upload multiplo in photos/
  • Filtra automaticamente immagini dal Drive

📝 TrubaxNotes

Note veloci stile Google Keep. Colori, ricerca, salvataggio locale.

Storage

Le note sono salvate in localStorage (chiave: trubax_notes). Non richiede autenticazione.

🧅 TrubaxTor

Browser .onion via proxy Tor server-side. Navigazione anonima.

API Endpoints

// Proxy Tor (supporta .onion)
GET /api/tor-proxy?url=http://example.onion

// Check IP
GET /api/ip-check
{ "clientIp": "1.2.3.4", "serverIp": "5.6.7.8" }
⚠️ Privacy Il traffico passa attraverso il server TrubaxCloud → Tor. Il server può vedere le richieste. Per anonimato completo usa Tor Browser nativo.

🎤 STT/TTS Server-Side

Speech-to-Text e Text-to-Speech server-side per compatibilità iOS Safari.

⚠️ Problema iOS Safari iOS non supporta Web Speech API per STT. Le chiamate WebRTC e il riconoscimento vocale in Idea IA Web non funzionano su iOS. Su Android funziona tutto.

Soluzione: API Server-Side

// STT - Speech to Text (upload audio, get text)
POST /api/stt
Content-Type: multipart/form-data
file: audio.webm

{ "text": "Testo riconosciuto", "confidence": 0.95 }

// TTS - Text to Speech (get audio)
POST /api/tts
{ "text": "Ciao mondo", "lang": "it-IT", "voice": "female" }

Response: audio/mpeg (MP3 stream)

Implementazione Suggerita

  • STT: Whisper (OpenAI) o Vosk locale
  • TTS: Piper TTS locale o Google Cloud TTS
  • Fallback: Web Speech API su browser supportati
📱 Status Implementazione
  • ✅ Android: Web Speech API funziona
  • ❌ iOS Safari: richiede STT/TTS server-side
  • 🔄 TODO: Implementare endpoint /api/stt e /api/tts

⚡ Idea IA — App Mobile & Web

App React Native + Web per elettricisti e idraulici. Chat IA con analisi immagini, manuali PDF, navigatore GPS professionale, sistema approvazione operatori.

Registrazione in TrubaxCloud

// Admin Console → Apps → Nuova App
Nome: Idea IA
Package: com.ideaia
Slug: ideaia
Redirect URI: ideaia://auth/callback

// Ottieni App Secret per SDK
APP_SECRET: tc_app_xxxxxxxxxxxxx

Sistema Approvazione Operatori

Stati Operatore pending → In attesa | approved → Approvato | rejected → Rifiutato | removed → Rimosso
// Collection: ideaia_operators
{
  id: 'op_mario_rossi',
  email: '[email protected]',
  name: 'Mario Rossi',
  status: 'pending' | 'approved' | 'rejected' | 'removed',
  createdAt: '2026-05-04T...',
  approvedAt?: '...',
  approvedBy?: '[email protected]'
}

// Admin emails autorizzate
'[email protected]', '[email protected]'

Sistema Notifiche

🔔

Web

Campanella header con badge, dropdown notifiche, browser notifications, polling 15s

📱

Mobile

NotificationBell con modal fullscreen, badge animato, deep linking, polling 30s

// Tipi notifica supportati
'rapportino'  // Notifiche rapportino giornaliero
'approval'    // Richieste approvazione (solo admin)
'chat'        // Messaggi chat
'reminder'    // Promemoria urgenti
'welcome'     // Benvenuto dopo approvazione

Navigatore GPS Professionale

  • Ricalcolo automatico: Quando l'utente devia >100m dal percorso (3 rilevamenti consecutivi)
  • Freccia bussola: Usa DeviceOrientation API per rotazione in tempo reale
  • Gesture 2 dita: Zoom/rotazione stile Google Maps
  • Vista 3D: Tilt prospettico durante navigazione
  • TTS nativo: Annunci vocali in italiano
  • Tile layer: OpenStreetMap DE (più dettagliato per edifici)
// API Navigazione
GET /api/geo/navigate?lat1=...&lng1=...&lat2=...&lng2=...&destName=...

// Risposta
{
  destination: 'Cantiere Via Roma',
  distance: { km: 5.2, text: '5.2 km' },
  duration: { minutes: 12, text: '12 min' },
  steps: [{ step: 1, icon: '🚗', instruction: 'Parti verso nord', ... }],
  geometry: { type: 'LineString', coordinates: [[lng, lat], ...] }
}

Chat IA con Analisi Immagini

// Storage immagini chat
Bucket: 'chat-images'
Path: 'chat-images/{chatId}/{messageId}.jpg'

// Recupero immagine
GET /storage/chat-images/{chatId}/{messageId}.jpg

// Analisi immagine con Vision AI
POST /api/ai/vision
{ image: 'base64...', prompt: 'Analizza questo impianto' }

Manuali PDF (RAG)

// Upload manuale PDF
POST /api/documents/upload
Content-Type: multipart/form-data
{ file: PDF, category: 'comelit', subcategory: 'antifurto' }

// Ricerca semantica nei manuali
POST /api/documents/search
{ query: 'come collegare sensore volumetrico', category: 'comelit' }

// Risposta con chunks rilevanti
{ results: [{ content: '...', page: 15, score: 0.92 }] }

Funzionalità Complete

  • Chat IA con LLM locale (analisi immagini, manuali PDF)
  • Analisi stanze 3D (fotocamera)
  • Calcoli CEI 64-8 per elettricisti
  • Chiamate WebRTC (audio/video)
  • Navigatore GPS cantieri con ricalcolo automatico
  • Sistema approvazione operatori real-time
  • Notifiche campanella (web + mobile)
  • Rapportini giornalieri con promemoria
  • Storage immagini persistente

Build

# Mobile Debug
cd "C:\Users\Trubax\Desktop\BETA\IDEA IA"
npx react-native run-android

# Mobile Release
cd android
.\gradlew.bat assembleRelease

# Web Build & Deploy
cd "C:\Users\Trubax\Desktop\BETA\Idea ia web"
npm run build
node deploy.js

🔍 TrubaxSearch — App Mobile

Browser mobile con supporto .onion, AdBlock, TrubaxCloud login.

Registrazione in TrubaxCloud

// Admin Console → Apps → Nuova App
Nome: TrubaxSearch
Package: com.trubaxsearch
Slug: trubaxsearch
Redirect URI: trubaxsearch://auth/callback

Funzionalità

  • WebView browser con tabs
  • Supporto .onion via /api/tor-proxy
  • AdBlock DOM-level
  • Bookmarks in AsyncStorage
  • TrubaxCloud login/logout

Build Release

# Richiede keystore per release
cd "C:\Users\Trubax\Desktop\BETA\trubax-search\android"

# Genera keystore (una volta sola)
keytool -genkeypair -v -storetype PKCS12 -keystore release.keystore ^
  -alias trubaxsearch -keyalg RSA -keysize 2048 -validity 10000

# Configura in gradle.properties
MYAPP_RELEASE_STORE_FILE=release.keystore
MYAPP_RELEASE_KEY_ALIAS=trubaxsearch
MYAPP_RELEASE_STORE_PASSWORD=xxxxx
MYAPP_RELEASE_KEY_PASSWORD=xxxxx

# Build
.\gradlew.bat assembleRelease