<?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 Kubgak</title>
    <description>The latest articles on DEV Community by David Kubgak (@david_kubgak).</description>
    <link>https://dev.to/david_kubgak</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%2F3986990%2Ff693a403-f1b7-49ce-be33-8a97230365c0.jpg</url>
      <title>DEV Community: David Kubgak</title>
      <link>https://dev.to/david_kubgak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/david_kubgak"/>
    <language>en</language>
    <item>
      <title>I made my SaaS dashboard load instantly — here's exactly how</title>
      <dc:creator>David Kubgak</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:53:33 +0000</pubDate>
      <link>https://dev.to/david_kubgak/i-made-my-saas-dashboard-load-instantly-heres-exactly-how-ggh</link>
      <guid>https://dev.to/david_kubgak/i-made-my-saas-dashboard-load-instantly-heres-exactly-how-ggh</guid>
      <description>&lt;p&gt;I just made my dashboard go from 2-3 second loading &lt;br&gt;
spinner to instant. Here's the exact technique.&lt;/p&gt;

&lt;p&gt;The problem: every time a user opened the dashboard, &lt;br&gt;
they'd see a spinner while we fetched their plan, &lt;br&gt;
repos, and docs from the API. Even on fast connections &lt;br&gt;
it felt slow.&lt;/p&gt;

&lt;p&gt;The solution: stale-while-revalidate with localStorage&lt;/p&gt;

&lt;p&gt;Here's the pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On load, check localStorage for cached data&lt;/li&gt;
&lt;li&gt;If found, show it IMMEDIATELY (no spinner)&lt;/li&gt;
&lt;li&gt;Always fetch fresh data in background&lt;/li&gt;
&lt;li&gt;Update the UI silently when fresh data arrives&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The user sees their data in milliseconds. If data &lt;br&gt;
changed since last visit they see the update &lt;br&gt;
a second later with zero disruption.&lt;/p&gt;

&lt;p&gt;The cache utility (TypeScript):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;`typescript&lt;br&gt;
interface CacheEntry {&lt;br&gt;
  data: T&lt;br&gt;
  timestamp: number&lt;br&gt;
  userId: string&lt;br&gt;
  version: string&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;export function getCached(&lt;br&gt;
  key: string, &lt;br&gt;
  userId: string, &lt;br&gt;
  ttlMs: number&lt;br&gt;
): T | null {&lt;br&gt;
  try {&lt;br&gt;
    const raw = localStorage.getItem(`pushpen_\${key}&lt;code&gt;)&lt;br&gt;
    if (!raw) return null&lt;br&gt;
    const entry: CacheEntry&amp;lt;T&amp;gt; = JSON.parse(raw)&lt;br&gt;
    if (entry.userId !== userId) return null&lt;br&gt;
    if (Date.now() - entry.timestamp &amp;gt; ttlMs) return null&lt;br&gt;
    return entry.data&lt;br&gt;
  } catch { return null }&lt;br&gt;
}&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Usage in the dashboard:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;`typescript&lt;br&gt;
async function fetchUserPlan(userId: string) {&lt;br&gt;
  // Show cached data instantly&lt;br&gt;
  const cached = getCached('user_plan', userId, 300000)&lt;br&gt;
  if (cached) {&lt;br&gt;
    setUserPlan(cached)&lt;br&gt;
    setLoading(false)&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;// Always fetch fresh in background&lt;br&gt;
  const res = await fetch('/api/user/plan')&lt;br&gt;
  const data = await res.json()&lt;br&gt;
  setUserPlan(data)&lt;br&gt;
  setCached('user_plan', userId, data)&lt;br&gt;
}&lt;br&gt;
`&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;TTLs I use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User plan: 5 minutes&lt;/li&gt;
&lt;li&gt;Connected repos: 3 minutes&lt;/li&gt;
&lt;li&gt;Docs list: 2 minutes&lt;/li&gt;
&lt;li&gt;Templates: 10 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also preloaded the interactive demo iframe 2 seconds &lt;br&gt;
after page load so clicking play is instant.&lt;/p&gt;

&lt;p&gt;The result: dashboard feels native-app fast.&lt;/p&gt;

&lt;p&gt;I built this for Pushpen (pushpen.dev) — an AI tool &lt;br&gt;
that auto-generates GitHub docs on every push.&lt;/p&gt;

&lt;p&gt;What performance tricks have worked for your SaaS?&lt;/p&gt;

</description>
      <category>performance</category>
      <category>tutorial</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I built an AI that writes GitHub docs automatically on every push</title>
      <dc:creator>David Kubgak</dc:creator>
      <pubDate>Tue, 16 Jun 2026 08:42:17 +0000</pubDate>
      <link>https://dev.to/david_kubgak/i-built-an-ai-that-writes-github-docs-automatically-on-every-push-336m</link>
      <guid>https://dev.to/david_kubgak/i-built-an-ai-that-writes-github-docs-automatically-on-every-push-336m</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.tourl"&gt;&lt;/a&gt;Every developer I know has the same problem.&lt;/p&gt;

&lt;p&gt;The README describes a project from 6 months ago. The changelog &lt;br&gt;
is either empty or a list of git hashes nobody can read. New &lt;br&gt;
engineers spend their first two weeks asking questions that should &lt;br&gt;
be answered by documentation.&lt;/p&gt;

&lt;p&gt;Nobody fixes it because nobody has time.&lt;/p&gt;

&lt;p&gt;I got tired of this and built Pushpen.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Pushpen connects to your GitHub repository via webhook. Every time &lt;br&gt;
you push code, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads the diff across all commits in the push&lt;/li&gt;
&lt;li&gt;Understands what actually changed — not just commit messages&lt;/li&gt;
&lt;li&gt;Generates updated documentation&lt;/li&gt;
&lt;li&gt;Opens a pull request for you to review and merge&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The documentation it generates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;README — kept accurate to your actual codebase&lt;/li&gt;
&lt;li&gt;Changelog — written in plain English from your diff&lt;/li&gt;
&lt;li&gt;API docs — updated when endpoints change&lt;/li&gt;
&lt;li&gt;Onboarding guide — so new team members can actually follow it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why a PR and not a direct commit
&lt;/h2&gt;

&lt;p&gt;I made a deliberate choice here. Pushpen never writes directly &lt;br&gt;
to your codebase. Every update comes as a pull request.&lt;/p&gt;

&lt;p&gt;You review it. You approve it. You merge it. Or you ignore it.&lt;/p&gt;

&lt;p&gt;No surprises. No AI touching production directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else it does
&lt;/h2&gt;

&lt;p&gt;Beyond documentation, Pushpen also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Summarizes every PR with impact analysis and risk assessment&lt;/li&gt;
&lt;li&gt;Triages new GitHub issues automatically&lt;/li&gt;
&lt;li&gt;Analyzes CI failures and suggests fixes&lt;/li&gt;
&lt;li&gt;Tracks your repository health score over time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The tech stack
&lt;/h2&gt;

&lt;p&gt;Built with Next.js 14, Supabase, Clerk, and Claude API via &lt;br&gt;
OpenRouter. GitHub webhooks handle the event pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it free
&lt;/h2&gt;

&lt;p&gt;Free plan — no credit card required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pushpen.dev" rel="noopener noreferrer"&gt;https://pushpen.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would love feedback from the dev.to community. &lt;br&gt;
What would make you actually use something like this?&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctghgw8v4q87sha0icb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctghgw8v4q87sha0icb9.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
