Runze Yuan

Runze Yuan 袁润泽

Développeur full-stack Java / React, IA appliquée. Élève-ingénieur en dernière année à CY Tech (diplôme 2027).

Je cherche un stage de fin d’études de six mois à partir du 4 mai 2027, à Paris ou en Île-de-France.

En bref

Formation
Ingénieur en informatique, CY Tech, diplôme 2027
Expérience
2 ans et 8 mois en entreprise avant CY Tech ; depuis 2026, un CDI à temps partiel et une mission freelance
Langues
Français B2, anglais B2, chinois natif
Stage
Six mois, à partir du 4 mai 2027
D’ici là
Disponible dès maintenant pendant les semaines entreprise de mon cursus
Après le stage
Ouvert à une embauche en CDI
Lieu
Cergy (95), Île-de-France

Seul développeur, en orchestrant des agents IA, j’ai conçu et mis en production le système de pilotage d’une usine de cuir (MES / IIoT). Il collecte les mesures des machines, les fiabilise, calcule les quantités produites et la paie à la pièce, et présente le tout dans huit applications web et Android.

8
applications web et Android sur un seul contrat d’API
49
versions livrées en 5 mois, soit plus de deux par semaine
≈ 10 500
tests automatisés, en Java et en Kotlin
≈ 10
machines d’atelier connectées en temps réel
Que montre l’animation ?

Simulation : chaque ligne est une fenêtre de mesures d’une machine de pulvérisation, la plus récente s’écrit en bas. Une mesure suspecte n’est jamais corrigée en silence : elle est signalée en rouge, avec le code de l’anomalie.

Un système IIoT complet, de la machine à l’écran

Jiarun IOT : logiciel de pilotage de production (MES) et de machines connectées (IIoT) pour l’industrie du cuir. Mission indépendante (freelance), seul développeur, depuis mai 2026. En production chez un fabricant de cuir ; version 1.4.11 déployée le 12 octobre 2026. Site du produit : jiarun.tech.

Le trajet d’une mesure, de la machine à l’écran, en six étapes :

  1. Atelier : les machines

    Détails

    Chaque machine a un écran industriel (IHM) relié à son automate. J’ai défini le format des messages que ces écrans envoient (protocole MQTT) et l’identité de chaque machine ; les ingénieurs de l’usine configurent les écrans selon cette spécification.

    device/{clientId}/spray device/{clientId}/energy-points

    • Pulvérisation, v1 puis v2 : la v2 numérote chaque message, ce qui permet de reconnaître un doublon.
    • Énergie (électricité, vapeur, eau) : un format fixe à 6 canaux (77 champs) et un format à points configurables, décrit par un inventaire versionné terminal → équipement → point ; au plus 64 équipements, 256 points et 128 Kio par message.
    • Identité : un identifiant de connexion (ClientID) permanent par machine, attribué par le back-end de la plateforme et jamais réutilisé.
  2. Broker MQTT : le relais des messages

    Détails

    Le broker (Mosquitto) reçoit les messages des machines et les transmet au back-end. Livraison garantie (QoS 1) et sessions persistantes : si le back-end s’arrête, le broker garde jusqu’à 20 000 messages, soit environ 80 minutes d’arrêt absorbées sans perte.

    • VerneMQ, évalué un temps, a été retiré : un seul broker à exploiter.
    • Côté Java, client Paho avec cleanSession=false : la session reprend là où elle s’était arrêtée.
  3. Réception : rien de perdu, rien en double

    Détails

    Le back-end ne confirme un message au broker qu’une fois celui-ci enregistré en base. Si l’écriture échoue, le message n’est pas confirmé et le broker le renvoie. Un message reçu deux fois n’est compté qu’une fois.

    • Clé d’unicité client|seq|deviceTime : un renvoi est reconnu comme doublon ; la même clé avec un contenu différent est rejetée.
    • Un message mal formé ne peut pas couper la connexion.
    • Les mesures enregistrées ne sont jamais modifiées. Une mesure arrivée en retard recalcule les intervalles voisins en une seule transaction, dans l’ordre chronologique de la machine.
  4. Qualité : signaler, ne jamais maquiller

    Détails

    Une mesure suspecte n’est pas corrigée : elle reçoit des drapeaux qui disent pourquoi. Exemples : valeur impossible ou hors de la plage physique, code spécial, message manquant ou en double, horloge décalée de plus de 10 minutes. La valeur brute est conservée, mais exclue des statistiques.

    • On peut ajouter des drapeaux, jamais changer le sens des anciens ; la valeur stockée n’est jamais réécrite.
    • Indicateurs à trois états : vrai, faux ou inconnu (une donnée absente n’est pas « faux »). Codes spéciaux connus : une vitesse de 99 signifie « nettoyage ».
    • Compteurs : remises à zéro, débordements 16 et 32 bits, valeurs manquantes, trous trop longs. Unités converties à l’arrivée (jin chinois et kg, pied² et m², g/m²).
    • Pas d’interpolation, pas de zéro inventé : un intervalle douteux sort des statistiques, et un total incomplet est publié comme « partiel », avec son taux de couverture.
  5. Stockage et API

    Détails

    PostgreSQL 16 avec TimescaleDB, une extension pour les séries temporelles. Les totaux par heure et par jour sont recalculés seulement là où une mesure a changé, et les écrans se mettent à jour en temps réel (WebSocket). Une requête trop lourde échoue plutôt que de renvoyer un total incomplet.

    • Deux back-ends Spring Boot (Java 25, 10 modules Maven) : l’un fait tourner l’usine, l’autre gère la plateforme ; chacun a sa base et ses migrations Flyway.
    • Tests : ArchUnit vérifie les frontières entre modules, Testcontainers lance un vrai PostgreSQL pour les tests d’intégration, PIT mesure l’efficacité des tests par mutation.
    • Erreurs : le client reçoit un code stable et un identifiant de trace, jamais de SQL, de pile d’appels ni de donnée personnelle.
    • Pagination par curseur : des listes stables, même quand de nouvelles mesures arrivent pendant la lecture.
  6. Huit applications

    Détails

    Un seul contrat d’API (openapi.json) génère le code client Kotlin et TypeScript de toutes les applications : si l’API change, les applications Android ne compilent plus tant qu’elles n’ont pas suivi. Règle métier : les mesures des machines ne créent jamais de déclaration de production ni de salaire. La machine mesure ; seul un humain déclare ce qui est payé.

    • Console de production et de paieReact 19
    • Centre d’exploitationReact 18
    • Site publicNext.js 15
    • Analyse IA pour la directionPWA
    • Tablette d’atelierKotlin
    • Téléphone d’opérateurKotlin
    • Application mobileKotlin
    • Écran de poste de travailKotlin
    Technologies des applications
    • Web : React 19, TypeScript, TanStack Router, Query et Table, Zustand, react-hook-form et Zod, react-intl, Tailwind ; tests avec Vitest, MSW et Playwright ; frontières de modules vérifiées par ESLint.
    • Android : Kotlin 2.2, Jetpack Compose, Hilt, Room, Retrofit, WorkManager, CameraX ; sept langues ; mode kiosque (Device Owner) et mises à jour à distance (OTA).
    • Voix : un service Python (faster-whisper) transcrit les enregistrements vocaux.
Des machines aux huit applications : broker MQTT, réception, qualité, stockage, contrat d'API Atelier ≈ 10 machines, compteurs Broker MQTT Mosquitto, QoS 1 Réception confirmé après écriture Qualité drapeaux d'anomalie PostgreSQL + Timescale 2 back-ends Spring Boot Agent IA lecture seule openapi.json WebOpsSitePWA IAPadPhoneMobilePoste
Contexte, chiffres, cinq décisions≈ 2 min de lecture

Le contexte : l’usine applique des finitions sur des peaux par pulvérisation et paie ses ouvriers à la pièce. Elle veut savoir, machine par machine et poste par poste, ce qui a été produit, consommé et payé. La difficulté : les écrans industriels des machines perdent des messages, se font parfois passer les uns pour les autres et changent d’unités, alors que la paie ne tolère aucune approximation.

Tests
Environ 5 200 tests Java et 5 300 tests Kotlin, plus 226 fichiers de tests front-end.
Livraison
49 versions depuis mai 2026. La dernière a appliqué 6 migrations de base de données en 0,6 s, sans erreur.
Matériel
Environ 10 machines de pulvérisation connectées, et 13 terminaux Android enregistrés : 4 tablettes, 7 téléphones, 2 écrans de poste.
Performance
Test de charge synthétique sur le vrai code : 65,7 messages enregistrés par seconde, 95 % d’entre eux en moins de 18,9 ms, 0 erreur. Une mesure de test, pas un SLA de production.

Chiffres relevés le 12 octobre 2026.

Cinq décisions, et ce qu’elles m’ont coûté

Confirmer un message seulement une fois enregistré

PourquoiUn message n’est perdu que si la base l’a refusé, et dans ce cas le broker le renvoie.

Ce que ça m’a coûtéChaque renvoi crée un doublon à reconnaître : il faut une clé d’unicité sur chaque message, et une règle claire quand une même clé revient avec un contenu différent.

Signaler les anomalies, ne jamais réécrire les valeurs

PourquoiUne valeur réécrite est une preuve détruite. Quand une règle de nettoyage change, il faut pouvoir recalculer tout l’historique.

Ce que ça m’a coûtéLes statistiques se calculent à la lecture ou se reconstruisent. Chaque changement d’algorithme oblige à recalculer l’historique, après une répétition sur une copie de la production.

Ne jamais inventer un zéro

PourquoiUn compteur absent ne vaut pas zéro. La paie et les totaux de production ne peuvent pas reposer sur une estimation.

Ce que ça m’a coûtéCertains totaux restent « partiels », et l’interface doit l’afficher : un tableau de bord moins flatteur, mais juste.

Un seul contrat d’API pour huit applications

PourquoiHuit applications qui évoluent chacune à leur rythme doivent comprendre le serveur exactement de la même façon.

Ce que ça m’a coûtéChaque changement de champ oblige à régénérer le code et à recompiler les modules Android. Côté TypeScript, l’outil (springdoc) ne marque pas les champs obligatoires : la forme des données est vérifiée, pas leur présence. Ce travail d’annotation reste à faire.

Intégrer vite, ne déployer que ce qui est entièrement validé

PourquoiLes agents produisent plus vite que la batterie complète de tests ne tourne : l’attendre à chaque fusion aurait bloqué le travail.

Ce que ça m’a coûtéLa branche principale peut rester rouge un moment ; on corrige en avançant. Seule une version validée par toute la batterie, sur une machine de test dédiée, peut partir en production.

Quand les données de terrain mentent

Un système industriel se juge sur ses vraies données. La règle : recalculer l’historique, jamais retoucher une mesure brute.

Quatre problèmes trouvés en production

Un filtre trop strict effaçait de la vraie production

Cause et correction
Constat
Sur une machine, la surface produite en une journée était sous-comptée de 54 %.
Cause
Un filtre anti-bruit rejetait tout débit supérieur à 8 unités par seconde. Or certaines cadences réelles dépassaient ce plafond.
Correction
Filtre remplacé par un algorithme appliqué à la lecture (spray-interval-v4), sans toucher aux mesures brutes, puis historique recalculé. Répétition d’abord sur une copie de la production : 1 363 lignes horaires et 75 lots de production recalculés en 4 minutes environ.
Preuve
Sur 4 jours-machine, les totaux publiés concordent avec une référence externe, à 1 % près au pire.

Huit machines, une seule identité

Cause et correction
Constat
Les données de chaque machine n’arrivaient que 8 à 33 % du temps.
Cause
Huit écrans utilisaient le même identifiant de connexion MQTT. Le broker n’accepte qu’une connexion par identifiant : les écrans s’éjectaient les uns les autres, environ 25 000 fois par jour.
Diagnostic
Des mesures perdues, mais jamais attribuées à la mauvaise machine : ce qui arrivait restait fiable.
Correction
Un identifiant permanent par machine, attribué par le back-end, et un plan de migration machine par machine pour l’usine.

Un champ qui ne voulait pas dire ce que son nom disait

Cause et correction
Constat
La matière consommée par une machine était surestimée d’environ 4,5 fois.
Cause
Son champ « poids utilisé » (usedWeight) ne contenait pas un cumul, mais un écart : W0 − totalWeight.
Détection
Un bilan matière : une machine ne peut pas consommer plus que ce qu’on y a chargé.
Correction
Le calcul utilise désormais la vraie signification du champ pour cette machine.

Un incident en production, corrigé le jour même

Cause et correction
Constat
En production, les données de pulvérisation ont cessé de se mettre à jour.
Cause
Un rafraîchissement en temps réel relisait une table entière chaque seconde.
Correction
Correctif livré le jour même (version 1.4.7, le 5 octobre 2026), avec au plus 79 s d’interruption de l’API, puis consolidé dans la version 1.4.8.
Démo : pourquoi une moyenne ment≈ 1 min de lecture

Pourquoi une moyenne « mesure par mesure » ment

Une machine envoie plus de mesures quand elle travaille que quand elle est à l’arrêt. Une moyenne calculée mesure par mesure donne donc trop de poids aux moments d’activité, et elle change dès que l’on stocke moins de mesures. Pondérée par la durée de chaque mesure, la moyenne reste juste.

0 min15 min30 min45 min60 minpondérée par la duréemesure par mesure
Débit moyen sur une heure simulée, en m²/h. Valeur réelle : 535,1
StockageMesure par mesurePondérée par la durée
1 mesure / 2 s783,9 +46,5 %535,1 0,0 %
1 mesure / 10 s667,9 +24,8 %535,1 0,0 %
1 mesure / 60 s518,0 −3,2 %535,1 0,0 %
Simulation pédagogique. Sur les vraies données de l’usine, le même test donnait un écart médian de ±13 % pour la moyenne mesure par mesure, contre 0 pour la moyenne pondérée par la durée. Les statistiques utilisent donc la pondération par la durée, et le volume stocké n’est réduit qu’après avoir prouvé, en rejouant l’historique, que les résultats ne changent pas.

L’IA dans mes produits : le modèle propose, le code vérifie

Trois systèmes, une même règle : le serveur vérifie chaque chiffre, chaque plat et chaque correction avant qu’ils n’arrivent à l’utilisateur.

Un agent d’analyse pour l’usine, écrit sans framework

Jiarun IOT, 2026. Java. Intégré au back-end de production, activable usine par usine.

Le dirigeant pose une question ; l’agent répond avec des graphiques dont aucun chiffre n’est écrit par le modèle.

Voir la démo et le détail≈ 2 min de lecture

Je n’utilise pas de framework d’agents : j’écris moi-même la boucle, et je limite ce que le modèle a le droit de faire.

Le dirigeant de l’usine pose une question en langage courant. L’agent interroge la base en lecture seule et répond avec des graphiques dont chaque chiffre vient de la base, pas du modèle. Le même agent sert d’aide intégrée au produit, c’est-à-dire de support client.

Quelle machine a consommé le plus d’énergie cette semaine ?
  1. brouillon enregistré, en attente de confirmation
  2. confirmé : le brouillon est exécuté tel quel, 90 s au plus
  3. 1describeliste les vues autorisées pour ce rôle (lecture seule)
  4. 2querySELECT machine, SUM(kwh) AS kwh FROM v_energie_jour WHERE jour >= current_date - 7 GROUP BY machine ORDER BY kwh DESC12 lignes, complet → evidence-1
  5. 3chart{ evidenceId: "evidence-1", type: "BAR" }le serveur lit les valeurs dans evidence-1 ; usine ✓ unité ✓
  6. 4reviewsans outils : rédige la réponse finale
  7. rapport PDF enregistré, empreinte SHA-256 vérifiée au téléchargement
Trace d’exemple, données fictives. Le modèle n’a écrit aucun des quatre chiffres du graphique : il a seulement cité evidence-1.
  • Une boucle bornée : 16 étapes et 64 appels d’outils au plus. Chaque appel est vérifié (outil autorisé, paramètres conformes) avant tout accès à la base.
  • Lecture seule, sur des vues approuvées, avec un compte de base de données par usine et par rôle. Si ce compte manque, l’agent refuse ; il ne se rabat jamais sur un compte qui peut écrire.
  • Le modèle n’écrit aucun chiffre : un graphique cite une preuve (le résultat d’une requête), et le serveur en lit les valeurs en vérifiant l’usine, les unités et que le résultat est complet.
  • Mode aide, qui sert de support client : 32 articles relus, filtrés selon l’application et le rôle. L’agent lit l’article en entier avant de répondre et cite ses sources.
Plus de détails
  • Brouillon, puis confirmation : la question est enregistrée, puis exécutée telle quelle ; confirmer deux fois ne la relance pas, et le rapport PDF porte une empreinte SHA-256.
  • Application mobile (PWA) pour la direction, avec dictée vocale sur l’appareil (sherpa-onnx en WebAssembly, modèle de 102 Mo vérifié par SHA-256) : la voix ne quitte jamais le téléphone.

Un assistant WhatsApp pour des restaurants

Ruby Tech, 2026. Seul responsable de l’assistant au sein de l’équipe (194 des 199 commits du module). Java 21, Spring Boot 3, PostgreSQL 16, Redis.

Il répond aux clients à partir des vraies données du restaurant ; plats et allergènes sont contrôlés par le code.

Voir la démo et le détail≈ 2 min de lecture

Les clients d’un restaurant écrivent sur WhatsApp ou sur le site : horaires, carte, allergènes, réservation. L’assistant répond dans leur langue à partir des vraies données du restaurant, et passe la main à l’équipe quand il le faut.

  1. Bonsoir, vous êtes ouverts dimanche midi ?

  2. Bonsoir ! Je suis l’assistant IA du restaurant. Oui, dimanche de 12 h à 14 h 30. Je vous réserve une table ?

    RéserverVoir la carte

    débitentréequotacachebudgetmodèle

    horaire vérifié dans les données du restaurant

  3. Vous avez un plat sans gluten ?

  4. Oui : le risotto aux cèpes et le saumon grillé sont indiqués sans gluten par le restaurant.

    Voir la carte

    débitentréequotacachebudgetmodèle

    plats en vente uniquement, selon les étiquettes du restaurant

  5. Je parle à une vraie personne ?

  6. Non, je suis une IA. Je préviens l’équipe : quelqu’un vous répondra pendant les heures d’ouverture.

    Appeler le restaurant

    débitentréequotacachebudgetmodèle

    mention IA obligatoire, relais vers un humain

Conversation d’exemple avec un restaurant fictif. Sous chaque réponse : les contrôles franchis avant d’appeler le modèle, puis la vérification faite par le serveur.
  • Un seul circuit de réponse pour le site, WhatsApp et les messages vocaux : un nouveau canal n’est qu’un adaptateur, jamais un second circuit.
  • Cinq contrôles avant d’appeler le modèle, du moins cher au plus cher : débit, validité de l’entrée, quotas et interrupteurs d’arrêt, cache de réponses, réservation de budget.
  • Une hallucination n’est pas une instruction : chaque plat proposé par le modèle est revérifié contre la carte en vente, et les allergènes comme les mentions légales sont garantis par le code, pas par le prompt.
  • Intégration directe de l’API WhatsApp Business : messages signés (HMAC), réponse immédiate puis traitement en arrière-plan, doublons écartés, fenêtre de 24 h respectée. Si un format de message échoue, l’envoi se replie pas à pas jusqu’au texte simple, pour que la mention « je suis une IA » exigée par l’AI Act (art. 50) arrive toujours.
Plus de détails
  • Évaluation automatique : des cas de test tirés de chaque restaurant, des vérifications faites par le code (intention, plats en vente, allergènes ; chaque prix et chaque horaire cités doivent exister dans les données) et le coût de chaque campagne.
  • Couche IA maison multi-fournisseurs (API compatibles OpenAI et Anthropic) : routage, plafonds de coût, cache de prompt. Six langues. Les messages vocaux sont transcrits en mémoire, jamais stockés.

Jellydog : une correction de phrases par IA, mesurée avant la mise en ligne

Projet personnel, en ligne sur jellydog.fr. Go, React et TypeScript, PostgreSQL 17.

L’IA corrige une phrase en quelques secondes ; sa qualité a été mesurée contre des seuils fixés à l’avance.

Voir la démo et l’évaluation≈ 2 min de lecture

Une application de vocabulaire pour les étudiants sinophones en France. L’apprenant écrit une phrase avec le mot du jour ; l’IA la corrige en quelques secondes et explique les erreurs en chinois. Pas de note ni d’avis sur le style : seulement les erreurs objectives.

Mot du jour emprunter

Hier, j’ai emprunté deux livre à la bibliothèque.

Hier, j’ai emprunté deux livres à la bibliothèque.

名词复数要加 -s:deux livres。 (« Un nom au pluriel prend un -s. »)

Emploi du mot du jour : correct

  • Un filtre simple passe avant l’IA : 30 des 197 phrases de test (impossibles à évaluer, ou simple copie de l’exemple) sont traitées sans appeler le modèle.
  • Réponse au format JSON strict (JSON Schema) : chaque erreur signalée doit apparaître une seule fois dans la phrase, sans chevauchement, et c’est le serveur qui reconstruit la phrase corrigée. Le modèle ne réécrit jamais la phrase.
Plus de détails
  • Des fiches d’erreurs fréquentes pour chaque exercice, que le modèle cite par numéro : une seule référence invalide rejette tout le résultat.
  • Chaque campagne d’évaluation enregistre l’empreinte du prompt, du jeu de test, du schéma et des fiches ; le validateur en Go doit rejeter exactement ce que rejette le validateur Python.
Seuils fixés avant de mesurer ; résultats sur les 167 phrases envoyées au modèle
CritèreSeuilSans fichesAvec fiches
Emploi du mot du jour bien jugé≥ 90 %94,6 %95,2 %
Mauvais emploi accepté à tort≤ 5 %3,6 %1,8 %
Réponses inexploitables≤ 1 %0 %0 %
Temps de réponse (95 % des cas)≤ 3,2 s3,16 s2,12 s
Prompt servi par le cache–0 %76 %
Coût de la campagne–0,024 $0,013 $

Premier passage avec fiches : 92,8 %. Le modèle prenait les détails du scénario pour un changement de sens ; j’ai corrigé deux phrases de la consigne, relancé, et conservé les trois passages. Les phrases de test sont synthétiques : ce n’est pas une correction d’enseignant.

Travailler avec des agents IA : je décide, ils exécutent, les tests tranchent

Outils : Claude Code, Codex et Cursor, avec plusieurs agents en parallèle.

L’IA ne m’a pas surtout fait coder plus vite. Elle m’a libéré du temps pour ce qui ne se délègue pas, décider :

Environ 3 900 commits et 49 versions en cinq mois, seul développeur, avec jusqu’à une vingtaine d’agents en parallèle, chacun dans sa propre copie du dépôt. Avec des agents, le volume ne prouve plus rien : ce qui compte, c’est ce que les tests et la production confirment.

Le trajet d’une modification, de l’agent à la production :

  1. Copie isoléechaque agent travaille dans sa propre copie du dépôt (worktree Git) et s’arrête à un commit ; je relis le diff
  2. Intégrationrebase, migrations de base vérifiées (numéros uniques, jamais modifiées), tests rapides des applications touchées
  3. Branche mainla batterie complète de tests démarre sur une machine de test dédiée
  4. main-verifiedn’avance que sur un commit où tous les tests passent
  5. Productionne reçoit que ce commit, après une répétition sur une copie de la production et un retour arrière testé
Mes principes, et un test A/B≈ 1 min de lecture

Le contexte est un budget

Le fichier d’instructions lu à chaque session ne contient que les malentendus qui coûtent cher et des pointeurs ; le reste est chargé à la demande.

Une règle importante doit être vérifiée par une machine

Si une règle peut être vérifiée automatiquement, elle devient un hook, un test d’architecture ou un contrôle de cohérence. Une règle qu’il faut répéter aux agents est mal placée.

Le test est le contre-pouvoir

Un bon test juge le code de l’extérieur au lieu de le recopier : c’est ce qui empêche un agent de valider son propre travail.

Une source, plusieurs outils

Les règles sont écrites une fois, puis générées pour chaque outil d’agent ; un vérificateur refuse toute divergence. Le même principe que le contrat d’API, appliqué aux règles.

J’ai mesuré l’effet de mes propres consignes d’agent

Mes consignes réutilisables (« skills ») changent-elles vraiment le comportement de l’agent ? Test A/B avec un protocole fixé avant de mesurer, dans un bac à sable avec un vrai dépôt distant. Les verdicts viennent de l’état du dépôt, pas du récit de l’agent ; scénarios placebo et relecture à l’aveugle.

  1. Nouvelle fonctionnalité

    Avec le skillteste les cas d’erreur, attend une validation

    Sansse déclare « terminé » et commite directement

    Verdictléger avantage

  2. Réécriture de données

    Avec le skillrésultat identique

    Sansidentique, octet pour octet

    Verdictskill inutile, retiré

  3. Commit et envoi

    Avec le skilla lu la règle, puis a quand même poussé sur la branche principale

    Sansa ouvert une branche

    Verdictrègle transformée en blocage automatique (hook)

Résultat : +26 % de tokens par exécution, pour un gain irrégulier face à un modèle déjà performant. Deux skills retirés ; ce qui doit absolument tenir est passé dans un hook qui bloque. Essai pilote, une exécution par variante : un signal, pas une statistique.

Parcours

Deux ans et huit mois en entreprise avant l’école d’ingénieur, puis trois produits menés en parallèle des études.

  1. mai 2026 →

    Jiarun IOT

    Développeur full-stack, seul sur tout le logiciel, mission indépendante (freelance)

    Logiciel de pilotage de production et de machines connectées pour l’industrie du cuir, en production chez un fabricant. Du protocole des machines jusqu’aux applications. Site du produit : jiarun.tech.

  2. mai 2026 →

    Ruby Tech

    Développeur full-stack, CDI à temps partiel, après un stage de quatre mois

    Plateforme de commande et de fidélisation pour restaurants. J’y développe l’assistant IA WhatsApp, une partie du back-office (React, TypeScript) et le déploiement sur le terrain : serveurs installés automatiquement dans les restaurants, tablettes Android en mode kiosque, centre d’exploitation auto-hébergé pour surveiller et mettre à jour le parc à distance.

  3. 2026 →

    Jellydog

    Projet personnel, en ligne sur jellydog.fr

    Application d’apprentissage du vocabulaire français, avec correction de phrases par IA ; 201 leçons en ligne.

  4. 2025 → 2027

    CY Tech, CY Cergy Paris Université

    Diplôme d’ingénieur en informatique, spécialité informatique embarquée

    Cursus suivi intégralement en français.

  5. sept. 2021 → avr. 2024

    Tangshan Huahong Technology, Chine

    Développeur front-end (Vue 2)

    Interfaces web en Vue 2 et JavaScript : équipements de numérisation 3D et terminal de paiement par reconnaissance faciale.

  6. 2017 → 2021

    Université Xidian, Xi’an

    Licence en ingénierie électronique et de l’information, parcours sino-français

Compétences

Tout ce qui suit a servi en production, pas seulement en projet d’école.

Back-end
Java 17–25, Spring Boot 3 / 4 (Security, JWT, Data JPA, WebSocket, Actuator), Go, API REST sous contrat OpenAPI, Flyway, Maven
Front-end
TypeScript, React 18 / 19 (TanStack Router, Query, Table, react-hook-form, Zod, Zustand), Next.js 15, Vue 3, Tailwind, PWA, internationalisation, accessibilité
Mobile
Android Kotlin (Jetpack Compose, Hilt, Room, Retrofit, WorkManager, CameraX), mode kiosque, mises à jour OTA
Données et IoT
PostgreSQL, TimescaleDB, MySQL, Redis, MQTT (Mosquitto, Paho), séries temporelles, qualité des données
IA appliquée
agents écrits sans framework (appels d’outils), sorties structurées (JSON Schema), évaluation avec seuils fixés à l’avance, cache de prompt, OpenAI, Anthropic, DeepSeek, Gemini, WhatsApp Business API, sherpa-onnx, faster-whisper
Développement avec l’IA
Claude Code, Codex, Cursor ; agents en parallèle sur des worktrees Git, règles d’agent vérifiées par des hooks
Qualité
JUnit 5, ArchUnit, Testcontainers, PIT, Vitest, Testing Library, MSW, Playwright, Robolectric, go test -race
Exploitation
Linux, Docker Compose, Nginx, systemd, Prometheus, Alertmanager, Grafana, VictoriaMetrics, GitHub Actions, GitLab CI
Langues
Français B2 (cursus d’ingénieur suivi en français), anglais B2, chinois langue maternelle

Ce que je cherche

Un stage de fin d’études de six mois à partir du 4 mai 2027, à Paris ou en Île-de-France, en développement full-stack, et je suis ouvert à une embauche en CDI à l’issue du stage. Idéalement dans une équipe proche de ses clients, qui utilise l’IA pour concevoir et pas seulement pour exécuter. J’aime prendre tôt la responsabilité d’un périmètre : c’est comme ça que j’ai le plus appris.