<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Houda Debza</title><description>Full Stack Engineer specializing in scalable SaaS platforms and AI microservices. NestJS, Next.js, TypeScript, Laravel.</description><link>https://personal-website-two-delta-37.vercel.app/</link><language>en-us</language><item><title>Introduction au JavaScript : Au-delà du langage interprété</title><link>https://personal-website-two-delta-37.vercel.app/blog/05-javascript-intro/</link><guid isPermaLink="true">https://personal-website-two-delta-37.vercel.app/blog/05-javascript-intro/</guid><description>Une introduction aux concepts fondamentaux de JavaScript moderne : compilation JIT, bytecode, typage dynamique, paradigmes de programmation et gestion de la mémoire.</description><pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Vous êtes surement tombé sur une définition de JavaScipt similaire a celle ci: JavaScript est un langage &lt;strong&gt;haut niveau&lt;/strong&gt;, &lt;strong&gt;interprété&lt;/strong&gt;, &lt;strong&gt;dynamique&lt;/strong&gt; et le seul langage de programmation nativement compris par les navigateur ce qui en fait un élément fondamental du développement web moderne.&lt;/p&gt;
&lt;p&gt;Cependant, cette définition est aujourd&apos;hui incomplète. Les moteurs JavaScript modernes, comme V8 (Chrome), SpiderMonkey (Firefox), utilisent des techniques bien plus avancées que les interpréteurs basique pour améliorer les performances.&lt;/p&gt;
&lt;h2&gt;Donc en réalité, c&apos;est quoi JavaScript ?&lt;/h2&gt;
&lt;p&gt;JavaScript est un langage de programmation de &lt;strong&gt;haut niveau&lt;/strong&gt;, &lt;strong&gt;dynamique&lt;/strong&gt;, &lt;strong&gt;multi-paradigme&lt;/strong&gt; et &lt;strong&gt;principalement mono-thread&lt;/strong&gt;. Il est exécuté par des moteurs spécialisés qui combinent interprétation et compilation JIT afin d&apos;obtenir de bonnes performances tout en conservant la flexibilité du langage.&lt;/p&gt;
&lt;p&gt;Autrement dit, JavaScript n&apos;est plus simplement un langage interprété : il est aujourd&apos;hui exécuté grâce à une combinaison intelligente d&apos;interprétation et de compilation.&lt;/p&gt;
&lt;p&gt;A noter que JavaScript n&apos;est plus le seul language de programmation natif des navigateur,&lt;/p&gt;
&lt;h3&gt;JIT (Just In Time Compilation)&lt;/h3&gt;
&lt;p&gt;On a souvent entendu dire que JavaScript est un langage interprété. Historiquement, cette affirmation était correcte. Mais avant de comprendre le fonctionnement du JIT, il faut distinguer interpréteur et compilateur.&lt;/p&gt;
&lt;h4&gt;Interpréteur&lt;/h4&gt;
&lt;p&gt;Un interpréteur lit le programme et exécute les instructions au fur et à mesure.&lt;/p&gt;
&lt;p&gt;Pour mieux visualiser ce processus, prenons l&apos;exemple suivant :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let sum = 0;

for (let i = 0; i &amp;lt; 10; i++) {
  sum = sum + i;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Un interpréteur pur pourrait exécuter le programme de manière conceptuelle comme suit :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ligne 1 : créer la variable sum = 0

Ligne 2 : créer la variable i = 0
          vérifier i &amp;lt; 10 → vrai

Ligne 3 : calculer sum + i
          stocker le résultat dans sum

Ligne 2 : i++
          vérifier i &amp;lt; 10 → vrai

Ligne 3 : calculer sum + i
          stocker le résultat dans sum

...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;À chaque itération, les mêmes instructions doivent être relues et réanalysées avant d&apos;être exécutées.&lt;/p&gt;
&lt;p&gt;L&apos;avantage est un démarrage rapide de l&apos;exécution. En revanche, lorsque certaines portions du code sont exécutées des milliers ou des millions de fois, cette approche devient moins efficace.&lt;/p&gt;
&lt;h4&gt;Compilateur&lt;/h4&gt;
&lt;p&gt;Un compilateur adopte une approche différente.&lt;/p&gt;
&lt;p&gt;Avant l&apos;exécution, il analyse l&apos;ensemble du programme puis le transforme dans une représentation plus proche de la machine.&lt;/p&gt;
&lt;p&gt;Le processus est généralement :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Code source
      ↓
Analyse
      ↓
Compilation
      ↓
Code machine
      ↓
Exécution
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;L&apos;avantage principal est la performance : le programme compilé s&apos;exécute généralement beaucoup plus vite et les erreur sont detecter avant l&apos;execution du programme.&lt;/p&gt;
&lt;p&gt;L&apos;inconvénient est qu&apos;il faut attendre la fin de la compilation avant de commencer l&apos;exécution.&lt;/p&gt;
&lt;h4&gt;JIT&lt;/h4&gt;
&lt;p&gt;Le JIT (Just In Time Compilation) combine les avantages des deux approches.&lt;/p&gt;
&lt;p&gt;Lorsqu&apos;un programme JavaScript démarre :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Le moteur lit rapidement le code.&lt;/li&gt;
&lt;li&gt;Il génère du bytecode exécutable.&lt;/li&gt;
&lt;li&gt;Le programme commence immédiatement à s&apos;exécuter.&lt;/li&gt;
&lt;li&gt;Le moteur observe quelles parties du code sont utilisées fréquemment.&lt;/li&gt;
&lt;li&gt;Les portions les plus exécutées (&quot;hot code&quot;) sont compilées en code machine optimisé le reste n&apos;est pas optimiser.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Le processus peut être résumé ainsi :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Code JavaScript
        ↓
Parsing
        ↓
Bytecode
        ↓
Exécution
        ↓
Détection du code fréquent
        ↓
Compilation JIT
        ↓
Code machine optimisé
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cette stratégie permet d&apos;obtenir un démarrage rapide tout en bénéficiant de performances proches des langages compilés.&lt;/p&gt;
&lt;p&gt;Pour clarifier voyons ces deux examples:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(&quot;test&quot;);
for (let i = 0; i &amp;lt; 10; i++) {
  console.log(test);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;En executant ce code vous allez remarquer qui ca donne:&lt;/p&gt;
&lt;p&gt;Si JavaScript été completement compilé, l&apos;erreur aurait été afficher au tout debut de l&apos;execution pas après le premier console.log.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const sum = 0;
for (let i = O; i &amp;lt; 10; i++) {
  sum = sum + i;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La boucle for est execute plusieur fois, le JIT va la considerer comme &lt;strong&gt;Hot code&lt;/strong&gt; et generer son code machine.&lt;/p&gt;
&lt;h3&gt;Types dynamiques&lt;/h3&gt;
&lt;p&gt;JavaScript est un langage à typage dynamique.&lt;/p&gt;
&lt;p&gt;Le type d&apos;une variable est déterminé au moment de l&apos;exécution et peut changer au cours du programme.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let value = 42; // Number

value = &quot;Bonjour&quot;; // String

value = true; // Boolean
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Contrairement aux langages à typage statique comme Java ou C++, il n&apos;est pas nécessaire de déclarer explicitement le type d&apos;une variable.&lt;/p&gt;
&lt;h3&gt;Multi-paradigme&lt;/h3&gt;
&lt;p&gt;JavaScript supporte plusieurs styles de programmation.&lt;/p&gt;
&lt;h4&gt;Programmation procédurale&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function add(a, b) {
  return a + b;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Programmation orientée objet&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;class User {
  constructor(name) {
    this.name = name;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Programmation fonctionnelle&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;const numbers = [1, 2, 3];

const doubled = numbers.map((n) =&amp;gt; n * 2);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cette flexibilité permet aux développeurs de choisir le paradigme le plus adapté au problème à résoudre.&lt;/p&gt;
&lt;h3&gt;Unique Thread&lt;/h3&gt;
&lt;p&gt;JavaScript est principalement mono-thread.&lt;/p&gt;
&lt;p&gt;Cela signifie qu&apos;une seule instruction JavaScript est exécutée à la fois.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(&quot;A&quot;);
console.log(&quot;B&quot;);
console.log(&quot;C&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La sortie sera toujours :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A
B
C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pour gérer les opérations longues sans bloquer l&apos;application, JavaScript s&apos;appuie sur &lt;a href=&quot;https://personal-website-two-delta-37.vercel.app/blog/02-javascript-event-loop/&quot;&gt;L&apos;Event Loop&lt;/a&gt;, les Web APIs du navigateur et les mécanismes asynchrones tels que :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Callbacks&lt;/li&gt;
&lt;li&gt;Promises&lt;/li&gt;
&lt;li&gt;async/await&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Garbage Collected&lt;/h3&gt;
&lt;p&gt;JavaScript dispose d&apos;un ramasse-miettes (Garbage Collector).&lt;/p&gt;
&lt;p&gt;Lorsqu&apos;un objet n&apos;est plus accessible par le programme, la mémoire qu&apos;il occupe peut être automatiquement libérée.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let user = {
  name: &quot;Alice&quot;,
};

// pas besoin de le faire manuellement, JavaScript le fait automatiquement quant une variables n&apos;est plus utiliser
user = null;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Après cette affectation, l&apos;objet original n&apos;est plus référencé et pourra être supprimé par le Garbage Collector.&lt;/p&gt;
&lt;p&gt;Cette gestion automatique de la mémoire simplifie considérablement le développement par rapport à des langages nécessitant une libération manuelle.&lt;/p&gt;
&lt;h3&gt;Récap en carte mentale&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blogs/js/js-mind-map.png&quot; alt=&quot;Carte Mentale de JavaScript&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Histoire de JavaScript&lt;/h2&gt;
&lt;p&gt;JavaScript a été créé en 1995 par Brendan Eich chez Netscape.&lt;/p&gt;
&lt;p&gt;Le langage a été développé en seulement dix jours afin d&apos;ajouter de l&apos;interactivité aux pages web, qui étaient jusque-là essentiellement statiques.&lt;/p&gt;
&lt;p&gt;Au fil des années, JavaScript a évolué grâce à la standardisation ECMAScript :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1995 : création de JavaScript par Brendan Eich, en 10 jours, nomme Motcha puis LiveScript et finalement JavaScript pour des raison marketting car Java été trend a cette époque&lt;/li&gt;
&lt;li&gt;1997 : première standardisation ECMAScript&lt;/li&gt;
&lt;li&gt;2009 : ES5&lt;/li&gt;
&lt;li&gt;2015 : ES6 (ECMAScript 2015)&lt;/li&gt;
&lt;li&gt;Aujourd&apos;hui : nouvelles versions publiées régulièrement (en general chaque année)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Initialement limité au navigateur, JavaScript est désormais utilisé côté serveur grâce à Node.js, ainsi que pour le développement mobile, desktop et même l&apos;Internet des objets.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blogs/js/historygram-js.png&quot; alt=&quot;Histogramme de JavaScript&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;JavaScript est souvent décrit comme un langage interprété, mais cette définition ne reflète plus complètement la réalité actuelle. Les moteurs modernes utilisent des techniques sophistiquées combinant interprétation et compilation JIT afin d&apos;offrir un excellent compromis entre rapidité de démarrage et performances d&apos;exécution.&lt;/p&gt;
&lt;p&gt;Grâce à son typage dynamique, son support de plusieurs paradigmes, son modèle d&apos;exécution basé sur un thread principal et sa gestion automatique de la mémoire, JavaScript est devenu bien plus qu&apos;un simple langage pour animer des pages web : il constitue aujourd&apos;hui l&apos;un des écosystèmes de développement les plus importants au monde.&lt;/p&gt;
&lt;p&gt;Ce blog est le premier d&apos;une serie dont on va decomposer chaque concept de JavaScript, Le prochain blog va attaquer les variable est type en profondeur.&lt;/p&gt;
</content:encoded><category>JavaScript</category><category>Web Development</category></item><item><title>NestJS JWT Auth with Email Verification</title><link>https://personal-website-two-delta-37.vercel.app/blog/04-nest-auth/</link><guid isPermaLink="true">https://personal-website-two-delta-37.vercel.app/blog/04-nest-auth/</guid><description>A step-by-step guide to building JWT authentication with email verification using NestJS, React, Drizzle ORM, and Resend. Covers registration, validation, and a production-ready auth flow.</description><pubDate>Tue, 05 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Authentication is a feature that exists in most of the applications, so as a backend or full-stack developer, you need to implement it properly, not just “make it work”.&lt;/p&gt;
&lt;p&gt;It’s one of the first features we build, and one of the easiest to get wrong. Especially at the beginning, a simple setup might seem sufficient but if not validated and structured, it can quickly open security issues and unreliable user flows.&lt;/p&gt;
&lt;p&gt;There are lots of authentication strategies out there, and each has its own pros and cons. In this article, we will focus on one of the most popular approaches: JWT authentication.&lt;/p&gt;
&lt;p&gt;We won’t just output a token and stop. Instead, we’re going to build a fuller flow with email verification. This makes sure that users really own the email addresses they sign up with, which is a necessary step in most real world applications.&lt;/p&gt;
&lt;p&gt;The idea is to keep the implementation simple, but structured in a way that resembles how authentication is done in production systems.&lt;/p&gt;
&lt;h2&gt;What are we going to do&lt;/h2&gt;
&lt;p&gt;We are going to build a JWT auth in NestJS and React using passport-jwt and send a validation email to validate the user account using Resend.&lt;/p&gt;
&lt;p&gt;Here is the pipeline we will follow:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ User ]
   │
   │ Register
   ▼
[ Backend ]
   │
   │ Create account (unverified)
   │ Send verification email
   ▼
[ Email Inbox ]
   │
   │ Click verification link
   ▼
[ Backend ]
   │
   │ Validate account
   ▼
[ User ]
   │
   │ Login
   ▼
[ Backend ]
   │
   │ Generate JWT
   ▼
[ Authenticated User ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this first part we will only focus on the user registry, the envirenment setup and the email verification, we will implement the login in the second part.&lt;/p&gt;
&lt;h2&gt;Setting up the environment&lt;/h2&gt;
&lt;p&gt;To achieve this, we should first set up our project; in my case, I&apos;m going to use a monorepo setup using Turborepo (you can also use separate projects for the frontend and backend). If you have any struggle setting up the monorepo, this article will help you: &lt;a href=&quot;https://personal-website-two-delta-37.vercel.app/blog/01-turbo-repo-setup/&quot;&gt;Setting Up TurboRepo Is Easy… Until You Add Another App&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Create The Database module and the user schema&lt;/h2&gt;
&lt;h3&gt;Initiating the Database&lt;/h3&gt;
&lt;p&gt;You can literally store your users in a table in memory, in a JSON file, or in any storage you prefer; for this example, I&apos;m going to use a MySQL database with Drizzle as an ORM (feel free to use Prisma, TypeORM, ...).&lt;/p&gt;
&lt;p&gt;First let&apos;s install the necessary dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd apps/api
pnpm install drizzle-orm mysql2 dotenv @nestjs/config drizzle-kit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a .env file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## .env
DATABASE_URL=&quot;mysql://root:root@localhost:3306/auth&quot;
## the first root stands for the database user
## the second root stands for the database password
## auth is our database name
## 3306 is the database port
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now create your database manually (either locally or using Docker) using your corresponding credentials, or you can make a Docker Compose file to create it and start it in the future (yes, I get you have too many steps to start, but it&apos;s a good future optimization).&lt;/p&gt;
&lt;p&gt;Here is an example of the Docker Compose file (you can either create it in the project or even in another location):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## docker-compose.yaml
services:
  db:
    image: mysql:9.7
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: auth
    ports:
      - &apos;3306:3306&apos;
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: [&apos;CMD&apos;, &apos;mysqladmin&apos;, &apos;ping&apos;, &apos;-h&apos;, &apos;localhost&apos;, &apos;-uroot&apos;, &apos;-proot&apos;]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  mysql_data:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and run it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Creating the database module&lt;/h4&gt;
&lt;p&gt;Now, our database is ready. We can create our database module by running the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nest g module db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated module code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// db.module.ts
import { Module } from  &apos;@nestjs/common&apos;;
@Module({
	providers:  []
})
export  class  DbModule {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since most of the future modules will depend on the database, we’ll add the &lt;code&gt;@Global()&lt;/code&gt; decorator at the top of this module. This allows us to access it anywhere in the application without having to import it in every module.&lt;/p&gt;
&lt;p&gt;Then we should define what this module will do in the providers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// db.module.ts
import { Global, Module } from &apos;@nestjs/common&apos;;
import { ConfigService } from &apos;@nestjs/config&apos;;
import { drizzle } from &apos;drizzle-orm/mysql2&apos;;
import mysql from &apos;mysql2/promise&apos;;

@Global()
@Module({
  providers: [
    {
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) =&amp;gt; {
        const connection = await mysql.createConnection(
          configService.get&amp;lt;string&amp;gt;(&apos;DATABASE_URL&apos;)!
        );

        return drizzle(connection, {
          mode: &apos;default&apos;, 
        });
      },
    },
  ],
})
export class DatabaseModule {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our module uses the &lt;code&gt;useFactory&lt;/code&gt; method, which allows us to dynamically create the database connection based on the value present in the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Finally, we need to give it a provider name, which NestJS will use to inject it in the other modules automatically, and then export the module.&lt;/p&gt;
&lt;p&gt;The final database module:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// db.module.ts
import { Global, Module } from &apos;@nestjs/common&apos;;
import { ConfigService } from &apos;@nestjs/config&apos;;
import { drizzle } from &apos;drizzle-orm/mysql2&apos;;
import mysql from &apos;mysql2/promise&apos;;

export const DATABASE_CONNECTION = &apos;DATABASE_CONNECTION&apos;;

@Global()
@Module({
  providers: [
    {
      provide: DATABASE_CONNECTION,
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) =&amp;gt; {
        const connection = await mysql.createConnection(
          configService.get&amp;lt;string&amp;gt;(&apos;DATABASE_URL&apos;)!
        );

        return drizzle(connection, {
          mode: &apos;default&apos;, 
        });
      },
    },
  ],
  exports: [DATABASE_CONNECTION],
})
export class DatabaseModule {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But if you try to start your application and hope that everything will work, I&apos;m sorry to say it, but it won&apos;t since you have to register the config module in the app module (because we used it in the database module), like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// app.module.ts
import { Module } from  &apos;@nestjs/common&apos;;
import { AppController } from  &apos;./app.controller&apos;;
import { AppService } from  &apos;./app.service&apos;;
import { DatabaseModule } from  &apos;./db/db.module&apos;;
import { ConfigModule } from  &apos;@nestjs/config&apos;;

@Module({
	imports:  [
		ConfigModule.forRoot({
			isGlobal: true,
		}),
		DatabaseModule,
	],
	controllers:  [AppController],
	providers:  [AppService],
})
export  class  AppModule {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can run it and see that everything is going well; let&apos;s move to the next step.&lt;/p&gt;
&lt;h4&gt;Creating the database Schema&lt;/h4&gt;
&lt;p&gt;Right now we have a project and a database that are connected together, but we need a table in that database to store the users, so let&apos;s do it.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We need to create a schema file under the db module folder, like this:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// schema.ts
import {
	mysqlTable,
	varchar,
	boolean,
	timestamp,
	mysqlEnum,
} from  &apos;drizzle-orm/mysql-core&apos;;

export  const  users  =  mysqlTable(&apos;users&apos;, {
	id:  varchar(&apos;id&apos;, { length:  36 }).primaryKey(),
	email:  varchar(&apos;email&apos;, { length:  255 }).unique().notNull(),
	password:  varchar(&apos;password&apos;, { length:  255 }).notNull(),
	role:  mysqlEnum(&apos;role&apos;, [&apos;seller&apos;, &apos;customer&apos;]).notNull(),
	isVerified:  boolean(&apos;is_verified&apos;).default(false).notNull(),
	emailVerificationToken:  varchar(&apos;email_verification_token&apos;, { length:  255 }),
	emailVerificationExpires:  timestamp(&apos;email_verification_expires&apos;),
	createdAt:  timestamp(&apos;created_at&apos;).defaultNow().notNull(),
});
export  type  User  =  typeof  users.$inferSelect;
export  type  InsertUser  =  typeof  users.$inferInsert;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you noticed, I added a user type (I reused it from a marketplace project), so you can better understand role-based authentication.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We need to add it into the module provider:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// db.module.ts
return drizzle(connection, {
		schema,
		mode: &apos;default&apos;, 
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before we can generate and apply this migration. We should first create a drizzle config file, since drizzle doesn&apos;t know about your NestJS code; the config will allow it to know where your schema is and where to create the migration files. You need to create it in your backend root folder; it will contain the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// drizzle.config.ts
import  &apos;dotenv/config&apos;;
import { defineConfig } from  &apos;drizzle-kit&apos;;

export  default  defineConfig({
	dialect:  &apos;mysql&apos;,
	schema:  &apos;./src/db/schema.ts&apos;, // make sure it matches your schema file path
	out:  &apos;./drizzle&apos;,
	dbCredentials: {
		url:  process.env.DATABASE_URL!,
	},
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add migrate and generate the script into the package.json (you can run the Drizzle commands directly also, but if you are going to work in a team, it&apos;s better to treat the ORM as a black box).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// packages.json
&quot;scripts&quot;: {
	...
	&quot;db:generate&quot;: &quot;drizzle-kit generate&quot;,
	&quot;db:migrate&quot;: &quot;drizzle-kit migrate&quot;
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now we can run those two scripts in our terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm db:generate
pnpm db:migrate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are not sure whether the migration is applied, you can verify the tables of the database before we move to the auth part.&lt;/p&gt;
&lt;h3&gt;Authentication module&lt;/h3&gt;
&lt;p&gt;So, before starting the authentication module, let&apos; install the required dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd apps/api
pnpm install bcryptjs passport passport-jwt @nestjs/jwt @nestjs/swagger zod
## bcryptjs =&amp;gt; hash password
## passport, passport-jwt, @nestjs/jwt =&amp;gt; generate and manage the user access token
## swagger =&amp;gt; a UI to test and document the API (you can skip it)
## zod =&amp;gt; schema validation for incoming data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&apos;s generate the module, service, and controller of our auth module using the Nest CLI:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nest g module auth  
nest g controller auth  
nest g service auth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And create our register&apos;s incoming data schema validation using Zod.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* 
You can either: 
- create a validation folder in the backend root folder and put this file in it 
- or create it in the auth folder, 
- or if you are working under a monorepo, you can add a validation package that allows you to share the types between the frontend and backend and guarantees the consistency. 
- To make it easy to follow, I will create a validation folder in our backend and add this file into it.
*/
// auth.ts
import { z } from  &apos;zod&apos;;
export  const  RegisterSchema  =  z.object({
	email:  z.string().email(&apos;Invalid email address&apos;),
	password:  z.string().min(8, &apos;Password must be at least 8 characters&apos;),
	role:  z.enum([&apos;seller&apos;, &apos;customer&apos;], { error:  &apos;Role must be seller or customer&apos; }),
});
export  type  RegisterInput  =  z.infer&amp;lt;typeof  RegisterSchema&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then create the register service:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// auth.service.ts
import { ConflictException, Injectable, Inject } from  &apos;@nestjs/common&apos;;
import { eq } from  &apos;drizzle-orm&apos;;
import * as  bcrypt  from  &apos;bcryptjs&apos;;
import { users } from  &apos;../db/schema&apos;;
import { DATABASE_CONNECTION } from  &apos;src/db/db.module&apos;;
import { RegisterInput } from  &apos;../../validation/auth&apos;;
import { randomBytes } from  &apos;crypto&apos;;

@Injectable()
export  class  AuthService {
	constructor(@Inject(DATABASE_CONNECTION) private  readonly  db:  any) {}
	
	async  register(input:  RegisterInput):  Promise&amp;lt;{ message:  string }&amp;gt; {
		// check if the user already exists
		const  existingUser  =  await  this.db
			.select()
			.from(users)
			.where(eq(users.email, input.email))
			.limit(1);
		if (existingUser.length  &amp;gt;  0) {
			throw  new  ConflictException(&apos;User with this email already exist&apos;);
		}
		
		// hash the password
		const  hashedPassword  =  await  bcrypt.hash(input.password, 12);
		// generate user ID
		const  userId  =  randomBytes(16).toString(&apos;hex&apos;);

		//Insert the user into the database
		await  this.db.insert(users).values({
			id:  userId,
			email:  input.email,
			password:  hashedPassword,
			role:  input.role,
			isVerified: false,
			emailVerificationToken: null,
			emailVerificationExpires: null,
		});
		return {
			message:  &apos;Registration successful&apos;,
		};
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s break down this code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you remember the database module we created and set here, we injected it with its provider name; I guess now it&apos;s clearer why we added that const.&lt;/li&gt;
&lt;li&gt;We are checking if a user with the same email already exists in the db; if so, the user should be redirected to the login page.&lt;/li&gt;
&lt;li&gt;If the user doesn&apos;t exist, then we should create it; we start by hashing the password and generating an ID for this new user.&lt;/li&gt;
&lt;li&gt;Then we call our database to create an entry for this new user (the emailVerificationToken and emailVerificationExpires are set to null right now; we will update this when adding the email verification logic).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We finally need the register controller to handle the HTTP requests:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// auth.controller.ts
import { Body, Controller, Post } from  &apos;@nestjs/common&apos;; 
import { AuthService } from  &apos;./auth.service&apos;;
import  type { RegisterInput } from  &apos;validation/auth&apos;;

@Controller(&apos;auth&apos;)
export  class  AuthController {
constructor(private  readonly  authService:  AuthService) {}
	@Post(&apos;register&apos;)
	async  register(@Body() body:  RegisterInput) {
		return  this.authService.register(body);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s explain this code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We injected our service into the controller.&lt;/li&gt;
&lt;li&gt;We called our service register function inside the post request.&lt;/li&gt;
&lt;li&gt;We added the &lt;code&gt;@Post(&apos;register&apos;)&lt;/code&gt; decorator. This decorator tells NestJS that this method will handle HTTP &lt;code&gt;POST&lt;/code&gt; requests sent to &lt;code&gt;/auth/register&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can open Postman and test this endpoint, or as a bonus step, you can set up the Swagger UI in the main.ts&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// main.ts
import { NestFactory } from  &apos;@nestjs/core&apos;;
import { AppModule } from  &apos;./app.module&apos;;
import { SwaggerModule, DocumentBuilder } from  &apos;@nestjs/swagger&apos;;

async  function  bootstrap() {
	const  app  =  await  NestFactory.create(AppModule);

	const  config  =  new  DocumentBuilder()
		.setTitle(&apos;API&apos;)
		.setDescription(&apos;WeStore marketplace API&apos;)
		.setVersion(&apos;1.0&apos;)
		.addBearerAuth()
		.addTag(&apos;Authentication&apos;, &apos;User registration&apos;)
		.build();

	const  document  =  SwaggerModule.createDocument(app, config);
	SwaggerModule.setup(&apos;docs&apos;, app, document);

	await  app.listen(process.env.PORT  ??  4000);
}
bootstrap();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then add the appropriate decorators of swagger into your controller; it&apos;s a long list of decorators, so check my repo if you want to go further with swagger: &lt;a href=&quot;https://github.com/Houda-DE/jwt-auth-monorepo-nest-react&quot;&gt;jwt-auth-monorepo-nest-react&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now run the application and test the register endpoint with this json format:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;email&quot;: &quot;user@example.com&quot;,
  &quot;password&quot;: &quot;securePassword123&quot;,
  &quot;role&quot;: &quot;customer&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything works fine.&lt;/p&gt;
&lt;h2&gt;Email verification&lt;/h2&gt;
&lt;p&gt;I guess that you remember this in the auth service:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// auth.service.ts
//Insert the user into the database
await  this.db.insert(users).values({
	id:  userId,
	email:  input.email,
	password:  hashedPassword,
	role:  input.role,
	isVerified: false,
	emailVerificationToken: null,
	emailVerificationExpires: null,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We initially set the email verification token and its expiration to &lt;code&gt;null&lt;/code&gt; since we hadn’t implemented the verification logic yet. Now, let’s add that functionality.&lt;/p&gt;
&lt;h3&gt;Install the dependencies&lt;/h3&gt;
&lt;p&gt;First let&apos;s start by installing the needed dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm install resend
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Getting an API key&lt;/h3&gt;
&lt;p&gt;Let&apos;s go to &lt;a href=&quot;https://resend.com/api-keys&quot;&gt;resend&lt;/a&gt; and create a new API key.&lt;/p&gt;
&lt;p&gt;Once you get it, let&apos;s add it into the &lt;code&gt;.env&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// .env
DATABASE_URL=mysql://root:root@localhost:3306/auth

RESEND_API_KEY=re_..........
FROM_EMAIL=onboarding@resend.dev
## In development envirenment, emails are automatically sent from Resend’s default email. You can customize the sender address in production once you’ve added your domain.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Email module&lt;/h3&gt;
&lt;p&gt;Now let&apos;s generate a module and a service for our email sending verification process.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nest g module email
nest g service email
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the service let&apos;s add this.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//email.service.ts
import { Injectable } from  &apos;@nestjs/common&apos;;
import { Resend } from  &apos;resend&apos;;

@Injectable()
export  class  EmailService {
	private  readonly  resend  =  new  Resend(process.env.RESEND_API_KEY);
	async  sendVerificationEmail(email:  string, token:  string):  Promise&amp;lt;void&amp;gt; {
	const  verificationUrl  =  `${process.env.API_URL ?? &apos;http://localhost:4000&apos;}/auth/verify-email?token=${token}`;
	const { error } =  await  this.resend.emails.send({
		from:  &apos;auth &amp;lt;onboarding@resend.dev&amp;gt;&apos;,
		to:  email,
		subject:  &apos;Verify your auth account&apos;,
		html:  `
			&amp;lt;div style=&quot;font-family:sans-serif;max-width:480px;margin:0 auto;padding:32px 24px&quot;&amp;gt;
				&amp;lt;h2 style=&quot;color:#09B1BA;margin:0 0 8px&quot;&amp;gt;Auth&amp;lt;/h2&amp;gt;
				&amp;lt;p style=&quot;color:#111;font-size:16px;font-weight:600;margin:0 0 16px&quot;&amp;gt;Confirm your email address&amp;lt;/p&amp;gt;
				&amp;lt;p style=&quot;color:#555;font-size:14px;line-height:1.6;margin:0 0 24px&quot;&amp;gt;
					Click the button below to verify your account. This link expires in 24 hours.
				&amp;lt;/p&amp;gt;
				&amp;lt;a href=&quot;${verificationUrl}&quot;
					style=&quot;display:inline-block;background:#09B1BA;color:#fff;text-decoration:none;padding:12px 28px;border-radius:8px;font-size:14px;font-weight:600&quot;&amp;gt;
					Verify email
				&amp;lt;/a&amp;gt;
				&amp;lt;p style=&quot;color:#aaa;font-size:12px;margin:24px 0 0&quot;&amp;gt;
					If you didn&apos;t create an account, you can safely ignore this email.
				&amp;lt;/p&amp;gt;
			&amp;lt;/div&amp;gt;
			`,
	});

		if (error) {
			console.error(&apos;Resend error:&apos;, error);
			throw  new  Error(`Failed to send verification email: ${error.message}`);
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a UI of the verification email that will be sent to the user (you can customize the UI).&lt;/p&gt;
&lt;p&gt;If you noticed, there is &lt;code&gt;verificationUrl&lt;/code&gt; that which takes a token, so let&apos;s go create the email verification logic that generates this token.&lt;/p&gt;
&lt;h3&gt;Email verification, auth service&lt;/h3&gt;
&lt;p&gt;Go back to the auth service; let&apos;s define the email verification function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async  verifyEmail(token:  string):  Promise&amp;lt;{ message:  string }&amp;gt; {
	if (!token) {
		throw  new  BadRequestException(&apos;Verification token is required&apos;);
	}

	const  user  =  await  this.db
		.select()
		.from(users)
		.where(eq(users.emailVerificationToken, token))
		.limit(1);
		
	if (user.length  ===  0) {
		throw  new  NotFoundException(&apos;Invalid or expired verification token&apos;);
	}
	const  userRecord  =  user[0];
	if (
		userRecord.emailVerificationExpires  &amp;amp;&amp;amp;
		new  Date() &amp;gt;  userRecord.emailVerificationExpires
	) {
		throw  new  BadRequestException(&apos;Verification token has expired&apos;);
	}
	if (userRecord.isVerified) {
		throw  new  BadRequestException(&apos;Email is already verified&apos;);
	}
	await  this.db
		.update(users)
		.set({
			isVerified: true,
			emailVerificationToken: null,
			emailVerificationExpires: null,
		})
	.where(eq(users.id, userRecord.id));
	return {
		message:  &apos;Email verified successfully. You can now log in.&apos;,
	};
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;let&apos;s explain this code&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We first check if a token is provided in the request.&lt;/li&gt;
&lt;li&gt;We query the database to find a user that has the same email verification token.&lt;/li&gt;
&lt;li&gt;We check if the token has expired by comparing the current date with the expiration date stored in the database.&lt;/li&gt;
&lt;li&gt;We also check if the user is already verified (no need to reverify).&lt;/li&gt;
&lt;li&gt;If everything is valid, we mark the user as verified and remove the verification token and its expiration date (preventing reuse).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But it&apos;s checking a token that we didn&apos;t generate; let&apos;s add the generation logic in the register service function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// auth.service.ts

// add this line to the constructor private  readonly  emailService:  EmailService,

// Note: in production ot&apos;s recommended to hash the email verification token, it&apos;s just a simplification for the tutaorial purpose.
const  emailVerificationToken  =  randomBytes(32).toString(&apos;hex&apos;);
const  emailVerificationExpires  =  new  Date(Date.now() +  24  *  60  *  60  *  1000); // 24 hours

const  userId  =  randomBytes(16).toString(&apos;hex&apos;);

await  this.emailService.sendVerificationEmail(
	input.email,
	emailVerificationToken,
);

await  this.db.insert(users).values({
	id:  userId,
	email:  input.email,
	password:  hashedPassword,
	role:  input.role,
	isVerified: false,
	emailVerificationToken,
	emailVerificationExpires,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I guess that this code need some clarification&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We generate a random token that will be used to verify the user’s email.&lt;/li&gt;
&lt;li&gt;Then we create an expiration date for the token (24 hours),  you can skip this step, but it&apos;s improves security.&lt;/li&gt;
&lt;li&gt;We store both the token and its expiration date in the database along with the user’s information (you remeber that in the verification we were checking the token).&lt;/li&gt;
&lt;li&gt;After saving the user, we send a verification email that contains a link with the token. When the user clicks this link, it will trigger the verification process.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Some side note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;since we imported the email service in the auth service you need to make sure that you exported the email service in it&apos;s module and imported it in the auth module.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Test the email verification&lt;/h3&gt;
&lt;p&gt;First let add the controller endpoint that will allow us to test&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Get(&apos;verify-email&apos;)
async  verifyEmail(@Query(&apos;token&apos;) token:  string) {
	return  this.authService.verifyEmail(token);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then let&apos;s create a new user with the email you used to authenticate to Resend and create the api key, since in dev mode it allows sending email only to that email.&lt;/p&gt;
&lt;p&gt;In my side I checked that the email is sent, so it&apos;s working.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Thanks for reading this article; the second part will follow soon.&lt;/p&gt;
&lt;p&gt;You can find the boilerplate of the full pipeline (with login and UI included) in my GitHub repo: &lt;a href=&quot;https://github.com/Houda-DE/jwt-auth-monorepo-nest-react&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you have any question or want to hire me, my contact infos are available on my blog/portfolio.&lt;/p&gt;
</content:encoded><category>NestJS</category><category>Authentication</category><category>JWT</category><category>React</category><category>Backend</category><category>Full Stack</category><category>Web Development</category></item><item><title>Cross-Platform Fake Profile Detection: Experimental Machine Learning Graduation Project</title><link>https://personal-website-two-delta-37.vercel.app/blog/03-graduation-project/</link><guid isPermaLink="true">https://personal-website-two-delta-37.vercel.app/blog/03-graduation-project/</guid><description>A graduation project focused on building an experimental machine learning system for robust fake profile detection across Facebook, Twitter, and Instagram. The work combines multi-dataset benchmarking, feature engineering, classical ML models, and metaheuristic optimization techniques to evaluate model performance in a systematic and reproducible way.</description><pubDate>Fri, 24 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;After a long journey at the Higher School of Computer Science in Sidi Bel Abbès, I finally graduated on September 22, 2025.&lt;/p&gt;
&lt;p&gt;In this blog, I will explain the steps I followed to build my graduation project, which was: &lt;strong&gt;“An experimental ML system for robust fake profile detection across social platforms using multi-strategy feature selection and model benchmarking”&lt;/strong&gt;, using metaheuristic and machine learning methods.&lt;/p&gt;
&lt;h2&gt;Table of Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#the-journey&quot;&gt;The Journey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#the-problem-i-tried-to-solve&quot;&gt;The Problem I Tried to Solve&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#data--sources&quot;&gt;Data &amp;amp; Sources&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#research-papers&quot;&gt;Research Papers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#datasets&quot;&gt;Datasets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#metaheuristic-research-papers&quot;&gt;Metaheuristic Research Papers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#methodology-overview&quot;&gt;Methodology Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#system-implementation&quot;&gt;System Implementation&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#step-1-generic-metaheuristic-engine&quot;&gt;Step 1: Generic Metaheuristic Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-2-data-preprocessing-and-cleaning&quot;&gt;Step 2: Data Preprocessing and Cleaning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-3-feature-selection&quot;&gt;Step 3: Feature Selection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-4-machine-learning&quot;&gt;Step 4: Machine Learning&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#step-41-algorithms&quot;&gt;Step 4.1: Algorithms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-42-splits&quot;&gt;Step 4.2: Splits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-43-validation-strategy&quot;&gt;Step 4.3: Validation Strategy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-44-metrics--evaluation-strategy&quot;&gt;Step 4.4: Metrics &amp;amp; Evaluation Strategy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-45-hyperparameter-optimization&quot;&gt;Step 4.5: Hyperparameter Optimization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-46-recap&quot;&gt;Step 4.6: Recap&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-5-feature-scoring&quot;&gt;Step 5: Feature Scoring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#step-6-retraining-with-best-features-and-best-algorithm&quot;&gt;Step 6: Retraining with Best Features and Best Algorithm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#results--comparison&quot;&gt;Results&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#discussion&quot;&gt;Discussion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#deployment&quot;&gt;Deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#improvements-for-future-work&quot;&gt;Improvements for Future Work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The journey&lt;/h2&gt;
&lt;p&gt;Although it was a long journey that took about &lt;strong&gt;8 months&lt;/strong&gt; of serious work, it’s the period where I evolved the most during my academic path.&lt;/p&gt;
&lt;p&gt;It may look simple, you just have to follow this steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;try something&lt;/li&gt;
&lt;li&gt;criticize it&lt;/li&gt;
&lt;li&gt;improve it&lt;/li&gt;
&lt;li&gt;and repeat&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But in reality, it’s much harder than that.&lt;/p&gt;
&lt;p&gt;You constantly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;question your own work&lt;/li&gt;
&lt;li&gt;go back and redo things from scratch&lt;/li&gt;
&lt;li&gt;test multiple strategies that don’t always work&lt;/li&gt;
&lt;li&gt;and spend hours waiting for results that might not always satisfies you&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first months felt like I wasn’t making real progress.&lt;br /&gt;
I was implementing metaheuristics in a generic, reusable way, but it didn’t produce immediate results. I was also trying to figure out the best direction to follow, which made things even more confusing.&lt;/p&gt;
&lt;p&gt;But looking back, those were actually the months where I progressed the most.&lt;/p&gt;
&lt;p&gt;They built the foundation for everything that came after. Once that part was done, the next steps became much easier and much faster.&lt;/p&gt;
&lt;h2&gt;The Problem I Tried to solve&lt;/h2&gt;
&lt;p&gt;There is a large number of research papers on the topic of fake profile detection across social networks. These works have contributed significantly to the field, both in terms of methods and results.&lt;/p&gt;
&lt;p&gt;However, from the analysis of many of them, I noticed a common pattern.&lt;/p&gt;
&lt;p&gt;Most of the papers I studied work under relatively limited settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;they focus on &lt;strong&gt;one or two social platforms&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;they use &lt;strong&gt;one or two datasets&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;they test &lt;strong&gt;a small number of heuristics or optimization methods (if any)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;and they usually rely on &lt;strong&gt;one or two data split strategies&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In most cases, each study explores a specific and constrained configuration, but rarely the problem in a broader and more systematic way.&lt;/p&gt;
&lt;p&gt;So the question that came to me was: What if we go further?&lt;/p&gt;
&lt;p&gt;What if instead of evaluating models in a limited experimental setup, we try to build a more &lt;strong&gt;general and experimental system&lt;/strong&gt;, that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;works across multiple social platforms&lt;/li&gt;
&lt;li&gt;uses multiple datasets&lt;/li&gt;
&lt;li&gt;explores multiple metaheuristic optimization strategies&lt;/li&gt;
&lt;li&gt;tests different data splits&lt;/li&gt;
&lt;li&gt;and provides a more rigorous and comparative benchmarking of models&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Data &amp;amp; Sources&lt;/h2&gt;
&lt;h3&gt;Research papers&lt;/h3&gt;
&lt;p&gt;I analysed 6 research papers on 3 main platforms:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Twitter (X now)&lt;/li&gt;
&lt;li&gt;Facebook&lt;/li&gt;
&lt;li&gt;Instagram&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All of them expose labeled datasets created manually by researchers and use machine learning or deep learning methods. They also report performance scores, which allowed me to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;understand existing approaches&lt;/li&gt;
&lt;li&gt;identify gaps and limitations&lt;/li&gt;
&lt;li&gt;reuse datasets for fair comparison&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Datasets&lt;/h3&gt;
&lt;p&gt;I worked on &lt;strong&gt;5 datasets&lt;/strong&gt; in total:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 Facebook dataset&lt;/li&gt;
&lt;li&gt;1 Twitter dataset&lt;/li&gt;
&lt;li&gt;3 Instagram datasets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This multi-platform setup allowed me to evaluate how models behave across different social media environments and test their generalization ability.&lt;/p&gt;
&lt;p&gt;All datasets were collected via platform APIs and manually labeled in the original studies.&lt;/p&gt;
&lt;h3&gt;Metaheuristic research papers&lt;/h3&gt;
&lt;p&gt;In addition to machine learning methods, I explored a wide range of &lt;strong&gt;metaheuristic optimization algorithms&lt;/strong&gt; inspired by different real-world systems and games.&lt;/p&gt;
&lt;p&gt;These algorithms are often designed as &lt;em&gt;search strategies&lt;/em&gt; that simulate natural or social behaviors, such as competition, cooperation, or exploration.&lt;/p&gt;
&lt;p&gt;I studied the following approaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most Valuable Player Algorithm (MVPA)&lt;/li&gt;
&lt;li&gt;Multi-Objective Volleyball Premier League (MOVPL)&lt;/li&gt;
&lt;li&gt;Shell Game Optimization (SGO)&lt;/li&gt;
&lt;li&gt;Tug of War Optimization (TWO)&lt;/li&gt;
&lt;li&gt;Ring Toss Game Based Optimization&lt;/li&gt;
&lt;li&gt;Puzzle Optimization Algorithm (POA)&lt;/li&gt;
&lt;li&gt;Mixed Leader Based Optimizer (MLBO)&lt;/li&gt;
&lt;li&gt;Soccer-Inspired Metaheuristics&lt;/li&gt;
&lt;li&gt;Tiki-Taka Algorithm (TTA)&lt;/li&gt;
&lt;li&gt;Running City Game Optimizer (RCGO)&lt;/li&gt;
&lt;li&gt;Golf Optimization Algorithm (GOA)&lt;/li&gt;
&lt;li&gt;Hide Objects Game Optimization (HOGO)&lt;/li&gt;
&lt;li&gt;Football Game Based Optimization (FGBO)&lt;/li&gt;
&lt;li&gt;Billiards-inspired Optimization Algorithm (BOA)&lt;/li&gt;
&lt;li&gt;Kho-Kho Optimization Algorithm (KKO)&lt;/li&gt;
&lt;li&gt;Orientation Search Algorithm (OSA)&lt;/li&gt;
&lt;li&gt;Dice Game Optimizer (DGO)&lt;/li&gt;
&lt;li&gt;Binary Orientation Search Algorithm (BOSA)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These methods may look very different on the surface, but they all share a common goal: &lt;strong&gt;explore a search space efficiently to find near-optimal solutions&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Methodology Overview&lt;/h2&gt;
&lt;p&gt;Once the problem and data were clear, I designed the following pipeline to structure the entire system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;labeled input data is collected&lt;/li&gt;
&lt;li&gt;data is cleaned&lt;/li&gt;
&lt;li&gt;data is preprocessed&lt;/li&gt;
&lt;li&gt;feature selection is applied&lt;/li&gt;
&lt;li&gt;dataset is split into train/test (with different split strategies)&lt;/li&gt;
&lt;li&gt;models are trained and tested&lt;/li&gt;
&lt;li&gt;cross-validation is applied for more reliable evaluation&lt;/li&gt;
&lt;li&gt;hyperparameter optimization is performed&lt;/li&gt;
&lt;li&gt;best combination is selected:
&lt;ul&gt;
&lt;li&gt;best features&lt;/li&gt;
&lt;li&gt;best algorithm&lt;/li&gt;
&lt;li&gt;best split strategy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;final model is retrained using the best configuration&lt;/li&gt;
&lt;li&gt;final model is deployed&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;[Labeled Data]
      |
      v
[Cleaning &amp;amp; Preprocessing]
      |
      v
[Feature Selection]
      |
      v
[Train / Test + Cross Validation + Splits]
      |
      v
[Model Benchmarking]
      |
      v
[Best Features + Best Model + Best Split]
      |
      v
[Final Retraining]
      |
      v
[Deployment (Hugging Face)]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;System Implementation&lt;/h2&gt;
&lt;h3&gt;Step 1: Generic Metaheuristic Engine&lt;/h3&gt;
&lt;p&gt;I started by implementing metaheuristic algorithms in a generic way, so I could reuse the same implementation for feature selection, scoring, and machine learning evaluation.&lt;/p&gt;
&lt;p&gt;During this step, you don’t really feel the progress, since it takes a lot of time (more than a month in my case because of the number of algorithms). But once this foundation is done, the progress on the next steps becomes much faster and smoother.&lt;/p&gt;
&lt;h3&gt;Step 2: Data preprocessing and cleaning&lt;/h3&gt;
&lt;p&gt;I started working on this step in parallel with the first step in order to save time later in the process. The data preprocessing and cleaning phase was not identical for all datasets, as each one had its own structure, but in general it followed a common pipeline.&lt;/p&gt;
&lt;p&gt;First, the usual preprocessing steps were applied, such as handling missing values and removing empty or irrelevant entries.&lt;/p&gt;
&lt;p&gt;Then, for datasets containing raw profile names, I tried to extract as much useful information as possible. This included encoding the text and adding additional engineered features such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;number of characters in the profile name&lt;/li&gt;
&lt;li&gt;number of words in the profile name&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The idea was that even simple textual patterns could carry useful signals for fake profile detection.&lt;/p&gt;
&lt;p&gt;Finally, all features were normalized so that each attribute would have the same scale and contribute fairly to the learning process, avoiding bias toward features with larger numerical ranges.&lt;/p&gt;
&lt;h3&gt;Step 3: Feature selection&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Variance Threshold (0.7)&lt;/li&gt;
&lt;li&gt;SelectKBest&lt;/li&gt;
&lt;li&gt;RFE (Recursive Feature Elimination)&lt;/li&gt;
&lt;li&gt;Sequential Feature Selection&lt;/li&gt;
&lt;li&gt;Mutual Information (MI) &lt;em&gt;(combined with all implemented metaheuristics)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Gini Index &lt;em&gt;(combined with all implemented metaheuristics)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Fisher Score &lt;em&gt;(combined with all implemented metaheuristics)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to these classical feature selection methods, I also integrated metaheuristic optimization techniques into the feature selection process.&lt;/p&gt;
&lt;p&gt;The main idea was to go beyond standard deterministic selection methods and explore the feature space in a more flexible and intelligent way, allowing the model to discover feature combinations that traditional approaches might miss.&lt;/p&gt;
&lt;p&gt;To make this exploration efficient and controlled, I designed a custom stopping strategy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The optimization is executed in blocks of 100 iterations&lt;/li&gt;
&lt;li&gt;After each block, I keep the best solution found so far&lt;/li&gt;
&lt;li&gt;Then I launch the next block of 100 iterations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now comes the stopping logic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the solution does not improve for 3 consecutive blocks, the process stops and the best solution is kept&lt;/li&gt;
&lt;li&gt;Otherwise, it continues until a maximum of 10 blocks, after which the best overall solution is selected&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, this acts as a controlled exploration mechanism: the algorithm is given multiple opportunities to improve, but it is stopped early when it clearly starts to stagnate, avoiding unnecessary computation while preserving performance.&lt;/p&gt;
&lt;h3&gt;Step 4: Machine Learning&lt;/h3&gt;
&lt;h4&gt;Step 4.1: Algorithms&lt;/h4&gt;
&lt;p&gt;I started this step by identifying the most performing algorithms for each dataset.&lt;/p&gt;
&lt;p&gt;The idea was simple: before applying feature selection and optimization, I wanted to evaluate all models using the &lt;strong&gt;full feature space&lt;/strong&gt;. This allowed me to understand which algorithms naturally perform better depending on the dataset, so I could later combine the strongest models with the most relevant features.&lt;/p&gt;
&lt;p&gt;At the same time, I explored different hyperparameter configurations for each algorithm to ensure a fair and robust comparison.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Random forest&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;n_estimators
max_depth
min_samples_split
min_samples_leaf
criterion
max_features
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Logistic regression&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;C
penalty
solver
class_weight
max_iter
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Naive bayes&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;alpha
fit_prior
class_prior
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Linear SVC&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;C
penalty
loss
dual
tol
class_weight
max_iter
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;XGBoost&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;max_depth
learning_rate
n_estimators
subsample
colsample_bytree
scale_pos_weight
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Deep Forest (Cascade forest)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;n_estimators
max_depth
min_samples_split
min_samples_leaf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This initial benchmarking step helped me identify strong baseline models, which were later refined through feature selection and optimization.&lt;/p&gt;
&lt;h4&gt;Step 4.2: Splits&lt;/h4&gt;
&lt;p&gt;We often encounter the famous &lt;strong&gt;80/20 split&lt;/strong&gt;, where 80% of the data is used for training and 20% for testing. But how can we be sure that this split is the most optimal one?&lt;/p&gt;
&lt;p&gt;I decided to go deeper and test multiple splits, almost like a detective: I tried 50/50, 60/40, 70/30, the classic 80/20, and finally 90/10.&lt;/p&gt;
&lt;p&gt;Is there a difference? Yes, they tend to give different results. Is 80/20 always the most optimal one?&lt;br /&gt;
The answer is not always, as we will see in the results section just a bit later.&lt;/p&gt;
&lt;h4&gt;Step 4.3: Validation Strategy&lt;/h4&gt;
&lt;p&gt;To make the evaluation more reliable, I used &lt;strong&gt;cross-validation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The idea is simple. Let’s take the example of an 80/20 split:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instead of doing a single split (80% training / 20% testing)&lt;/li&gt;
&lt;li&gt;The dataset is divided into &lt;strong&gt;multiple parts (folds)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, with &lt;strong&gt;5-fold cross-validation&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The dataset is split into 5 equal parts&lt;/li&gt;
&lt;li&gt;At each iteration:
&lt;ul&gt;
&lt;li&gt;4 parts (≈80%) are used for training&lt;/li&gt;
&lt;li&gt;1 part (≈20%) is used for testing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This process is repeated &lt;strong&gt;5 times&lt;/strong&gt;, each time changing the test part&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So every sample:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is used for training multiple times&lt;/li&gt;
&lt;li&gt;is used for testing at least once&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;How is the data divided?&lt;/h5&gt;
&lt;p&gt;The data is divided into &lt;strong&gt;k equal subsets&lt;/strong&gt;, called &lt;em&gt;folds&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;let&apos;s take the example of 5 folds&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Fold 1 → Test | Train Train Train Train  
Fold 2 → Train | Test Train Train Train  
Fold 3 → Train | Train | Test Train Train  
Fold 4 → Train | Train Train | Test Train  
Fold 5 → Train | Train Train Train | Test
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Why I did this step&lt;/h5&gt;
&lt;p&gt;At first, it might look like an unnecessary step.&lt;br /&gt;
Why not just split the data once and train/test directly?&lt;/p&gt;
&lt;p&gt;The problem is that a &lt;strong&gt;single split can be biased&lt;/strong&gt;. Some samples may be easier or harder than others, which can lead to misleading results.&lt;/p&gt;
&lt;p&gt;With cross-validation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the model is evaluated on &lt;strong&gt;different subsets of the data&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;the results become &lt;strong&gt;more stable and reliable&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;and the evaluation better reflects the model’s ability to generalize&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, instead of depending on one “lucky” split, this approach gives a more &lt;strong&gt;robust estimation of performance&lt;/strong&gt; across the entire dataset.&lt;/p&gt;
&lt;h4&gt;Step 4.4: Metrics &amp;amp; Evaluation Strategy&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;What are all the metrics i recorded&lt;/strong&gt;
To evaluate model performance, I recorded a wide range of metrics for two main reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To ensure that everything was working correctly (no missing steps, no overfitting, and stable training behavior)&lt;/li&gt;
&lt;li&gt;To guarantee a fair comparison with other research papers, since not all of them report the same metrics—even though I focused my optimization on precision&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The metrics I recorded were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Accuracy&lt;/li&gt;
&lt;li&gt;Precision (&lt;code&gt;precision_score&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Recall (&lt;code&gt;recall_score&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;F1-score (&lt;code&gt;f1_score&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Cohen’s Kappa (&lt;code&gt;cohen_kappa_score&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Balanced Accuracy (&lt;code&gt;balanced_accuracy_score&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Confusion Matrix&lt;/li&gt;
&lt;li&gt;Best Hyperparameters&lt;/li&gt;
&lt;li&gt;Training Time (s)&lt;/li&gt;
&lt;li&gt;Testing Time (s)&lt;/li&gt;
&lt;li&gt;Validation Time (s)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This combination allowed me to evaluate the models from multiple perspectives: performance quality, robustness, and computational cost.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why precision&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At first glance, one might ask: why choose precision instead of accuracy or F1-score? After all, accuracy gives a global view of performance, and F1-score balances precision and recall.&lt;/p&gt;
&lt;p&gt;However, in the context of fake profile detection, the cost of errors is not symmetric.&lt;/p&gt;
&lt;p&gt;If a fake profile is classified as real, the consequences can be serious:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;users may trust malicious accounts&lt;/li&gt;
&lt;li&gt;misinformation can spread more easily&lt;/li&gt;
&lt;li&gt;in some cases (e-commerce, social engineering), it can lead to real harm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is why &lt;strong&gt;precision becomes the most critical metric&lt;/strong&gt; in this context. It directly measures how many predicted “real profiles” are actually real. In other words, the higher the precision, the fewer fake profiles are incorrectly labeled as trustworthy.&lt;/p&gt;
&lt;p&gt;So instead of optimizing for general correctness, I focused on minimizing this specific and risky type of error.&lt;/p&gt;
&lt;h4&gt;Step 4.5: Hyperparameter Optimization&lt;/h4&gt;
&lt;p&gt;I experimented with several optimization approaches, including well-known ones such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Grid Search&lt;/li&gt;
&lt;li&gt;Randomized Search&lt;/li&gt;
&lt;li&gt;Bayesian Optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But I didn’t stop there. I also used metaheuristics with a custom stopping condition (the one we explained in the feature selection).&lt;/p&gt;
&lt;p&gt;A brief recap of it&apos;s details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I run the optimization in blocks of 100 iterations&lt;/li&gt;
&lt;li&gt;After each block, I keep the best solution found&lt;/li&gt;
&lt;li&gt;Then I launch another block of 100 iterations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now comes the stopping logic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the solution does &lt;strong&gt;not improve for 3 consecutive blocks&lt;/strong&gt;, I stop and keep the best result&lt;/li&gt;
&lt;li&gt;Otherwise, I continue until I reach a maximum of &lt;strong&gt;10 blocks&lt;/strong&gt;, and then select the best solution overall&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So in short, it’s like a controlled exploration: I give the algorithm multiple chances to improve, but I stop early if it clearly stagnates.&lt;/p&gt;
&lt;p&gt;The stopping condition was based on &lt;strong&gt;precision not improving&lt;/strong&gt; we just explained the why above.&lt;/p&gt;
&lt;h4&gt;Step 4.6: Recap&lt;/h4&gt;
&lt;p&gt;so here is the recap of all the training part&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    ┌────────────────────────────┐
                    │   Full Feature Dataset     │
                    └─────────────┬──────────────┘
                                  │
                                  v
                    ┌────────────────────────────┐
                    │  Model Benchmarking        │
                    │  (Multiple Algorithms)     │
                    │  RF / LR / SVC / XGB / NB  │
                    │  Deep Forest               │
                    └─────────────┬──────────────┘
                                  │
                                  v
                    ┌────────────────────────────┐
                    │ Hyperparameter Tuning      │
                    │ (Grid / Random / Bayesian  │
                    │ + Metaheuristics)          │
                    └─────────────┬──────────────┘
                                  │
                                  v
                    ┌────────────────────────────┐
                    │ Evaluation Strategy        │
                    │ - Train/Test Splits        │
                    │ - Multiple split ratios    │
                    │ - Cross Validation (k-fold)│
                    └─────────────┬──────────────┘
                                  │
                                  v
                    ┌────────────────────────────┐
                    │ Metrics Computation        │
                    │ Acc / Prec / Rec / F1      │
                    │ Kappa / Balanced Acc       │
                    │ Confusion Matrix           │
                    │ Time metrics               │
                    └─────────────┬──────────────┘
                                  │
                                  v
                    ┌────────────────────────────┐
                    │ Best Model Selection       │
                    │ + Best Hyperparameters     │
                    │ + Best Split Strategy      │
                    └────────────────────────────┘

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 5: Feature scoring&lt;/h3&gt;
&lt;p&gt;You might ask the question: if I tested many approaches, did I use all of them for the final selection?&lt;/p&gt;
&lt;p&gt;The answer is no. But then how did I get the final best feature set?&lt;/p&gt;
&lt;p&gt;I followed a simple approach: I scored the features. At the beginning, all features have a score of 0. Every time a feature is selected by an algorithm, its score is incremented by 1.&lt;/p&gt;
&lt;p&gt;At the end of all iterations, each feature has a final score. I simply sorted the features based on this score, and I got the overall best feature set.&lt;/p&gt;
&lt;h3&gt;Step 6: Retraining with the best feature and best algorithm&lt;/h3&gt;
&lt;p&gt;Now that I had identified both the best feature set and the best performing algorithm, the next step was to combine them into a final optimized model.&lt;/p&gt;
&lt;p&gt;To build the most efficient version of the system, I retrained the model using only the &lt;strong&gt;top-ranked features&lt;/strong&gt;, selected through the scoring method. In my case, I chose the &lt;strong&gt;top 5 features&lt;/strong&gt;, which allowed me to reduce complexity while keeping strong predictive power.&lt;/p&gt;
&lt;p&gt;Then, I retrained the &lt;strong&gt;best-performing algorithm&lt;/strong&gt; using this reduced feature set. This step was important because it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ensures the model is trained only on the most informative signals&lt;/li&gt;
&lt;li&gt;reduces noise coming from less relevant features&lt;/li&gt;
&lt;li&gt;improves generalization and stability&lt;/li&gt;
&lt;li&gt;makes the final model lighter and faster to evaluate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a result, I obtained a final model that is not only &lt;strong&gt;high-performing&lt;/strong&gt;, but also &lt;strong&gt;simpler and easier to test and deploy&lt;/strong&gt; in practice.&lt;/p&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dataset&lt;/th&gt;
&lt;th&gt;Accuracy&lt;/th&gt;
&lt;th&gt;Precision&lt;/th&gt;
&lt;th&gt;F1-score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Facebook&lt;/td&gt;
&lt;td&gt;0.9880&lt;/td&gt;
&lt;td&gt;0.9953&lt;/td&gt;
&lt;td&gt;0.9953&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Twitter&lt;/td&gt;
&lt;td&gt;0.9200&lt;/td&gt;
&lt;td&gt;0.9078&lt;/td&gt;
&lt;td&gt;0.9212&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instagram (Dataset 1)&lt;/td&gt;
&lt;td&gt;0.9378&lt;/td&gt;
&lt;td&gt;0.9706&lt;/td&gt;
&lt;td&gt;0.9333&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instagram (Dataset 2)&lt;/td&gt;
&lt;td&gt;0.9378&lt;/td&gt;
&lt;td&gt;0.9381&lt;/td&gt;
&lt;td&gt;0.9333&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instagram (Dataset 3)&lt;/td&gt;
&lt;td&gt;0.9880&lt;/td&gt;
&lt;td&gt;0.9953&lt;/td&gt;
&lt;td&gt;0.9953&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Discussion&lt;/h2&gt;
&lt;p&gt;For sure, the “everything law” still doesn’t exist, as well as a universal best model in machine learning. However, I noticed some patterns in social media labeled datasets: tree-based algorithms often give the best results (like XGBoost and Random Forest), and in many cases, grid search is one of the most reliable methods for hyperparameter optimization.&lt;/p&gt;
&lt;h2&gt;Deployment&lt;/h2&gt;
&lt;p&gt;I deployed the final model on &lt;strong&gt;Hugging Face&lt;/strong&gt;, choosing the best-performing version trained with the full feature set (I deployed the best of each platform which means one for facebook, one for X and one for Instagram).&lt;/p&gt;
&lt;p&gt;The goal of this step was to make the model accessible and easy to test in a real-world setting, without requiring any local setup or complex dependencies.&lt;/p&gt;
&lt;p&gt;By deploying the complete model (with all features), I ensured that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;no information loss occurs due to feature reduction&lt;/li&gt;
&lt;li&gt;users can directly test realistic predictions&lt;/li&gt;
&lt;li&gt;the pipeline remains consistent from training to deployment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This step marked the transition from a research-oriented system to a usable and interactive machine learning application.&lt;/p&gt;
&lt;h2&gt;Improvements for Future Work&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I initially created separate Google Colab notebooks for each dataset, which led to some code repetition. I started with one dataset and then replicated the workflow for the others. In hindsight, I would design a shared module from the beginning to make the process more scalable and reusable.&lt;/li&gt;
&lt;li&gt;I also started the experiments on Google Colab, but long training times and occasional disconnections made it less convenient. I later moved to a local Jupyter Notebook setup, and if I were to redo it, I would start directly with a local environment and GitHub for better version control and stability.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This project investigated fake profile detection across Facebook, Twitter, and Instagram using a full experimental machine learning pipeline. It combined multiple datasets, several classification algorithms, diverse feature selection techniques, and different optimization strategies to evaluate model performance in a systematic and comparable way.&lt;/p&gt;
&lt;p&gt;A wide range of metrics was used, with a particular focus on precision due to the high cost of false positives in real-world scenarios. Cross-validation and multiple train/test splits were applied to ensure robust and reliable evaluation across datasets.&lt;/p&gt;
&lt;p&gt;The results show that well-tuned ensemble methods such as Random Forest and Gradient Boosting achieve strong performance across platforms (in 4 out of 5 datasets). Metaheuristic-based feature selection sometimes provided some improvements, but did not consistently outperform classical methods (in 3 of the 5 datasets we tried the classical methods outperformed and were less time consuming), highlighting that sometimes simple strategies give better results.&lt;/p&gt;
&lt;p&gt;Overall, this work demonstrates that robust fake profile detection can be effectively achieved through a well-designed classical ML pipeline combined with rigorous experimental evaluation across multiple datasets.&lt;/p&gt;
</content:encoded><category>Machine Learning</category><category>Data Science</category><category>Fake Profile Detection</category><category>Python</category><category>AI Project</category></item><item><title>What Really Happens When You Run JavaScript Code</title><link>https://personal-website-two-delta-37.vercel.app/blog/02-javascript-event-loop/</link><guid isPermaLink="true">https://personal-website-two-delta-37.vercel.app/blog/02-javascript-event-loop/</guid><description>In this article, we explore how JavaScript really executes code behind the scenes. You’ll understand the call stack, asynchronous behavior, task queues, microtasks, and why setTimeout doesn’t always run when you expect.</description><pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;You think you know JavaScript… but can you explain why &lt;code&gt;setTimeout&lt;/code&gt; doesn’t always run when you expect?&lt;/p&gt;
&lt;p&gt;The answer is in how JavaScript schedules and executes tasks. But how does it actually work?&lt;/p&gt;
&lt;p&gt;To understand this, we need to talk about the event loop, what it is and how it works behind the scenes.&lt;/p&gt;
&lt;h2&gt;What is the Call Stack?&lt;/h2&gt;
&lt;p&gt;The event loop is a runtime mechanism that allows JavaScript to decide which task to execute next.&lt;/p&gt;
&lt;p&gt;Before understanding it, you need to know that JavaScript is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Single-threaded (it runs on a single main thread)&lt;/li&gt;
&lt;li&gt;Non-blocking (it can handle asynchronous operations without stopping execution)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So how does the event loop manage this single thread and decide which task to execute next without blocking the execution?&lt;/p&gt;
&lt;p&gt;We first need to look at &lt;strong&gt;the call stack&lt;/strong&gt;, which, as the name implies, is a stack that handles all function calls in JavaScript. Let’s take a look at this code to understand how it works.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function first(){
	console.log(&quot;I&apos;m first function&quot;);
	second()
}
function second(){
	console.log(&quot;I&apos;m second function&quot;);
	third()
}
function third(){
	console.log(&quot;I&apos;m third function&quot;);
	fourth()
}
function fourth(){
	console.log(&quot;I&apos;m forth function&quot;);
}
fourth()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;strong&gt;call stack&lt;/strong&gt; tries to execute code in a strict order, line by line.&lt;br /&gt;
It starts by encountering the call to &lt;code&gt;first()&lt;/code&gt;. At this point, &lt;code&gt;first()&lt;/code&gt; is pushed onto the stack and executed.&lt;/p&gt;
&lt;p&gt;Inside &lt;code&gt;first()&lt;/code&gt;, there is a call to &lt;code&gt;second()&lt;/code&gt;, so &lt;code&gt;second()&lt;/code&gt; is pushed on top of the stack and executed next.&lt;br /&gt;
Then &lt;code&gt;second()&lt;/code&gt; calls &lt;code&gt;third()&lt;/code&gt;, which is also pushed onto the stack.&lt;br /&gt;
Finally, &lt;code&gt;third()&lt;/code&gt; calls &lt;code&gt;fourth()&lt;/code&gt;, which is pushed last and executed at the top of the stack.&lt;/p&gt;
&lt;p&gt;At the moment when &lt;code&gt;fourth()&lt;/code&gt; is being executed, the stack looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fourth()  
third()  
second()  
first()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then execution happens from the top of the stack.   &lt;code&gt;fourth()&lt;/code&gt; executes first and is removed from the stack, then control returns to &lt;code&gt;third()&lt;/code&gt;, followed by &lt;code&gt;second()&lt;/code&gt;, and finally &lt;code&gt;first()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But it still doesn’t explain something important: why doesn’t &lt;code&gt;setTimeout&lt;/code&gt; always run when we expect it?&lt;/p&gt;
&lt;h2&gt;Understanding Async Execution&lt;/h2&gt;
&lt;p&gt;To understand that, we need to step outside the call stack and look at how JavaScript handles asynchronous tasks.&lt;/p&gt;
&lt;p&gt;There is a &lt;strong&gt;task queue&lt;/strong&gt;, which is where asynchronous tasks are stored once they are ready to be executed. It is essentially a waiting line of callbacks that will be processed later.&lt;/p&gt;
&lt;p&gt;However, these tasks are not executed immediately. Even if a task is ready, it must wait until the &lt;strong&gt;call stack is empty&lt;/strong&gt; before it can be processed. This is because JavaScript always executes synchronous code first.&lt;/p&gt;
&lt;p&gt;This is what makes JavaScript non-blocking in practice.&lt;/p&gt;
&lt;h2&gt;How &lt;code&gt;setTimeout&lt;/code&gt; Really Works&lt;/h2&gt;
&lt;p&gt;To better understand how the &lt;strong&gt;task queue&lt;/strong&gt; and the &lt;strong&gt;call stack&lt;/strong&gt; work together, let’s look at the following example and try to predict its output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function  prepareDinner() {  
	setTimeout(() =&amp;gt; {  
		console.log(&quot;I&apos;m here&quot;);  
	}, 0);
  
	console.log(&quot;Starting dinner preparation&quot;);  
		cookFood();  
}  
  
function  cookFood() {  
	console.log(&quot;Cooking food&quot;);  
	serveFood();  
}  
  
function  serveFood() {  
	console.log(&quot;Serving food&quot;);  
}  
  
prepareDinner();  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At first glance, you might think the output will be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;I&apos;m here
Starting dinner preparation
Cooking food  
Serving food  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the actual output is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Starting dinner preparation
Cooking food  
Serving food 
I&apos;m here 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So why does this happen, even though the delay is set to &lt;code&gt;0&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;As we said before, JavaScript executes &lt;strong&gt;synchronous code first&lt;/strong&gt;, which is pushed directly to the &lt;strong&gt;call stack&lt;/strong&gt;.&lt;br /&gt;
Asynchronous code, like &lt;code&gt;setTimeout&lt;/code&gt;, is handled separately and its callback is pushed to the &lt;strong&gt;task queue&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;JavaScript will only execute tasks from the queue &lt;strong&gt;after finishing all the code in the call stack&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So even if &lt;code&gt;setTimeout&lt;/code&gt; is set to &lt;code&gt;0&lt;/code&gt;, it doesn’t run immediately. It just means that the callback will be pushed to the task queue after &lt;code&gt;0ms&lt;/code&gt;, that’s all.&lt;/p&gt;
&lt;p&gt;For example, if you set a &lt;code&gt;setTimeout&lt;/code&gt; with a delay of &lt;code&gt;1s&lt;/code&gt;, the callback will be pushed to the task queue after 1 second.&lt;/p&gt;
&lt;p&gt;But it &lt;strong&gt;may take more than 1 second to actually execute&lt;/strong&gt;, because it still has to wait for the call stack to become empty.&lt;/p&gt;
&lt;p&gt;There is one more important thing in the event loop that we didn’t introduce yet.&lt;/p&gt;
&lt;p&gt;You might think that all asynchronous tasks are the same, and that all of them simply wait for the call stack to be empty before being executed, right?&lt;/p&gt;
&lt;p&gt;There is another queue with &lt;strong&gt;higher priority than the task queue&lt;/strong&gt; (which we can refer to as the &lt;strong&gt;macrotask queue&lt;/strong&gt;, where &lt;code&gt;setTimeout&lt;/code&gt; callbacks are placed).&lt;/p&gt;
&lt;p&gt;This higher-priority queue is called the &lt;strong&gt;microtask queue&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is where &lt;strong&gt;&lt;code&gt;Promise.then&lt;/code&gt; callbacks&lt;/strong&gt; are executed.&lt;/p&gt;
&lt;p&gt;Microtasks have higher priority than the &lt;strong&gt;macrotask queue&lt;/strong&gt; (like &lt;code&gt;setTimeout&lt;/code&gt;), but they do not run before the call stack.&lt;/p&gt;
&lt;p&gt;Instead, once the call stack becomes empty, JavaScript will execute all microtasks first, before moving to macrotasks.&lt;/p&gt;
&lt;p&gt;Let&apos;s take a look at this code to understand better:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function prepareDinner() {
  setTimeout(() =&amp;gt; {
    console.log(&quot;I&apos;m here&quot;);
  }, 0);

  Promise.resolve().then(() =&amp;gt; {
    console.log(&quot;Promise resolved&quot;);
  });

  console.log(&quot;Starting dinner preparation&quot;);
  cookFood();
}

function cookFood() {
  console.log(&quot;Cooking food&quot;);
  serveFood();
}

function serveFood() {
  console.log(&quot;Serving food&quot;);
}

prepareDinner();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So at the moment &lt;code&gt;prepareDinner()&lt;/code&gt; starts executing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;call stack&lt;/strong&gt; contains:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;serveFood
cookFood  
prepareDinner  
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;macrotask queue&lt;/strong&gt; contains:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;setTimeout callback
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;microtask queue&lt;/strong&gt; contains:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;Promise callback
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We said that the sync code in the call stack executes first so the output of it will be&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Starting dinner preparation  
Cooking food    
Serving food  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then the microtask right after when the call stack gets empty&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Promise resolved
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;the macrotask gets executed only when the call stack is empty and all microtasks have already been executed&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;I&apos;m here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final output will be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Starting dinner preparation  
Cooking food    
Serving food  
Promise resolved
I&apos;m here
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Web APIs and JavaScript Environment&lt;/h2&gt;
&lt;p&gt;We said that &lt;code&gt;setTimeout&lt;/code&gt; is async code that gets pushed to the macrotask queue, and that is true, but there is something missing here.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;setTimeout()&lt;/code&gt;, like &lt;code&gt;fetch&lt;/code&gt;, and &lt;code&gt;addEventListener&lt;/code&gt;, are &lt;strong&gt;external APIs provided by the browser&lt;/strong&gt; (or by Node.js in backend environments). They are not part of JavaScript itself.&lt;/p&gt;
&lt;p&gt;JavaScript only provides the &lt;strong&gt;execution engine (call stack + event loop model)&lt;/strong&gt;, but these APIs are provided by the environment.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;setTimeout&lt;/code&gt; does not get pushed directly to the macrotask queue.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;setTimeout&lt;/code&gt; is called, it first goes to the &lt;strong&gt;Web APIs&lt;/strong&gt;, where the timer starts counting.&lt;/p&gt;
&lt;p&gt;Only after the timer finishes does the callback get pushed to the &lt;strong&gt;macrotask queue&lt;/strong&gt;, waiting for its turn to be executed.&lt;/p&gt;
&lt;p&gt;Then, the event loop will pick it only when the &lt;strong&gt;call stack is empty&lt;/strong&gt; and after all &lt;strong&gt;microtasks are finished&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Now you can explain with much more confidence why &lt;code&gt;setTimeout&lt;/code&gt; does not guarantee execution immediately after the time has finished.&lt;/p&gt;
&lt;p&gt;The reason is that &lt;code&gt;setTimeout&lt;/code&gt; is not executed directly by JavaScript. Even when the timer is done, the callback still has to wait in the &lt;strong&gt;task queue&lt;/strong&gt; until the &lt;strong&gt;call stack is empty&lt;/strong&gt; and all &lt;strong&gt;microtasks are completed&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Only then does the &lt;strong&gt;event loop&lt;/strong&gt; pick it up and push it to the call stack for execution.&lt;/p&gt;
&lt;p&gt;That’s why the delay in &lt;code&gt;setTimeout&lt;/code&gt; is not an exact execution time, but only a minimum waiting time before it becomes eligible to run.&lt;/p&gt;
&lt;p&gt;Hope you enjoyed this article. Feel free to explore more posts to keep learning.&lt;/p&gt;
</content:encoded><category>JavaScript</category><category>Event Loop</category><category>Programming</category></item><item><title>Setting Up TurboRepo Is Easy… Until You Add Another App</title><link>https://personal-website-two-delta-37.vercel.app/blog/01-turbo-repo-setup/</link><guid isPermaLink="true">https://personal-website-two-delta-37.vercel.app/blog/01-turbo-repo-setup/</guid><description>A practical guide on setting up a TurboRepo monorepo and the real issues you face when adding multiple applications like NestJS and Django, including scripts, ports, and integration challenges.</description><pubDate>Sun, 19 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Setting up a monorepo is usually a straightforward task, you just run this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm dlx create-turbo@latest 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and you think you are done, right ?&lt;/p&gt;
&lt;p&gt;The setup feels complete as soon as the command finishes, but in practice, that’s rarely the case.&lt;/p&gt;
&lt;p&gt;The command generates a ready-to-use boilerplate with this structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
apps/
  ├── web/
  ├── docs/
packages/
  ├── ui/
  ├── config/
turbo.json
package.json

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this stage, you simply install the dependencies, and you already have a working Next.js web application along with a ready-to-use Next.js documentation app.&lt;/p&gt;
&lt;p&gt;But what if you want to add another application to this structure?&lt;/p&gt;
&lt;p&gt;Here I will focus on two cases, but the same approach applies to any framework or library you might want to add: NestJS and Django.&lt;/p&gt;
&lt;h2&gt;Adding a New Application&lt;/h2&gt;
&lt;p&gt;First you navigate to apps folder:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd apps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you install your application in the usual way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;for Nest.js&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pnpm dlx @nestjs/cli new api
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;for Django&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;django-admin startproject api
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you continue by installing the required dependencies for each application. Everything is fine till now, right ?&lt;/p&gt;
&lt;h2&gt;The First Issue: Application Not Running&lt;/h2&gt;
&lt;p&gt;However, once you navigate back to the root of your monorepo and try to run everything:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ../..
pnpm dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;only the web and documentation applications start, but why ?`&lt;/p&gt;
&lt;h2&gt;Understanding the Problem&lt;/h2&gt;
&lt;p&gt;TurboRepo doesn’t “discover” how to start each application automatically, it look for a specific script in each application, this script is &quot;dev&quot;.&lt;/p&gt;
&lt;p&gt;You can take a look to the turborepo package.json file and confirm that:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
	&quot;name&quot;: &quot;...&quot;,
	&quot;private&quot;: true,
	&quot;scripts&quot;: {
		&quot;build&quot;: &quot;turbo run build&quot;,
		&quot;dev&quot;: &quot;turbo run dev&quot;,
		&quot;lint&quot;: &quot;turbo run lint&quot;,
		&quot;format&quot;: &quot;prettier --write \&quot;**/*.{ts,tsx,md}\&quot;&quot;,
		&quot;check-types&quot;: &quot;turbo run check-types&quot;
	},
	&quot;devDependencies&quot;: {
		...
	},
	...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However in the Nest.js case you have this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
	&quot;scripts&quot;: {
		...
		&quot;start:dev&quot;: &quot;nest start --watch&quot;,
		...
	},
	...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Renaming &lt;code&gt;start:dev&lt;/code&gt; to &lt;code&gt;dev&lt;/code&gt; allows the monorepo to pick up the application. However, when running it, the service crashes — revealing another issue.&lt;/p&gt;
&lt;h2&gt;The Second Issue: Port Conflict&lt;/h2&gt;
&lt;p&gt;The root cause is a &lt;strong&gt;port conflict&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;By default, both the Next.js application and the NestJS server attempt to run on the same port. As a result, it fails to start.&lt;/p&gt;
&lt;p&gt;The solution is straightforward: assign a different port to one of the services.&lt;/p&gt;
&lt;p&gt;For example, you can update the NestJS application to run on port &lt;code&gt;4000&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	await app.listen(process.env.PORT  ??  4000);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that the NestJS case is resolved, what about the Django application, which doesn’t belong to the JavaScript ecosystem?&lt;/p&gt;
&lt;h2&gt;Integrating Django&lt;/h2&gt;
&lt;p&gt;Unlike NestJS, Django doesn’t rely on a &lt;code&gt;package.json&lt;/code&gt;, so TurboRepo has no direct way to detect or run it.&lt;/p&gt;
&lt;p&gt;To integrate it into the monorepo workflow, you need to explicitly define how it should be executed.&lt;/p&gt;
&lt;p&gt;One practical approach is to add a minimal &lt;code&gt;package.json&lt;/code&gt; inside the Django application directory and expose a &lt;code&gt;dev&lt;/code&gt; script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;name&quot;: &quot;api&quot;,
    &quot;scripts&quot;: {
      &quot;dev&quot;: &quot;python manage.py runserver 0.0.0.0:8000&quot;,
      &quot;migrate&quot;: &quot;python manage.py migrate&quot;,
      ...
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows TurboRepo to treat the Django app like any other workspace and include it when running, also as before, make sure the Django server runs on a different port to avoid conflicts with other services.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Setting up a monorepo is fast, but integrating multiple applications into the workflow requires more attention.&lt;/p&gt;
&lt;p&gt;Whether you’re working with JavaScript frameworks like NestJS or external ecosystems like Django, the key is to make every application conform to the unified interface.&lt;/p&gt;
&lt;p&gt;And now you can enjoy your monorepo.&lt;/p&gt;
</content:encoded><category>Next.js</category><category>Monorepo</category><category>Turborepo</category><category>Javascript</category><category>Django</category></item></channel></rss>