Apogee
Carica centinaia di pubblicità su Meta in pochi minuti
Incasso mensile: 4200 USD (fonte indicata nella scheda)
Cosa fa
Strumento per chi gestisce pubblicità su Meta: caricare in blocco centinaia di immagini e video, un lavoro che con gli strumenti di Meta è lentissimo.
Come guadagna
Ha entrate ricorrenti ogni mese, verificate su TrustMRR. Prezzi e piani esatti sono indicati sul sito del progetto.
Rendilo tuo
- Per agenzie italiane con tanti clienti piccoli.
- Nomi delle campagne generati in automatico con una regola.
Le frasi da scrivere all'AI
1. Base del sito e grafica
Crea un'app web in italiano chiamata "Carica Tutto": permette a chi gestisce pubblicità su Facebook e Instagram di caricare in blocco centinaia di immagini e video come annunci, con nomi e testi ordinati, in pochi minuti. Usa React, Vite, TypeScript e Tailwind CSS.
Pagine da creare:
1. Pagina iniziale con il confronto "3 ore a mano / 5 minuti" e prezzi
2. Registrazione e collegamento degli account pubblicitari Meta
3. Nuovo caricamento: trascina i file, scegli campagna e gruppo, imposta i testi
4. Avanzamento del caricamento in tempo reale
5. Cronologia dei caricamenti
Stile: efficiente e tecnico: sfondo grigio chiaro #F1F5F9, blu #2563EB, verde #16A34A per i completati, rosso #DC2626 per gli errori, carattere "Inter", tabelle compatte. 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:
- "caricamenti": account, campagna, gruppo di annunci, impostazioni comuni (testo, titolo, link, invito all'azione), collegati all'utente
- "coda": un elemento per ogni file da caricare, con stato (in attesa, in corso, fatto, errore), tentativi ed eventuale messaggio di errore
Regole di sicurezza obbligatorie:
- ogni utente vede solo i suoi caricamenti e la sua coda
- i token di Meta stanno solo lato server
- la coda la lavora solo la Edge Function
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. Il caricamento in coda
Collega uno o più account pubblicitari con il login di Facebook e le API ufficiali di Meta (Marketing API).
Nel nuovo caricamento l'utente trascina fino a 500 file, sceglie campagna e gruppo di annunci, e imposta testi comuni con segnaposto ({nome_file}, {numero}). Una tabella mostra ogni annuncio che verrà creato, modificabile riga per riga.
I file vanno nello Storage e ognuno diventa un elemento della "coda". Una Edge Function, chiamata ogni minuto, prende 20 elementi alla volta (codice nei Dettagli tecnici), li carica su Meta e crea gli annunci in pausa. Rispetta i limiti di Meta: se Meta risponde "troppe richieste", aspetta e riprova; dopo 3 errori segna l'elemento come "errore" con il motivo.
4. Avanzamento e cronologia
Pagina di avanzamento aggiornata in tempo reale: barra con fatti/totale, tabella con lo stato di ogni file, e per gli errori il motivo in italiano ("Immagine troppo piccola: minimo 600 pixel") con il pulsante "Riprova".
Cronologia dei caricamenti con data, numero di annunci, errori e link per aprire la campagna in Meta.
5. Pagamenti con Stripe
Aggiungi un abbonamento a 29 € al mese. Gratis l'utente ha: 50 annunci al mese e un solo account. Con il piano Pro sblocca: annunci illimitati, più account pubblicitari e modelli di testo salvati.
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. Coda: chiudi il browser durante un caricamento di 100 file e riaprilo: il caricamento deve essere andato avanti da solo e nessun file deve essere caricato due volte.
Correggi quello che non va e scrivimi cosa hai cambiato.
Dettagli tecnici
La coda di lavoro
Ogni file è un lavoro in coda. La funzione prende un gruppo di lavori in modo sicuro: anche se due esecuzioni partono insieme, nessun file viene preso due volte (grazie a "skip locked").
create table caricamenti (
id uuid primary key default gen_random_uuid(),
utente_id uuid not null references auth.users(id) on delete cascade,
account_meta text not null,
gruppo_annunci text not null,
impostazioni jsonb not null,
creato_il timestamptz not null default now()
);
create table coda (
id bigint generated always as identity primary key,
caricamento_id uuid not null references caricamenti(id) on delete cascade,
utente_id uuid not null references auth.users(id) on delete cascade,
file_path text not null,
stato text not null default 'in_attesa'
check (stato in ('in_attesa', 'in_corso', 'fatto', 'errore')),
tentativi int not null default 0,
errore text,
id_annuncio_meta text,
aggiornato_il timestamptz not null default now()
);
alter table caricamenti enable row level security;
create policy "i miei caricamenti" on caricamenti
for all using (auth.uid() = utente_id) with check (auth.uid() = utente_id);
alter table coda enable row level security;
create policy "leggo la mia coda" on coda for select using (auth.uid() = utente_id);
-- Prende fino a "quanti" lavori e li segna in corso, senza doppioni
create function prendi_lavori(quanti int) returns setof coda
language sql security definer set search_path = public as $
update coda set stato = 'in_corso', tentativi = tentativi + 1, aggiornato_il = now()
where id in (
select id from coda
where stato = 'in_attesa'
or (stato = 'in_corso' and aggiornato_il < now() - interval '10 minutes') -- bloccati
order by id
limit quanti
for update skip locked
)
returning *;
$;
revoke execute on function prendi_lavori(int) from public, anon, authenticated;
grant execute on function prendi_lavori(int) to service_role;Riprovare quando Meta dice "troppe richieste"
Se l'API risponde con un limite di velocità, aspetta sempre di più prima di riprovare (1, 2, 4 secondi...).
export async function conRiprova<T>(azione: () => Promise<Response>, tentativi = 4): Promise<T> {
for (let i = 0; i < tentativi; i++) {
const r = await azione();
if (r.ok) return r.json();
const errore = await r.json().catch(() => ({}));
const limite = r.status === 429 || [4, 17, 32, 613].includes(errore?.error?.code);
if (!limite || i === tentativi - 1) {
throw new Error(errore?.error?.message ?? "Errore " + r.status);
}
await new Promise((ok) => setTimeout(ok, 1000 * 2 ** i)); // 1s, 2s, 4s...
}
throw new Error("Troppi tentativi");
}
Pezzi comuni a tutti i progetti
Glossario
- Storage
- Lo spazio di Supabase dove si salvano i file, come foto e audio, con le sue regole di accesso.
- 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.
- Coda di lavoro
- Un elenco di compiti da fare uno dopo l'altro sul server, che continua anche se l'utente chiude il browser.