<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Raviv Gilady</title>
    <description>The latest articles on Forem by Raviv Gilady (@raviv_gilady).</description>
    <link>https://forem.com/raviv_gilady</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3445767%2F346492d7-5da7-4352-a9bd-17fa775bb8bd.jpg</url>
      <title>Forem: Raviv Gilady</title>
      <link>https://forem.com/raviv_gilady</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/raviv_gilady"/>
    <language>en</language>
    <item>
      <title>♟️ Building a Chess App with React, Node.js, Kafka, and AWS (Part 1)</title>
      <dc:creator>Raviv Gilady</dc:creator>
      <pubDate>Thu, 28 Aug 2025 18:12:16 +0000</pubDate>
      <link>https://forem.com/raviv_gilady/building-a-chess-app-with-react-nodejs-kafka-and-aws-part-1-4bph</link>
      <guid>https://forem.com/raviv_gilady/building-a-chess-app-with-react-nodejs-kafka-and-aws-part-1-4bph</guid>
      <description>&lt;p&gt;I built a chess web app where you play entirely through algebraic notation instead of a visual board.&lt;br&gt;&lt;br&gt;
It runs on a React frontend, a Node.js server service, and a Kafka-powered Stockfish microservice, all Dockerized and deployed on AWS.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔎 App Overview
&lt;/h2&gt;

&lt;p&gt;This app lets you play chess in the browser—with a twist:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moves are entered in algebraic notation (no drag-and-drop board)
&lt;/li&gt;
&lt;li&gt;You play against a Stockfish-based bot (Elo ~2000)
&lt;/li&gt;
&lt;li&gt;Games run in real time over WebSockets
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click “Start Game” and you w randomly assigned White or Black against the bot. A blinking cursor means it’s your turn—type a move (e.g., &lt;code&gt;e4&lt;/code&gt;, &lt;code&gt;Nf3&lt;/code&gt;) and press Enter. When the bot replies, the top bar updates with the new move in the list.&lt;/p&gt;

&lt;p&gt;At any moment you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Peek board — quickly visualize the current position
&lt;/li&gt;
&lt;li&gt;Restart game — begin a new session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://algebric-chess.vercel.app/" rel="noopener noreferrer"&gt;Try the app here&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🌱 Why I Built This
&lt;/h2&gt;

&lt;p&gt;I’ve been playing chess casually for the past few years, and I got fascinated by the idea that you can actually play without a board — just by remembering every move in your head and keeping track of the board state mentally.  &lt;/p&gt;

&lt;p&gt;That sparked an idea: &lt;em&gt;what if I built an app that focused on the moves themselves, not a fancy board UI?&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;At the same time, I had a personal goal. Most of my professional experience has been backend (mainly Java), and I wanted to push myself to build and deploy a full-stack app end-to-end. Not just a local prototype, but something I could share via a link.  &lt;/p&gt;

&lt;p&gt;This project was the perfect excuse to:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deepen my experience with Node.js and React beyond the basics
&lt;/li&gt;
&lt;li&gt;Practice Docker and cloud deployment
&lt;/li&gt;
&lt;li&gt;Ship a portfolio piece that I own end-to-end: idea → code → infra → deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As the project evolved, I also started experimenting with &lt;strong&gt;microservices&lt;/strong&gt; (Kafka + a separate bot service), because I wanted to practice real-world architecture patterns I hadn’t touched in my day job yet.&lt;/p&gt;
&lt;h2&gt;
  
  
  ♟️ What the App Does
&lt;/h2&gt;

&lt;p&gt;Right now the app is focused on a very specific experience:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Play vs. Stockfish bot&lt;/strong&gt; → you make a move, the bot responds.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Moves are in algebraic notation only&lt;/strong&gt; (e.g., &lt;code&gt;e4&lt;/code&gt;, &lt;code&gt;Nf3&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guest login&lt;/strong&gt; → the server issues a JWT token automatically when you connect.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time play&lt;/strong&gt; → all communication runs over WebSockets.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Peek board mode&lt;/strong&gt; → temporarily visualize the current board state if you don’t want to keep it fully in your head.
What’s &lt;em&gt;not&lt;/em&gt; there yet:
&lt;/li&gt;
&lt;li&gt;No user accounts.
&lt;/li&gt;
&lt;li&gt;No human-vs-human mode.
&lt;/li&gt;
&lt;li&gt;If you close the page, you can’t rejoin the same game.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are things I plan to add later, but the current foundation is already robust: the &lt;strong&gt;Game object&lt;/strong&gt; on the server service is generalized enough that exposing new modes (like human-vs-human) will just mean connecting the right APIs and adding persistence.  &lt;/p&gt;

&lt;p&gt;Here’s a gif of the app in action:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F3aT3gv8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F3aT3gv8.gif" alt="App In Action" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  🏗️ Architecture Deep Dive
&lt;/h2&gt;

&lt;p&gt;When I started this project, my main goal wasn’t just &lt;em&gt;“make a chess app”&lt;/em&gt; — it was to practice thinking in &lt;strong&gt;systems&lt;/strong&gt;. That meant splitting responsibilities, experimenting with microservices, and forcing myself to deal with infra pieces like Docker, Kafka, and AWS.  &lt;/p&gt;

&lt;p&gt;Here’s the architecture as it stands today:  &lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F34cgummhnwa6yaeitbre.png" alt="Architechture" width="800" height="263"&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  🌐 Frontend (React/Preact)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;UI built in React (Vite + Tailwind + shadcn).
&lt;/li&gt;
&lt;li&gt;Users type their moves in &lt;strong&gt;algebraic notation&lt;/strong&gt; (e.g., &lt;code&gt;e4&lt;/code&gt;, &lt;code&gt;Nf3&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Communicates with the server via &lt;strong&gt;WebSockets&lt;/strong&gt; for real-time play.
&lt;/li&gt;
&lt;li&gt;Deployed on &lt;strong&gt;Vercel&lt;/strong&gt; for quick hosting and iteration.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For v1 I skipped real user accounts to keep the product accessible. I still wanted the JWT plumbing, so the app performs an automatic guest login: on load (or when a token expires), the client requests a guest JWT and uses it as a temporary user ID for socket auth. This is exposed via an AuthContext at the app root, alongside a GameContext for game state.&lt;/p&gt;

&lt;p&gt;The frontend is intentionally light right now; there’s more to build, but the structure feels solid (GameContext + AuthContext).&lt;br&gt;
More to come!&lt;/p&gt;


&lt;h3&gt;
  
  
  ⚙️ Server Service — Node.js, Express, WebSocket
&lt;/h3&gt;

&lt;p&gt;The server is deliberately lightweight right now. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Acts as the entry point and handles HTTP routing&lt;/li&gt;
&lt;li&gt;Issues JWTs for guest login (used for socket auth)&lt;/li&gt;
&lt;li&gt;Manages WebSocket connections and keeps game state in memory&lt;/li&gt;
&lt;li&gt;Validates moves with chess.js&lt;/li&gt;
&lt;li&gt;Publishes move requests to Kafka when the opponent is a bot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the game logic is handled by a generalized &lt;strong&gt;Game object&lt;/strong&gt;, adding new features like human-vs-human play or persistent sessions will be straightforward. For example, today if a user closes the browser, they can’t return to the game. Once I add a proper &lt;strong&gt;user system&lt;/strong&gt; and persistence layer, it will be simple to support &lt;strong&gt;re-login to active games&lt;/strong&gt; without changing much in the game server itself.  &lt;/p&gt;

&lt;p&gt;Here’s a simplified version of how I modeled the Game and players. The idea was to make the game logic generic enough so it doesn’t care if the opponent is a human or a bot.&lt;/p&gt;

&lt;p&gt;game.js: &lt;a href="https://github.com/RavivGilady/AlgebraicChess/blob/master/server-service/Game/game.js" rel="noopener noreferrer"&gt;&lt;em&gt;Watch on Github&lt;/em&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Chess&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;whitePlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blackPlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentPlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentMoveId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;uuidv4&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gameId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;uuidv4&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;winner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gameOver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nf"&gt;startGame&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;whitePlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnMoveCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;whitePlayer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;move&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moveId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;moveId&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;whitePlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blackPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnMoveCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blackPlayer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;move&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moveId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;moveId&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blackPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;black&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentPlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;whitePlayer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentMoveId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="nf"&gt;makeMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moveDetails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moveDetails&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentPlayer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentMoveId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;moveDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;moveId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

                &lt;span class="nx"&gt;move&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;performMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moveDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getNewMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moveDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notifyMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isGameOver&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endGame&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;swapTurn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestMove&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HumanPlayer.js (Extend Player): &lt;a href="https://github.com/RavivGilady/AlgebraicChess/blob/master/server-service/players/HumanPlayer.js" rel="noopener noreferrer"&gt;&lt;em&gt;Watch on Github&lt;/em&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HumanPlayer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;playerDetails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;playerDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;playerDetails&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;requestMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moveId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMove&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;player doesn't have a callback!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;make move&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moveId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`move &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;moveId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onMove&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;move&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;moveId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;moveId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BotPlayer.js (Extend Player): &lt;a href="https://github.com/RavivGilady/AlgebraicChess/blob/master/server-service/players/BotPlayer.js" rel="noopener noreferrer"&gt;&lt;em&gt;Watch on Github&lt;/em&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//....&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BotPlayer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isValidNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;elo must be between 1320 and 3000!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;elo&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;board&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Chess&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextMoveId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;requestMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextMoveId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextMoveId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextMoveId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;assignMoveIdToBotPlayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextMoveId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;sendMoveRequest&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;moveId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nextMoveId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;fen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;board&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fen&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="na"&gt;elo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elo&lt;/span&gt;   
        &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to send move request:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ♟️ Bot Service (Stockfish + Kafka Consumer)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Runs Stockfish inside a Docker container as an independent microservice.
&lt;/li&gt;
&lt;li&gt;Subscribes to a &lt;strong&gt;Kafka topic&lt;/strong&gt; for move requests.
&lt;/li&gt;
&lt;li&gt;Calculates the best move with Stockfish.
&lt;/li&gt;
&lt;li&gt;Publishes results back to another &lt;strong&gt;Kafka topic&lt;/strong&gt;, which the Server Service consumes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This decoupling keeps the bot logic isolated: the server doesn’t need to know how the bot works, and if the bot crashes, it can restart independently without breaking the rest of the system.  &lt;/p&gt;




&lt;h3&gt;
  
  
  🐳 Infrastructure (Docker + Kafka + AWS)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local development:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Orchestrated with &lt;strong&gt;Docker Compose&lt;/strong&gt; (server service, bot service, Kafka, Zookeeper).
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Production:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Deployed on &lt;strong&gt;AWS EC2&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Server + bot service run as Docker containers.
&lt;/li&gt;
&lt;li&gt;Kafka + Zookeeper containerized as well.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nginx reverse proxy&lt;/strong&gt; in front, handling SSL termination.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This setup worked well for a first deployment. The next step is to move to &lt;strong&gt;ECS Fargate&lt;/strong&gt; for more flexibility and easier scaling.  &lt;/p&gt;

&lt;p&gt;Overview Sketch&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ad406i4cdx92tmr50az.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ad406i4cdx92tmr50az.png" alt="Chess App Overview" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🔄 Flow of a Bot Game
&lt;/h3&gt;

&lt;p&gt;Here’s what happens when you play against the Stockfish bot:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Player submits a move → frontend → Server service via WebSocket.
&lt;/li&gt;
&lt;li&gt;Server validates the move with &lt;code&gt;chess.js&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;If the opponent is a bot → Server publishes a &lt;code&gt;move.request&lt;/code&gt; to Kafka.
&lt;/li&gt;
&lt;li&gt;Bot service consumes the request, runs Stockfish, and publishes &lt;code&gt;move.response&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Server consumes the response → sends the bot’s move back to the frontend via WebSocket.
&lt;/li&gt;
&lt;li&gt;The frontend updates the board instantly.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  🔮 Future Architecture Ideas
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;OAuth login — real user accounts and persistent sessions
&lt;/li&gt;
&lt;li&gt;Rejoin active games — let users reconnect after a disconnect
&lt;/li&gt;
&lt;li&gt;Human-vs-human mode — built on the generalized game object
&lt;/li&gt;
&lt;li&gt;Matchmaking service — pair players automatically
&lt;/li&gt;
&lt;li&gt;Redis caching — keep active games/queues outside process memory
&lt;/li&gt;
&lt;li&gt;NoSQL DB (MongoDB Atlas or DynamoDB) — users, game history, stats
&lt;/li&gt;
&lt;li&gt;ECS Fargate migration — run services independently and scale cleanly
&lt;/li&gt;
&lt;li&gt;Move processing reliability — retries/acks to ensure every request is handled
&lt;/li&gt;
&lt;li&gt;Spectator mode — broadcast moves to watcher sockets&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Deployment Journey
&lt;/h2&gt;

&lt;p&gt;Early on I had a single service (including Stockfish) and briefly deployed it on Railway to get something live. I then split the bot into its own service and added Kafka via Docker Compose.&lt;/p&gt;

&lt;p&gt;Once that worked locally (server service, bot service, Kafka, Zookeeper), I redeployed on AWS EC2. Both EC2 and ECS Fargate were new to me, but EC2 let me ship fastest—and the deployment was smooth.&lt;/p&gt;

&lt;p&gt;Production setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server Service and Bot Service as Docker containers on EC2
&lt;/li&gt;
&lt;li&gt;Kafka and Zookeeper as containers on the same instance
&lt;/li&gt;
&lt;li&gt;Nginx reverse proxy as the entry point, handling routing and SSL (Let’s Encrypt)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only tuning was operational: security groups, container networking, and SSL certificates. Getting it online quickly made the project feel real and validated the Docker setup.&lt;/p&gt;

&lt;p&gt;Next step: migrate to ECS Fargate so each service can run independently in a more cloud-native, scalable way.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Wrapping Up (Part 1)
&lt;/h2&gt;

&lt;p&gt;This post covered the overview, motivation, core features, architecture, and deployment journey of my chess app — from the idea of “chess without a board” to running it live on AWS with Docker, Kafka, and a Stockfish bot service.  &lt;/p&gt;

&lt;p&gt;For me this project is more than just a chess app: it was a way to practice building and deploying an end-to-end system, learning how pieces like WebSockets, JWTs, Kafka, and Docker actually fit together in production.  &lt;/p&gt;

&lt;p&gt;In Part 2, I’ll share:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The challenges and small gotchas I hit along the way
&lt;/li&gt;
&lt;li&gt;The lessons learned while working across the stack
&lt;/li&gt;
&lt;li&gt;My roadmap: OAuth login, rejoin active games, human-vs-human play, Redis caching, NoSQL persistence, ECS Fargate, and more
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned for &lt;strong&gt;Part 2: Challenges, Lessons Learned, and What’s Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🔗 Live demo: &lt;a href="https://algebric-chess.vercel.app/" rel="noopener noreferrer"&gt;your-app-link.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;
💻 Code: &lt;a href="https://github.com/RavivGilady/AlgebraicChess" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>react</category>
      <category>webdev</category>
      <category>docker</category>
    </item>
    <item>
      <title>Starting Now — Building, Learning, and Shipping in Public</title>
      <dc:creator>Raviv Gilady</dc:creator>
      <pubDate>Thu, 21 Aug 2025 21:45:15 +0000</pubDate>
      <link>https://forem.com/raviv_gilady/starting-now-building-learning-and-shipping-in-public-2b4e</link>
      <guid>https://forem.com/raviv_gilady/starting-now-building-learning-and-shipping-in-public-2b4e</guid>
      <description>&lt;h2&gt;
  
  
  Why I’m Writing This Now
&lt;/h2&gt;

&lt;p&gt;I asked ChatGPT how to get more involved in the dev community. One answer hit hard: &lt;em&gt;show your work&lt;/em&gt;. So here I am—sharing wins, mistakes, and the messy middle in public.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who I Am
&lt;/h2&gt;

&lt;p&gt;I’m 29 (08/2025). I fell in love with programming in high school at 15. Between 18–22 I barely coded. At 22 I started a B.Sc. in Software Engineering at Ben-Gurion University and finished at 26.&lt;/p&gt;

&lt;p&gt;Since then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A small React internship.&lt;/li&gt;
&lt;li&gt;Security Analyst at Check Point (IPS + network vulnerabilities). Learned a lot, realized pure cyber isn’t for me.&lt;/li&gt;
&lt;li&gt;Backend Developer (Java) at Skybox Security for ~2.5 years. The company went bankrupt, so I’m looking for my next role now.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I’m Aiming For
&lt;/h2&gt;

&lt;p&gt;I’m looking for a backend or full-stack role. I really enjoy Node.js and JavaScript (no idea why—something about it just feels neat… maybe because I used VS Code only for JS?). I’m still open-minded about stack and language. Long term, I want to contribute as an engineer/architect, maybe CTO, maybe even co-found a startup. Not chasing people-management roles right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You’ll Get Here
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Decision diaries: the tradeoffs I’m facing and why I picked A over B.&lt;/li&gt;
&lt;li&gt;Short reflections from interviews and the job hunt.&lt;/li&gt;
&lt;li&gt;Favorite reads of the week (1–3 links + one-line takeaway), plus a couple things I learned.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I’m Working On
&lt;/h2&gt;

&lt;p&gt;1) ♟️ &lt;strong&gt;Chess app&lt;/strong&gt; — play vs. computer or human using &lt;a href="https://www.chess.com/terms/chess-notation" rel="noopener noreferrer"&gt;algebraic notation&lt;/a&gt;. My rapid ELO is ~975—feel free to &lt;a href="https://link.chess.com/friend/qYAKD5" rel="noopener noreferrer"&gt;add me on chess.com&lt;/a&gt;!&lt;br&gt;&lt;br&gt;
2) 🚀 &lt;strong&gt;MVP practice&lt;/strong&gt; — building and reusing a small framework so I can ship faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join In
&lt;/h2&gt;

&lt;p&gt;I’m always up for a quick chat or a chess game.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.linkedin.com/in/raviv-gilady/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://link.chess.com/friend/qYAKD5" rel="noopener noreferrer"&gt;Chess.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>beginners</category>
      <category>buildinpublic</category>
      <category>career</category>
      <category>todayilearned</category>
    </item>
  </channel>
</rss>
