<?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: agile turtles</title>
    <description>The latest articles on DEV Community by agile turtles (@agileturtles).</description>
    <link>https://dev.to/agileturtles</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3807835%2Fa1333b42-b9d5-4f0f-bcd6-34b171909fe5.png</url>
      <title>DEV Community: agile turtles</title>
      <link>https://dev.to/agileturtles</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/agileturtles"/>
    <language>en</language>
    <item>
      <title>We built an admin dashboard that Claude can reshape into anything — here's how</title>
      <dc:creator>agile turtles</dc:creator>
      <pubDate>Thu, 05 Mar 2026 12:54:27 +0000</pubDate>
      <link>https://dev.to/agileturtles/we-built-an-admin-dashboard-that-claude-can-reshape-into-anything-heres-how-3f3f</link>
      <guid>https://dev.to/agileturtles/we-built-an-admin-dashboard-that-claude-can-reshape-into-anything-heres-how-3f3f</guid>
      <description>&lt;p&gt;We just put out &lt;a href="https://agileturtles.gumroad.com/l/dashwise" rel="noopener noreferrer"&gt;Dashwise&lt;/a&gt; over at agile turtles. It's an admin dashboard kit where every directory has a &lt;code&gt;CLAUDE.md&lt;/code&gt; — so you can open it in Claude Code, say "make this into a CRM" or "turn this into a project tracker", and it actually works. The AI knows the architecture, the conventions, and where everything goes.&lt;/p&gt;

&lt;p&gt;Before we get into the AI stuff — the stack. We went with the latest everything.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dashwise.netlify.app" rel="noopener noreferrer"&gt;Here's the demo&lt;/a&gt; if you want to click around first.&lt;/p&gt;




&lt;h2&gt;
  
  
  the stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 16.1&lt;/strong&gt; with Turbopack as the default bundler. View Transitions baked in. No config needed — one flag in &lt;code&gt;next.config.ts&lt;/code&gt; and every &lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt; navigation gets a smooth crossfade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React 19.2&lt;/strong&gt; — &lt;code&gt;startTransition&lt;/code&gt; driving those View Transitions, plus all the Server Component stuff actually working properly now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS v4&lt;/strong&gt; — this is a big one. The whole color system moved from hsl to &lt;strong&gt;oklch&lt;/strong&gt;. Perceptually uniform colors. You can build a theme switcher by rotating one hue value and every color in the palette stays visually consistent. Try doing that with hsl.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;shadcn/ui&lt;/strong&gt; on the latest — 31 components, all pre-installed. We didn't touch any of them. That's the rule: &lt;code&gt;npx shadcn@latest add&lt;/code&gt;, never hand-edit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;zod 4&lt;/strong&gt; — breaking changes from v3, nothing dramatic but enough to burn an afternoon if you're not paying attention. &lt;code&gt;required_error&lt;/code&gt; is now just &lt;code&gt;error&lt;/code&gt;. &lt;code&gt;.refine()&lt;/code&gt; breaks TypeScript inference with zodResolver and you need a gnarly type assertion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;@dnd-kit&lt;/strong&gt; for drag-and-drop — not react-beautiful-dnd (deprecated), not react-dnd (painful API). @dnd-kit with the &lt;code&gt;DragOverlay&lt;/code&gt; pattern for proper cross-column kanban dragging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TanStack Table 8&lt;/strong&gt; — headless, typed, does sorting/filtering/pagination without fighting you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recharts 3.7&lt;/strong&gt; — clean API, works well with Server Components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs on Node 20.9+. &lt;code&gt;npm install &amp;amp;&amp;amp; npm run dev&lt;/code&gt; and you're up. No Docker, no database, no env vars to configure.&lt;/p&gt;




&lt;h2&gt;
  
  
  oklch changed how we think about theming
&lt;/h2&gt;

&lt;p&gt;This deserves its own section because it changes how theming works.&lt;/p&gt;

&lt;p&gt;Tailwind v4 defaults to oklch. The "L" channel is perceptually uniform — a blue at &lt;code&gt;oklch(0.6 0.15 265)&lt;/code&gt; and a green at &lt;code&gt;oklch(0.6 0.15 150)&lt;/code&gt; actually look the same brightness. With hsl, that was never true. Colors at "50% lightness" looked wildly different depending on the hue.&lt;/p&gt;

&lt;p&gt;We built a 6-color theme switcher on top of this. Each preset just rotates the hue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.488&lt;/span&gt; &lt;span class="m"&gt;0.243&lt;/span&gt; &lt;span class="m"&gt;264.376&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;           &lt;span class="c"&gt;/* violet */&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"blue"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.488&lt;/span&gt; &lt;span class="m"&gt;0.243&lt;/span&gt; &lt;span class="m"&gt;240&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c"&gt;/* blue */&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"green"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.488&lt;/span&gt; &lt;span class="m"&gt;0.243&lt;/span&gt; &lt;span class="m"&gt;150&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;/* green */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All six look coherent without manual per-color tuning. That's oklch doing the work.&lt;/p&gt;

&lt;p&gt;The catch: if you write &lt;code&gt;hsl(var(--primary))&lt;/code&gt; out of muscle memory (or because you copied from an old shadcn/ui tutorial), nothing renders. No error. Just invisible elements. We stared at a blank screen for an hour before figuring that one out. Everything in the project uses Tailwind semantic classes — &lt;code&gt;bg-primary&lt;/code&gt;, &lt;code&gt;text-muted-foreground&lt;/code&gt; — and we documented this in the CLAUDE.md files so nobody else (human or AI) repeats it.&lt;/p&gt;




&lt;h2&gt;
  
  
  the AI-native thing — why it matters
&lt;/h2&gt;

&lt;p&gt;Every directory has a &lt;code&gt;CLAUDE.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CLAUDE.md              — project overview, architecture, common tasks
src/app/CLAUDE.md      — routing patterns, how to add pages
src/components/CLAUDE.md — component conventions, what not to touch
src/lib/CLAUDE.md      — data layer, schemas, utilities
src/hooks/CLAUDE.md    — hook patterns
src/types/CLAUDE.md    — type conventions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These aren't regular docs. They're structured context for AI coding assistants. Each one covers how to add new things (with copy-paste templates), conventions that aren't obvious from the code, and gotchas that would waste time.&lt;/p&gt;

&lt;p&gt;Real example. You open the project in Claude Code and say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Add an invoices page with a table showing invoice number, client, amount, status, and due date."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without CLAUDE.md, the AI would probably put things in weird places, use &lt;code&gt;hsl()&lt;/code&gt; for colors, add event handlers to Server Components, and build a table from scratch instead of using TanStack Table.&lt;/p&gt;

&lt;p&gt;With the CLAUDE.md chain, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creates the page in &lt;code&gt;src/app/(dashboard)/invoices/page.tsx&lt;/code&gt; as a Server Component&lt;/li&gt;
&lt;li&gt;Puts the interactive bits in a separate &lt;code&gt;"use client"&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Defines columns following the existing TanStack Table pattern&lt;/li&gt;
&lt;li&gt;Adds mock data with &lt;code&gt;// TODO: Replace with your API call&lt;/code&gt; markers&lt;/li&gt;
&lt;li&gt;Adds the sidebar nav item&lt;/li&gt;
&lt;li&gt;Creates a loading skeleton&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Same patterns, same structure, same conventions as the rest of the codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  what you can build with it
&lt;/h2&gt;

&lt;p&gt;Dashwise ships as a generic admin dashboard — 10 pages, 5 auth flows, theme customizer. But because of the CLAUDE.md files, you can reshape it into pretty much anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SaaS dashboard&lt;/strong&gt; — swap mock data for your API, add billing, ship it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;project management tool&lt;/strong&gt; — kanban board is already built, add projects and teams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CRM&lt;/strong&gt; — tables, profile page, inbox are your starting point&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;analytics platform&lt;/strong&gt; — charts page + theme customizer = white-label analytics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;client portal&lt;/strong&gt; — auth pages exist, add role-based views&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;internal tool&lt;/strong&gt; — forms and settings are ready, hook up your internal APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CLAUDE.md files guide the AI to follow existing patterns. You describe what you want, and it builds it consistently with the rest of the codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  the architecture (kept simple on purpose)
&lt;/h2&gt;

&lt;p&gt;We kept things predictable because that's what makes AI assistance actually useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every page follows one pattern:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Kanban&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;KanbanPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-y-6"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PageHeader&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Kanban Board"&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Drag and drop tasks"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KanbanContent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* "use client" — all state lives here */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;Server Component exports metadata. Client Component handles interaction. Every single page. No exceptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All data comes from one file:&lt;/strong&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;kanbanTasks&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/mock-data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// TODO: Replace with your API call&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;grep -r "TODO: Replace"&lt;/code&gt; finds every integration point. When you connect a real backend, you know exactly what to swap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route groups split the layouts:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(dashboard)/&lt;/code&gt; wraps pages in sidebar + topbar. &lt;code&gt;(auth)/&lt;/code&gt; wraps pages in a full-screen gradient layout. The parentheses don't show up in URLs. Clean separation, no layout nesting headaches.&lt;/p&gt;




&lt;h2&gt;
  
  
  stuff that bit us
&lt;/h2&gt;

&lt;p&gt;We documented these in the CLAUDE.md files so neither you nor the AI repeat them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;oklch not hsl&lt;/strong&gt; — invisible elements, no error, nothing. use Tailwind classes only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server Component event handlers&lt;/strong&gt; — we added an &lt;code&gt;onClick&lt;/code&gt; to a page file. twice. React just silently ignores it. the interactive stuff has to live in a &lt;code&gt;"use client"&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;zod 4 migration&lt;/strong&gt; — &lt;code&gt;error&lt;/code&gt; instead of &lt;code&gt;required_error&lt;/code&gt;. small change, silent breakage. &lt;code&gt;.refine()&lt;/code&gt; needs a type assertion with zodResolver or TypeScript complains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;@dnd-kit click vs drag&lt;/strong&gt; — without &lt;code&gt;activationConstraint: { distance: 5 }&lt;/code&gt;, every tiny mouse movement during a click triggers a drag. buttons on kanban cards become unusable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;shadcn/ui files&lt;/strong&gt; — never edit &lt;code&gt;components/ui/&lt;/code&gt; directly. we learned this the hard way when an update overwrote our changes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  links
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://agileturtles.gumroad.com/l/dashwise" rel="noopener noreferrer"&gt;agile turtles on gumroad&lt;/a&gt;. MIT license. BFF — no subscriptions, no lock-in.&lt;/p&gt;

&lt;p&gt;demo: &lt;a href="https://dashwise.netlify.app" rel="noopener noreferrer"&gt;dashwise.netlify.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;if you end up building something with it, we'd like to hear about it.&lt;/p&gt;

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