Formflow
Moduli e questionari interattivi, senza programmare
Incasso mensile: 6000 USD (fonte indicata nella scheda)
Cosa fa
Permette di creare moduli online belli e personalizzati (iscrizioni, sondaggi, richieste) trascinando i campi, e di raccogliere le risposte in un unico posto.
Come guadagna
Ha entrate ricorrenti ogni mese, verificate su TrustMRR. Prezzi e piani esatti sono indicati sul sito del progetto.
Rendilo tuo
- Specializzalo: moduli di iscrizione per palestre e associazioni sportive, con pagamento della quota.
- Oppure questionari per ristoranti, collegati alle recensioni Google.
- Modelli pronti in italiano per le esigenze più comuni.
Le frasi da scrivere all'AI
1. Base del sito e grafica
Crea un'app web in italiano chiamata "Questionario": crea moduli e questionari belli (iscrizioni, sondaggi, richieste di preventivo) trascinando i campi, con logica condizionale e risultati in grafici. Usa React, Vite, TypeScript e Tailwind CSS.
Pagine da creare:
1. Pagina iniziale con modelli pronti e prezzi
2. Registrazione e accesso
3. Creatore: campi a sinistra, anteprima al centro, impostazioni a destra
4. Pagina pubblica del modulo /q/:slug, una domanda alla volta
5. Risultati: grafici, tabella ed esportazione
Stile: moderno e amichevole: sfondo lilla chiarissimo #F5F3FF, viola #6D28D9, testo #1E1B4B, carattere "Plus Jakarta Sans", pagina pubblica con una domanda per schermata e transizioni morbide. 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:
- "questionari": titolo, slug, campi in JSON con le regole condizionali, tema grafico, aperto o chiuso, collegati all'utente
- "risposte": risposte di ogni compilazione in JSON, data e tempo impiegato
Regole di sicurezza obbligatorie:
- i questionari aperti si compilano senza account
- le risposte si controllano sul server rispetto ai campi del questionario
- solo il proprietario vede le risposte
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. Campi e logica condizionale
Crea il creatore: tipi di campo (testo breve, testo lungo, email, telefono, numero, scelta singola, scelta multipla, scala da 1 a 10, data, sì/no), obbligatori o no, con testo di aiuto.
Logica condizionale: per ogni domanda si può dire "mostrala solo se la domanda X ha risposta Y". La pagina pubblica mostra una domanda alla volta, salta quelle nascoste, e ha la barra di avanzamento.
Le risposte si inviano a una Edge Function che le controlla (codice nei Dettagli tecnici): campi obbligatori presenti, email valide, scelte tra quelle previste, numeri nei limiti. Così nessuno può inviare dati sbagliati scavalcando il modulo.
4. Risultati
Nella pagina risultati mostra per ogni domanda un grafico adatto: barre per le scelte, media e distribuzione per le scale, elenco per i testi. Filtri per data e per risposta a una domanda ("solo chi ha risposto Sì alla 3").
Tabella completa con esportazione CSV ed Excel, notifica email per ogni risposta, e chiusura automatica del questionario a una data o dopo N risposte.
5. Pagamenti con Stripe
Aggiungi un abbonamento a 9 € al mese. Gratis l'utente ha: 3 questionari, 100 risposte al mese e niente logica condizionale. Con il piano Pro sblocca: questionari e risposte illimitati, logica condizionale, temi personalizzati ed esportazione Excel.
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. Validazione: invia direttamente alla Edge Function una risposta senza i campi obbligatori o con una scelta inventata: deve essere rifiutata.
Correggi quello che non va e scrivimi cosa hai cambiato.
Dettagli tecnici
Tabelle del database
Questionari con i campi in JSON e risposte. Le risposte le scrive solo la Edge Function, dopo il controllo.
create table questionari (
id uuid primary key default gen_random_uuid(),
utente_id uuid not null references auth.users(id) on delete cascade,
slug text not null unique,
titolo text not null,
campi jsonb not null default '[]',
aperto boolean not null default false,
chiude_il timestamptz
);
alter table questionari enable row level security;
create policy "aperti visibili" on questionari for select using (aperto or auth.uid() = utente_id);
create policy "gestisco i miei" on questionari
for all using (auth.uid() = utente_id) with check (auth.uid() = utente_id);
create table risposte (
id uuid primary key default gen_random_uuid(),
questionario_id uuid not null references questionari(id) on delete cascade,
dati jsonb not null,
secondi int,
creato_il timestamptz not null default now()
);
alter table risposte enable row level security;
create policy "risposte dei miei" on risposte for select using (exists (
select 1 from questionari q where q.id = questionario_id and q.utente_id = auth.uid()));Controllo delle risposte sul server
Confronta ogni risposta con i campi del questionario, compresa la logica condizionale: le domande nascoste non sono obbligatorie.
type Campo = {
id: string;
tipo: "testo" | "email" | "numero" | "scelta" | "multipla" | "scala" | "sino";
obbligatorio: boolean;
opzioni?: string[];
min?: number; max?: number;
mostraSe?: { campo: string; valore: string };
};
export function controllaRisposte(campi: Campo[], dati: Record<string, unknown>): string[] {
const errori: string[] = [];
for (const c of campi) {
const visibile = !c.mostraSe || dati[c.mostraSe.campo] === c.mostraSe.valore;
const v = dati[c.id];
if (!visibile || v === undefined || v === "") {
if (visibile && c.obbligatorio) errori.push(c.id + ": obbligatorio");
continue;
}
if (c.tipo === "email" && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(String(v))) errori.push(c.id + ": email non valida");
if (c.tipo === "scelta" && !c.opzioni?.includes(String(v))) errori.push(c.id + ": scelta non prevista");
if (c.tipo === "multipla" && (!Array.isArray(v) || v.some((x) => !c.opzioni?.includes(x)))) errori.push(c.id + ": scelte non previste");
if (c.tipo === "numero" || c.tipo === "scala") {
const n = Number(v);
if (Number.isNaN(n) || (c.min !== undefined && n < c.min) || (c.max !== undefined && n > c.max)) errori.push(c.id + ": numero fuori dai limiti");
}
}
// Scarta i campi che non esistono nel questionario
for (const chiave of Object.keys(dati)) if (!campi.some((c) => c.id === chiave)) errori.push(chiave + ": campo sconosciuto");
return errori;
}
Pezzi comuni a tutti i progetti
Glossario
- JSONB
- Un tipo di colonna che contiene dati strutturati flessibili, come un piccolo documento.
- CSV
- Un file di testo con i dati separati da virgole, che si apre con Excel.
- Slug
- La parte finale e leggibile dell'indirizzo di una pagina, es. /pizzeria-da-mario.
- Logica condizionale
- Domande che compaiono solo in base alle risposte precedenti, così ognuno vede solo quelle che lo riguardano.