<?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: Eshwar Reddy T</title>
    <description>The latest articles on DEV Community by Eshwar Reddy T (@eshwar_reddyt_0b8564239c).</description>
    <link>https://dev.to/eshwar_reddyt_0b8564239c</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%2F2686937%2F43299bbf-ce61-4bbc-bbc9-2285b5c9e32c.png</url>
      <title>DEV Community: Eshwar Reddy T</title>
      <link>https://dev.to/eshwar_reddyt_0b8564239c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eshwar_reddyt_0b8564239c"/>
    <language>en</language>
    <item>
      <title>Beyond the Demo: Architecting a Security-First AI Journal with Gemini</title>
      <dc:creator>Eshwar Reddy T</dc:creator>
      <pubDate>Wed, 02 Sep 2026 17:01:27 +0000</pubDate>
      <link>https://dev.to/eshwar_reddyt_0b8564239c/beyond-the-demo-architecting-a-security-first-ai-journal-with-gemini-pjl</link>
      <guid>https://dev.to/eshwar_reddyt_0b8564239c/beyond-the-demo-architecting-a-security-first-ai-journal-with-gemini-pjl</guid>
      <description>&lt;p&gt;Most "AI-powered" side projects follow the same arc: a slick demo, a hardcoded API key, one shared database, zero auth boundaries — and it falls apart the moment a second user shows up. I wanted to build something different: a real, production-shaped application, designed the way a security engineer would design it before a single line of code got written.&lt;/p&gt;

&lt;p&gt;That's how &lt;strong&gt;Personal Gemini Journal&lt;/strong&gt; came together — a private, AI-powered diary and brainstorming partner where every architectural decision starts with "what happens if someone tries to abuse this?" instead of "does this work in the demo?"&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Does
&lt;/h2&gt;

&lt;p&gt;Personal Gemini Journal isn't just another chatbot wrapper. It's a secure, fully isolated journaling space where you sign in, have real multi-turn conversations with Gemini to brainstorm or reflect, and have those conversations automatically summarized and saved — privately, to you.&lt;/p&gt;

&lt;p&gt;The feature I'm most excited about is &lt;strong&gt;semantic search over your own past entries&lt;/strong&gt;. Instead of scrolling through weeks of journal history, you can ask something like &lt;em&gt;"When did I talk about feeling stuck on my job search?"&lt;/em&gt; and get back the actual entries that match — not by keyword, but by meaning.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; React 19 (Vite), Tailwind CSS v4, Lucide React&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Node.js + Express, written in TypeScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI:&lt;/strong&gt; the &lt;code&gt;@google/genai&lt;/code&gt; SDK — Gemini 2.5 Flash for conversation and summarization, &lt;code&gt;text-embedding-004&lt;/code&gt; for vector embeddings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth &amp;amp; Data:&lt;/strong&gt; Firebase Authentication (Google SSO) + Cloud Firestore&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Google Cloud Secret Manager for API key protection, Zod for payload validation, and Firestore's native Vector Search&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Four Features, Four Threat Models
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Secure Authentication.&lt;/strong&gt; The frontend never hands the backend a user ID and asks it to be trusted — it sends a Firebase ID token (JWT), and a custom Express middleware verifies that token server-side via the Firebase Admin SDK before deriving identity. The user is always &lt;em&gt;who the token says they are&lt;/em&gt;, never who the request body claims they are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-Turn AI Journaling.&lt;/strong&gt; Conversation history lives in Firestore, maintained by the backend — not the client — so context can't be tampered with mid-conversation. Every call to Gemini is proxied through the server; the API key never touches the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic Search via RAG.&lt;/strong&gt; When an entry is saved, the backend asks Gemini 2.5 Flash for a concise summary, then passes that summary to &lt;code&gt;text-embedding-004&lt;/code&gt; to generate a vector embedding. A search query gets embedded the same way and matched against those vectors using Firestore's native &lt;code&gt;findNearest&lt;/code&gt; with cosine distance — real retrieval-augmented search, not string matching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strict Data Isolation.&lt;/strong&gt; This is the part I care about most. Data lives under &lt;code&gt;users/{userId}/conversations/{conversationId}&lt;/code&gt;, and isolation is enforced in &lt;em&gt;two independent layers&lt;/em&gt;: the Express backend hardcodes every query — including vector search — to the authenticated user's ID, and Firestore Security Rules separately enforce &lt;code&gt;request.auth.uid == userId&lt;/code&gt;. Even if the backend were somehow bypassed, cross-user data leakage (IDOR) isn't just unlikely — it's structurally prevented.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security-First Angle
&lt;/h2&gt;

&lt;p&gt;The part of this build that made it feel genuinely different from a typical hackathon project was the process, not just the output:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No client-side secrets, ever.&lt;/strong&gt; The Gemini API key is pulled from GCP Secret Manager at server startup and cached in memory — never bundled into the Vite build, never logged, never returned in a response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validated input everywhere.&lt;/strong&gt; Every API route runs through Zod schemas enforcing max lengths and rejecting malformed payloads, which matters more than it sounds — an unvalidated free-text endpoint hitting a billed LLM API is an open door to a cost-exhaustion attack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least privilege by default.&lt;/strong&gt; The backend's service account gets &lt;code&gt;roles/secretmanager.secretAccessor&lt;/code&gt; scoped to exactly the Gemini API key it needs — not broad project access "to be safe."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this shows up in a demo GIF. All of it is the difference between a toy and something you could actually ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This, Why Now
&lt;/h2&gt;

&lt;p&gt;AI-assisted coding tools can generate a working app in minutes — but "working" and "production-ready" are different bars. The interesting engineering problem isn't getting Gemini to respond to a prompt; it's making sure the system around that response holds up under real users, real attackers, and real scale. Deploying this kind of security-conscious, isolated architecture on Cloud Run is what makes the difference between a weekend demo and something you'd actually trust with your own data.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Gemini 2.5 Flash, Firebase, Firestore, and Cloud Run.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#AccelerateAIwithCloudRun&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>googlecloud</category>
      <category>firebase</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
