Athenify
Il cronometro dello studio: quante ore studi davvero e su cosa
Incasso mensile: 2400 USD (fonte indicata nella scheda)
Cosa fa
App per studenti che registra il tempo di studio per materia e mostra statistiche e progressi.
Come guadagna
Ha entrate ricorrenti ogni mese, verificate su TrustMRR. Prezzi e piani esatti sono indicati sul sito del progetto.
Rendilo tuo
- Per l'università italiana: esami, crediti, media ponderata e tempo per esame.
- Sfide con gli amici di corso su chi studia di più nella settimana.
Le frasi da scrivere all'AI
1. Base del sito e grafica
Crea un'app web in italiano chiamata "Ore di Studio": aiuta studenti universitari e delle superiori a contare il tempo di studio per materia, darsi obiettivi e vedere i progressi verso gli esami. Usa React, Vite, TypeScript e Tailwind CSS.
Pagine da creare:
1. Pagina iniziale con esempio di statistiche e prezzi
2. Registrazione e creazione delle materie (nome, colore, data dell'esame)
3. Cronometro grande con la materia scelta e il metodo Pomodoro facoltativo
4. Statistiche: ore per giorno, per materia, serie di giorni
5. Esami: conto alla rovescia e ore fatte rispetto all'obiettivo
Stile: da studio concentrato: sfondo crema #FFFBF2, blu inchiostro #1E3A8A, un colore per ogni materia, carattere "Inter" e numeri del cronometro in "JetBrains Mono" enormi. 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:
- "materie": nome, colore, data dell'esame, ore obiettivo, collegate all'utente
- "sessioni": materia, inizio, fine, note, collegate all'utente
Regole di sicurezza obbligatorie:
- ogni utente vede e modifica solo le sue materie e sessioni
- 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. Il cronometro che non si perde
Crea la pagina del cronometro: si sceglie la materia e si preme Avvia. Il tempo deve continuare a contare anche se si chiude la scheda o si spegne il telefono: salva l'ora di inizio (non i secondi trascorsi) e calcola il tempo dalla differenza (codice nei Dettagli tecnici).
Modalità Pomodoro facoltativa: 25 minuti di studio e 5 di pausa, con suono e notifica. Pulsante Pausa, e alla fine una nota facoltativa ("capitoli 3 e 4").
Se si dimentica il cronometro acceso più di 4 ore, alla riapertura chiedi "Hai studiato davvero fino ad ora?" con la possibilità di correggere l'orario di fine.
4. Statistiche ed esami
Pagina statistiche: grafico a barre delle ore degli ultimi 14 giorni colorate per materia, torta delle ore per materia del mese, serie di giorni consecutivi e media giornaliera.
Pagina esami: per ogni materia conto alla rovescia, ore fatte rispetto all'obiettivo e "Per arrivare all'obiettivo ti servono 1,5 ore al giorno". Inserimento manuale di sessioni dimenticate.
5. Pagamenti con Stripe
Aggiungi un abbonamento a 2,99 € al mese o 19,99 € all'anno. Gratis l'utente ha: 3 materie e statistiche degli ultimi 7 giorni. Con il piano Pro sblocca: materie illimitate, statistiche complete, esami con obiettivi ed esportazione CSV.
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. Cronometro: avvia una sessione, chiudi il browser, riaprilo dopo 10 minuti: il tempo deve risultare giusto.
Correggi quello che non va e scrivimi cosa hai cambiato.
Dettagli tecnici
Tabelle e ore per materia
Le materie, le sessioni di studio e la query delle ore studiate per materia nell'ultima settimana.
create table materie (
id uuid primary key default gen_random_uuid(),
utente_id uuid not null references auth.users(id) on delete cascade,
nome text not null,
colore text not null default '#1E3A8A',
data_esame date,
ore_obiettivo int
);
create table sessioni (
id uuid primary key default gen_random_uuid(),
utente_id uuid not null references auth.users(id) on delete cascade,
materia_id uuid not null references materie(id) on delete cascade,
inizio timestamptz not null,
fine timestamptz, -- null = cronometro ancora acceso
note text,
check (fine is null or fine > inizio)
);
alter table materie enable row level security;
create policy "le mie righe" on materie
for all using (auth.uid() = utente_id) with check (auth.uid() = utente_id);
alter table sessioni enable row level security;
create policy "le mie righe" on sessioni
for all using (auth.uid() = utente_id) with check (auth.uid() = utente_id);
-- Ore per materia negli ultimi 7 giorni
select m.nome, m.colore,
round(sum(extract(epoch from (s.fine - s.inizio))) / 3600, 1) as ore
from sessioni s
join materie m on m.id = s.materia_id
where s.utente_id = auth.uid()
and s.fine is not null
and s.inizio > now() - interval '7 days'
group by m.id, m.nome, m.colore
order by ore desc;Un cronometro che sopravvive alla chiusura
Non conta i secondi uno per uno: ricorda quando è partito e calcola la differenza. Così il tempo è giusto anche se il telefono si spegne.
const CHIAVE = "cronometro-attivo";
type Attivo = { materiaId: string; inizio: number }; // inizio in millisecondi
export function avvia(materiaId: string) {
const attivo: Attivo = { materiaId, inizio: Date.now() };
localStorage.setItem(CHIAVE, JSON.stringify(attivo));
return attivo;
}
export function inCorso(): Attivo | null {
try { return JSON.parse(localStorage.getItem(CHIAVE) ?? "null"); }
catch { return null; }
}
// Da chiamare ogni secondo solo per aggiornare il numero sullo schermo
export function trascorso(attivo: Attivo): string {
const s = Math.floor((Date.now() - attivo.inizio) / 1000);
const due = (n: number) => String(n).padStart(2, "0");
return due(Math.floor(s / 3600)) + ":" + due(Math.floor((s % 3600) / 60)) + ":" + due(s % 60);
}
export function ferma() {
const attivo = inCorso();
localStorage.removeItem(CHIAVE);
return attivo && { ...attivo, fine: Date.now() }; // da salvare nella tabella "sessioni"
}
Pezzi comuni a tutti i progetti
Glossario
- CSV
- Un file di testo con i dati separati da virgole, che si apre con Excel.
- localStorage
- Un piccolo spazio nel browser dove il sito salva dati che restano anche chiudendo la pagina.