Tous les projetsProjet 01 / 06

Vellume

Année
2025
Rôle
SaaS éducatif · IA · Fullstack
Stack
Next.js 16, TypeScript, MySQL, Drizzle ORM, Better-Auth, Gemini AI, FSRS, Tailwind 4, Shadcn/UI, next-intl
Liens
Voir le siteDépôt privé

SaaS d'études pour les apprentis CFC ICT suisses. Scan de cours en PDF ou photo, génération de flashcards par IA (Gemini), tuteur RAG ancré dans tes propres notes, révisions selon l'algorithme FSRS, suivi complet des modules et compétences du plan de formation officiel. Architecture multi-providers IA (Gemini, Claude, BYOK), i18n FR/DE/IT, dark mode, CV PDF généré dynamiquement.

Étude de cas

Le contexte

Les apprentis CFC ICT révisent des dizaines de modules et de compétences, souvent avec des notes éparpillées. Vellume transforme leurs propres cours en fiches de révision et leur donne un tuteur qui répond à partir de leurs notes.

Mon rôle

Seul, de la conception à la production : produit, design, base de données, IA et déploiement. Le site est en ligne avec de vrais utilisateurs.

Défis techniques

  1. 01

    Un tuteur ancré dans les cours

    Le tuteur s'appuie sur la recherche augmentée (RAG) : il retrouve les passages utiles dans les documents importés avant de répondre, pour rester fidèle à ce que l'élève a réellement étudié.

  2. 02

    Des quotas IA impossibles à contourner

    Supprimer ses messages ou ses cartes remettait les compteurs à zéro. Chaque appel réserve maintenant une ligne dans un journal en ajout seul avant d'appeler le fournisseur, puis recompte : même des requêtes parallèles ne passent pas sous la limite.

  3. 03

    Un audit de sécurité complet

    Relais d'e-mails ouvert, injection HTML dans l'e-mail de vérification, pré-détournement de compte Google, SSRF sur les notifications push : une dizaine de failles corrigées, puis des sauvegardes nocturnes chiffrées.

Extrait de code

lib/rate-limit.tsExtrait d'un dépôt privé
/** Insère la réservation puis recompte ; au-delà de la limite, elle est retirée. */async function reserve(  userId: string,  kind: Kind,  units: number,  over: (usage: { calls: number; units: number }) => Extract<LimitResult, { ok: false }> | null,): Promise<Reservation> {  const id = crypto.randomUUID()  await db.insert(aiUsage).values({ id, userId, kind, units, createdAt: new Date() })  const usage = await usageSince(userId, kind)  const refused = over(usage)  if (refused) {    await db.delete(aiUsage).where(eq(aiUsage.id, id))    return refused  }  return { ok: true, id }}
Réserver avant d'appeler l'IA, puis recompter : la limite tient même sous des requêtes simultanées.

Résultat

En ligne sur vellume.ch : flashcards générées par IA, révisions FSRS, suivi des modules et des compétences du plan de formation, en français, allemand et italien.

Vellume — Page d'accueil
Fig. 01Page d'accueil
Vellume — Tableau de bord
Fig. 02Tableau de bord
Vellume — Révisions FSRS
Fig. 03Révisions FSRS
Vellume — Tuteur IA (RAG)
Fig. 04Tuteur IA (RAG)
Vellume — Notes par module
Fig. 05Notes par module
Vellume — Suivi des compétences
Fig. 06Suivi des compétences
Vellume — Profil apprenti
Fig. 07Profil apprenti
Vellume — Mode sombre « ardoise »
Fig. 08Mode sombre « ardoise »
Vellume — Fonctionnalités
Fig. 09Fonctionnalités
Vellume — Fonctionnement
Fig. 10Fonctionnement
© 2026 Giovanni Salcuni · Conçu & développé par moi-mêmeHeure locale (Suisse) ·
Mode présentationConfidentialité