<?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: David Rueda</title>
    <description>The latest articles on DEV Community by David Rueda (@druedaro).</description>
    <link>https://dev.to/druedaro</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%2F4098815%2F50744130-0ee3-4290-b52c-e50559898174.png</url>
      <title>DEV Community: David Rueda</title>
      <link>https://dev.to/druedaro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/druedaro"/>
    <language>en</language>
    <item>
      <title>I Built a Voice-First AI Sports Journal (And Why I Didn't Over-Engineer It)</title>
      <dc:creator>David Rueda</dc:creator>
      <pubDate>Fri, 28 Aug 2026 11:15:08 +0000</pubDate>
      <link>https://dev.to/druedaro/i-built-a-voice-first-ai-sports-journal-and-why-i-didnt-over-engineer-it-2i27</link>
      <guid>https://dev.to/druedaro/i-built-a-voice-first-ai-sports-journal-and-why-i-didnt-over-engineer-it-2i27</guid>
      <description>&lt;p&gt;There is a fundamental problem with fitness tracking apps today: friction. &lt;/p&gt;

&lt;p&gt;After a grueling workout, when your hands are sweaty, your heart rate is 160 BPM, and you are trying to catch your breath, the absolute last thing you want to do is open an app, navigate through five different dropdown menus, search for the exact exercise variant you did, and type out how you felt on a tiny mobile keyboard.&lt;/p&gt;

&lt;p&gt;Because of this friction, most of us either default to raw data (Apple Watch rings) which lacks context, or we stop tracking our subjective experiences entirely.&lt;/p&gt;

&lt;p&gt;That’s why I built &lt;strong&gt;&lt;a href="https://trainlog-journal.vercel.app/" rel="noopener noreferrer"&gt;Trainlog&lt;/a&gt;&lt;/strong&gt; — a voice-first sports reflection journal that uses AI to understand your training through natural speech. You just hit record, talk about your session for 15 seconds ("&lt;em&gt;I ran 5k today, felt great but my calves are tight&lt;/em&gt;"), and the app transcribes it, extracts structured metrics (fatigue, sleep, emotions), and builds a persistent calendar history.&lt;/p&gt;

&lt;p&gt;But this isn't just a product pitch. Building an AI wrapper in 2024 is easy. Building a production-ready AI application that feels native, respects user privacy, and doesn't break when the LLM hallucinates is hard. &lt;/p&gt;

&lt;p&gt;When planning the architecture, it was tempting to fall into the classic AI trap: vector databases, multi-agent orchestrators, and infinite LangChain wrappers. Instead, I chose a boring, robust stack: &lt;strong&gt;React 19, Firebase, Tailwind, Zod, and Groq (Whisper + Llama 3)&lt;/strong&gt;.&lt;br&gt;
Here are the 7 technical lessons I learned building a resilient AI app without over-engineering it.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Voice is the ultimate UI, but it needs a safety net
&lt;/h3&gt;

&lt;p&gt;The core interaction of Trainlog relies on the browser-native &lt;code&gt;MediaRecorder&lt;/code&gt; API to capture audio, which is then sent to a Vercel Serverless Function and processed by Groq's Whisper model. &lt;/p&gt;

&lt;p&gt;Whisper is incredibly fast and accurate, but ambient gym noise or heavy breathing can still confuse it. Initially, I passed the transcription directly to the AI for analysis. This was a mistake. If the transcription missed a "not" (e.g., "I did &lt;em&gt;not&lt;/em&gt; sleep well"), the entire analysis was poisoned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt; Human-in-the-loop. Before any AI analysis happens, the user is presented with the raw transcription in an editable text area. They can fix typos or add context before hitting "Analyze". Never trust raw sensory input without giving the user the steering wheel.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. You don't need a complex Agent framework (Just Prompt + Zod)
&lt;/h3&gt;

&lt;p&gt;When you start building AI features, every tutorial tells you to use a heavy agentic framework. But for extracting structured data (Activities, Intensity, Fatigue level, Emotions), a massive agent graph is pure overhead that introduces latency and points of failure.&lt;/p&gt;

&lt;p&gt;Instead of an agent, Trainlog relies on &lt;strong&gt;Strict Schema Validation&lt;/strong&gt;. I defined the exact TypeScript interfaces I needed for the frontend, translated them into a Zod schema, and instructed Llama 3 to output raw JSON matching that exact shape. &lt;/p&gt;

&lt;p&gt;When the response hits the server, Zod parses it. If the LLM hallucinates a string where a number should be for the "fatigue" metric, Zod catches it, the server gracefully handles the error, and the UI doesn't crash. Strict boundaries &amp;gt; Complex Agents.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. PWA is the secret weapon for solo developers
&lt;/h3&gt;

&lt;p&gt;I wanted Trainlog to feel like a native app on iOS and Android — full screen, no browser UI, offline capabilities, and an app icon on the home screen. &lt;/p&gt;

&lt;p&gt;Instead of rewriting the codebase in React Native or Swift, I used &lt;code&gt;vite-plugin-pwa&lt;/code&gt;. With a simple &lt;code&gt;manifest.json&lt;/code&gt; and a Service Worker, Trainlog became installable. To make it feel truly native, I implemented Mobile-First UI patterns: bottom navigation bars on mobile, side navigation rails on tablets/desktop (&lt;code&gt;md:flex-row&lt;/code&gt;), and smooth CSS micro-animations (&lt;code&gt;animate-in fade-in&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;If you are a solo developer building a consumer app, don't build two codebases. Build a spectacular PWA.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Push Notifications on the Web are finally viable
&lt;/h3&gt;

&lt;p&gt;One of the biggest missing pieces of Web Apps used to be engagement. Users forget to log their workouts. I needed a daily reminder system.&lt;br&gt;
Thanks to Firebase Cloud Messaging (FCM) and the Web Push API, Trainlog now asks for notification permissions during the onboarding flow. If granted, the frontend registers a Service Worker (&lt;code&gt;firebase-messaging-sw.js&lt;/code&gt;), securely stores the FCM token in Firestore, and a Vercel Cron Job runs every evening at 20:00 to ping users who haven't logged a session that day. &lt;/p&gt;

&lt;p&gt;Getting Apple to play nice with Web Push on iOS was a journey, but it works flawlessly now.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. AI features must be rate-limited from day one
&lt;/h3&gt;

&lt;p&gt;When you expose an endpoint that calls an LLM, you are essentially putting an open tab at a bar on the internet. If a malicious user or a bot spams your &lt;code&gt;/api/analyze&lt;/code&gt; endpoint, your API bills will skyrocket.&lt;/p&gt;

&lt;p&gt;I didn't want to build a complex queueing system, so I reached for &lt;strong&gt;Upstash Redis&lt;/strong&gt;. With just a few lines of code in the Vercel Serverless functions, I implemented a sliding window rate limiter. If an IP or User ID requests more than 10 analyses per minute, the server responds with a &lt;code&gt;429 Too Many Requests&lt;/code&gt;. It’s a 5-minute implementation that saves you from a massive headache.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Gamification shouldn't cause anxiety
&lt;/h3&gt;

&lt;p&gt;Health and fitness apps love "Streaks" (doing something for X consecutive days). But streaks are psychologically punishing; if you get sick or take a rest day, losing a 100-day streak feels devastating and often causes users to abandon the app entirely.&lt;/p&gt;

&lt;p&gt;For Trainlog, I built a gamification system based on &lt;strong&gt;Milestones and Exploration, not just consistency&lt;/strong&gt;. Users earn badges for emotional resilience (logging after a bad day), exploration (trying new activities), and total volume, rather than punishing them for breaking a chain. The logic is handled seamlessly on the backend when saving an entry, comparing their historical Firestore data against achievement criteria.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Data Privacy is a feature, not an afterthought
&lt;/h3&gt;

&lt;p&gt;When dealing with health data, sleep metrics, and personal reflections, privacy is paramount. &lt;/p&gt;

&lt;p&gt;I architected Trainlog with strict Firebase Security Rules to ensure per-user data isolation. But more importantly, I applied &lt;strong&gt;PII Sanitization&lt;/strong&gt; before the data ever reaches the LLM. &lt;br&gt;
Regular expressions scrub potential phone numbers, emails, or IDs from the voice transcripts before they are sent to Groq. Furthermore, no entry is ever saved to the database until the user explicitly reviews the AI's analysis and clicks "Confirm". If they delete their account, a cloud function wipes their entire Firestore document tree instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Boring Stack Wins Again
&lt;/h3&gt;

&lt;p&gt;If there’s a single takeaway from building Trainlog, it’s this: &lt;strong&gt;Start with the smallest stack that solves the problem.&lt;/strong&gt;&lt;br&gt;
I didn't need a vector database because users can filter their calendar history by date and activity natively in the UI. I didn't need a heavy memory layer because the AI Coach ("Anna") simply loads the user's recent Firestore history into the system prompt context window. &lt;/p&gt;

&lt;p&gt;Complexity is easy to add and brutally hard to remove. The best AI apps aren't the ones with the most impressive architecture diagrams. They are the ones that solve a real user problem with zero friction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try it out!
&lt;/h3&gt;

&lt;p&gt;I’ve open-sourced the entire project. You can check out the code, steal the prompt architecture, or just use the app to track your next gym session.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://trainlog-journal.vercel.app/" rel="noopener noreferrer"&gt;trainlog-journal.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub Repo:&lt;/strong&gt; &lt;a href="https://github.com/druedaro/trainlog" rel="noopener noreferrer"&gt;github.com/druedaro/trainlog&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’d love to hear your thoughts! Have you fallen into the AI over-engineering trap recently? Drop a comment below or let me know what you think of the app. Happy coding (and training)! 🏋️‍♂️&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>react</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
