StrataWeather
Quando inizia a piovere esattamente dove sei, combinando 27 previsioni
Cosa fa
Previsioni ultra-locali sull'orario della pioggia, ottenute combinando i risultati di 27 modelli meteo diversi.
Come guadagna
Startup appena presentata su BetaList, che non dichiara incassi. Idee nostre per guadagnare con un progetto simile: abbonamento per avvisi personalizzati, versione per chi lavora all'aperto.
Rendilo tuo
- Per chi lavora all'aperto in Italia: cantieri, agricoltori, ambulanti, matrimoni all'aperto.
- Avviso sul telefono 30 minuti prima della pioggia.
Le frasi da scrivere all'AI
1. Base del sito e grafica
Crea un'app web in italiano chiamata "Piove Fra Poco?": dice se e quando pioverà nelle prossime ore nel punto esatto in cui sei, mettendo insieme più modelli meteo ad alta risoluzione, con un avviso sul telefono prima che inizi. Usa React, Vite, TypeScript e Tailwind CSS.
Pagine da creare:
1. Pagina principale: "Pioggia tra 25 minuti" in grande, con il grafico delle prossime 6 ore
2. Dettaglio: quanto piove a ogni quarto d'ora e quanto sono d'accordo i modelli
3. I miei luoghi (casa, lavoro, campo da calcio)
4. Avvisi: "avvisami 20 minuti prima"
5. Come funziona e fonti
Stile: meteo pulito: sfondo azzurro chiaro #E0F2FE di giorno e blu notte #0C1A2E di sera, blu pioggia #2563EB, carattere "Inter", numero dei minuti gigante. Nessuna immagine generica di stock.
Tutto deve funzionare perfettamente da telefono. Tutti i testi in italiano, chiari e senza parole tecniche.
2. Database, account e sicurezza
Collega il progetto a Supabase e attiva la registrazione con email e password.
Crea queste tabelle:
- "luoghi": nome, coordinate, collegati all'utente
- "avvisi": luogo, minuti di anticipo, iscrizione alle notifiche push, ultimo avviso inviato
Regole di sicurezza obbligatorie:
- ogni utente vede solo i suoi luoghi e avvisi
- la posizione esatta si usa solo per la previsione e non si condivide
- il piano non si modifica dal browser
Usa esattamente il codice SQL che trovi nei "Dettagli tecnici" di questa scheda: eseguilo nel SQL Editor di Supabase prima di continuare, poi collega le pagine alle tabelle.
3. Più modelli insieme
Le previsioni vengono da Open-Meteo, che offre gratuitamente diversi modelli meteo ad alta risoluzione sull'Europa con dati ogni 15 minuti. Per lo stesso punto si chiedono più modelli insieme e si combinano: la pioggia prevista è la mediana dei modelli, e l'"accordo" è la quota di modelli che prevedono pioggia (codice nei Dettagli tecnici).
La pagina mostra in grande "Pioggia tra X minuti" o "Niente pioggia nelle prossime 3 ore", il grafico a barre ogni 15 minuti e quanto sono d'accordo i modelli ("8 modelli su 10").
Si cita sempre la fonte dei dati (Open-Meteo e i servizi meteo dei modelli) come richiesto dalla licenza.
4. Avvisi prima della pioggia
Per i luoghi salvati, ogni 15 minuti una funzione controlla la previsione e manda una notifica push se è probabile pioggia entro il tempo scelto (es. 20 minuti), una sola volta per evento di pioggia.
Pro: più luoghi, avvisi personalizzati (solo se pioggia forte, solo in certi orari), e storico di quanto le previsioni ci hanno preso.
5. Pagamenti con Stripe
Aggiungi un abbonamento a 1,99 € al mese o 14,99 € all'anno. Gratis l'utente ha: previsione nel punto attuale, senza avvisi. Con il piano Pro sblocca: luoghi salvati, avvisi push prima della pioggia, avvisi personalizzati e storico.
A pagamento riuscito il webhook porta l'utente al piano Pro; se l'abbonamento viene disdetto o non rinnovato lo riporta al piano gratuito.
Per la sessione di pagamento e il webhook segui la guida "Pagamenti con Stripe" di Fattibile.
6. Controlli specifici di questo progetto
Oltre ai controlli della guida "Controllo finale", verifica in particolare:
1. Avvisi: con pioggia prevista, controlla che l'avviso arrivi una sola volta e non ogni 15 minuti finché piove.
Correggi quello che non va e scrivimi cosa hai cambiato.
Dettagli tecnici
Pioggia dei prossimi quarti d'ora da più modelli
Chiede a Open-Meteo la pioggia ogni 15 minuti da più modelli e calcola mediana e accordo tra i modelli, poi trova quando inizia a piovere.
const MODELLI = ["icon_d2", "meteofrance_arome_france_hd", "italia_meteo_arpae_icon_2i", "best_match"];
type Quarto = { ora: string; mm: number; accordo: number }; // accordo: quota di modelli con pioggia
export async function pioggiaProssimeOre(lat: number, lng: number): Promise<Quarto[]> {
const url = "https://api.open-meteo.com/v1/forecast?latitude=" + lat + "&longitude=" + lng +
"&minutely_15=precipitation&forecast_minutely_15=24&timezone=Europe%2FRome&models=" + MODELLI.join(",");
const dati = (await fetch(url).then((r) => r.json())).minutely_15;
const ore: string[] = dati.time;
return ore.map((ora, i) => {
const valori = MODELLI.map((m) => dati["precipitation_" + m]?.[i]).filter((v): v is number => typeof v === "number");
const ordinati = [...valori].sort((a, b) => a - b);
const mediana = ordinati.length ? ordinati[Math.floor(ordinati.length / 2)] : 0;
return { ora, mm: mediana, accordo: valori.length ? valori.filter((v) => v >= 0.1).length / valori.length : 0 };
});
}
// Minuti all'inizio della pioggia (almeno metà dei modelli d'accordo), o null
export function minutiAllaPioggia(quarti: Quarto[], adesso = new Date()): number | null {
const primo = quarti.find((q) => q.mm >= 0.1 && q.accordo >= 0.5 && new Date(q.ora) >= adesso);
return primo ? Math.max(0, Math.round((new Date(primo.ora).getTime() - adesso.getTime()) / 60000)) : null;
}Avvisi una volta sola per ogni pioggia
Ogni avviso ricorda quando è stato inviato l'ultimo: non se ne manda un altro finché non sono passate 3 ore senza pioggia prevista.
create table luoghi (
id uuid primary key default gen_random_uuid(),
utente_id uuid not null references auth.users(id) on delete cascade,
nome text not null,
lat double precision not null,
lng double precision not null
);
create table avvisi (
id uuid primary key default gen_random_uuid(),
luogo_id uuid not null references luoghi(id) on delete cascade,
utente_id uuid not null references auth.users(id) on delete cascade,
minuti_anticipo int not null default 20 check (minuti_anticipo between 10 and 120),
iscrizione_push jsonb not null, -- endpoint e chiavi della notifica push
ultimo_inviato timestamptz
);
alter table luoghi enable row level security;
create policy "le mie righe" on luoghi
for all using (auth.uid() = utente_id) with check (auth.uid() = utente_id);
alter table avvisi enable row level security;
create policy "le mie righe" on avvisi
for all using (auth.uid() = utente_id) with check (auth.uid() = utente_id);
-- Avvisi da controllare ora: non inviati nelle ultime 3 ore
select a.id, l.lat, l.lng, a.minuti_anticipo, a.iscrizione_push
from avvisi a join luoghi l on l.id = a.luogo_id
where a.ultimo_inviato is null or a.ultimo_inviato < now() - interval '3 hours';
Pezzi comuni a tutti i progetti
Glossario
- Cron
- Un'operazione programmata che parte da sola a orari fissi, per esempio ogni lunedì mattina.
- JSONB
- Un tipo di colonna che contiene dati strutturati flessibili, come un piccolo documento.
- Modello meteo
- Un programma che simula l'atmosfera per prevedere il tempo: modelli diversi danno risultati un po' diversi.
- Notifica push
- Un avviso che arriva sul telefono anche quando il sito non è aperto.