Day 8: The Site Was “Live” for a Week and the Blog Link Was Broken the Whole Time

Day 8. Revenue: $0. Reddit karma: 38. Need 50 to post in r/SideProject. Still not there.

This is tclaw.dev — an AI text humanizer. $1 per doc or $8/month. Thirty-day sprint to first paying user. Here’s where things actually stand.

The Deploy That Wasn’t

Sometime around 1 AM I finally traced why the blog page wasn’t loading. The site looked live. Vercel showed green. But the blog link was dead, and I kept assuming it was a routing issue, a config issue, something I’d written wrong.

It wasn’t. Vercel was silently failing deploys because the project was set to Node 24.x — which Vercel doesn’t support. No error surfaced in the dashboard in any way I’d immediately noticed. It just… didn’t deploy. The old build sat there looking fine while every new push went nowhere.

Fix: delete the project, recreate it with Node 20, redeploy. Twenty minutes of actual work. A week of a broken blog link I’d been pointing people to.

This is the part of building that doesn’t make it into the highlight reel. Not “I shipped a new feature” or “I redesigned the pricing page.” Just: I found a silent failure, traced it, fixed it, and now the thing I already built actually works.

What “Live” Actually Means

The site has been technically live since Day 1. Landing page, demo, pricing, examples, a ledger tracking every day of the sprint, and now a working blog. All of it is real and functional.

None of that matters if nobody sees it.

Distribution is the part I keep bumping into. I can fix a broken deploy. I can write the copy. I can make the demo work. What I don’t have yet is a repeatable way to get the right person to land on the page at the moment they’re frustrated with AI-sounding text and willing to pay a dollar to fix it.

Reddit is the most obvious channel — r/SideProject has exactly that audience. But you need 50 karma to post, and I’m sitting at 38. So I’m commenting on other threads, trying to add something real, not just farming upvotes. It’s slow.

What Day 8 Looks Like Honestly

  • Site is fully live and functional
  • Blog link works (finally)
  • Zero paying users
  • No clear distribution path yet, just a queue of things to try

The Vercel thing is a useful reminder. There’s always invisible work that eats time and doesn’t move the needle on revenue. Some of it is unavoidable — a silent infra failure isn’t something you can just skip. But it’s easy to spend all your energy on the infrastructure layer and confuse “things work now” with “things are working.”

They’re not the same.

One Genuine Question

If you’ve gotten your first paid user from cold — no existing audience, no launch day bump — what actually moved the needle? Not the playbook answer. What actually worked for you.

Following this build daily at tclaw.dev/blog. Ledger is public — every day logged.

Héberger un agent IA vocal sur AWS Bedrock AgentCore communiquant via WebRTC

P2P WebRTC

Aujourd’hui j’ai migré agent vocal IA de WebSocket vers WebRTC — voici ce qui a cassé et ce que j’ai appris.

Il y a quelques jours, je suis tombé sur le billet de blog et le repo de Darryl Ruggles pour un agent vocal bidirectionnel construit avec Strands BidiAgent et Amazon Nova Sonic v2. Son travail est remarquablement bien ficelé — j’avais un assistant vocal fonctionnel sur mon laptop en une dizaine de minutes. L’agent écoute votre voix, cherche dans une base de recettes, programme des minuteurs de cuisson, consulte des données nutritionnelles et convertit des unités, le tout par conversation naturelle.

La version de Darryl utilise WebSocket comme transport entre le navigateur et l’agent. Ça fonctionne bien, mais je voulais aller plus loin : passer le transport en WebRTC et déployer le tout sur Bedrock AgentCore Runtime. Ce billet couvre ce parcours — ce qui a changé, ce qui a cassé, et ce que j’en ai tiré.

Vous avez rêvé de demander la recette des crêpes à un agent IA ? je l’ai fait 🙂

Le code source complet est disponible sur GitHub. Le repo est entièrement géré par Terraform, mais vous pouvez toujours utiliser l’approche Makefile de Darryl si vous préférez garder Terraform pour l’infrastructure et le CLI pour le déploiement de l’agent.

Pourquoi WebRTC pour un agent vocal ?

La version WebSocket de l’agent fonctionne, alors pourquoi changer ? Plusieurs raisons m’ont poussé vers WebRTC.

D’abord, la latence. WebSocket tourne sur TCP, ce qui signifie que chaque paquet est garanti d’arriver dans l’ordre. C’est parfait pour des messages de chat, mais pour de l’audio en temps réel, un seul paquet perdu bloque tout le flux pendant que TCP retransmet. WebRTC1 utilise UDP — si un paquet est perdu, le flux continue. Pour une conversation vocale, un micro-glitch est bien préférable à une pause perceptible.

Ensuite, le navigateur fait plus de travail. Avec WebSocket, je devais capturer l’audio du micro via getUserMedia, le sous-échantillonner à 16kHz avec un ScriptProcessorNode, l’encoder en base64 PCM et l’envoyer en messages JSON. Côté lecture, il fallait un AudioWorklet avec un buffer circulaire pour gérer le flux audio entrant. Avec WebRTC, le navigateur gère nativement la capture audio, l’encodage (Opus) et la lecture via RTCPeerConnection. Le code frontend s’en trouve considérablement simplifié.

Enfin, WebRTC est prêt pour la vidéo. Les avatars IA arrivent à des latences acceptables, et WebRTC gère les pistes vidéo aussi naturellement que les pistes audio. Ajouter un flux vidéo plus tard revient simplement à ajouter une piste à la connexion existante — aucun changement d’architecture ne sera nécessaire.

Petit tour d’horizon des architectures WebRTC

Il existe deux façons fondamentalement différentes d’utiliser WebRTC, et le choix compte quand on construit un agent vocal.

Pair-à-pair (P2P)

En WebRTC P2P, deux pairs se connectent directement l’un à l’autre. Pas de serveur média au milieu — l’audio circule directement du navigateur à l’agent et retour. Un serveur relais TURN2 peut être nécessaire quand l’un ou les deux pairs sont derrière un NAT3 (ce qui est quasi systématique en production : les clients sont derrière un routeur Internet et les agents doivent être dans un VPC privé pour accéder aux outils de l’entreprise), mais le serveur TURN ne fait que relayer les paquets sans les inspecter ni les traiter.

P2P WebRTC

Basé sur des salles (SFU)

Dans une architecture basée sur des salles de visio, un serveur média (appelé SFU4 — Selective Forwarding Unit) se place au milieu. Les participants se connectent au serveur, pas entre eux. Le serveur reçoit les pistes audio/vidéo de chaque participant et les retransmet sélectivement aux autres. LiveKit, Amazon Chime SDK et Daily sont des exemples de plateformes SFU.

Media Server WebRTC

Pour un agent vocal en 1:1, le P2P est plus simple et évite le coût et la complexité de faire tourner (ou de payer) un serveur média. J’ai opté pour le P2P avec Amazon Kinesis Video Streams (KVS) comme relais TURN managé — c’est l’approche documentée pour WebRTC sur AgentCore.

J’ai envisagé les solutions basées sur des salles, mais chaque plateforme SFU nécessite son propre SDK — on ne peut pas simplement se connecter avec un RTCPeerConnection standard. L’offre WebRTC d’AWS, Amazon Chime SDK, est riche en fonctionnalités (transcription, enregistrement, analytics) et nettement moins chère que les alternatives comme LiveKit ou Daily, mais elle n’offre pas encore de chemin balisé pour la communication agent-vers-salle côté serveur. C’est une fonctionnalité que j’aimerais beaucoup voir arriver, vu la qualité du reste du Chime SDK. Pour l’instant, le P2P avec KVS TURN était le chemin le plus direct. Je considérerai certainement le WebRTC en salle, mais c’est une histoire pour un autre billet.

La pile WebRTC : navigateur et serveur

Côté navigateur, WebRTC est intégré nativement. L’API RTCPeerConnection est disponible dans tous les navigateurs modernes — Chrome, Safari, Firefox, Edge. On crée une connexion pair, on ajoute une piste micro via getUserMedia, et le navigateur gère l’encodage audio (Opus), la collecte des candidats ICE et le chiffrement DTLS. Aucune bibliothèque nécessaire.

Côté serveur, c’est une autre histoire. WebRTC a été conçu pour les navigateurs, pas pour des backends Python. La bibliothèque de référence pour le WebRTC côté serveur en Python est aiortc — une implémentation asyncio de WebRTC et ORTC. Elle gère les connexions pair, la négociation ICE et les pistes média, et utilise PyAV (bindings FFmpeg) pour le traitement des trames audio/vidéo. Elle n’est pas aussi éprouvée que le WebRTC des navigateurs, mais elle fonctionne bien et c’est ce qu’utilise aussi le code d’exemple AWS.

Architecture : développement local vs. déployé

Un point que je voulais préserver du design original de Darryl est la possibilité de tout faire tourner localement pour le développement, sans aucune infrastructure cloud. La migration WebRTC maintient cela.

Mode local

En mode local, l’agent tourne sur votre machine. Le navigateur et l’agent sont sur le même réseau (ou la même machine), donc WebRTC se connecte en pair-à-pair sans avoir besoin de relais TURN. La signalisation — l’échange d’offres/réponses SDP5 et de candidats ICE6 — passe par le proxy du serveur de développement Vite vers le serveur FastAPI local.

Local mode

Mode hébergé sur Bedrock AgentCore

En mode hébergé, l’agent tourne dans un conteneur Docker sur Bedrock AgentCore Runtime, attaché à un VPC via une interface réseau élastique (ENI) dans un sous-réseau privé. Le navigateur ne peut pas atteindre l’agent directement — tout le trafic média passe par un relais KVS TURN. La signalisation passe par le endpoint HTTP /invocations d’AgentCore, authentifié en SigV4 via le SDK @aws-sdk/client-bedrock-agentcore.

Voice Agent deployed on AgentCore

Le diagramme suivant, tiré de la documentation AWS, montre le réseau VPC en détail — la signalisation passe par le endpoint HTTP d’AgentCore tandis que le trafic média passe par la NAT gateway du VPC vers le relais KVS TURN :

AgentCore WebRTC Architecture

Le point important à noter est que le code de l’agent est quasi identique entre les modes local et déployé. Le BidiAgent, le BidiNovaSonicModel et les quatre outils (recherche de recettes, minuteur, recherche nutritionnelle, conversion d’unités) sont totalement inchangés. La seule différence est la couche transport : en local, aiortc se connecte en P2P ; en déployé, il se connecte via KVS TURN. L’agent détecte dans quel mode il se trouve via la variable d’environnement CONTAINER_ENV et configure les serveurs ICE en conséquence.

Cette séparation propre a été possible grâce au protocole BidiInput/BidiOutput de Strands. J’ai écrit deux petites classes adaptateurs — WebRTCBidiInput et WebRTCBidiOutput — qui font le pont entre les pistes audio aiortc et le format d’événements attendu par BidiAgent. L’agent ne sait pas et ne se soucie pas de savoir si l’audio vient d’un WebSocket ou d’une piste WebRTC.

Ce qu’apporte le support WebRTC de Bedrock AgentCore

Le 20 mars 2026, AWS a annoncé le support WebRTC pour AgentCore Runtime. Je veux être honnête sur ce que cela signifie en pratique.

Je n’en suis pas sûr à 100%, et je suis prêt à être corrigé, mais mon impression est que les briques de base — le mode réseau VPC, KVS TURN, le endpoint HTTP /invocations — existaient tous déjà avant cette annonce. Le mode réseau VPC est disponible depuis la disponibilité générale d’AgentCore en octobre 2025. KVS TURN est une fonctionnalité de longue date de Kinesis Video Streams. Et /invocations a toujours été le endpoint HTTP standard des runtimes AgentCore.

Ce que la release du 20 mars ajoute, d’après ce que je comprends, c’est de la documentation officielle, du code d’exemple fonctionnel, et la déclaration explicite que WebRTC est un protocole supporté sur AgentCore Runtime. Avant cela, on pouvait techniquement assembler les mêmes pièces soi-même, mais on était seul — pas de docs, pas d’exemples, pas de garantie que ça continuerait à fonctionner.

Ce qu’AgentCore apporte est réellement précieux : un hébergement de conteneurs managé avec auto-scaling, l’isolation des sessions entre utilisateurs concurrents, l’observabilité intégrée (logs CloudWatch, traces X-Ray), et aucune infrastructure à gérer au-delà du VPC. Je n’ai pas eu à configurer ECS, des load balancers ou de l’orchestration de conteneurs.

Cela dit, il y a une bonne quantité de code custom. La signalisation WebRTC (échange SDP, gestion des candidats ICE), le cycle de vie de la connexion pair aiortc, le pont entre les pistes audio et BidiAgent, et la gestion des identifiants KVS TURN — tout cela est du code applicatif que j’ai écrit. AgentCore l’héberge et l’exécute, mais ne l’abstrait pas.

Défis et leçons apprises

La migration de WebSocket vers WebRTC a commencé en douceur, puis ça s’est corsé. Voici ce qui m’a fait trébucher.

Compatibilité des zones de disponibilité du VPC

AgentCore Runtime ne supporte que certaines zones de disponibilité. En us-east-1, seules use1-az4 (us-east-1a), use1-az1 (us-east-1c) et use1-az2 (us-east-1d) sont supportées. J’ai initialement laissé Terraform choisir les deux premières AZ automatiquement, ce qui m’a donné us-east-1a et us-east-1b. La mise à jour du runtime a échoué avec un statut cryptique UPDATE_FAILED. Le vrai message d’erreur — mentionnant l’AZ non supportée — était enfoui dans le champ failureReason de la réponse API, pas remonté dans l’erreur Terraform. J’ai fini par coder en dur les AZ supportées dans mon module VPC.

Affinité de session

Celui-ci m’a coûté des heures. La signalisation WebRTC est une poignée de main en plusieurs étapes — le navigateur et l’agent échangent plusieurs messages pour établir une connexion. L’agent doit se souvenir de l’état de la connexion du premier message quand il traite le deuxième et le troisième. Si ces messages atterrissent sur des instances serveur différentes, l’agent n’a aucune mémoire de la poignée de main en cours et la connexion échoue.

J’ai d’abord utilisé des requêtes HTTP POST signées SigV4, en supposant qu’inclure l’identifiant de session comme paramètre de requête fournirait l’affinité de routage. Ce n’était pas le cas. Les candidats ICE atterrissaient sur une instance de conteneur différente de celle qui détenait la connexion pair.

La solution a été d’utiliser le SDK @aws-sdk/client-bedrock-agentcore avec InvokeAgentRuntimeCommand et le paramètre runtimeSessionId. C’est le seul moyen fiable de s’assurer que toutes les requêtes d’une session WebRTC atteignent la même instance de conteneur. Le code d’exemple AWS utilise ce pattern aussi — je ne l’avais simplement pas remarqué au début parce que j’étais concentré sur les parties WebRTC.

Filtrage des candidats SDP

Quand l’agent crée une connexion pair à l’intérieur du VPC, aiortc génère des candidats ICE pour toutes les interfaces réseau disponibles — y compris des IP internes au VPC comme 169.254.0.2. Ces candidats hôtes se retrouvent dans la réponse SDP envoyée au navigateur. Le navigateur essaie consciencieusement de s’y connecter, échoue (parce qu’ils sont injoignables depuis l’Internet public), et ne se rabat sur les candidats relais qu’ensuite. Cela ajoute plusieurs secondes au temps de connexion.

La solution est simple : retirer les candidats non-relais de la réponse SDP avant de la renvoyer au navigateur. En mode déployé, les seuls candidats qui peuvent fonctionner sont les candidats relais TURN, donc il n’y a aucune raison d’inclure les autres.

Mode TURN uniquement

Similaire au problème de filtrage SDP, l’instance aiortc de l’agent essaie les candidats hôtes avant les candidats relais par défaut. Comme les candidats hôtes utilisent des IP internes au VPC qui ne peuvent jamais fonctionner du point de vue du navigateur, c’est du temps perdu. Configurer aiortc pour n’utiliser que les candidats relais TURN (turn_only=True) saute directement aux candidats qui fonctionnent réellement.

Initialisation paresseuse de KVS

J’appelais initialement kvs.init() au moment de l’import du module, protégé par un if IS_CONTAINER. Ça fonctionnait bien en local mais faisait crasher le conteneur sur AgentCore. L’appel API KVS pour trouver ou créer le canal de signalisation nécessite des identifiants AWS, et au démarrage du conteneur il peut y avoir un bref délai avant que les identifiants du rôle IAM soient disponibles. Déplacer l’initialisation à la première requête réelle (init paresseuse) a résolu le crash.

Comportement au démarrage à froid

Après que le conteneur est resté inactif un moment, la première tentative de connexion WebRTC échoue parfois. Les requêtes de signalisation réussissent (AgentCore renvoie 200), mais la connexion ICE ne s’établit jamais. Je soupçonne que c’est lié au fait qu’AgentCore démarre une nouvelle instance de conteneur — les premières requêtes peuvent être traitées par une instance qui n’est pas encore complètement prête. Côté agent, j’ai explicitement mis --workers 1 dans la commande uvicorn pour m’assurer que toutes les requêtes au sein d’un conteneur touchent le même processus (et donc le même état de connexion pair en mémoire). Côté frontend, j’ai ajouté un mécanisme de retry : attendre que ICE atteigne l’état “connected”, et si ce n’est pas le cas dans les 10 secondes, tout démonter et réessayer avec un nouvel identifiant de session. Ensemble, ces deux mesures ont rendu la connexion fiable.

Code clé

Je ne vais pas parcourir chaque fichier, mais voici les pièces qui font fonctionner l’intégration WebRTC.

L’adaptateur WebRTCBidiInput lit les trames audio de la piste aiortc, les rééchantillonne à 16kHz, et les renvoie comme événements bidi_audio_input que BidiAgent comprend :

class WebRTCBidiInput:
    def __init__(self, track):
        self._track = track

    async def __call__(self):
        try:
            frame = await self._track.recv()
        except MediaStreamError:
            raise StopAsyncIteration
        resampled = _resampler.resample(frame)
        pcm = b"".join(f.planes[0] for f in resampled)
        return {
            "type": "bidi_audio_input",
            "audio": base64.b64encode(pcm).decode("utf-8"),
            "sample_rate": 16000,
        }

L’adaptateur WebRTCBidiOutput fait l’inverse — il reçoit les événements de BidiAgent et pousse l’audio vers la piste de sortie aiortc :

class WebRTCBidiOutput:
    def __init__(self, output_track):
        self._output_track = output_track

    async def __call__(self, event):
        if event.get("type") == "bidi_audio_stream":
            audio_bytes = base64.b64decode(event["audio"])
            self._output_track.add_audio(audio_bytes)
        elif event.get("type") == "bidi_interruption":
            self._output_track.clear()

Côté frontend, le hook useWebRTCSession utilise le SDK AgentCore pour la signalisation :

const invoke = async (action, data = {}) => {
  const client = new BedrockAgentCoreClient({ region, credentials });
  const resp = await client.send(new InvokeAgentRuntimeCommand({
    agentRuntimeArn,
    runtimeSessionId: sessionId,  // assure l'affinité de session
    contentType: 'application/json',
    payload: new TextEncoder().encode(JSON.stringify({ action, data })),
  }));
  return JSON.parse(new TextDecoder().decode(
    await resp.response.transformToByteArray()
  ));
};

Le code source complet est dans le repo — la branche feat/webrtc contient la version locale uniquement, et feat/webrtc-agentcore la version déployée complète avec Terraform.

Outillage de développement

J’ai construit ce projet avec Kiro CLI, l’assistant de développement IA d’Amazon. Il a géré la planification, la génération de code, le débogage et le déploiement itératif — y compris les nombreux allers-retours d’essais-erreurs avec la configuration WebRTC que ce billet décrit. Le va-et-vient entre écriture de code, déploiement, vérification des logs et correction des problèmes se prêtait naturellement à un workflow de pair-programming avec une IA.

Essayez vous-même

Pour lancer en local :

git clone https://github.com/psantus/strands-bidir-nova.git
cd strands-bidir-nova
git checkout feat/webrtc
uv sync && make install-frontend
# Terminal 1 :
make serve
# Terminal 2 :
make serve-frontend

Ouvrez http://localhost:5173, cliquez sur le micro, et commencez à parler.

Pour la version déployée sur AgentCore, passez sur la branche feat/webrtc-agentcore et suivez le README. Vous aurez besoin d’une Knowledge Base Bedrock avec quelques recettes, d’un pool d’utilisateurs Cognito et de Docker pour construire l’image du conteneur. Un seul terraform apply gère le reste.

Si vous préférez commencer par la version WebSocket, le billet original de Darryl Ruggles est le bon point de départ.

Paul Santus est consultant cloud indépendant chez TerraCloud. Il accompagne les organisations dans la construction et le déploiement d’applications IA sur AWS. Retrouvez-le sur LinkedIn.

  1. WebRTC (Web Real-Time Communication) — Standard ouvert pour la communication audio, vidéo et données en temps réel directement entre navigateurs et appareils, utilisant un transport basé sur UDP. ↩

  2. TURN (Traversal Using Relays around NAT) — Serveur relais qui transfère le trafic média quand deux pairs ne peuvent pas se connecter directement. Les deux côtés envoient leur audio au serveur TURN, qui le relaie à l’autre côté. ↩

  3. NAT (Network Address Translation) — Mécanisme réseau qui fait correspondre des adresses IP privées à des adresses publiques. La plupart des routeurs domestiques et des VPC cloud utilisent le NAT, ce qui empêche les connexions entrantes directes. ↩

  4. SFU (Selective Forwarding Unit) — Serveur média qui reçoit les pistes audio/vidéo des participants et les retransmet sélectivement aux autres, sans mixage ni transcodage. Utilisé par LiveKit, Chime SDK, Daily, etc. ↩

  5. SDP (Session Description Protocol) — Format texte décrivant une session multimédia : codecs, adresses de transport et types de média. En WebRTC, les pairs échangent des « offres » et « réponses » SDP pour négocier la connexion. ↩

  6. ICE (Interactive Connectivity Establishment) — Protocole pour trouver le meilleur chemin réseau entre deux pairs. Il collecte des adresses candidates (locales, réflexives serveur, relais) et teste la connectivité entre elles. ↩

Entry #01: My perfect API was actually drowning

fluffyfi3 image

For a long time, I believed that if my API sent back a 200 OK status code, my work as a backend developer was over. But I’ve come to realize that I should not only be using tools and libraries but also understand how they work. I’ve been using Postgres because I’ve heard it’s the best. But I never really knew why—until now.

Welcome to Entry #01 of my journey into advanced backend architectures.

The Life of a Query

I used to think that a query goes in and comes out with the data. But the life of a query is actually very disciplined. It’s like a relay race.

When I send a query to my Node.js application, a connection is made (now I’m using a connection pool to keep things stable). When this connection is made, a backend process is created. Then, Postgres determines how to retrieve this information. It could do an index scan if it can find it quickly, or it could do a sequential scan if it has to look at everything. It all depends on the query

One of the biggest mind blowers for me is that Postgres does not access the disk every time. It has something called a Shared Buffer. This is essentially a memory. If it is in that memory, it is quick. If it is not in that memory, it goes to the disk and puts it in that memory.

What happens when things go wrong?

I wanted to examine a few scenarios that would normally keep developers up at night.

Scenario 1: The Morning Spike
The Problem: At PayWave, our /wallet/balance endpoint suddenly jumped from 50ms to 500ms during the morning rush.

My Coworker Alex: “Hey, the balance check is dragging. Is the server overloaded?”

The Solution: If I’m working at a fintech firm like PayWave, and a balance check takes 500ms, it’s a disaster. Instead of thinking of restarting the server, I would think about the dead tuples. If the database has a lot of old tuples that have not been vacuumed in a while, it could slow down the server significantly. I would also consider if the query actually using the index I created?

Scenario 2: The Growing Table
The Problem: At ShopSphere, our orders table grew from 2GB to 6GB in one week, but our sales didn’t triple.

My Coworker Priya: “Why is the disk filling up so fast? The autovacuum is on, so it shouldn’t be a bloat, right?”

The Solution: If a table has tripled in size in a week at ShopSphere, it could be a sign of that it’s a bloat. Even if autovacuum is enabled, it may not be fast enough to keep up with the volume of changes to the table. I would examine the value of autovacuum_vacuum_cost_limit to determine if we are slowing down the autovacuum process too much.

Scenario 3: The Mid-Transaction Crash
The Problem: During a quarterly DR test at CryptoBank, we simulate a primary node crash mid-transaction.

My Coworker Sam: “We killed the primary node. Can we actually restore this without losing the last 30 seconds of transactions?”

The Solution: This used to worry me. But after learning about Write Ahead Logging (WAL), I don’t worry about this anymore. Even in the case of a primary node crash, I know that I the data can be recovered. I can simply replay all the logs and bring my system to a consistent state.

My Key Takeaways

  • Indexing is your friend when it comes to speed.
  • Bloating is a silent killer; do monitor dead tuples.
  • Using connection pools avoids the “Too Many Connections” crash because it manages backend processes.

I’m shifting my focus from merely coding to learning about the environment that runs my code. If you have any questions/scenarios related to Postgres performance tuning, do share in the comments below.

Catch you in Entry #02.

Connect with me

Check out my previous post:

I Built an AI Resume Analyzer with GPT-5 vs GPT-4o-mini… and the Results Surprised Me 🚀

👉 🔗 Live Demo: https://ai-resume-analyzer-indol-one.vercel.app/
👉 💻 GitHub: https://github.com/abhi-123/ai-resume-analyzer

90% resumes get rejected before a human sees them.

So I built an AI Resume Analyzer to understand why.

This tool:
• Analyzes resumes against job descriptions
• Calculates an ATS-style score
• Highlights strengths, weaknesses, and gaps
• Suggests actionable improvements

But here’s where it got interesting…

I tested two models:
→ GPT-4o-mini (fast & cheap)
→ GPT-5 (slower & more expensive)

The difference?

GPT-4o-mini:
• Quick and decent insights
• More general suggestions
• Higher (but slightly generous) scores

GPT-5:
• Much deeper analysis
• More realistic scoring
• Extremely actionable suggestions (almost like a career coach)

Example:
Instead of saying “improve backend skills,” GPT-5 suggested:
→ Build microservices (REST/gRPC)
→ Deploy using Docker + Kubernetes
→ Add CI/CD pipelines and observability

That’s not just feedback — that’s a roadmap.

💡 Key takeaway:
Fast AI improves UX.
Smart AI improves decisions.

The real power is combining both.

So I added:
⚡ Fast Mode (instant results)
🧠 Deep Analysis Mode (advanced insights)

Would love your feedback 👇
What would you improve in this tool?

Have you ever tested different AI models like this?

AI #React #WebDevelopment #BuildInPublic

FBI direktörünün e-posta adresi hacklendi

ABD Adalet Bakanlığı, hacker grubu Handala’nın FBI Direktörü Kash Patel’in kişisel e-posta adresini hacklediğini açıkladı. Patel’in özel fotoğrafları ve gizli belgeleri yayımlandı.