☁️ 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.
📖 Introduzione
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
Browser (tag script)
<!-- 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
sdk/trubaxcloud.js nel tuo progetto come src/services/trubaxCloud.js oppure usa direttamente le API REST.const TrubaxCloud = require('./trubaxcloud'); // oppure import TrubaxCloud from './trubaxcloud'; const app = TrubaxCloud.initializeApp({ url: 'http://10.0.2.2:4000' // emulatore Android });
🚀 Quickstart
// 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
Registrazione e Login
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
| Metodo | Ritorna | Descrizione |
|---|---|---|
| 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.currentUser | User|null | Utente sincrono (può essere stale) |
| auth.onAuthStateChanged(cb) | () => void | Listener, ritorna funzione di cleanup |
| auth.updateProfile(data) | Promise<User> | Aggiorna displayName, avatar |
| auth.changePassword(old, new) | Promise | Cambio password autenticato |
| auth.uploadAvatar(file) | Promise | Upload foto profilo (max 5MB) |
| auth.removeAvatar() | Promise | Rimuovi foto profilo |
| auth.deleteAccount(password) | Promise | Elimina 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
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)
// 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
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/
POST /storage/:bucket/:path con body { data: "<base64>", contentType: "image/jpeg" }⚡ Cloud Functions
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)
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
/sites/:slug/.Metodi di deploy
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)
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
# 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
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
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
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
// 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
| Endpoint | Metodo | Descrizione |
|---|---|---|
| POST /api/keys/generate | POST | Genera nuova chiave (auth utente) |
| GET /api/keys/list | GET | Lista chiavi (admin: tutte, user: proprie) |
| GET /api/keys/reveal/:id | GET | Rivela chiave completa (owner/admin) |
| PUT /api/keys/update/:id | PUT | Aggiorna nome, servizi, scadenza |
| PUT /api/keys/toggle/:id | PUT | Abilita/disabilita chiave |
| DELETE /api/keys/client/:id | DELETE | Elimina 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
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
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" }
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
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
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
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; }
📋 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/visioncon 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
downloadUrlper il download +archiveContentsper 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 conprovider:"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
imagein base64, il modello risponde solo come LLM testo senza vedere l'immagine. Verificare che Idea IA invii il campoimagecorrettamente!
🌐 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/visiono/api/ai/vision/video - → Il backend usa Gemini 2.0 Flash (gratuito, veloce, dettagliato)
- → Richiede
geminiApiKeyconfigurata 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/chataccetta:{ messages, model, systemInstruction, temperature, maxTokens, modalita, format }temperature: 0= notaio preciso,0.6= tecnico colloquiale,0.7= conversazionalemaxTokens: 150= risposta corta,300= media,2048= lungasystemInstruction= 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 interpretaformat: "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
systemInstructionper decidere se risposta secca o discorsiva - Idea IA uso tipico: utente chiede "coppia serraggio AC Peimar" → frontend cerca PDF via
/api/web-searchconfiletype:pdf→ passa URL a/api/ai/rag-pdf
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
modalitava 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-pdfcontemperature: 0per dato certificato - → Poi chiama
/api/ai/chatcon il dato come contesto +temperature: 0.6per risposta umana - → Tutto gestito dal frontend, il server non sa nulla della doppia analisi
4. Video + Immagini + Provider:
- Immagini →
/api/ai/visionconprovider: "local"|"gemini" - Video (max 1 min) →
/api/ai/vision/videoconprovider: "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/chat | Chat LLM — params: messages, model, systemInstruction, temperature, maxTokens, modalita, format |
| POST /api/ai/vision | Analisi immagine — params: image (base64), prompt, provider (local|gemini) |
| POST /api/ai/vision/video | Analisi video — params: video (base64), prompt, provider (local|gemini) |
| POST /api/ai/rag-pdf | Estrazione PDF — params: pdf_url, domanda, temperature, max_tokens, systemInstruction |
| GET /api/web-search | Ricerca web — params: q, max, type (web|images|videos) |
| POST /api/web-search/deep | Deep search + LLM — params: query, maxSources, type, model |
| GET /api/extract | Estrai documenti — params: url, chunk_size, chunk |
| POST /api/webrtc/credentials | Credenziali ICE per WebRTC TURN/STUN |
| GET /api/ai/status | Stato modelli + chiavi (defaultModel, textModels[], visionModels[]) |
| GET /api/ai/log | Log interazioni IA (admin) — params: limit |
| GET /api/geo/geocode | Geocoding — params: q, limit |
| GET /api/geo/reverse | Reverse geocoding — params: lat, lng |
| GET /api/geo/route | Percorso stradale (OSRM) — params: lat1, lng1, lat2, lng2 |
| GET /api/geo/navigate | Navigazione turn-by-turn — params: lat1, lng1, lat2, lng2, destName — restituisce steps[], geometry GeoJSON |
| POST /api/geo/geofence | Check geofence — body: { lat, lng, zoneId? } |
| POST /api/geo/attendance/full | Presenze completo — body: { lat, lng, vehicleId?, action? } |
| GET /api/geo/attendance/summary | Riepilogo giornata — params: user, date (YYYY-MM-DD) |
| GET/POST/PUT/DELETE /api/geo/zones | CRUD 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:
- Mattina 07:30 — L'operaio apre l'app → GPS automatico →
POST /api/geo/attendance/full { lat, lng }→ server risponde CHECK_IN + zona - Durante il giorno — L'app invia posizione ogni 5-10 min (background) → server logga e traccia se in cantiere/transito/sede
- Dopo le 16:30 — Il server marca automaticamente
STRAORDINARIOcon minuti extra. Nessuna azione richiesta dall'operaio - Riconsegna mezzo — L'operaio arriva in sede col furgone →
POST /api/geo/attendance/full { lat, lng, vehicleId: "FIAT-001", action: "vehicle_return" } - Uscita sede —
POST /api/geo/attendance/full { lat, lng, action: "sede_exit" }→ si registra chi esce e quando (l'ultimo chiude!) - 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, Napoliper 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/fullcalcola automaticamentetravelToSedese 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_CONFIGnel 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
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 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:
// 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)
// 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
| Metodo | Endpoint | Descrizione |
|---|---|---|
POST | /api/webrtc/credentials | Genera credenziali ICE temporanee (auth richiesta) |
GET | /api/webrtc/status | Stato del server TURN/STUN (auth richiesta) |
GET | /api/webrtc/config | Configurazione completa (solo admin) |
PUT | /api/webrtc/config | Modifica configurazione (porta, realm, TTL, ecc.) |
POST | /api/webrtc/start | Avvia il server TURN/STUN |
POST | /api/webrtc/stop | Ferma il server TURN/STUN |
POST | /api/webrtc/rotate-secret | Ruota il secret HMAC (invalida tutte le credenziali) |
GET | /api/webrtc/users | Lista utenti TURN attivi |
Configurazione
{
"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)
}
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.
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
Endpoint API
| Metodo | Endpoint | Descrizione |
|---|---|---|
| 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/geofence | Check se un punto è dentro una o più zone |
| POST | /api/geo/attendance | Check-in/out semplice (auto-detect zona) |
| POST | /api/geo/attendance/full | Presenze completo: overtime, mezzo, stima ritorno sede |
| GET | /api/geo/attendance/summary?user=&date= | Riepilogo giornata operaio |
| GET | /api/geo/zones | Lista zone geofence |
| POST | /api/geo/zones | Crea zona (admin): { name, lat, lng, radius, type, address } |
| PUT | /api/geo/zones/:id | Modifica zona (admin) |
| DELETE | /api/geo/zones/:id | Elimina zona (admin) |
| GET | /api/geo/log?limit=&user= | Log eventi geofence (admin) |
Tipi di zona
Sede aziendale. Registra arrivo/uscita e riconsegna mezzi.
Cantiere attivo. Auto check-in quando l'operaio è nel raggio.
Punto di ritiro/deposito materiali.
Sistema presenze automatico
Dopo le 16:30 → evento marcato
STRAORDINARIO con conteggio minuti extraPrima delle 07:30 → marcato
PRE-TURNOEvent types:
SEDE_PRESENT, CANTIERE_PRESENT, IN_TRANSIT, VEHICLE_RETURN, SEDE_EXITVeicoli: passa
vehicleId + action: "vehicle_return" quando un operaio riporta il mezzo in sedeUscita sede:
action: "sede_exit" per registrare chi esce ultimo (porta aperta!)
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)
/api/geo/navigate restituisce indicazioni stradali passo-passo con icone manovra, GeoJSON per disegnare il percorso su mappa, stima carburante e tempo.{
"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], ...] }
}
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.
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
| Funzionalità | Google Firebase | TrubaxCloud | Stato |
|---|---|---|---|
| Authentication | Firebase Auth (OAuth, email, phone) | JWT Auth (email, password, verifica email, reset) | ✅ Parità |
| Firestore Database | Cloud Firestore (NoSQL, realtime) | SQLite Firestore-like (CRUD, SSE realtime) | ✅ Parità |
| Storage | Cloud Storage (GCS buckets) | File Storage (upload, download, list, quota) | ✅ Parità |
| Cloud Functions | Cloud Functions (Node.js, Python) | Cloud Functions (JS sandbox, HTTP trigger) | ✅ Parità |
| Hosting | Firebase Hosting (CDN global) | Self-hosted (Caddy + sites) | ✅ Parità |
| Push Notifications | Firebase Cloud Messaging (FCM) | Web Push (VAPID) + Mobile polling | ✅ Parità |
| Security Rules | Firestore Security Rules | Custom Security Rules per collection | ✅ Parità |
| AI/ML | Vertex AI, ML Kit | LLM locale (Ollama), Gemini, Vision, Video AI, RAG PDF, Deep Search | ✅ Superiore |
| Geocoding | Google Maps Geocoding API ($$$) | Nominatim (OpenStreetMap, GRATIS) | ✅ Parità |
| Directions/Navigation | Google Maps Directions API ($$$) | OSRM turn-by-turn (GRATIS) | ✅ Parità |
| Geofencing | Non integrato (servizio separato) | Geofence API + zone cantiere/sede | ✅ Superiore |
| Attendance/Presenze | Non disponibile | Auto check-in/out, overtime, veicoli | ✅ Esclusivo |
| WebRTC TURN/STUN | Non incluso | Server TURN/STUN integrato | ✅ Esclusivo |
| Web Search | Non disponibile | DuckDuckGo scraper + Deep Search AI | ✅ Esclusivo |
| Analytics | Google Analytics (completo) | Stats base (utenti, storage, funzioni) | ⚠️ Base |
| Remote Config | Firebase Remote Config | server-config endpoint | ⚠️ Base |
| Crashlytics | Firebase Crashlytics | Non disponibile | ❌ Manca |
| A/B Testing | Firebase A/B Testing | Non disponibile | ❌ Manca |
| Dynamic Links | Firebase Dynamic Links (deprecato) | Non necessario | ➖ N/A |
| Costo | $0.06/100K reads, $0.18/100K writes, Maps APIs $$$ | €0 — GRATIS per sempre | ✅ Imbattibile |
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
Come funziona l'isolamento
| Servizio | Namespace | Esempio |
|---|---|---|
| Firestore | u_<uid>_<collection> | Utente crea "prodotti" → salvato come u_abc123_prodotti |
| Storage | Bucket user_<uid> | File caricati in user_abc123 |
| Hosting | Campo owner = uid | L'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.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
Struttura regole 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
| Valore | Chi può accedere |
|---|---|
| public | Chiunque, anche senza token |
| auth | Qualsiasi utente autenticato con token valido |
| owner | Solo l'utente il cui UID corrisponde al campo userId del documento |
| admin | Solo utenti con ruolo admin |
| false / deny | Nessuno (accesso negato) |
Regole utente (per-user rules)
u_<uid>_*).// 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\" } } }" }
📱 Registrazione App Android
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
| Endpoint | Metodo | Descrizione |
|---|---|---|
| POST /user/apps/android | POST | Registra nuova app (auth utente) |
| GET /user/apps | GET | Lista app dell'utente |
| PUT /user/apps/:id | PUT | Aggiorna nome, SHA-256 o API key associata |
| DELETE /user/apps/:id | DELETE | Elimina app registrata |
| GET /admin/apps | GET | Lista tutte le app (solo admin) |
Ottenere la SHA-256
# 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
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() } }
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
/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
src/services/trubaxCloud.ts già creato nel progetto MagicPics e SpotifyX. Funziona identicamente ma usa 10.0.2.2:4000 per l'emulatore Android.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
── 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
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
| Metodo | Endpoint | Descrizione |
|---|---|---|
| POST /auth/me/avatar | multipart avatar | Upload foto profilo (max 5MB, JPG/PNG/GIF/WebP) |
| GET /auth/avatar/:id | public | Scarica avatar utente (cacheable 1h, SVG default se assente) |
| DELETE /auth/me/avatar | auth | Rimuovi foto profilo |
| PUT /auth/me | auth { displayName } | Aggiorna nome visualizzato |
| DELETE /auth/me | auth { password } | Elimina il proprio account (irreversibile) |
Esempio: Upload avatar da frontend
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
// 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)
DELETE /auth/me con body { "password": "..." }.
🔔 Push Notifications v10.0
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
| Metodo | Endpoint | Descrizione |
|---|---|---|
| GET /messaging/vapid-public-key | public | Ottieni VAPID public key per subscription |
| POST /messaging/subscribe | auth { subscription, topics } | Iscriviti a push notifications |
| POST /messaging/unsubscribe | auth { endpoint } | Disiscriviti |
| GET /messaging/poll | auth | Ricevi notifiche pendenti (mobile SDK) |
| POST /messaging/read/:id | auth | Segna notifica come letta |
| POST /messaging/send | admin { title, body, topic } | Invia notifica (admin) |
Esempio: Service Worker per Push
// 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
// 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'] }) });
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
✅ 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
- Setup utente post-registrazione: wizard con campi dati personali (nome, cognome, data nascita, telefono, bio) salvati nel campo
metadatadel DB - SDK endpoint avatar: aggiungere
/auth/sdk/userresponse conavatarUrlcompleto (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
── 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
| Status | Errore | Causa |
|---|---|---|
| 401 | Token non valido | Token scaduto o mancante nell'header |
| 403 | Accesso negato | Ruolo insufficiente o regola di sicurezza |
| 404 | Non trovato | Documento, sito o funzione non esistente |
| 400 | Richiesta non valida | Campi mancanti o formato errato |
| 500 | Errore server | Eccezione interna, vedi log server |
| 502 | API esterna fallita | Es. Gemini API error (vedi error.message) |
🔍 TrubaxSearch
Motore di ricerca stile Google. Scraping DuckDuckGo, risultati sponsorizzati TrubaxCloud, zero tracking.
Caratteristiche
- Ricerca web pubblica (no auth richiesta)
- Risultati sponsorizzati TrubaxCloud in cima
- Tabs: Web, Immagini, Video
- Rate limit: 30 ricerche/minuto per IP
API Endpoint
// Ricerca pubblica (no auth) GET /search/scrape?q=query&max=10 // Response { "query": "...", "results": [...], "count": 10, "source": "ddg" }
/api/web-search con Bearer token per funzionalità avanzate.
📁 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 }
🗺️ 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" }
🎤 STT/TTS Server-Side
Speech-to-Text e Text-to-Speech server-side per compatibilità iOS Safari.
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
- ✅ 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
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