<?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>DEV Community: CodenificienT</title>
    <description>The latest articles on DEV Community by CodenificienT (@codenificient).</description>
    <link>https://dev.to/codenificient</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4050404%2F52da94ab-406d-4cd9-8a51-5eaab47acae8.png</url>
      <title>DEV Community: CodenificienT</title>
      <link>https://dev.to/codenificient</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/codenificient"/>
    <language>en</language>
    <item>
      <title>I Lost the Cluster: Six Weeks Dark, and the Rebuild That Followed</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Sun, 02 Aug 2026 01:58:24 +0000</pubDate>
      <link>https://dev.to/codenificient/i-lost-the-cluster-six-weeks-dark-and-the-rebuild-that-followed-2ami</link>
      <guid>https://dev.to/codenificient/i-lost-the-cluster-six-weeks-dark-and-the-rebuild-that-followed-2ami</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on August 1, 2026 at &lt;a href="https://afrotomation.com/blog/2026-08-01-i-lost-the-cluster" rel="noopener noreferrer"&gt;afrotomation.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Between March and April 2026 I published four retrospectives about my infrastructure. &lt;a href="https://afrotomation.com/blog/2026-03-29-ai-agents-migrate-to-paperclip-orchestration" rel="noopener noreferrer"&gt;Eight AI agents orchestrated on one Oracle box&lt;/a&gt;. &lt;a href="https://afrotomation.com/blog/2026-04-14-migrating-40-apps-from-vercel-to-coolify" rel="noopener noreferrer"&gt;Forty-seven apps moved off Vercel onto a self-hosted Coolify cluster&lt;/a&gt;. &lt;a href="https://afrotomation.com/blog/2026-04-23-from-coolify-to-k3s-gitops-migration" rel="noopener noreferrer"&gt;That cluster torn down nine days later and rebuilt on k3s with ArgoCD, SOPS, and CloudNativePG&lt;/a&gt;. Then &lt;a href="https://afrotomation.com/blog/2026-04-26-k3s-post-migration-trenches" rel="noopener noreferrer"&gt;a trenches post&lt;/a&gt; about the bugs that showed up three days in.&lt;/p&gt;

&lt;p&gt;I was proud of all four. The last one even opened with a joke about how every infra retrospective ends with &lt;em&gt;"and now everything works."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;June 15, 2026&lt;/strong&gt;, at 04:54 UTC, the last write-ahead log segment shipped to my off-site backup bucket. Nothing shipped after it.&lt;/p&gt;

&lt;p&gt;I did not find out until &lt;strong&gt;July 21&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By the time I looked, both Contabo nodes had been suspended for non-payment, then terminated. The disks were wiped. The IP address of my primary node had been reassigned to a different Contabo customer — who was, at that moment, serving their own Nextcloud on it, on a domain my DNS records still pointed at.&lt;/p&gt;

&lt;p&gt;Almost every app I run was dark from June 15 to late July. This is the post-mortem, and the rebuild.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: What actually happened
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The setup that failed
&lt;/h3&gt;

&lt;p&gt;The k3s cluster was three nodes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;node&lt;/th&gt;
&lt;th&gt;provider&lt;/th&gt;
&lt;th&gt;role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vps50&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Contabo&lt;/td&gt;
&lt;td&gt;k3s server, CloudNativePG primary, GitLab CE, MinIO, MongoDB, Ghost, Uptime Kuma&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vps10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Contabo&lt;/td&gt;
&lt;td&gt;async Postgres replica, Loki&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ada&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Oracle Cloud (Always Free, ARM)&lt;/td&gt;
&lt;td&gt;agent node&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two of those three nodes were on the same paid account with the same provider. That is the whole story in one sentence, and everything below is a footnote to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The timeline
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;~June 15&lt;/strong&gt; — Contabo billing lapses. Services suspended. WAL archiving to Backblaze B2 stops at 04:54 UTC. Last base backup was 04:04 the same morning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~June 16&lt;/strong&gt; — &lt;code&gt;mbp23&lt;/code&gt;, the MacBook that held my SOPS &lt;code&gt;age&lt;/code&gt; key, my node SSH keys, and my kubeconfig, dies. It never powers on again. Multiple repair shops fail to revive it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;June 15 – July 21&lt;/strong&gt; — I am heads-down on client and agrobusiness work. Apps are down. I assume it's a transient thing I'll get to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;July 21&lt;/strong&gt; — I sit down to fix "the cluster" — on a &lt;strong&gt;new MacBook&lt;/strong&gt;, which has none of it: no SOPS &lt;code&gt;age&lt;/code&gt; key, no node SSH keys, no kubeconfig, not one real &lt;code&gt;.env&lt;/code&gt;. Everything I'd need to touch the fleet died with the old machine. I pay the outstanding Contabo bill through payment links buried in the suspension emails, because the web panel won't let me log in. I probe &lt;code&gt;173.212.219.250&lt;/code&gt;, see port 443 answering, and conclude vps50 is alive but wedged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;July 22&lt;/strong&gt; — I discover the server answering on that IP is &lt;strong&gt;not mine&lt;/strong&gt;. rDNS says &lt;code&gt;vmd200597.contaboserver.net&lt;/code&gt;. It serves &lt;code&gt;nextcloud.zumbahnhof40.de&lt;/code&gt;. Both my VPSes are terminated, both disks wiped, and my primary node's IP now belongs to a stranger. &lt;code&gt;vps10&lt;/code&gt; had already passed Contabo's 30-day recovery window and was unrecoverable by policy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That July 21 reading — "the box is up, the cluster is just wedged" — is the part that still bothers me most. I was reading liveness off a machine I did not own and had no way to distinguish from my own. &lt;strong&gt;A port answering is not proof of identity.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What died, ranked
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Gone, no copy anywhere:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitLab CE&lt;/strong&gt; — issues, merge requests, wikis, CI history, container registry. It ran as Omnibus with its own bundled Postgres inside a 60 GiB PVC, &lt;em&gt;not&lt;/em&gt; on CloudNativePG. My backup job only ever touched the CNPG cluster. There was no &lt;code&gt;gitlab-rake backup&lt;/code&gt; job. I had believed for months that GitLab was covered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loki&lt;/strong&gt; — all log history, on the node that got terminated first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MinIO&lt;/strong&gt; object storage, &lt;strong&gt;MongoDB&lt;/strong&gt;, &lt;strong&gt;Uptime Kuma&lt;/strong&gt; history — no off-node backups at all, ever.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ghost&lt;/strong&gt; — the blog engine and its content. (The posts themselves survived in a separate export; more on that below.)&lt;/li&gt;
&lt;li&gt;All Postgres writes between &lt;strong&gt;June 15 and June 30&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Survived:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every repository. GitLab CE one-way mirrored to GitHub, so the code was safe even though the surrounding project management was not.&lt;/li&gt;
&lt;li&gt;The CNPG &lt;code&gt;app&lt;/code&gt; database, through June 15, in B2.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ada&lt;/code&gt; — the Oracle node. It's on the &lt;strong&gt;Always Free&lt;/strong&gt; tier, so it was never billed, so it never lapsed. The one node I hadn't been paying for is the one that lived.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And one thing I had already written off. For weeks I carried &lt;code&gt;sahelprosperity-wv&lt;/code&gt; in my head as the unrecoverable loss — GitLab-only, never mirrored, gone. It wasn't. The work was sitting on the &lt;code&gt;main&lt;/code&gt; branch of the &lt;code&gt;sahelprosperity&lt;/code&gt; GitHub repo the entire time, invisible to me because production deployed from &lt;code&gt;master&lt;/code&gt; and &lt;code&gt;master&lt;/code&gt; was the only branch I ever looked at.&lt;/p&gt;

&lt;p&gt;That is its own small lesson, and not a flattering one: &lt;strong&gt;my inventory of what I owned was as stale as my backups.&lt;/strong&gt; I spent part of an outage mourning something I already had. If you keep a list of what you'd lose, check it against &lt;code&gt;git branch -a&lt;/code&gt; before you believe it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The honest cause
&lt;/h3&gt;

&lt;p&gt;It is tempting to write this as "self-hosting bit me" or "k3s was too complex." Neither is true, and both would be a cheap ending.&lt;/p&gt;

&lt;p&gt;The actual failure chain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Billing was an unmonitored production dependency.&lt;/strong&gt; I watched pods. I did not watch invoices. An unpaid invoice took down more infrastructure than any outage in the previous two years.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My backups covered one database, not my platform.&lt;/strong&gt; I had a mental model that said "Postgres is backed up, therefore my data is backed up." Six stateful services said otherwise. I never wrote down the list of things that hold state — if I had, the gaps would have been obvious in ten minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I never tested a restore.&lt;/strong&gt; My infra docs referenced two runbooks: &lt;code&gt;restore-postgres-from-b2.md&lt;/code&gt; and &lt;code&gt;replace-k3s-node.md&lt;/code&gt;. Neither was ever written. An untested backup is a hypothesis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key custody was a single point of failure that HA cannot fix.&lt;/strong&gt; Three nodes, two providers, replicated Postgres — and one laptop holding the only copy of the SOPS age key and every SSH key. When that laptop died, my cluster was cryptographically unreachable regardless of how healthy it was. High availability of &lt;em&gt;compute&lt;/em&gt; means nothing if &lt;em&gt;access&lt;/em&gt; has a single copy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two of three nodes shared one failure domain.&lt;/strong&gt; Same provider, same account, same invoice. I built what looked like a distributed system and it had the blast radius of one machine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is a smaller, more embarrassing finding too. When I later got into &lt;code&gt;ada&lt;/code&gt; and looked at disk usage, a &lt;strong&gt;146 GB ClickHouse volume&lt;/strong&gt; turned out to be 99.9% ClickHouse's own internal logs — &lt;code&gt;trace_log&lt;/code&gt; at 127 GB, &lt;code&gt;text_log&lt;/code&gt; at 18 GB. The actual analytics data I cared about was &lt;strong&gt;324 KB&lt;/strong&gt;. A disk that full almost certainly caused kubelet disk-pressure evictions and contributed to the instability I'd been shrugging at for weeks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: The rebuild
&lt;/h2&gt;

&lt;p&gt;Ten days, roughly, from "I understand what happened" to "everything is green." Here's the order it went in, because the order mattered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 0 — Stop pointing my domains at a stranger
&lt;/h3&gt;

&lt;p&gt;Before restoring anything, I had to stop actively endangering myself and my users. My DNS still pointed dozens of hostnames at IPs that now belonged to other people.&lt;/p&gt;

&lt;p&gt;I audited both zones and deleted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;85 &lt;code&gt;A&lt;/code&gt; records&lt;/strong&gt; aimed at the two reassigned Contabo IPs, across &lt;code&gt;afrotomation.com&lt;/code&gt; and &lt;code&gt;tioye.dev&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;96 stale &lt;code&gt;TXT&lt;/code&gt; records&lt;/strong&gt; — dead &lt;code&gt;_acme-challenge&lt;/code&gt; entries and external-dns heritage junk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zone sizes went from 95 → 15 records on &lt;code&gt;afrotomation.com&lt;/code&gt; and 143 → 42 on &lt;code&gt;tioye.dev&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two of those records deserve calling out. &lt;code&gt;cloud.afrotomation.com&lt;/code&gt; still pointed at the reassigned IP — meaning any device still running a Nextcloud sync client would have been offering credentials to a stranger's server. And Cloudflare's security scanner had flagged the &lt;em&gt;second&lt;/em&gt; reassigned IP as an &lt;strong&gt;exposed RDP host&lt;/strong&gt;: the new owner was running RDP on an address my DNS was still advertising as mine.&lt;/p&gt;

&lt;p&gt;If you take one operational thing from this post: &lt;strong&gt;when a server dies, deleting its DNS records is the first task, not the last.&lt;/strong&gt; A dead A record is not inert. It's a redirect to whoever gets that IP next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Emergency landing zone on Netlify
&lt;/h3&gt;

&lt;p&gt;I needed things &lt;em&gt;visible&lt;/em&gt; before I needed them &lt;em&gt;right&lt;/em&gt;. Netlify was the fastest path to that.&lt;/p&gt;

&lt;p&gt;This immediately hit a licensing wall: neither Netlify's nor Vercel's free tier will deploy private &lt;strong&gt;organization&lt;/strong&gt;-owned repos. So I transferred the deployable repos from the &lt;code&gt;afrotomation&lt;/code&gt; org back to my personal GitHub account, and pushed the priority apps out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tioye.dev&lt;/code&gt; — the portfolio. The domain had actually lapsed into expired-grace during the outage; I renewed it and transferred the registrar to Cloudflare the same day.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;auth.afrotomation.com&lt;/code&gt; — the SSO server, which everything else depends on. This had to come up first.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;afrotomation.com&lt;/code&gt;, plus ClickRise, SahelFoods, Bugginator, Sahel Prosperity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reviving SSO took three stacked fixes&lt;/strong&gt;, each hiding the next:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;My password hash predated the June 15 backup, so the credentials in the restored database were older than the ones in my password manager. I generated a fresh Better Auth scrypt hash locally and updated the row directly.&lt;/li&gt;
&lt;li&gt;Sign-in then returned 429 for &lt;em&gt;everyone&lt;/em&gt;. The rate limiter was &lt;strong&gt;failing closed&lt;/strong&gt; because its Upstash Redis credentials had died with the cluster. I changed it: production without Redis now degrades to in-memory limiting, with &lt;code&gt;RATE_LIMIT_FAIL_CLOSED=true&lt;/code&gt; available to restore strict behavior deliberately.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get-session&lt;/code&gt; then threw &lt;em&gt;"Failed to decrypt private key."&lt;/em&gt; The JWKS row in the database was encrypted with the &lt;strong&gt;old&lt;/strong&gt; &lt;code&gt;BETTER_AUTH_SECRET&lt;/code&gt; — which was gone with the cluster. Deleting the row let Better Auth regenerate the keypair.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every one of those three is a "your secrets were cluster-side" problem in a different costume.&lt;/p&gt;

&lt;p&gt;Netlify's own limits then bit: I burned &lt;strong&gt;363 of 300&lt;/strong&gt; monthly credits, and the failure mode was strange — external uptime checkers reported 200s while the sites were genuinely unreachable from some edge locations. Don't trust third-party "it's up globally" checks for an over-limit account. I upgraded, and reachability was restored immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Get back into the Oracle box
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ada&lt;/code&gt; had survived. I could not log into it.&lt;/p&gt;

&lt;p&gt;The authorized SSH key was on the dead laptop. I tried the documented escape hatches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OCI Run Command&lt;/strong&gt; — unavailable. The Ubuntu &lt;strong&gt;Minimal&lt;/strong&gt; image ships 11 plugins, and &lt;code&gt;Compute Instance Run Command&lt;/code&gt; isn't one of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OCI Bastion&lt;/strong&gt; — created the bastion and a managed SSH session, watched it hang in &lt;code&gt;Creating&lt;/code&gt; for eight minutes, and gave up. Not a firewall problem, since public SSH answered fine. The plugin reported Enabled and Running and simply did not work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What worked was a &lt;strong&gt;boot-volume swap&lt;/strong&gt;: detach &lt;code&gt;ada&lt;/code&gt;'s boot volume, attach it as a data volume to a second throwaway instance, mount it, write my new public key into &lt;code&gt;authorized_keys&lt;/code&gt;, detach, reattach, boot. Crude, reliable, no vendor tooling involved.&lt;/p&gt;

&lt;p&gt;One thing to know if you ever do this: &lt;code&gt;ada&lt;/code&gt; has &lt;strong&gt;two&lt;/strong&gt; users, &lt;code&gt;opc&lt;/code&gt; at UID 1000 and &lt;code&gt;ubuntu&lt;/code&gt; at UID &lt;strong&gt;1001&lt;/strong&gt;. Assuming 1000 is the login account will waste you an hour.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Demolish the zombie
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ada&lt;/code&gt; was still running a k3s agent pointed at a control plane that no longer existed. ingress-nginx was 404ing on 80/443 with an &lt;code&gt;afrotomation.com&lt;/code&gt; certificate that had expired on July 23. The API server was down, etcd quorum permanently lost. Nothing there was recoverable.&lt;/p&gt;

&lt;p&gt;Uninstalling reclaimed &lt;strong&gt;164 GB&lt;/strong&gt; — the box went from 190/193 GB used to 35 GB.&lt;/p&gt;

&lt;p&gt;A gotcha worth writing down: if both &lt;code&gt;k3s-uninstall.sh&lt;/code&gt; and &lt;code&gt;k3s-agent-uninstall.sh&lt;/code&gt; exist on a node, the &lt;em&gt;server&lt;/em&gt; uninstaller bails with &lt;code&gt;"Additional k3s services installed, skipping"&lt;/code&gt; and removes only the systemd unit. The &lt;strong&gt;agent&lt;/strong&gt; uninstaller is the one that actually deletes &lt;code&gt;/var/lib/rancher&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — Coolify, and the four things that blocked it
&lt;/h3&gt;

&lt;p&gt;Coolify 4.1.2 went on the box. The dashboard lives on port 8000 and I deliberately never opened that port publicly — it's reachable over Tailscale only.&lt;/p&gt;

&lt;p&gt;Then four fleet-wide blockers, in the order they surfaced:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Ingress: the OCI security list only allows port 22.&lt;/strong&gt; Not the instance firewall — the VCN itself. I proved it with &lt;code&gt;tcpdump&lt;/code&gt;: &lt;code&gt;0 packets captured&lt;/code&gt; while curling from outside. The confusing part is that Oracle's virtual network completes the TCP handshake before dropping you, so &lt;code&gt;nc&lt;/code&gt; cheerfully reports success on a port that will never deliver a byte. Use &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;tcpdump&lt;/code&gt;, never &lt;code&gt;nc&lt;/code&gt;, to test this.&lt;/p&gt;

&lt;p&gt;The fix wasn't allowlisting Cloudflare's CIDRs. &lt;code&gt;ada&lt;/code&gt; was already running a healthy &lt;code&gt;cloudflared&lt;/code&gt; tunnel left over from an earlier era. I repointed its ingress at the new Traefik and the origin stayed sealed — &lt;code&gt;curl http://&amp;lt;public-ip&amp;gt;/&lt;/code&gt; returns nothing at all, while everything serves fine through Cloudflare.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The tunnel has to speak HTTPS to Traefik.&lt;/strong&gt; Routing &lt;code&gt;*.afrotomation.com&lt;/code&gt; to &lt;code&gt;http://127.0.0.1:80&lt;/code&gt; produces an infinite redirect loop, because Coolify's Traefik force-redirects HTTP→HTTPS and the response bounces back out through Cloudflare. The working shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.afrotomation.com"&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://127.0.0.1:443&lt;/span&gt;
    &lt;span class="na"&gt;originRequest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;noTLSVerify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;noTLSVerify&lt;/code&gt; is fine here — the hop is loopback and the tunnel is already encrypted.&lt;/p&gt;

&lt;p&gt;Also: &lt;code&gt;cloudflared tunnel route dns&lt;/code&gt; only works for the zone the tunnel's cert covers. Point it at a &lt;code&gt;tioye.dev&lt;/code&gt; hostname and it will silently create &lt;code&gt;tioye.dev.afrotomation.com&lt;/code&gt; instead of erroring. Second-zone hostnames need the CNAME created by hand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. &lt;code&gt;bun&lt;/code&gt; does not install on ARM + Alpine — and it broke 47 of my 55 Dockerfiles.&lt;/strong&gt; Every one of them had &lt;code&gt;RUN npm install -g bun@X&lt;/code&gt;, which fails on aarch64 musl with &lt;code&gt;Failed to find package "@oven/bun-linux-aarch64"&lt;/code&gt;. Bun's npm distribution has no musl+ARM build. The one-line fix, which also respects my no-Docker-Hub policy since the GCR mirror carries it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=mirror.gcr.io/oven/bun:1.2.17-alpine /usr/local/bin/bun /usr/local/bin/bun&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Deploy keys were disabled at the GitHub org level&lt;/strong&gt;, so Coolify could not clone a single private repo. One org setting, forty broken deploys.&lt;/p&gt;

&lt;p&gt;(There was a fifth, chronic one: &lt;strong&gt;stale &lt;code&gt;bun.lock&lt;/code&gt; files&lt;/strong&gt; from Renovate PRs that were never rebuilt. &lt;code&gt;bun install --frozen-lockfile&lt;/code&gt; dies with &lt;em&gt;"lockfile had changes, but lockfile is frozen."&lt;/em&gt; &lt;code&gt;bun install --lockfile-only&lt;/code&gt;, commit, move on. This same problem had already bitten me on Netlify.)&lt;/p&gt;

&lt;p&gt;With those cleared, deploys became routine: dedicated read-only deploy key per repo, &lt;code&gt;POST /applications/private-deploy-key&lt;/code&gt;, DNS via the tunnel, deploy. About three minutes per app. &lt;strong&gt;As of August 1, all 41 resources in the Coolify project report &lt;code&gt;running&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 — The data
&lt;/h3&gt;

&lt;p&gt;One Coolify-managed PostgreSQL instance, one database per app.&lt;/p&gt;

&lt;p&gt;The image matters: &lt;code&gt;postgis/postgis&lt;/code&gt; is &lt;strong&gt;amd64-only&lt;/strong&gt; — the exact wall that had kept Postgres off the ARM node in the old cluster. The multi-arch community build &lt;code&gt;imresamu/postgis:17-3.5&lt;/code&gt; works, reporting PostgreSQL 17.6 on aarch64.&lt;/p&gt;

&lt;p&gt;Then I restored the B2 backup into a scratch instance and merged it into the live databases. Additive only — &lt;code&gt;INSERT ... WHERE NOT EXISTS (pk)&lt;/code&gt;, never update, never delete, converges to zero rows on a re-run. Run it repeatedly to a fixpoint, because child rows need their parents from an earlier pass.&lt;/p&gt;

&lt;p&gt;Roughly &lt;strong&gt;14,000 rows&lt;/strong&gt; came back:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;database&lt;/th&gt;
&lt;th&gt;rows recovered&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;clickrise&lt;/td&gt;
&lt;td&gt;9,260&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bookshelf&lt;/td&gt;
&lt;td&gt;4,462&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sahelfoods&lt;/td&gt;
&lt;td&gt;190&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;codeniserver&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;everything else&lt;/td&gt;
&lt;td&gt;~22&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Four staging traps each produced a "successful" merge that silently skipped most tables.&lt;/strong&gt; The only reason I caught them was asserting that the staged table count equalled the source table count:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;\restrict&lt;/code&gt; in plain-SQL dumps.&lt;/strong&gt; Modern &lt;code&gt;pg_dump&lt;/code&gt; wraps plain output in &lt;code&gt;\restrict&lt;/code&gt;/&lt;code&gt;\unrestrict&lt;/code&gt;; &lt;code&gt;psql&lt;/code&gt; then rejects the &lt;code&gt;\.&lt;/code&gt; COPY terminators and most tables fail to load. Use &lt;code&gt;--format=custom&lt;/code&gt; and &lt;code&gt;pg_restore&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing &lt;code&gt;uuid-ossp&lt;/code&gt;.&lt;/strong&gt; Columns default to &lt;code&gt;uuid_generate_v4()&lt;/code&gt;; without the extension, every such table fails to create.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ALTER SCHEMA public RENAME TO bk&lt;/code&gt; moves the extensions with it&lt;/strong&gt;, so those defaults become &lt;code&gt;bk.uuid_generate_v4()&lt;/code&gt; — which won't exist in the live database. Strip defaults and FK/CHECK constraints from the staging schema after renaming (keep the primary keys; the merge needs them).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-account ID drift.&lt;/strong&gt; The backup and the live database issued &lt;em&gt;different&lt;/em&gt; IDs for the &lt;em&gt;same&lt;/em&gt; email. You have to build an old→new map by joining on &lt;code&gt;lower(email)&lt;/code&gt; and rewrite every foreign key onto users. Hard-coding one admin ID recovers almost nothing — that mistake is what initially hid two OAuth clients owned by a different test identity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two apps turned out not to have lost data at all — they'd drifted behind their own migrations. &lt;code&gt;bookshelf&lt;/code&gt; was nine Prisma migrations behind, blocked by a &lt;em&gt;failed&lt;/em&gt; migration inherited from its previous host that ended in a &lt;code&gt;GRANT&lt;/code&gt; to a role that didn't exist on the new box. &lt;code&gt;sahelfoods&lt;/code&gt; had no Drizzle migrations table whatsoever and only 61 of its 86 tables. Both recovered once the schema caught up.&lt;/p&gt;

&lt;p&gt;Every application database is now on the box. &lt;strong&gt;Zero Neon references remain in any deployed app.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6 — Split the fleet on purpose
&lt;/h3&gt;

&lt;p&gt;The old architecture put everything behind one control plane. The new one deliberately does not:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;tier&lt;/th&gt;
&lt;th&gt;platform&lt;/th&gt;
&lt;th&gt;what lives there&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dynamic apps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Coolify on Oracle &lt;code&gt;ada&lt;/code&gt; (4 OCPU / 24 GB ARM)&lt;/td&gt;
&lt;td&gt;41 resources — Next.js apps, Postgres, supporting services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Static sites&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloudflare Pages&lt;/td&gt;
&lt;td&gt;6 CRA/static builds, direct-upload via &lt;code&gt;wrangler&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overflow / legacy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Netlify&lt;/td&gt;
&lt;td&gt;11 remaining non-cornerstone sites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blog&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;dev.to&lt;/td&gt;
&lt;td&gt;43 posts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cloudflare Pages gotchas, since they cost me time: it &lt;strong&gt;rejects any file over 25 MiB&lt;/strong&gt; (a CRA source map killed one deploy — &lt;code&gt;GENERATE_SOURCEMAP=false&lt;/code&gt;), it sets &lt;code&gt;CI=true&lt;/code&gt; which promotes CRA ESLint warnings to build errors, and its default &lt;code&gt;npm ci&lt;/code&gt; fails across this entire fleet because every repo uses &lt;code&gt;bun.lock&lt;/code&gt; and none has a &lt;code&gt;package-lock.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The sizing constraint on the Coolify box is CPU, not memory: 24 GB fits about 40 containers, but 4 OCPUs realistically supports 25–30 apps with concurrent builds set to 1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7 — The blog moved to dev.to
&lt;/h3&gt;

&lt;p&gt;Ghost died with the cluster. I did not want to run a blog engine again.&lt;/p&gt;

&lt;p&gt;I considered Hashnode — I'd used it before — but its API went Pro-only in May 2026, and I'm not paying a subscription for write access to my own words. &lt;strong&gt;dev.to&lt;/strong&gt; it is. All 43 posts are live there, and &lt;code&gt;tioye.dev/blog&lt;/code&gt; renders from the dev.to API through a &lt;code&gt;lib/devto.ts&lt;/code&gt; module that replaced the dead Ghost client with the same interface.&lt;/p&gt;

&lt;p&gt;Two dev.to API lessons, both of which cost me real time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RSS-imported articles embed front matter inside &lt;code&gt;body_markdown&lt;/code&gt;&lt;/strong&gt;, and a &lt;code&gt;published: false&lt;/code&gt; in that embedded block &lt;strong&gt;overrides&lt;/strong&gt; the API's &lt;code&gt;published&lt;/code&gt; field. You have to rewrite the body's front matter to actually publish them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The API rejects backdated &lt;code&gt;published_at&lt;/code&gt;&lt;/strong&gt; — "only future or current." So 23 older posts are all stamped with their import date, and the site parses each post's true date out of its opening &lt;em&gt;"Originally published on…"&lt;/em&gt; line and sorts by that instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And one gotcha that had nothing to do with dev.to: after the swap, browsers reported &lt;em&gt;"Failed to fetch"&lt;/em&gt; while server-side renders worked perfectly. My &lt;code&gt;next.config.js&lt;/code&gt; CSP &lt;code&gt;connect-src&lt;/code&gt; still allowed only the dead Ghost origin. &lt;strong&gt;When you change a client-fetched data source, update your CSP and your image &lt;code&gt;remotePatterns&lt;/code&gt; in the same commit.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8 — The things that quietly depended on the cluster
&lt;/h3&gt;

&lt;p&gt;Weeks later I was still finding these.&lt;/p&gt;

&lt;p&gt;My portfolio's project screenshots came from a k3s CronJob. With that gone, the grid fell back to a live third-party capture API on every card render, blew through its free daily quota instantly, and rendered "coming soon" placeholders across the whole page. The replacement is a headless Chromium container on the box, cron'd for Sunday mornings, uploading to Cloudinary — &lt;strong&gt;41 real covers, zero placeholders.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;(Docker note, since this one wasted an afternoon: headless Chromium needs &lt;code&gt;--shm-size=1g&lt;/code&gt; alongside &lt;code&gt;--disable-dev-shm-usage&lt;/code&gt;. With Docker's default 64 MB &lt;code&gt;/dev/shm&lt;/code&gt;, the GPU process crashes mid-capture and writes &lt;strong&gt;no file at all&lt;/strong&gt; — no error, no image.)&lt;/p&gt;

&lt;p&gt;While auditing costs I also found the actual money leak, and it wasn't hosting. &lt;strong&gt;99 repositories were running Renovate on bare &lt;code&gt;config:recommended&lt;/code&gt;&lt;/strong&gt; — no schedule, no grouping. Every dependency PR fired a CI build. That, plus 37 dead workflow files still pointing at a runner set that no longer existed, was the burn. Throttled, deleted, and Dependabot removed from the 30 repos where it overlapped with Renovate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell April-me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Write the list of stateful things.&lt;/strong&gt; Not "is Postgres backed up" — an actual enumerated list of every service that holds state, with the backup mechanism next to each one, and a blank next to the ones without. Mine would have had six blanks and I'd have seen it in ten minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A backup you haven't restored is a hypothesis.&lt;/strong&gt; Both of my restore runbooks were referenced in documentation and never written. Restore into a scratch environment on a schedule, or you don't know what you have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get your keys off your laptop.&lt;/strong&gt; Not "back them up eventually" — today. HA compute plus single-copy credentials is not a resilient system, it's a fragile system with expensive decoration. My cluster was fine. I just couldn't get in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Billing is production.&lt;/strong&gt; Put invoices and card expiries in the same alerting channel as your uptime checks. A lapsed payment did more damage to me than any technical failure in two years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spread the blast radius across providers, not just machines.&lt;/strong&gt; Three nodes across two providers still meant two-thirds of my cluster on one invoice. The node that survived is the one on a tier that &lt;em&gt;cannot&lt;/em&gt; lapse for non-payment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Delete DNS for dead hosts immediately.&lt;/strong&gt; A dangling &lt;code&gt;A&lt;/code&gt; record isn't a broken link. It's a live pointer at whoever the cloud provider hands that IP to next — and in my case that was someone running an exposed RDP service on an address my domain was still vouching for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't trust liveness you didn't design.&lt;/strong&gt; I spent a day working from the belief that my server was up, because something answered on its IP. Check identity — a TLS certificate, a health endpoint you wrote, an rDNS lookup — not just a port.&lt;/p&gt;

&lt;h2&gt;
  
  
  Was self-hosting the mistake?
&lt;/h2&gt;

&lt;p&gt;No, and I want to be precise about why, because "just use a PaaS" is the wrong lesson to draw from this.&lt;/p&gt;

&lt;p&gt;Nothing here was caused by Kubernetes being hard, or by running my own metal. The cluster didn't crash. It was &lt;em&gt;deleted&lt;/em&gt;, by a billing event, and I couldn't recover it because I'd centralized the recovery path into one laptop and one incomplete backup job. Those are operational failures I'd have committed on any platform. Vercel taught me the same lesson from the opposite direction last year — that's &lt;em&gt;why&lt;/em&gt; I self-host.&lt;/p&gt;

&lt;p&gt;What did change is the shape. The old fleet was one control plane, one key, one backup target: a distributed system with the blast radius of a single machine. The new one is three independent tiers on three independent providers, with credentials that live somewhere other than my desk. If the Oracle box vanishes tomorrow, the static sites stay up and the blog stays up, and the recovery path is a rebuild script and a password manager rather than a boot-volume swap and a prayer.&lt;/p&gt;

&lt;p&gt;Six weeks dark is a real cost. But I'd been running on an untested backup for months and simply hadn't found out yet. I'd rather have found out this way than the next way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Still open
&lt;/h2&gt;

&lt;p&gt;Being honest to the end, this isn't finished:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSO's auth database is off Netlify but still on a managed provider — it hasn't been migrated to the box yet.&lt;/li&gt;
&lt;li&gt;Eleven legacy sites are still on Netlify pending review.&lt;/li&gt;
&lt;li&gt;Distributed rate limiting still needs a Redis to come back.&lt;/li&gt;
&lt;li&gt;Every credential that ever sat on those Contabo disks — OAuth client secrets included — still needs rotating. Someone else owned those disks. It is the longest item on the list and the easiest to keep postponing.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This is part of the **Afrotomation Startup&lt;/em&gt;* series — building an automation agency in public, including the parts that go badly. Previous entries: &lt;a href="https://afrotomation.com/blog/2026-04-14-migrating-40-apps-from-vercel-to-coolify" rel="noopener noreferrer"&gt;47 Apps, One Week&lt;/a&gt; · &lt;a href="https://afrotomation.com/blog/2026-04-23-from-coolify-to-k3s-gitops-migration" rel="noopener noreferrer"&gt;From Click-Ops to GitOps&lt;/a&gt; · &lt;a href="https://afrotomation.com/blog/2026-04-26-k3s-post-migration-trenches" rel="noopener noreferrer"&gt;Three Days In&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>k3s</category>
      <category>postmortem</category>
      <category>selfhosting</category>
    </item>
    <item>
      <title>The Aspiring AI Engineer: Educative Learning Path</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:51:04 +0000</pubDate>
      <link>https://dev.to/codenificient/the-aspiring-ai-engineer-educative-learning-path-1453</link>
      <guid>https://dev.to/codenificient/the-aspiring-ai-engineer-educative-learning-path-1453</guid>
      <description>&lt;p&gt;Published on Aug 28th, 2025&lt;/p&gt;

&lt;p&gt;I've just finished &lt;strong&gt;Module 1: Learn Python&lt;/strong&gt; from the &lt;a href="https://www.educative.io/path/become-a-machine-learning-engineer" rel="noopener noreferrer"&gt;Machine Learning Engineer Career Path&lt;/a&gt; on &lt;a href="http://Educative.com" rel="noopener noreferrer"&gt;Educative.com&lt;/a&gt;, and I'm excited to share what I've learned! This foundational module has equipped me with the essential Python programming skills needed to tackle machine learning algorithms and data science projects.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 &lt;strong&gt;What I Accomplished&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Over the course of Module 1, I completed &lt;strong&gt;40+ hands-on Python exercises&lt;/strong&gt; that covered everything from basic syntax to building interactive applications. Each exercise was designed to reinforce programming concepts through practical, real-world scenarios.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 &lt;strong&gt;Core Concepts Mastered&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Python Fundamentals &amp;amp; Syntax&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Variables &amp;amp; Data Types&lt;/strong&gt;: Learned to work with strings, integers, floats, and boolean values&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input/Output Operations&lt;/strong&gt;: Mastered &lt;code&gt;print()&lt;/code&gt; statements and &lt;code&gt;input()&lt;/code&gt; functions for user interaction&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Basic Operations&lt;/strong&gt;: Arithmetic operations, string concatenation, and type conversion&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example from my work:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Hello.py - My first Python program
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Welcome to the Machine Learning course by Educative!!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;2. Control Flow &amp;amp; Decision Making&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conditional Statements&lt;/strong&gt;: Implemented &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;elif&lt;/code&gt;, and &lt;code&gt;else&lt;/code&gt; statements for program logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comparison Operators&lt;/strong&gt;: Used &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt; for decision making&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Logical Operators&lt;/strong&gt;: Combined conditions with &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, and &lt;code&gt;not&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world application:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Conditionals Movies.py - Age-appropriate movie recommendations
&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter your age: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You can watch R-rated movies&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You can watch PG-13 movies&lt;/span&gt;&lt;span class="sh"&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You can watch PG movies&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;3. Loops &amp;amp; Iteration&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For Loops&lt;/strong&gt;: Iterated through lists, ranges, and sequences&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;While Loops&lt;/strong&gt;: Created programs that run until specific conditions are met&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Loop Control&lt;/strong&gt;: Used &lt;code&gt;break&lt;/code&gt; and &lt;code&gt;continue&lt;/code&gt; statements effectively&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Practical example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# While Loops.py - Interactive user input handling
&lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter your name (or &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;quit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; to exit): &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;quit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;4. Data Structures&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lists&lt;/strong&gt;: Created, modified, and manipulated ordered collections&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dictionaries&lt;/strong&gt;: Built key-value pairs for storing related information&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Manipulation&lt;/strong&gt;: Added, removed, and updated elements in collections&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hands-on practice:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Lists.py - Working with collections
&lt;/span&gt;&lt;span class="n"&gt;fruits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apple&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;banana&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;orange&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;fruits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;grape&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Available fruits: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fruits&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;5. Functions &amp;amp; Code Organization&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Function Definition&lt;/strong&gt;: Created reusable code blocks with &lt;code&gt;def&lt;/code&gt; statements&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parameters &amp;amp; Return Values&lt;/strong&gt;: Built functions that accept input and produce output&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Reusability&lt;/strong&gt;: Organized code into logical, maintainable functions&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Advanced function example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# function adv layers.py - Interactive storytelling
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;jungle_adventure&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You find two paths: one goes to a river, the other to a mountain. Where do you go? &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;river&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You swim with dolphins!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mountain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You find an ancient temple!&lt;/span&gt;&lt;span class="sh"&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You wander into the savannah and get lost.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;jungle_adventure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;6. File Operations&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reading Files&lt;/strong&gt;: Opened and processed data from text files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Writing Files&lt;/strong&gt;: Created and updated files to store information&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File Management&lt;/strong&gt;: Handled file paths, error handling, and data persistence&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Practical file handling:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# file diary.py - Personal journal system
&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;diary.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write your diary entry: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;7. Graphics &amp;amp; Visualization&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Turtle Graphics&lt;/strong&gt;: Created visual patterns and shapes using Python's turtle module&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Color Manipulation&lt;/strong&gt;: Applied different colors and styles to graphics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Geometric Drawing&lt;/strong&gt;: Built hexagons, spirals, and complex patterns&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Creative coding:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# graphics hexagon.py - Geometric art
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;turtle&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;turtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Turtle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎮 &lt;strong&gt;Interactive Projects Built&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Temperature Converter&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Built a comprehensive temperature conversion tool that handles Celsius, Fahrenheit, and Kelvin conversions with user-friendly menus and multiple conversion options.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Personal Habit Tracker&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Created an interactive habit tracking system that allows users to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add multiple habits to track&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Record daily completion status&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View progress over time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Maintain streaks and motivation&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Mini Chatbot&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Developed a simple conversational bot that demonstrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;User input processing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conditional responses&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Basic AI interaction patterns&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Program flow control&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Interactive Adventure Story&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Built a text-based adventure game featuring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;User choice-driven narratives&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multiple story paths&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dynamic responses&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Function-based story structure&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 &lt;strong&gt;Key Learning Insights&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Problem-Solving Approach&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Break down complex problems&lt;/strong&gt; into smaller, manageable pieces&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with pseudocode&lt;/strong&gt; before writing actual code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test incrementally&lt;/strong&gt; as you build features&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Iterate and improve&lt;/strong&gt; based on testing results&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Code Organization&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Functions are your friend&lt;/strong&gt; - they make code reusable and maintainable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Meaningful variable names&lt;/strong&gt; improve code readability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comments matter&lt;/strong&gt; - they help you and others understand your code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistent formatting&lt;/strong&gt; makes debugging easier&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. User Experience&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear prompts&lt;/strong&gt; guide users through your programs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error handling&lt;/strong&gt; prevents crashes and improves usability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feedback loops&lt;/strong&gt; keep users engaged and informed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intuitive interfaces&lt;/strong&gt; make programs accessible to everyone&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔮 &lt;strong&gt;How This Prepares Me for Machine Learning&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Algorithm Foundation&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Control flow skills&lt;/strong&gt; will be essential for implementing ML algorithms&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Loop structures&lt;/strong&gt; are crucial for training models and processing data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conditional logic&lt;/strong&gt; helps in decision trees and classification systems&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Data Handling&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File operations&lt;/strong&gt; prepare me for reading datasets and saving results&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data structures&lt;/strong&gt; knowledge is fundamental for working with NumPy arrays and Pandas DataFrames&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input processing&lt;/strong&gt; skills will be needed for data preprocessing&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Problem-Solving Mindset&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Breaking down complex problems&lt;/strong&gt; is exactly what's needed for ML model development&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testing and iteration&lt;/strong&gt; mirrors the process of training and tuning ML models&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User interaction&lt;/strong&gt; skills will help in building ML applications and dashboards&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 &lt;strong&gt;What's Next: Module 2 Preview&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;With Module 1 complete, I'm now ready to tackle &lt;strong&gt;Module 2: Python Libraries&lt;/strong&gt;, where I'll learn to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Work with NumPy for numerical computing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Pandas for data manipulation and analysis&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create visualizations with Matplotlib and Seaborn&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apply data science techniques to real datasets&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🏆 &lt;strong&gt;Key Takeaways&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Python is powerful yet accessible&lt;/strong&gt; - perfect for beginners entering the ML field&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hands-on practice is essential&lt;/strong&gt; - theory alone isn't enough to build programming confidence&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Building real projects accelerates learning&lt;/strong&gt; - practical applications reinforce theoretical concepts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Foundation matters&lt;/strong&gt; - strong Python skills will make learning ML libraries much easier&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Problem-solving is a skill&lt;/strong&gt; - it improves with practice and experience&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  💬 &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Module 1 has been an incredible foundation-building experience. Starting with simple "Hello World" programs and progressing to interactive applications has given me the confidence to tackle more complex machine learning challenges. The hands-on approach of Educative's platform has made learning Python engaging and practical.&lt;/p&gt;

&lt;p&gt;I'm excited to continue this journey and can't wait to see how these Python fundamentals will translate into machine learning expertise. The road to becoming a Machine Learning Engineer is well-paved with these essential programming skills!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Ready to start your own ML journey? Check out the&lt;/em&gt; &lt;a href="https://www.educative.io/path/become-a-machine-learning-engineer" rel="noopener noreferrer"&gt;&lt;em&gt;Machine Learning Engineer Career Path&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on&lt;/em&gt; &lt;a href="http://Educative.com" rel="noopener noreferrer"&gt;&lt;em&gt;Educative.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt;!&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags&lt;/strong&gt;: #Python #MachineLearning #Programming #Educative #LearningJourney #DataScience #Coding #MLCareerPath&lt;/p&gt;

</description>
      <category>python</category>
      <category>machinelearning</category>
      <category>careergrowth</category>
      <category>educative</category>
    </item>
    <item>
      <title>Day 4 of Demolishing my Stack of Unfinished Projects: Secret Chat</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:50:56 +0000</pubDate>
      <link>https://dev.to/codenificient/day-4-of-demolishing-my-stack-of-unfinished-projects-secret-chat-532j</link>
      <guid>https://dev.to/codenificient/day-4-of-demolishing-my-stack-of-unfinished-projects-secret-chat-532j</guid>
      <description>&lt;p&gt;Published on Aug 21st, 2025&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;🚀 Made some progress&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Welcome back to my "Demolishing My Stack of Unfinished Projects" series! This week, I'm excited to share the story of how I transformed a simple chat idea into a fully-featured, production-ready real-time messaging application called &lt;strong&gt;CodeniChat&lt;/strong&gt; (formerly Secret Chat Bolt).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;🎯 The Project That Started It All&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Secret Chat&lt;/strong&gt; began as one of those "wouldn't it be cool if..." moments. I had this idea for a secure, real-time chat application that could handle multiple rooms, user invitations, and password resets. You know the drill - you start with enthusiasm, then life happens, and suddenly it's been months with just a README file and some half-baked code.&lt;/p&gt;

&lt;p&gt;But this week, I decided enough was enough. It was time to demolish this unfinished project and turn it into something I could actually be proud of. I started off with a short prompt into the bolt.new platform&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🛠️ The Tech Stack That Made It Possible&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Frontend&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Next.js 15&lt;/strong&gt; - The latest and greatest React framework&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;React 19&lt;/strong&gt; - Cutting-edge React with the new compiler&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TypeScript&lt;/strong&gt; - Because type safety is not optional&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tailwind CSS&lt;/strong&gt; - For rapid, beautiful UI development&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;shadcn/ui&lt;/strong&gt; - Pre-built, accessible components&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Backend &amp;amp; Database&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Neon Database&lt;/strong&gt; - Serverless PostgreSQL that scales with you&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Drizzle ORM&lt;/strong&gt; - Type-safe database operations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NextAuth.js&lt;/strong&gt; - Secure authentication system&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bcryptjs&lt;/strong&gt; - Password hashing and security&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Real-time Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Server-Sent Events&lt;/strong&gt; - For real-time message updates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WebSocket-like functionality&lt;/strong&gt; - Without the complexity&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🚀 The Week-Long Development Sprint&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Day 1: Foundation &amp;amp; Database&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I started by setting up the database schema with Drizzle ORM. The beauty of using a modern ORM is that you can define your relationships once and let TypeScript handle the rest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Core tables for the chat system&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pgTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;created_at&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;defaultNow&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rooms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pgTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rooms&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;notNull&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;isPrivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is_private&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;createdBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;created_by&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;created_at&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;defaultNow&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Day 2: Authentication &amp;amp; User Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;NextAuth.js made implementing authentication a breeze. I added signup, signin, and even a password reset flow that generates secure tokens and handles the entire reset process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Password Reset Flow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;User requests reset → Secure token generated&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Token stored with expiration → 24-hour validity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User clicks reset link → Token validated&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;New password set → Token marked as used&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Day 3: Real-Time Chat Core&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This was the fun part! I implemented the core chat functionality with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Message grouping&lt;/strong&gt; - Consecutive messages from the same user are visually grouped&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Auto-scroll&lt;/strong&gt; - Intelligent scrolling that doesn't interfere with user reading&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Room management&lt;/strong&gt; - Public and private rooms with automatic user assignment&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Day 4: The Invitation System&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;One of the most requested features in any chat app - the ability to invite users to rooms. I built:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Invite modal&lt;/strong&gt; - Select users from a filtered list&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pending invitations&lt;/strong&gt; - Sidebar display of received invites&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Accept/Decline actions&lt;/strong&gt; - One-click room joining&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Day 5: UI/UX Polish &amp;amp; Branding&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I transformed the generic "ChatApp" into &lt;strong&gt;CodeniChat&lt;/strong&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom favicon&lt;/strong&gt; - SVG-based chat icon&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Responsive design&lt;/strong&gt; - Works on all devices&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modern UI components&lt;/strong&gt; - Using shadcn/ui for consistency&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Footer addition&lt;/strong&gt; - Copyright and "made with love" message&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Day 6: Next.js 15 Upgrade&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This was a significant milestone. I upgraded from Next.js 13 to Next.js 15, which involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;React 19 upgrade&lt;/strong&gt; - Latest React features&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TypeScript improvements&lt;/strong&gt; - Stricter type checking&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build optimization&lt;/strong&gt; - Better performance and smaller bundles&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Day 7: Deployment &amp;amp; Final Touches&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The final day was all about getting this baby deployed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vercel configuration&lt;/strong&gt; - Optimized for Next.js 15&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment setup&lt;/strong&gt; - Secure configuration management&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Final testing&lt;/strong&gt; - Ensuring everything works in production&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🎨 Key Features That Make This App Special&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Intelligent Message Grouping&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groupedMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GroupedMessage&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prevMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isFirstInGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;prevMessage&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
      &lt;span class="nx"&gt;prevMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;prevMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Group logic implementation...&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="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;2. Smart Auto-Scroll&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The app intelligently detects when users are reading older messages and won't force-scroll them to the bottom. But when they're at the bottom, new messages automatically appear.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Room Invitation System&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Users can invite others to private rooms, and pending invitations are clearly displayed in the sidebar with accept/decline buttons.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Password Reset Flow&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Complete password recovery system with secure token generation and validation.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🚧 Challenges I Faced (And How I Overcame Them)&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Next.js 15 Compatibility Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; The upgrade introduced breaking changes in API routes and required new Suspense boundaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; I updated all API route parameters to use &lt;code&gt;Promise&amp;lt;{ roomId: string }&amp;gt;&lt;/code&gt; and wrapped components using &lt;code&gt;useSearchParams()&lt;/code&gt; in Suspense boundaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Vercel Deployment Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Next.js 15 peer dependency conflicts during deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Used &lt;code&gt;npm install --legacy-peer-deps&lt;/code&gt; in the build process and configured &lt;code&gt;vercel.json&lt;/code&gt; accordingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Real-Time Message Updates&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Implementing real-time features without WebSockets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Used Server-Sent Events with a custom hook that handles reconnection and message buffering.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;📊 What I Learned&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Modern React is Incredible&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;React 19 with the new compiler is a game-changer. The performance improvements and developer experience are noticeable from day one.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. TypeScript + Drizzle = Database Bliss&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Having type-safe database operations eliminates entire classes of bugs. I can't imagine building a production app without this combination.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Component Libraries Save Time&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;shadcn/ui provided beautiful, accessible components that I could customize while maintaining consistency. This saved me hours of CSS work.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Incremental Development Works&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By building features one day at a time, I was able to test and refine each component before moving to the next. This prevented the "everything is broken" syndrome.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🎯 What's Next for CodeniChat?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;While this project is now "complete" in terms of core functionality, I'm already thinking about future enhancements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File sharing&lt;/strong&gt; - Upload and share images, documents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Voice messages&lt;/strong&gt; - Audio recording and playback&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;End-to-end encryption&lt;/strong&gt; - For truly private conversations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mobile app&lt;/strong&gt; - React Native version&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Push notifications&lt;/strong&gt; - For important messages&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🏆 The Result: A Project I'm Actually Proud Of&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Secret Chat Bolt&lt;/strong&gt; went from being another unfinished project in my stack to a fully-functional, production-ready chat application. Here's what I accomplished in just one week:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Complete authentication system&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Real-time messaging&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Room management&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;User invitations&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Password reset flow&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Modern, responsive UI&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Next.js 15 + React 19&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Production deployment&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;💡 Key Takeaways for Fellow Developers&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Start Small, Build Incrementally&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Don't try to build everything at once. Pick one feature, implement it completely, then move to the next.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Use Modern Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Next.js 15, React 19, and Drizzle ORM made this project enjoyable instead of frustrating.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Focus on User Experience&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Little details like message grouping and smart scrolling make a huge difference in how users perceive your app.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Deploy Early and Often&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Getting your app running in production early helps identify issues you won't catch in development.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🔗 Project Links&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Live Demo:&lt;/strong&gt; [Your deployed URL]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GitHub Repository:&lt;/strong&gt; [Your repo URL]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tech Stack:&lt;/strong&gt; Next.js 15, React 19, TypeScript, Neon DB, Drizzle ORM&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;🎉 Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Secret Chat Bolt&lt;/strong&gt; is no longer part of my unfinished projects stack. It's a living, breathing application that people can actually use. The satisfaction of completing a project like this is incredible, and it's motivated me to tackle the next unfinished project in my stack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt; Every finished project started as an unfinished one. The key is to break it down into manageable pieces and tackle them one day at a time.&lt;/p&gt;

&lt;p&gt;What's the next unfinished project in your stack that you're going to demolish? Let me know in the comments below!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This post is part of my "Demolishing My Stack of Unfinished Projects" series, where I tackle one unfinished project per week and turn it into something I can be proud of. Follow along for more project completion stories, technical deep-dives, and lessons learned from the trenches of software development.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; #NextJS #React #TypeScript #ChatApp #FullStack #WebDevelopment #ProjectCompletion #RealTimeChat #Database #Authentication&lt;/p&gt;

</description>
      <category>endtoendencryption</category>
      <category>cursoride</category>
      <category>bolt</category>
    </item>
    <item>
      <title>Day 3 of Demolishing my Stack of Unfinished Projects: SmartNotes Project</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:50:49 +0000</pubDate>
      <link>https://dev.to/codenificient/day-3-of-demolishing-my-stack-of-unfinished-projects-smartnotes-project-j2f</link>
      <guid>https://dev.to/codenificient/day-3-of-demolishing-my-stack-of-unfinished-projects-smartnotes-project-j2f</guid>
      <description>&lt;p&gt;Published on Aug 18th, 2025&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;The Setup: When Everything Seems Perfect&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;After successfully implementing a chatbot based on ChatGPT in my portfolio (as detailed in my previous "Redesign Portfolio" post), I was feeling pretty good about myself. The AI integration was working smoothly, users could ask questions about my skills and projects, and I had successfully created content embeddings that made the chatbot intelligent and contextually aware.&lt;/p&gt;

&lt;p&gt;Little did I know that this "completed" project was about to become the perfect candidate for my "Unfinished Projects" series.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Crisis: When OpenAI Goes Silent&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It started with a simple error message: "OpenAI API account suspended." At first, I thought it was a simple configuration issue. Maybe I had accidentally exposed my API key or hit some rate limit. But after checking my environment variables and account status, I realized the problem was deeper.&lt;/p&gt;

&lt;p&gt;My OpenAI account was suspended, and suddenly, my "completed" AI chat functionality was completely broken. Suddenly, my SmartNotes app which also powers the chat functionality went offline.&lt;/p&gt;

&lt;p&gt;This was supposed to be a finished project. Instead, it had become the latest addition to my stack of unfinished work.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Panic: Scrambling for Solutions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The immediate challenge was clear: either abandon the chat functionality entirely or find an alternative solution. Given that I had already invested significant time in building the user interface and database integration, abandoning it wasn't an option.&lt;/p&gt;

&lt;p&gt;I started researching alternatives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Claude API&lt;/strong&gt;: Limited availability and different pricing structure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local AI models&lt;/strong&gt;: Required significant computational resources&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hugging Face&lt;/strong&gt;: Promising, but I had no experience with their inference API&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The clock was ticking, and my portfolio was broken.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Discovery: Hugging Face to the Rescue&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;After several hours of research and testing, I discovered that Hugging Face offered inference APIs that could potentially replace OpenAI's functionality. The catch? I had to completely rewrite the AI integration layer.&lt;/p&gt;

&lt;p&gt;This wasn't just a simple API swap - it was a complete architectural overhaul. I had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Replace OpenAI's embedding model with Hugging Face alternatives&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find a suitable text generation model&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handle different response formats&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implement proper error handling for a new service&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Implementation: Building Resilience&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Model Selection Hell&lt;/strong&gt; Finding the right model on Hugging Face proved more challenging than expected. My first attempts failed spectacularly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;microsoft/DialoGPT-medium&lt;/code&gt; - "No inference provider available"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;gpt2&lt;/code&gt; and &lt;code&gt;distilgpt2&lt;/code&gt; - Limited conversational capabilities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Qwen/Qwen3-4B&lt;/code&gt; - Finally worked with the &lt;code&gt;nebius&lt;/code&gt; provider&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Database Architecture Evolution&lt;/strong&gt; The migration also exposed a fundamental issue: my MongoDB setup wasn't ideal for production use. I decided to migrate to Neon PostgreSQL, which meant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Updating Prisma schema&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Migrating existing data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handling different ID types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Testing the new connection&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Streaming Responses: The Silver Lining&lt;/strong&gt; One positive outcome was implementing streaming text responses. Instead of waiting for complete AI responses, users now see text appear word-by-word, creating a ChatGPT-like experience that's actually better than the original implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Fallback System: Never Trust a Single Service&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I learned a valuable lesson about building robust systems. I implemented a multi-layered fallback approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vector Search&lt;/strong&gt;: Primary method using Pinecone embeddings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Text Search&lt;/strong&gt;: Fallback to simple text matching&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intelligent Responses&lt;/strong&gt;: Pre-built responses for common queries&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This ensures that even if the AI service fails, users still get helpful responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Current State: Better Than Before&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;What started as a crisis has evolved into a more robust, scalable system. The new implementation includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;✅ Hugging Face AI integration via Nebius&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Streaming text responses&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ PostgreSQL database backend&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Comprehensive error handling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Multiple fallback mechanisms&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Lessons Learned: Why This Project Wasn't Really "Finished"&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single Point of Failure&lt;/strong&gt;: Relying on one AI service provider is risky&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Production vs. Development&lt;/strong&gt;: What works in development might fail in production&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resilience by Design&lt;/strong&gt;: Building fallback systems from the start saves time and maintains user experience&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Definition of "Complete"&lt;/strong&gt;: A project isn't truly finished until it can handle real-world failures gracefully&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Unfinished Projects Paradox&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This experience taught me something important about my "Unfinished Projects" series. Sometimes, what appears to be a finished project is actually just waiting for the right failure to reveal its incompleteness.&lt;/p&gt;

&lt;p&gt;The AI chat integration wasn't truly finished until it could survive the loss of its primary service provider. In that sense, the "unfinished" phase was actually a blessing - it forced me to build something more robust than I originally planned.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What's Next: The Never-Ending Journey&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Even now, I'm not sure this project is truly "finished." I'm already planning improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;User analytics for chat interactions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conversation history persistence&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-language support&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integration with more AI models&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion: Embracing the Unfinished&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This project taught me that "unfinished" isn't always a negative state. Sometimes, it's the catalyst for building something better than originally envisioned. The AI chat integration that almost wasn't has become one of my portfolio's most resilient features.&lt;/p&gt;

&lt;p&gt;For developers facing similar challenges, remember: every obstacle is an opportunity to improve your architecture. What seems like a setback might actually be pushing you toward a better solution.&lt;/p&gt;

&lt;p&gt;The journey from "finished" to "unfinished" to "better than finished" is what makes development exciting. Embrace the chaos, build resilience, and never stop improving.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Technical Stack Used:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Next.js 15.0.0&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hugging Face Inference API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Neon PostgreSQL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prisma ORM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pinecone Vector Database&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Streaming text responses&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-layered fallback system&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://huggingface.co/models" rel="noopener noreferrer"&gt;Hugging Face Models&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://neon.tech/" rel="noopener noreferrer"&gt;Neon PostgreSQL&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Fault_tolerance" rel="noopener noreferrer"&gt;Building Resilient Systems&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This blog post captures the emotional journey, technical challenges, and valuable lessons learned while maintaining the honest, problem-solving tone that your "Unfinished Projects" series is known for. It shows how "unfinished" can actually lead to better outcomes!&lt;/p&gt;

</description>
      <category>openai</category>
      <category>portfoliowebsite</category>
      <category>pinecone</category>
    </item>
    <item>
      <title>16 Redesigning my Portfolio Website</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:50:42 +0000</pubDate>
      <link>https://dev.to/codenificient/16-redesigning-my-portfolio-website-1ee6</link>
      <guid>https://dev.to/codenificient/16-redesigning-my-portfolio-website-1ee6</guid>
      <description>&lt;p&gt;Published on Aug 18, 2025&lt;/p&gt;

&lt;h1&gt;
  
  
  A New Era of AI-Powered Coding Begins
&lt;/h1&gt;

&lt;p&gt;I have installed Cursor on my laptop this weekend, and I am amazed at how much it speeds up my coding. I have a new debugging buddy!!&lt;/p&gt;

&lt;p&gt;This week, I have made several updates to the Portfolio website.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Challenge: When OpenAI Falls Short&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In my previous post, I shared the excitement of implementing a chatbot based on ChatGPT for my portfolio website. The initial experience was promising - I successfully created content embeddings and integrated them with OpenAI's API. However, as many developers know, relying on a single service provider can lead to unexpected roadblocks.&lt;/p&gt;

&lt;p&gt;When my OpenAI account encountered issues, I faced a critical decision: abandon the chat functionality or find an alternative solution. I chose the latter, embarking on a journey that would transform my portfolio's AI capabilities and teach me valuable lessons about building robust, fallback-ready systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Migration: Embracing Open Source AI&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The transition from OpenAI to Hugging Face wasn't just a simple API swap - it was a complete architectural evolution. Here's what I learned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Model Selection Complexity&lt;/strong&gt; Finding the right model on Hugging Face proved more challenging than expected. After testing several options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;microsoft/DialoGPT-medium&lt;/code&gt; - No inference provider available&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;gpt2&lt;/code&gt; and &lt;code&gt;distilgpt2&lt;/code&gt; - Limited conversational capabilities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Qwen/Qwen3-4B&lt;/code&gt; - Perfect fit with the &lt;code&gt;nebius&lt;/code&gt; provider&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Database Architecture Evolution&lt;/strong&gt; The migration also prompted a database upgrade from MongoDB to Neon PostgreSQL. This wasn't just about changing providers - it was about building a more scalable, production-ready foundation for my portfolio.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Technical Implementation: Building Resilience&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Streaming Responses for Better UX&lt;/strong&gt; One of the most significant improvements was implementing streaming text responses. Instead of waiting for complete AI responses, users now see text appear word-by-word, creating a ChatGPT-like experience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Streaming implementation with word-by-word appearance&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&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;ReadableStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoder&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;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&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;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&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="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Robust Fallback System&lt;/strong&gt; I implemented a multi-layered fallback approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vector Search&lt;/strong&gt;: Primary method using Pinecone embeddings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Text Search&lt;/strong&gt;: Fallback to simple text matching&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intelligent Responses&lt;/strong&gt;: Pre-built responses for common queries&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;User Experience Improvements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Input Focus Management&lt;/strong&gt; Users can now have continuous conversations without losing focus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&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="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response Filtering&lt;/strong&gt; Hidden internal AI processing tags for cleaner output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cleanResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;think&amp;gt;.*&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;think&amp;gt;/g&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Performance &amp;amp; Scalability&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Database Optimization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Migrated from MongoDB to Neon PostgreSQL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Updated Prisma schema for better type safety&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implemented proper ID handling for vector search&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;API Efficiency&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reduced response times with streaming&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implemented proper error handling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Added comprehensive logging for debugging&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Lessons Learned&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Always Have a Plan B&lt;/strong&gt;: Building fallback systems from the start saves time and maintains user experience&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Open Source is Powerful&lt;/strong&gt;: Hugging Face provides enterprise-grade AI capabilities without vendor lock-in&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User Experience Matters&lt;/strong&gt;: Small details like input focus and streaming responses significantly improve perceived performance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Architecture&lt;/strong&gt;: Choosing the right database from the start prevents migration headaches later&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Current Status &amp;amp; Future Plans&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The chat functionality is now fully operational with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;✅ Hugging Face AI integration via Nebius&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Streaming text responses&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ PostgreSQL database backend&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Robust error handling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Clean, professional UI&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Implement user analytics for chat interactions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add conversation history persistence&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Explore multi-language support&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integrate with more AI models for specialized responses&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This migration taught me that technical challenges often lead to better solutions. What started as a simple API replacement evolved into a more robust, scalable, and user-friendly chat system. The journey from OpenAI to Hugging Face wasn't just about solving a problem - it was about building something better.&lt;/p&gt;

&lt;p&gt;For developers facing similar challenges, remember: every obstacle is an opportunity to improve your architecture and learn new technologies. The result is often a more resilient and feature-rich application.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Technical Stack Used:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Next.js 15.0.0&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hugging Face Inference API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Neon PostgreSQL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prisma ORM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pinecone Vector Database&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tailwind CSS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TypeScript&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://huggingface.co/models" rel="noopener noreferrer"&gt;Hugging Face Models&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://neon.tech/" rel="noopener noreferrer"&gt;Neon PostgreSQL&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.pinecone.io/" rel="noopener noreferrer"&gt;Pinecone Vector Database&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This blog post captures the technical journey, challenges faced, and solutions implemented while maintaining the professional tone and technical depth that your readers expect. It also provides valuable insights for other developers who might face similar migration challenges.&lt;/p&gt;

</description>
      <category>portfolio</category>
      <category>openai</category>
      <category>huggingface</category>
      <category>neondatabase</category>
    </item>
    <item>
      <title>15 Redesigning my portfolio website</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:50:35 +0000</pubDate>
      <link>https://dev.to/codenificient/15-redesigning-my-portfolio-website-3a9j</link>
      <guid>https://dev.to/codenificient/15-redesigning-my-portfolio-website-3a9j</guid>
      <description>&lt;p&gt;Published on Jun 21st, 2025&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks, NeonDB !
&lt;/h2&gt;

&lt;p&gt;I just started using NeonDB thanks to their generous free tier. I have migrated the SmartNotes application to NeonDB and recreated the notes.&lt;/p&gt;

&lt;h3&gt;
  
  
  June 19th, 2025 Update
&lt;/h3&gt;

&lt;p&gt;On Juneteenth, I started the migration process to Neon DB. I rewrote the Prisma queries and updated the database links. The app is able to generate a new Prisma client and create new tables on the remote database.&lt;/p&gt;

&lt;h3&gt;
  
  
  June 20th, 2025 Update
&lt;/h3&gt;

&lt;p&gt;The chat application works again for the SmartNotes app. However, there are lots of error messages in the Terminal, and I am not ready to deal with those right now. Will follow up on the next post..&lt;/p&gt;

</description>
      <category>portfolio</category>
      <category>prisma</category>
      <category>neondatabase</category>
    </item>
    <item>
      <title>14 Redesigning my Portfolio website</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:50:28 +0000</pubDate>
      <link>https://dev.to/codenificient/14-redesigning-my-portfolio-website-1c61</link>
      <guid>https://dev.to/codenificient/14-redesigning-my-portfolio-website-1c61</guid>
      <description>&lt;p&gt;Published on Jun 20th, 2025&lt;/p&gt;

&lt;p&gt;Currently the chat functionality on my portfolio is down because my website was probably accessed from abroad and my Open AI account got suspended.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read the fine print
&lt;/h3&gt;

&lt;p&gt;My account violated the terms of use which I did not read. I am now in the process of using some open source alternatives to get my chat functionality working again.&lt;/p&gt;

&lt;p&gt;I also moved a few portfolio applications away from Supabase to Neon and the chat database to Neon from MongoDB. I am still relying on Pinecone to store my vector embeddings. I can see a future enhancement where I store everything in the Neon thanks to pgvector to reduce my dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  June 20th, 2025 Udpate
&lt;/h3&gt;

&lt;p&gt;I worked on the portfolio for a few hours today. I am trying to swap out OpenAI and replace with HuggingFace. The inference website does not seem to work because there’s a mismatch between our OpenAI embeddings and the current version of the SmartNotes app.&lt;/p&gt;

&lt;p&gt;Recap: We created a note taking application called SmartNotes which has a chatbot. Trying to copy over the same code to my portfolio to so that both apps are using the same notes and the same database.&lt;/p&gt;

&lt;p&gt;I will recreate the Pinecone index using a different embedding model and reconnect to HugggingFace.&lt;/p&gt;

</description>
      <category>portfolio</category>
      <category>openai</category>
      <category>huggingface</category>
    </item>
    <item>
      <title>13 Redesigning my Portfolio Website</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:50:22 +0000</pubDate>
      <link>https://dev.to/codenificient/13-redesigning-my-portfolio-website-54f5</link>
      <guid>https://dev.to/codenificient/13-redesigning-my-portfolio-website-54f5</guid>
      <description>&lt;p&gt;Published on Jan 17th, 2024&lt;/p&gt;

&lt;h1&gt;
  
  
  Added Chat functionality
&lt;/h1&gt;

&lt;p&gt;I recently created a chatbot based on ChatGPT where I learned to create content embeddings to empower ChatGPT to chat with our data. The experience went as well as could be expected.&lt;/p&gt;

&lt;p&gt;I have added more information from my portfolio website to the Pinecone vector store and now the same chatbot is functional on tioye.dev&lt;/p&gt;

&lt;h2&gt;
  
  
  Removed the Chat page
&lt;/h2&gt;

&lt;p&gt;Since the chatbox is a popup window mimicking the chatbots on familiar websites, I have removed the initial placeholder chat page from the website. I have upgraded the navigation link to a button that triggers that chat window. Therefore, the Chat functionality can be triggered from any page. When the chat window is covering information on a page, the window can be closed and reopened without losing the conversation data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open chat
&lt;/h2&gt;

&lt;p&gt;Currently, the chatbot can answer questions about my portfolio, and is based on GPT 3.5 turbo. I do not require login to use the chat. I do not anticipate many visitors using the chat functionality, and this should be good for several months&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1705524726827%2F82613a12-89d9-4f81-b7c9-66d08cc86835.png%2520align%3D" 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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1705524726827%2F82613a12-89d9-4f81-b7c9-66d08cc86835.png%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>portfolio</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>12 Redesigning my portfolio website</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:50:15 +0000</pubDate>
      <link>https://dev.to/codenificient/12-redesigning-my-portfolio-website-1a99</link>
      <guid>https://dev.to/codenificient/12-redesigning-my-portfolio-website-1a99</guid>
      <description>&lt;p&gt;Published on &lt;a href="https://codenificient.hashnode.dev/12-redesigning-my-portfolio-website" rel="noopener noreferrer"&gt;Jan 4th, 2024&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The new version of the portfolio is live
&lt;/h2&gt;

&lt;p&gt;I have completed the Landing, Resume and Blog pages and I have edited the domain names on Vercel to point to tioye.dev. The previous build on Vercel is officially retired.&lt;/p&gt;

&lt;h3&gt;
  
  
  New Landing Page, New Beginnings
&lt;/h3&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1704409663729%2F4d646214-ba98-4b5d-9376-b68bb2ad46e5.png%2520align%3D" 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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1704409663729%2F4d646214-ba98-4b5d-9376-b68bb2ad46e5.png%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The theme is light mode by default. The deployed site feels faster and there is a big button to download a PDF copy of my resume.&lt;/p&gt;

&lt;h4&gt;
  
  
  Next steps
&lt;/h4&gt;

&lt;p&gt;Now that my updated portfolio is live, my free time going forward will be split between the AWS certification prep work, interview preparation, job applications / coding challenges, fixing the broken portfolio projects, and adding an AI powered chatbot to the portfolio.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.tioye.dev/" rel="noopener noreferrer"&gt;My Newly Deployed site&lt;/a&gt;&lt;/p&gt;

</description>
      <category>portfolio</category>
      <category>nextjs</category>
      <category>vercel</category>
    </item>
    <item>
      <title>My world in 2023</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:50:08 +0000</pubDate>
      <link>https://dev.to/codenificient/my-world-in-2023-pja</link>
      <guid>https://dev.to/codenificient/my-world-in-2023-pja</guid>
      <description>&lt;p&gt;Published on &lt;a href="https://codenificient.hashnode.dev/my-world-in-2023" rel="noopener noreferrer"&gt;Dec 31st, 2023&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codenificient.hashnode.dev/my-world-in-2023" rel="noopener noreferrer"&gt;A summary&lt;/a&gt; of the major events&lt;/p&gt;

&lt;h1&gt;
  
  
  Graduation: Class of 2023
&lt;/h1&gt;

&lt;p&gt;The 2023 year ended on a high note for me as I have completed grad school with my Master degree in Computer Science. Before I start freaking out about job interviews, and my 6-figure student loan, it would be a great time to &lt;strong&gt;reminisce&lt;/strong&gt; about the major events that have shaped the past year.&lt;/p&gt;

&lt;h3&gt;
  
  
  Facing deportation?
&lt;/h3&gt;

&lt;p&gt;Early in January 2023, I was panicking about the registration deadline at the University of Louisville. The automated system was not allowing me to register for my classes due to the unpaid tuition balance from the previous Fall semester. Past the registration deadline, I would miss the semester, which would have several implications for my immigration status and student visa. It was a worrisome situation which was remedied at the last minute. I started classes a week late&lt;/p&gt;

&lt;h3&gt;
  
  
  Summer of Uncertainty
&lt;/h3&gt;

&lt;p&gt;I got a 3.5 gpa during the Spring 2023 semester and was ready for my final semester. The remaining tuition balance from the Spring semester now remains to be paid. This time, there was no big check to provide to the bursar. I spent the summer trying several solutions. My income from the part time internship under the CPT was sufficient to make a small dent on the balance. I have considered selling my vehicle, but the offers were too low. The final solution came from the graduate school as they found some scholarship funds which they applied towards the tuition balance to allow me to register for my final semester. I feel fortunate about this outcome and will be empowered to pay it forward some day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Graduated, now what?
&lt;/h3&gt;

&lt;p&gt;Getting my master was the hardest thing I have ever done. There was a time that felt like everything that could have gone wrong has gone wrong. But I have persevered until I completed what I have started. I feel like if I can get through that, then I can get through anything! I am ready to go to many job interviews, until I land my first tech role. Bring it on!&lt;/p&gt;

</description>
      <category>graduates</category>
    </item>
    <item>
      <title>11 Redesigning my portfolio website</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:50:02 +0000</pubDate>
      <link>https://dev.to/codenificient/11-redesigning-my-portfolio-website-24bm</link>
      <guid>https://dev.to/codenificient/11-redesigning-my-portfolio-website-24bm</guid>
      <description>&lt;p&gt;Published on &lt;a href="https://codenificient.hashnode.dev/11-redesigning-my-portfolio-website" rel="noopener noreferrer"&gt;Dec 29th, 2023&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Enter TypeScript and Next.js 14
&lt;/h1&gt;

&lt;p&gt;I am continuing the process of visually overhauling my portfolio website. A few weeks after upgrading my site to Next.js, I have started using TypeScript for my web applications. I have spent the Fall semester finishing my master's degree, and contemplating several ways I can improve my portfolio website.&lt;/p&gt;

&lt;p&gt;I am now a recent graduate applying for my first full-time role in tech, and upgrading my portfolio site to TypeScript along with several visual improvements is a must.&lt;/p&gt;

&lt;h3&gt;
  
  
  Old Version
&lt;/h3&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1703902646323%2Ff6f0d743-f9e0-4c9a-b5be-5dbe09455396.png%2520align%3D" 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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1703902646323%2Ff6f0d743-f9e0-4c9a-b5be-5dbe09455396.png%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  New Version
&lt;/h3&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1703902655965%2F7fd1d7fb-12a9-49b1-8aa6-3c090ff1239a.png%2520align%3D" 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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1703902655965%2F7fd1d7fb-12a9-49b1-8aa6-3c090ff1239a.png%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  New Version with Dark Mode
&lt;/h1&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1703902666534%2F8876cde5-6d15-4525-a793-cf853126fdd5.png%2520align%3D" 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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1703902666534%2F8876cde5-6d15-4525-a793-cf853126fdd5.png%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have added a dark mode toggler to the improved navigation bar and I am planning to remove a few pages. I plan to add a chat page based on a vector database of my bio so users can chat with my data.&lt;/p&gt;

&lt;p&gt;Another noteworthy improvement is that the inclusion of TailwindCSS has reduced my coding time dramatically. It took me a week to get the main user interface working last time. This time, less than an hour. I already feel like a 10x developer :)!&lt;/p&gt;

&lt;h4&gt;
  
  
  Coming Soon!
&lt;/h4&gt;

&lt;p&gt;For now, I am deploying the new version of my portfolio on a separate vercel endpoint &lt;a href="https://tioyedev2024.vercel.app/" rel="noopener noreferrer"&gt;https://tioyedev2024.vercel.app/&lt;/a&gt; and my website &lt;strong&gt;&lt;a href="https://tioye.dev/" rel="noopener noreferrer"&gt;https://tioye.dev/&lt;/a&gt;&lt;/strong&gt; still points to previous build. I plan to make the switch once the 3 main pages, Landing, Resume and Experience, are deployed on the new endpoint&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>graduation</category>
    </item>
    <item>
      <title>10 Redesigning my portfolio app</title>
      <dc:creator>CodenificienT</dc:creator>
      <pubDate>Tue, 28 Jul 2026 03:49:55 +0000</pubDate>
      <link>https://dev.to/codenificient/10-redesigning-my-portfolio-app-ina</link>
      <guid>https://dev.to/codenificient/10-redesigning-my-portfolio-app-ina</guid>
      <description>&lt;p&gt;Published on &lt;a href="https://codenificient.hashnode.dev/10-redesigning-my-portfolio-app" rel="noopener noreferrer"&gt;Mar 16th, 2023&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://codenificient.hashnode.dev/10-redesigning-my-portfolio-app" rel="noopener noreferrer"&gt;Hashnode c&lt;/a&gt;onnected
&lt;/h3&gt;

&lt;p&gt;Today I followed the incredibly useful blog post by &lt;a href="https://catalins.tech/hashnode-api-how-to-display-your-blog-articles-on-your-portfolio-page/" rel="noopener noreferrer"&gt;CatalinPit&lt;/a&gt; and I connected my portfolio blog directly to Hashnode, skipping GraphCMS. This negates the need to create a duplicate post in GraphCMS after posting on Hashnode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Revalidate: 600
&lt;/h3&gt;

&lt;p&gt;I have kept the default refresh period in Vercel to 10 minutes. New blog posts on Hashnode will show up on my portfolio within 10 minutes, provided the Vercel platform rebuilds the new page in sub-30 seconds as usual.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub actions untouched
&lt;/h3&gt;

&lt;p&gt;I have not messed with anything I have already set up in GitHub. My latest blog should be synched to my GH profile every sunday as usual&lt;/p&gt;

&lt;h3&gt;
  
  
  One caveat
&lt;/h3&gt;

&lt;p&gt;The GraphCMS version of my blog was based on blog series which are almost mirrored from Hashnode. Unfortunately, the Series feature was glued onto Hashnode after the fact and the GraphQL API does not support fetching blogs based on blog series. I have attempted a simple fetch to grab the blog series, but I was getting error messages. Currently, I have removed the blog series header from the portfolio site. I have replaced the series badge on each blog post with an avatar of the author, aka, yours truly!&lt;/p&gt;

</description>
      <category>blogging</category>
      <category>graphql</category>
      <category>hashnode</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
