Bilal Houari

Software Engineering Graduate & Data Engineering Student
FR / EN

Stage / SOS Helper

Développeur Full Stack

Entreprise
Smart Automation Technologies
Période
Avr 2026 — Jui 2026
Lieu
Tanger, Hybride
Next.jsSupabasePostgreSQLTypeScriptAIRAGDocker

NOTE

Next.js 16 + Supabase · cycle de vie à 8 états · assistant RAG · 650+ tests sur base réelle.

Tâches

Toute l’appli tourne autour des tâches. Chaque tâche suit un cycle de vie à 8 états, et chaque transition est une seule requête atomique UPDATE ... WHERE status =. Cette requête sert aussi de verrou : si deux personnes agissent sur la même tâche en même temps, une seule gagne, et l’état n’est jamais corrompu.

Données et auth

La stack est Next.js 16 (App Router, Server Components, Server Actions) avec Supabase en dessous pour Postgres, Auth, Realtime, Storage et pgvector. La logique métier vit dans 11 services, câblés à la main via une seule fonction factory. Pas de conteneur IoC.

Supabase est utilisé via deux clients. Le client serveur porte la clé service_role, contourne les RLS et exécute toute la logique métier. Le client navigateur porte la clé anon, est limité par les RLS à 6 tables sur 16, et ne gère que les abonnements Realtime et les uploads directs. La séparation est volontaire : le client serveur n’a pas de JWT utilisateur, donc il ne peut pas ouvrir de connexions Realtime, et le client navigateur ne voit pas les tables dont la logique a besoin.

L’autorisation est en couches. Les politiques RLS refusent tout par défaut et restreignent même les colonnes de tasks (les clients ne voient que id et requester_id). Par-dessus, chaque méthode vérifie le propriétaire avant toute écriture. Chaque entrée passe par l’un des ~30 schémas Zod, et le HTML est nettoyé avec sanitize-html après validation.

Assistant IA

L’assistant IA a été ajouté pour répondre aux questions et expliquer la plateforme aux utilisateurs. Il tire ce qu’il sait des docs et specs internes via RAG. Le pipeline RAG implémenté a quatre étapes : découpage Markdown par en-têtes, embeddings Gemini en 1536 dimensions, recherche vectorielle dans pgvector avec index IVFFlat, et récupération des top 5 chunks au-dessus d’un seuil cosinus de 0,5. Les réponses sont générées par Gemma 4 31B via streamText() du SDK Vercel AI, en streaming.

Deux choses le rendent robuste. consumeStream() supprime la contre-pression pour que le modèle finisse sa réponse même si l’utilisateur se déconnecte, et un second handler garantit que le callback de persistance s’exécute même en cas d’abandon — la réponse est toujours sauvegardée. Les titres de conversation viennent d’un autre modèle (Qwen 3 32B sur Groq), donc une panne du fournisseur de chat n’emporte pas les titres.

Infra et tests

Pas de file de jobs. Les cinq minuteurs (complétion auto, détection d’absence, expiration, rappels, clôture des évaluations) tournent en pg_cron → pg_net → Edge Function, entièrement dans Postgres et Supabase. L’Edge Function lit la clé service role dans Vault via un helper SECURITY DEFINER, pour que la clé n’atteigne jamais le client.

Le projet a été construit en TDD : 650+ tests en 21 fichiers, contre un vrai Supabase local. Rien n’est mocké, et les tests encodent les critères d’acceptation directement depuis les specs.