Web app che, da un punto/poligono sulla mappa, stima impronta di carbonio e bilancio NPK "al cancello aziendale" usando solo dati pubblici (Tier 0), poi raffina con un chatbot di 5 driver (Tier 1). Output: piano di concimazione, risparmio concimi in €, compliance nitrati, benchmark, report PDF.
📋 Piano completo: ~/.claude/plans/realizza-il-piano-completo-tidy-zephyr.md
📚 Documenti di riferimento: documents/ (PRD, fonti dati, modello dati "Farm Data Requirements").
M0 — Fondamenta dati + KB + motore → ✅ in corso. Realizzato:
- Monorepo TypeScript (npm workspaces).
@core/kb— knowledge base versionata (YAML), cascata regione → paese → globale, con gate di validazione (ogni coefficiente deve averevalue/low/high/unit/source).@core/engine— motore di calcolo puro: carbon IPCC Tier 1 (Scope 1/2/3) + sequestro + bilancio NPK (Gross Nutrient Balance), con propagazione dell'incertezza (intervalli) e provenienza (estimated_public/declared_farmer/default_kb). Piano di concimazione + risparmio € + compliance nitrati ZVN.- Golden-set di test su un'azienda seminativa dell'Emilia-Romagna.
⚠️ I coefficienti marcati "DA VALIDARE" nella KB sono default standard di letteratura inseriti per far girare il motore: vanno spuntati su fonte primaria (IPCC 2019 Vol.4, ISPRA, DPI regionali) prima di qualsiasi uso operativo/commerciale.
Prossimo (M1): vertical slice "wow" Tier 0 — mappa + poligono (WFS catasto) → query dati pubblici → schermata stima in pochi secondi. Richiede provisioning Supabase/PostGIS e credenziali Sentinel Hub (CDSE).
packages/kb/ # @core/kb — knowledge base versionata + loader (gate di validazione)
packages/engine/ # @core/engine — motore carbon + sequestro + NPK (TS puro, golden-set)
documents/ # PRD, ricerca fonti dati, Farm Data Requirements
apps/web/ # (M1) Next.js: mappa, Tier 0, chatbot — da creare
supabase/ # (M0/M1) migrazioni PostGIS + job di ingest — da creare
npm install # installa le dipendenze del workspace
npm test # esegue i golden-set (vitest)
npm run typecheck # type-check TypeScript dell'intero workspace
npm run kb:validate# esegue il gate di validazione della knowledge base- Stack: TypeScript-only (Next.js su Vercel + Supabase/PostGIS). Python in Fase 2 dietro la "seam" dei provider.
- Dati Tier 0: ERA5-Land e SoilGrids NON sul percorso utente (lenti/instabili) → pre-ingeriti in PostGIS. NDVI live via Sentinel Hub Statistical API (CDSE). Niente Google Earth Engine in produzione.
- Settore-faro: seminativi, Italia (prima KB: Emilia-Romagna).
Estensioni oltre l'MVP (flusso utente, dashboard con report, chatbot testuale + vocale):
- Chatbot ibrido (testo) — la state machine guida flusso e calcolo (deterministici); l'LLM
(OpenAI, lato server in
/api/chat) fa SOLO NLU sul free-text ("3 bags of 50kg of 20-10-10" → kg N/P/K) e le spiegazioni. Validazione e mapping passano da@core/tier1(rawToPatch); se la chiave manca o l'LLM fallisce, si usa il parser deterministicoparseStepAnswer. I numeri non vengono mai inventati dall'LLM. - Chatbot vocale hands-free — scheda "Talk" nel chatbot: agente ElevenLabs Conversational AI
(STT+LLM+TTS) che riempie i 5 driver mentre si parla, aggiornando la stima live tramite client
tools. Signed URL generato lato server (
/api/voice), la chiave non lascia il server. - Account — Supabase Auth (email/password + Google) via client; le RPC viaggiano col JWT utente (RLS per-utente).
- Ricerca campo — barra indirizzo/luogo (Nominatim via
/api/geocode) che centra la mappa; poi si disegna il campo. Onboarding guidato (checklist auto-spuntante). - Persistenza + Dashboard — "Save to dashboard" → RPC
save_estimate./dashboard: riepilogo aziendale aggregato, lista "I miei campi", dettaglio campo con andamento nel tempo (grafico SVG), centro report (PDF ri-scaricabili) e link di condivisione pubblica (/share/[id]).
| Variabile | Scopo | Se assente |
|---|---|---|
OPENAI_API_KEY |
NLU free-text + spiegazioni del chatbot | fallback al parser deterministico |
OPENAI_MODEL |
modello (default gpt-4o-mini) |
usa il default |
ELEVENLABS_API_KEY |
sessione vocale (signed URL) | scheda "Talk" → "voice not set up" |
ELEVENLABS_AGENT_ID |
agente Conversational AI | scheda "Talk" → "voice not set up" |
NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEY sono pubbliche (la sicurezza è nelle RLS).
- Crea un agente in ElevenLabs → Conversational AI (LLM: il tuo OpenAI; lingua: inglese).
- Nel prompt di sistema dell'agente puoi usare le dynamic variables passate dall'app:
{{area_ha}},{{crop}},{{in_nvz}},{{crop_options}},{{species_options}}. - Definisci questi client tools (i nomi DEVONO combaciare con
components/VoiceAgent.tsx):set_crop(crop),set_management(organic),set_fertilizer(n_kg_ha, p_kg_ha, k_kg_ha),set_organic_nitrogen(n_kg_ha),set_yield(t_ha),set_residue(management)(incorporated/removed/burned),set_livestock(species, head),no_livestock(),set_diesel(litres_per_year),set_purchases(pesticide_kg),set_land(woodland_ha, hedgerow_km, trees),get_estimate(). - Copia
ELEVENLABS_API_KEYe l'agent_idnelle env Vercel. Il calcolo resta nel motore: l'agente raccoglie solo i valori, già validati lato client.