<?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: RapidKit </title>
    <description>The latest articles on DEV Community by RapidKit  (@rapidkit).</description>
    <link>https://dev.to/rapidkit</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%2F3639844%2Fd7e3b4b9-412a-4e84-b7b7-d2ac18c3a99a.png</url>
      <title>DEV Community: RapidKit </title>
      <link>https://dev.to/rapidkit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rapidkit"/>
    <language>en</language>
    <item>
      <title>I Spent 45 Minutes Setting Up a Backend… Before Writing a Single Line of Logic</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Tue, 28 Apr 2026 10:36:15 +0000</pubDate>
      <link>https://dev.to/rapidkit/i-spent-45-minutes-setting-up-a-backend-before-writing-a-single-line-of-logic-516o</link>
      <guid>https://dev.to/rapidkit/i-spent-45-minutes-setting-up-a-backend-before-writing-a-single-line-of-logic-516o</guid>
      <description>&lt;p&gt;Last week, I spun up a new FastAPI service.&lt;/p&gt;

&lt;p&gt;45 minutes later… I still hadn’t written a single line of business logic.&lt;/p&gt;

&lt;p&gt;Not because coding is hard —&lt;br&gt;
but because &lt;strong&gt;everything around the code is broken&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing &lt;code&gt;.env&lt;/code&gt; keys&lt;/li&gt;
&lt;li&gt;Docker half-working&lt;/li&gt;
&lt;li&gt;DB migrations out of sync&lt;/li&gt;
&lt;li&gt;One internal service silently failing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’ve built more than one backend, you’ve lived this.&lt;/p&gt;




&lt;h2&gt;
  
  
  We don’t have a coding problem
&lt;/h2&gt;

&lt;p&gt;We have a &lt;strong&gt;setup problem disguised as engineering&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Most of our time isn’t spent writing logic.&lt;/p&gt;

&lt;p&gt;It’s spent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reconfiguring environments&lt;/li&gt;
&lt;li&gt;fixing invisible dependencies&lt;/li&gt;
&lt;li&gt;debugging things we already debugged before&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The “Context Gap”
&lt;/h2&gt;

&lt;p&gt;Tools like Copilot help you write code faster.&lt;/p&gt;

&lt;p&gt;But backend work doesn’t happen at the file level.&lt;/p&gt;

&lt;p&gt;It happens at the &lt;strong&gt;workspace level&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your tools don’t know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your architecture&lt;/li&gt;
&lt;li&gt;your running services&lt;/li&gt;
&lt;li&gt;your conventions&lt;/li&gt;
&lt;li&gt;your dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you end up with:&lt;/p&gt;

&lt;p&gt;👉 Faster code&lt;br&gt;
👉 Same broken systems&lt;/p&gt;




&lt;h2&gt;
  
  
  I tried a different approach
&lt;/h2&gt;

&lt;p&gt;I got tired of this loop… so I started experimenting with a different idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if the workspace understood the system?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not just syntax.&lt;/p&gt;

&lt;p&gt;Not just files.&lt;/p&gt;

&lt;p&gt;But the &lt;strong&gt;actual backend state&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. No more blind debugging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Missing &lt;code&gt;.env&lt;/code&gt; → detected instantly&lt;/li&gt;
&lt;li&gt;Broken service → flagged before runtime&lt;/li&gt;
&lt;li&gt;Dependency issues → visible early&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Scaffolding that respects architecture
&lt;/h3&gt;

&lt;p&gt;Not just boilerplate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clean structure&lt;/li&gt;
&lt;li&gt;production-ready setup&lt;/li&gt;
&lt;li&gt;enforced conventions&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Change impact awareness
&lt;/h3&gt;

&lt;p&gt;Before refactoring:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This will affect 3 modules and 2 endpoints.”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  4. Debugging with context
&lt;/h3&gt;

&lt;p&gt;No more copy-pasting logs into AI.&lt;/p&gt;

&lt;p&gt;The system already understands the error.&lt;/p&gt;




&lt;h2&gt;
  
  
  The shift we’re ignoring
&lt;/h2&gt;

&lt;p&gt;We’re not just writing code anymore.&lt;/p&gt;

&lt;p&gt;We’re managing systems.&lt;/p&gt;

&lt;p&gt;But our tools are still stuck in:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“write this function”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;instead of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“understand this system”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Curious how others deal with this
&lt;/h2&gt;

&lt;p&gt;What’s the most frustrating part of your backend setup?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;boilerplate?&lt;/li&gt;
&lt;li&gt;debugging?&lt;/li&gt;
&lt;li&gt;environment issues?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Would love to hear real workflows.&lt;/p&gt;




&lt;p&gt;(If you're curious, I shared more details here: &lt;a href="https://www.workspai.com/" rel="noopener noreferrer"&gt;https://www.workspai.com/&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>backend</category>
    </item>
    <item>
      <title>The Best AI Feature for Backend Developers Is a Resolution Loop</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Sun, 26 Apr 2026 07:36:05 +0000</pubDate>
      <link>https://dev.to/rapidkit/the-best-ai-feature-for-backend-developers-is-a-resolution-loop-4gh3</link>
      <guid>https://dev.to/rapidkit/the-best-ai-feature-for-backend-developers-is-a-resolution-loop-4gh3</guid>
      <description>&lt;p&gt;AI devtools usually market themselves around a single visible surface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;chat&lt;/li&gt;
&lt;li&gt;code generation&lt;/li&gt;
&lt;li&gt;agent mode&lt;/li&gt;
&lt;li&gt;autocomplete&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those matter.&lt;/p&gt;

&lt;p&gt;But if you work mostly on backend systems, the feature that changes your day is usually not a standalone prompt box.&lt;/p&gt;

&lt;p&gt;It is a workflow that helps you go from incident to verified fix faster and with less risk.&lt;/p&gt;

&lt;p&gt;That is why I think the strongest AI pattern for backend tooling is a &lt;strong&gt;resolution loop&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;detect&lt;/li&gt;
&lt;li&gt;diagnose&lt;/li&gt;
&lt;li&gt;plan&lt;/li&gt;
&lt;li&gt;verify&lt;/li&gt;
&lt;li&gt;learn&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the product direction behind &lt;a href="https://www.workspai.com/" rel="noopener noreferrer"&gt;Workspai's&lt;/a&gt; Chat Brain surfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why backend work needs more than chat
&lt;/h2&gt;

&lt;p&gt;Backend incidents usually start from a live signal, not a blank question.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a failing startup command&lt;/li&gt;
&lt;li&gt;a broken health check&lt;/li&gt;
&lt;li&gt;an environment mismatch&lt;/li&gt;
&lt;li&gt;a change that might break routing or module wiring&lt;/li&gt;
&lt;li&gt;a repeated team convention the AI keeps forgetting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the AI only sits in a generic chat surface, the developer still has to manually package the problem.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;copying terminal output&lt;/li&gt;
&lt;li&gt;explaining the project structure&lt;/li&gt;
&lt;li&gt;listing installed modules&lt;/li&gt;
&lt;li&gt;describing the framework conventions&lt;/li&gt;
&lt;li&gt;guessing what action is safest next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is extra work exactly when the user wants less.&lt;/p&gt;

&lt;h2&gt;
  
  
  The killer features only make sense as a connected system
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Terminal bridge
&lt;/h3&gt;

&lt;p&gt;This is the best entry point because it captures the pain moment directly.&lt;/p&gt;

&lt;p&gt;Instead of asking the user to translate terminal noise into a prompt, the product can turn terminal evidence into a structured diagnosis and next action.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Change impact before fix
&lt;/h3&gt;

&lt;p&gt;One of the fastest ways to lose trust in an AI tool is to let it jump from idea to mutation with no guard rails.&lt;/p&gt;

&lt;p&gt;Impact analysis gives the user a chance to understand blast radius first.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Fix preview before apply
&lt;/h3&gt;

&lt;p&gt;Preview matters because backend teams need inspectable changes, not magic.&lt;/p&gt;

&lt;p&gt;The AI should make the intended path visible before asking for trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Verification after action
&lt;/h3&gt;

&lt;p&gt;This is the most underrated part.&lt;/p&gt;

&lt;p&gt;A tool is not trustworthy because it sounds correct. It is trustworthy because it helps prove whether the suggested change actually worked in this workspace.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Workspace memory
&lt;/h3&gt;

&lt;p&gt;The last step is compounding.&lt;/p&gt;

&lt;p&gt;If the same team keeps facing the same kinds of incidents, the tool should get better at routing and suggesting based on accumulated conventions and decisions.&lt;/p&gt;

&lt;p&gt;That is how AI moves from helper to operating layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes this stronger than a generic assistant
&lt;/h2&gt;

&lt;p&gt;A generic assistant answers.&lt;/p&gt;

&lt;p&gt;A backend resolution loop does four extra things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;starts from real workspace evidence&lt;/li&gt;
&lt;li&gt;constrains risky actions&lt;/li&gt;
&lt;li&gt;encourages verification&lt;/li&gt;
&lt;li&gt;saves useful context for future incidents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination is much more valuable than just adding another AI command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Product takeaway
&lt;/h2&gt;

&lt;p&gt;If you are building AI tooling for developers, do not just ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how do we make the chat better?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where does the real pain begin?&lt;/li&gt;
&lt;li&gt;what is the safest next action?&lt;/li&gt;
&lt;li&gt;how do we verify success?&lt;/li&gt;
&lt;li&gt;how do we keep the learning?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is where the real killer feature lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;For backend developers, the best AI feature is not a smarter chat window.&lt;/p&gt;

&lt;p&gt;It is a tighter resolution loop.&lt;/p&gt;

&lt;p&gt;That is the difference between an AI tool that looks impressive and one that becomes part of the daily workflow.&lt;/p&gt;

&lt;p&gt;What would you prioritize most in that loop: diagnosis, preview, verification, or memory?&lt;/p&gt;




&lt;p&gt;🔗 &lt;a href="https://www.workspai.com/" rel="noopener noreferrer"&gt;Workspai&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;Workspai on VS Code Marketplace&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://getrapidkit.com" rel="noopener noreferrer"&gt;RapidKit open-source platform&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://github.com/getrapidkit/rapidkit-vscode" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>workspai</category>
      <category>vscode</category>
      <category>backend</category>
    </item>
    <item>
      <title>Why Do Backend Teams Need a Workspace-Based AI Layer?</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Fri, 24 Apr 2026 05:09:45 +0000</pubDate>
      <link>https://dev.to/rapidkit/why-do-backend-teams-need-a-workspace-based-ai-layer-31lo</link>
      <guid>https://dev.to/rapidkit/why-do-backend-teams-need-a-workspace-based-ai-layer-31lo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Backend development breaks AI out of the file-level model fast. Here is why backend teams need a workspace-based AI layer, and how &lt;a href="https://www.workspai.com/" rel="noopener noreferrer"&gt;Workspai&lt;/a&gt; uses that architecture to make generation, debugging, health checks, module operations, and team context actually useful.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Do Backend Teams Need a Workspace-Based AI Layer?
&lt;/h2&gt;

&lt;p&gt;The AI workspace for backend teams.&lt;/p&gt;

&lt;p&gt;Build backend systems with AI that knows your workspace.&lt;/p&gt;

&lt;p&gt;Backend AI usually breaks on context, not raw model quality.&lt;/p&gt;

&lt;p&gt;Most AI coding tools operate at file level. That is enough for isolated tasks. It is not enough for real backend work, where the useful context lives across the workspace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;project structure&lt;/li&gt;
&lt;li&gt;framework, kit, and runtime&lt;/li&gt;
&lt;li&gt;whether the service is FastAPI, NestJS, Spring Boot, Go/Fiber, or Go/Gin&lt;/li&gt;
&lt;li&gt;installed modules&lt;/li&gt;
&lt;li&gt;runtime state&lt;/li&gt;
&lt;li&gt;health issues&lt;/li&gt;
&lt;li&gt;recent changes&lt;/li&gt;
&lt;li&gt;team conventions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why backend teams need a workspace-based AI layer. The workspace is the unit that makes the answers useful.&lt;/p&gt;

&lt;p&gt;Without that layer, AI for backend development keeps falling back to generic suggestions, missing project conventions, and answers that sound right but do not fit the actual system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why file-level AI breaks down so quickly in backend development
&lt;/h2&gt;

&lt;p&gt;Backend work is rarely one file deep. When you ask for help with a bug, a module decision, a startup issue, or a safe refactor, the real answer depends on more than the code under your cursor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether the project is FastAPI, NestJS, Spring Boot, Go/Fiber, or Go/Gin&lt;/li&gt;
&lt;li&gt;whether the structure is standard or more layered&lt;/li&gt;
&lt;li&gt;which modules are already installed&lt;/li&gt;
&lt;li&gt;what the workspace doctor has already flagged&lt;/li&gt;
&lt;li&gt;what conventions your team has decided to keep&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the AI does not know that context, it can still sound smart while being operationally wrong.&lt;/p&gt;

&lt;p&gt;That is exactly the kind of failure Workspai is trying to reduce for backend teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the workspace-based model changes for users
&lt;/h2&gt;

&lt;p&gt;From the user side, the value is simple: instead of re-explaining your backend every time you ask AI for help, the product already understands the surrounding system.&lt;/p&gt;

&lt;p&gt;The easiest way to see that is to walk through the feature surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The non-AI workspace platform features
&lt;/h2&gt;

&lt;p&gt;These are the features that make the workspace itself actionable inside VS Code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workspace Explorer
&lt;/h3&gt;

&lt;p&gt;The dedicated sidebar tree is the structural backbone of the extension. It exposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workspaces&lt;/li&gt;
&lt;li&gt;projects&lt;/li&gt;
&lt;li&gt;RapidKit modules&lt;/li&gt;
&lt;li&gt;quick actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because Workspai understands the workspace hierarchy, users do not have to jump between terminal commands, file explorers, and docs just to stay oriented.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Scaffolding
&lt;/h3&gt;

&lt;p&gt;Workspai supports one-command project creation for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FastAPI&lt;/li&gt;
&lt;li&gt;NestJS&lt;/li&gt;
&lt;li&gt;Spring Boot&lt;/li&gt;
&lt;li&gt;Go/Fiber&lt;/li&gt;
&lt;li&gt;Go/Gin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That matters because the generated structure becomes part of the AI context later.&lt;/p&gt;

&lt;p&gt;On the runtime side, the broader RapidKit stack now also supports Java-oriented workspace profiles such as &lt;code&gt;java-only&lt;/code&gt;, plus polyglot workspaces that include Java alongside Python, Node, and Go. That makes the workspace model even more important, because once a backend team is working across runtimes, file-level AI loses context even faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Module System
&lt;/h3&gt;

&lt;p&gt;Workspai exposes the RapidKit module system directly in the IDE, so users can browse and manage modules in a workspace-aware way instead of treating dependencies as disconnected package installs.&lt;/p&gt;

&lt;p&gt;The current surface highlights 100+ RapidKit modules, with examples like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auth_core&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;db_postgres&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stripe_payment&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a major architectural advantage because AI advice can be grounded in the real module ecosystem that the workspace already uses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Health Doctor
&lt;/h3&gt;

&lt;p&gt;The doctor feature checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;environment variables&lt;/li&gt;
&lt;li&gt;dependencies&lt;/li&gt;
&lt;li&gt;port conflicts&lt;/li&gt;
&lt;li&gt;kit configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because backend AI should not operate blind to system health.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dev Server Control
&lt;/h3&gt;

&lt;p&gt;Start, stop, and restart backend dev servers directly from the VS Code sidebar.&lt;/p&gt;

&lt;p&gt;This keeps operational state inside the same product surface that AI features rely on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workspace Dashboard
&lt;/h3&gt;

&lt;p&gt;The dashboard acts as the single pane of glass for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;project tree&lt;/li&gt;
&lt;li&gt;health status&lt;/li&gt;
&lt;li&gt;module inventory&lt;/li&gt;
&lt;li&gt;AI launch points&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where the workspace-based model becomes visible to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The current AI feature surface
&lt;/h2&gt;

&lt;p&gt;The AI side of Workspai only works because it sits on top of the workspace platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Create
&lt;/h3&gt;

&lt;p&gt;AI Create starts from product intent in plain language.&lt;/p&gt;

&lt;p&gt;Example prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Build a SaaS billing API with auth, Stripe, and Postgres&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From there, Workspai proposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workspace direction&lt;/li&gt;
&lt;li&gt;project kit&lt;/li&gt;
&lt;li&gt;likely modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That only works well when the product treats generation as a workspace problem, not just a code snippet problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Assistant
&lt;/h3&gt;

&lt;p&gt;This is context-aware Q&amp;amp;A grounded in the actual project files, modules, and architecture.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What breaks if I change this settings model?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The important part is that it answers in relation to the workspace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workspace Brain
&lt;/h3&gt;

&lt;p&gt;AI appears inline on every item in the workspace explorer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workspaces&lt;/li&gt;
&lt;li&gt;projects&lt;/li&gt;
&lt;li&gt;modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a very specific product choice. It means AI is embedded inside the structure of the backend system, not floating outside it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;@workspai&lt;/code&gt; in Chat
&lt;/h3&gt;

&lt;p&gt;The native VS Code Chat participant exposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/ask&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/debug&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;@workspai /debug Why does this endpoint return 500?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The chat surface becomes more useful because the product already knows the project context behind the question.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Debug Actions
&lt;/h3&gt;

&lt;p&gt;The editor lightbulb gives contextual AI debugging directly on files with issues.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why does this endpoint return 422 Unprocessable Entity?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This works better than generic debugging chat because the action starts from the local error and the broader workspace at the same time.&lt;/p&gt;

&lt;p&gt;The same idea matters for Java teams too. If part of your backend runs on Spring Boot, you still want debugging help to start from the real workspace context instead of a detached code sample or pasted error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Doctor Fix with AI
&lt;/h3&gt;

&lt;p&gt;Each health issue can open a context-rich AI fix flow.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fix missing environment variable in billing-platform&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is useful because it is anchored to an issue the workspace doctor already found.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix Preview Lite
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Preview the safest fix for this 500 error&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This matters because backend teams need inspectable actions, not blind mutations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change Impact Lite
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I change this auth middleware, what might break?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This treats the codebase as an interconnected workspace where changes have operational impact beyond one file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terminal → AI Bridge
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Analyze this pytest failure and suggest the fastest safe fix&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Terminal output without workspace context is noisy. With workspace context, it becomes much more actionable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workspace Memory
&lt;/h3&gt;

&lt;p&gt;Teams can write conventions into &lt;code&gt;.rapidkit/workspace-memory.json&lt;/code&gt; and have them injected into every AI prompt.&lt;/p&gt;

&lt;p&gt;Example memory:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Always use async SQLAlchemy and avoid sync session in routes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is one of the strongest reasons the workspace model matters: AI becomes cumulative instead of stateless.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory Wizard
&lt;/h3&gt;

&lt;p&gt;The wizard helps capture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;project overview&lt;/li&gt;
&lt;li&gt;conventions&lt;/li&gt;
&lt;li&gt;architecture decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That lowers the cost of making the workspace smarter over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Recipe Packs
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Run ship-readiness recipe for this workspace&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Recipe Packs make more sense in a workspace product than in a generic assistant, because they can assume a richer backend context and a repeatable operational flow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Module Advisor
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do I wire up db_postgres with auth_core?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI is not just answering abstract backend questions. It is guiding users through the real module system that exists in the workspace.&lt;/p&gt;

&lt;p&gt;For mixed-runtime teams, that matters even more. Once you have Python, Node, Go, and Java services inside one operational environment, the workspace becomes the only reliable context boundary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Telemetry Insights
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Show telemetry summary for the last 7 days&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Telemetry helps the team understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which AI actions are used&lt;/li&gt;
&lt;li&gt;which onboarding flows convert&lt;/li&gt;
&lt;li&gt;what becomes habit vs novelty&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is part of the model too. A workspace-based AI product needs evidence about how the actions are actually used.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The upcoming Pro and Team layer
&lt;/h2&gt;

&lt;p&gt;The roadmap also follows the same logic. These are not random upsells. They are natural extensions of the workspace-based model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Module Generator (Pro)
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add OTP login with Redis rate limiting and tests&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a multi-file, multi-concern operation that only works safely if the system understands project structure and module relationships.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Debugger (Advanced) (Pro)
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why is this endpoint returning 500 in staging?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Advanced debugging becomes much more valuable when it is grounded in the workspace rather than limited to pasted logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Generator (Pro)
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generate tests for the booking cancellation endpoint&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Test generation depends on understanding workspace boundaries and project conventions.&lt;/p&gt;

&lt;h3&gt;
  
  
  DevOps Assistant (Pro)
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generate a production-ready Compose file for this API&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is workspace-aware operations and environment design, not just code generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture Advisor (Pro)
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How should I scale this service for 10x traffic?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Architecture guidance without workspace context is generic. With it, guidance becomes much more useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Team AI Memory (Team)
&lt;/h3&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enforce our naming conventions across all new modules&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This extends the current Workspace Memory model from one workspace to a shared team layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why backend teams need this architecture, not just better prompts
&lt;/h2&gt;

&lt;p&gt;There are three reasons backend users benefit from this model.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Less context re-explaining
&lt;/h3&gt;

&lt;p&gt;Without the workspace as the core unit, users still have to manually restate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what stack they are using&lt;/li&gt;
&lt;li&gt;what modules are installed&lt;/li&gt;
&lt;li&gt;what conventions matter&lt;/li&gt;
&lt;li&gt;what the system health already says&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That repetition is one of the biggest taxes in AI-assisted backend work, and the workspace layer removes a big part of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Better backend-specific answers
&lt;/h3&gt;

&lt;p&gt;The model can only be as grounded as the context it receives.&lt;/p&gt;

&lt;p&gt;File-level AI misses too much backend reality. Workspace-level AI is not perfect, but it removes a large class of generic or contradictory responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. More trust in real workflows
&lt;/h3&gt;

&lt;p&gt;Backend teams need more than helpful answers. They need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bounded actions&lt;/li&gt;
&lt;li&gt;previews&lt;/li&gt;
&lt;li&gt;health-aware reasoning&lt;/li&gt;
&lt;li&gt;operational context&lt;/li&gt;
&lt;li&gt;team memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are user workflow problems as much as AI problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Backend teams need a workspace-based AI layer because backend development itself is workspace-shaped.&lt;/p&gt;

&lt;p&gt;The product has to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the system structure&lt;/li&gt;
&lt;li&gt;the module ecosystem&lt;/li&gt;
&lt;li&gt;the operational state&lt;/li&gt;
&lt;li&gt;the memory of past decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That becomes even more true as Java and Spring Boot enter the same ecosystem. The moment backend teams start mixing FastAPI, NestJS, Spring Boot, Go/Fiber, and Go/Gin across one working environment, the workspace stops being a convenience and becomes the only context boundary that actually matches how the system is built.&lt;/p&gt;

&lt;p&gt;That is what allows project scaffolding, module operations, health checks, AI assistance, debugging, preview flows, telemetry, and future pro features to feel useful in one connected workflow.&lt;/p&gt;

&lt;p&gt;The AI workspace for backend teams.&lt;/p&gt;

&lt;p&gt;Build backend systems with AI that knows your workspace.&lt;/p&gt;

&lt;p&gt;If you are using AI for backend development, the question is not just how smart the model is.&lt;/p&gt;

&lt;p&gt;It is this:&lt;/p&gt;

&lt;p&gt;What is the real unit of context your product is built around?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>backend</category>
      <category>vscode</category>
      <category>workspai</category>
    </item>
    <item>
      <title>Backend AI Needs an Action Surface, Not Just a Chat Box</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Thu, 23 Apr 2026 21:39:12 +0000</pubDate>
      <link>https://dev.to/rapidkit/backend-ai-needs-an-action-surface-not-just-a-chat-box-40h4</link>
      <guid>https://dev.to/rapidkit/backend-ai-needs-an-action-surface-not-just-a-chat-box-40h4</guid>
      <description>&lt;p&gt;Most AI developer tooling still assumes the main interface should be a chat box.&lt;/p&gt;

&lt;p&gt;That makes sense for open-ended questions. It makes less sense for day-to-day backend work.&lt;/p&gt;

&lt;p&gt;Backend workflows usually do not begin with a blank prompt. They begin with a broken startup command, a noisy terminal, a health check issue, a confusing project tree, a module decision, or a team convention that the AI does not know yet.&lt;/p&gt;

&lt;p&gt;That is why the latest Workspai release matters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.workspai.com/" rel="noopener noreferrer"&gt;Workspai&lt;/a&gt; v0.21.0 is not just a list of new commands. It is a step toward a different model for AI in VS Code: not just chat, but a workspace-aware action surface for backend teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with chat-first AI in backend work
&lt;/h2&gt;

&lt;p&gt;If an AI tool only waits in one prompt box, the user still has to do the routing.&lt;/p&gt;

&lt;p&gt;They have to decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what context matters&lt;/li&gt;
&lt;li&gt;what the right question is&lt;/li&gt;
&lt;li&gt;what file or output to paste&lt;/li&gt;
&lt;li&gt;what action should happen next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is friction.&lt;/p&gt;

&lt;p&gt;It gets worse in backend projects because the useful context usually lives outside the current file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;project structure&lt;/li&gt;
&lt;li&gt;installed modules&lt;/li&gt;
&lt;li&gt;framework conventions&lt;/li&gt;
&lt;li&gt;runtime state&lt;/li&gt;
&lt;li&gt;workspace health&lt;/li&gt;
&lt;li&gt;recent changes&lt;/li&gt;
&lt;li&gt;team decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even when the model is strong, the workflow is weak if everything has to pass through a generic prompt box.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed in &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;Workspai&lt;/a&gt; v0.21.0
&lt;/h2&gt;

&lt;p&gt;The new release expands the AI action surface across the command palette, sidebar actions, and quick-action views.&lt;/p&gt;

&lt;p&gt;The new flows include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI Quick Actions&lt;/li&gt;
&lt;li&gt;Smart Route&lt;/li&gt;
&lt;li&gt;Fix Preview Lite&lt;/li&gt;
&lt;li&gt;Change Impact Lite&lt;/li&gt;
&lt;li&gt;Analyze Terminal Output with AI&lt;/li&gt;
&lt;li&gt;Guided Workspace Memory Setup&lt;/li&gt;
&lt;li&gt;AI Recipe Packs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This changes the shape of the product.&lt;/p&gt;

&lt;p&gt;Instead of asking the user to translate every problem into a freeform prompt, the extension increasingly exposes backend-specific AI actions in the exact places where the problem already exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why small AI actions matter
&lt;/h2&gt;

&lt;p&gt;Each of these actions solves a different kind of backend friction.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Terminal Output Analysis
&lt;/h3&gt;

&lt;p&gt;Terminal output is one of the worst places to manually transfer context into AI.&lt;/p&gt;

&lt;p&gt;You run a command, get a wall of text, then copy the relevant part into another tool and explain what project you are in.&lt;/p&gt;

&lt;p&gt;If the AI already knows the workspace, terminal analysis becomes much more useful. The output is not interpreted in isolation. It is interpreted against the actual backend project it came from.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fix Preview Lite
&lt;/h3&gt;

&lt;p&gt;One reason teams hesitate to use more AI in backend workflows is trust.&lt;/p&gt;

&lt;p&gt;They do not want a tool that jumps straight from suggestion to mutation.&lt;/p&gt;

&lt;p&gt;Fix Preview Lite moves in a safer direction. It treats the AI as a planning and preview layer first. That is a much better fit for real engineering workflows than magic auto-apply behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Change Impact Lite
&lt;/h3&gt;

&lt;p&gt;Backend changes are rarely local. Even a small edit can have downstream effects across routing, modules, services, or startup flows.&lt;/p&gt;

&lt;p&gt;An AI tool that helps users reason about likely impact before they change code is more valuable than one that only answers after the fact.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Smart Route
&lt;/h3&gt;

&lt;p&gt;Sometimes the problem is not generating code. It is getting to the right place to act.&lt;/p&gt;

&lt;p&gt;Routing is one of the most underrated uses of workspace-aware AI. If the tool understands the project shape, it should be able to direct the user toward the right file, action, or flow without forcing them to search blindly.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Workspace Memory Wizard
&lt;/h3&gt;

&lt;p&gt;One of the biggest recurring costs in AI-assisted development is repeating team context.&lt;/p&gt;

&lt;p&gt;What architecture does this team use?&lt;br&gt;
What naming rules matter?&lt;br&gt;
What decisions have already been made?&lt;/p&gt;

&lt;p&gt;The workspace memory wizard matters because it makes that context easier to capture and reuse. This is how AI moves from session memory to workspace memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Recipe Packs
&lt;/h3&gt;

&lt;p&gt;Recipe Packs push the product further toward guided workflows.&lt;/p&gt;

&lt;p&gt;That matters because backend teams do not always want a blank canvas. Sometimes they want a known sequence of steps shaped around a recurring task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Telemetry is not just analytics vanity
&lt;/h2&gt;

&lt;p&gt;Another important part of v0.21.0 is the telemetry layer.&lt;/p&gt;

&lt;p&gt;The release adds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;telemetry summaries&lt;/li&gt;
&lt;li&gt;onboarding experiment stats&lt;/li&gt;
&lt;li&gt;structured success, error, and cancel outcomes for key AI surfaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In AI products, telemetry is often treated like growth reporting.&lt;/p&gt;

&lt;p&gt;But for a tool like Workspai, telemetry is also product learning.&lt;/p&gt;

&lt;p&gt;If you are expanding the AI action surface, you need to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which actions people actually use&lt;/li&gt;
&lt;li&gt;where they drop off&lt;/li&gt;
&lt;li&gt;what onboarding path leads to repeat usage&lt;/li&gt;
&lt;li&gt;which surfaces are noisy and which become habitual&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is especially important for backend AI because the winning interface probably will not be one monolithic surface. It will be a set of context-aware actions that earn their place in the workflow over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability work matters as much as visible features
&lt;/h2&gt;

&lt;p&gt;The release also fixes three less glamorous but more important issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;doctor metadata fetch safety&lt;/li&gt;
&lt;li&gt;bounded port probing for dev startup&lt;/li&gt;
&lt;li&gt;startup race conditions around workspace path initialization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because backend teams will not trust AI features if the surrounding runtime is fragile.&lt;/p&gt;

&lt;p&gt;Reliable scaffolding, stable startup flows, predictable health checks, and safe network behavior are part of the product, not separate from it.&lt;/p&gt;

&lt;p&gt;If Workspai is positioning itself as the AI workspace for backend teams, the trust layer cannot be optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger product direction
&lt;/h2&gt;

&lt;p&gt;The most important thing about v0.21.0 is not any one command.&lt;/p&gt;

&lt;p&gt;It is the direction it reveals.&lt;/p&gt;

&lt;p&gt;Workspai is moving beyond "AI chat in the editor" toward a workspace-aware backend operating layer inside VS Code.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more actions that begin from real workspace context&lt;/li&gt;
&lt;li&gt;more inspectable AI behavior&lt;/li&gt;
&lt;li&gt;more telemetry to understand which actions become useful habits&lt;/li&gt;
&lt;li&gt;more runtime hardening so the product feels dependable under daily use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a better direction for backend AI than simply adding more prompt surfaces.&lt;/p&gt;

&lt;p&gt;Backend teams do not just need AI that can answer.&lt;/p&gt;

&lt;p&gt;They need AI that can show up in the right place, with the right context, in the right form.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;If AI is going to become part of real backend workflows, it needs more than a better model and a nicer prompt box.&lt;/p&gt;

&lt;p&gt;It needs a better action surface.&lt;/p&gt;

&lt;p&gt;That is what Workspai v0.21.0 pushes forward.&lt;/p&gt;

&lt;p&gt;The AI workspace for backend teams.&lt;/p&gt;

&lt;p&gt;Build backend systems with AI that knows your workspace.&lt;/p&gt;

&lt;p&gt;If you use AI in backend work, what would you want one click away first: terminal analysis, fix preview, change impact, routing, or something else?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>workspai</category>
      <category>vscode</category>
      <category>backend</category>
    </item>
    <item>
      <title>AI Coding Tools Have a Context Problem — Here's the Fix</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Tue, 21 Apr 2026 08:11:47 +0000</pubDate>
      <link>https://dev.to/rapidkit/ai-coding-tools-have-a-context-problem-heres-the-fix-167i</link>
      <guid>https://dev.to/rapidkit/ai-coding-tools-have-a-context-problem-heres-the-fix-167i</guid>
      <description>&lt;h2&gt;
  
  
  The Wrong Unit of Context
&lt;/h2&gt;

&lt;p&gt;Most AI coding tools work at the &lt;strong&gt;file level&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's fine for a React component. A component is self-contained — the context needed to help you fits in the file.&lt;/p&gt;

&lt;p&gt;Backend services aren't self-contained. They live inside environments. They share infrastructure. They depend on modules installed at the workspace level.&lt;/p&gt;

&lt;p&gt;This is why AI backend debugging suggestions are often... almost right. They're missing environment context.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Backend AI Actually Needs
&lt;/h2&gt;

&lt;p&gt;Take this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A file-level AI tells you: Redis isn't running.&lt;/p&gt;

&lt;p&gt;A workspace-aware AI knows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have &lt;code&gt;redis-cache&lt;/code&gt; module installed in &lt;code&gt;auth-api&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Your Workspace Health check already flagged this&lt;/li&gt;
&lt;li&gt;You're using Docker Compose conventions (RapidKit workspace)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second answer is specific. The first is a starting point you still have to work from.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Workspace as Context Unit
&lt;/h2&gt;

&lt;p&gt;In Workspai, when AI responds to a debug action, it receives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"project"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auth-api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fastapi.standard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"modules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jwt-auth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redis-cache"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.12.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"health_warnings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Redis not reachable at localhost:6379"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ConnectionRefusedError at line 89"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not file contents. A structured workspace snapshot. The response is grounded from the first message.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the Workspace Format Matters
&lt;/h2&gt;

&lt;p&gt;This only works because &lt;strong&gt;RapidKit defines a structured workspace format&lt;/strong&gt;. It knows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which projects exist and what type they are&lt;/li&gt;
&lt;li&gt;Which modules are installed at each project&lt;/li&gt;
&lt;li&gt;The runtime version&lt;/li&gt;
&lt;li&gt;The current health state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this structure, you'd have to infer context from file contents — slow, unreliable, incomplete.&lt;/p&gt;

&lt;p&gt;With it, context assembly is deterministic. The AI starts informed.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Available Now (v0.20)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@workspai&lt;/code&gt; Chat Participant&lt;/strong&gt; — use &lt;code&gt;@workspai /ask&lt;/code&gt; for full-context Q&amp;amp;A scoped to your active project, or &lt;code&gt;@workspai /debug&lt;/code&gt; for structured root-cause + fix + prevention, directly in the VS Code Chat panel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Create with presets&lt;/strong&gt; — describe a project in plain language (or pick a smart preset), and AI plans the workspace, picks a kit, and selects modules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Debug Actions&lt;/strong&gt; — lightbulb in Python/TS/JS/Go files with workspace-aware context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doctor Fix with AI&lt;/strong&gt; — one-click AI resolution for workspace health issues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module Advisor&lt;/strong&gt; — compatible module suggestions based on what you're building&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workspace Memory&lt;/strong&gt; — persistent AI context scoped to the workspace, carried across sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All on top of the existing RapidKit workspace platform. No changes to CLI, kits, or modules.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;The teams that establish workspace structure now will leverage AI more effectively as the tools improve. Workspace-aware AI will become the baseline expectation — the file level will feel like working blind.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://www.workspai.com/" rel="noopener noreferrer"&gt;workspai.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;Workspai — VS Code Marketplace&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://getrapidkit.com" rel="noopener noreferrer"&gt;getrapidkit.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>workspai</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Stop Copy-Pasting Errors into ChatGPT — Use AI That Knows Your Backend Stack</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Sat, 18 Apr 2026 08:53:21 +0000</pubDate>
      <link>https://dev.to/rapidkit/stop-copy-pasting-errors-into-chatgpt-use-ai-that-knows-your-backend-stack-3fp0</link>
      <guid>https://dev.to/rapidkit/stop-copy-pasting-errors-into-chatgpt-use-ai-that-knows-your-backend-stack-3fp0</guid>
      <description>&lt;p&gt;Workspai's AI Debug Actions feed structured workspace context to the language model — project type, installed modules, Python version, health status. The result: debugging suggestions that actually apply to your setup.&lt;/p&gt;

&lt;p&gt;You know the loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Error appears in FastAPI service
2. Open ChatGPT/Claude/Copilot Chat
3. Paste traceback
4. Type: "I'm using FastAPI 0.115, Python 3.12, SQLAlchemy 2.0, 
         repository pattern, RapidKit workspace..."
5. Get generic answer
6. Iterate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Steps 3-4 are manual reconstruction of context your IDE already has.&lt;/p&gt;

&lt;p&gt;Here's how we closed that loop in &lt;strong&gt;Workspai&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the AI Actually Receives
&lt;/h2&gt;

&lt;p&gt;When you click a debug action on a diagnostic error, Workspai sends this to the language model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"project_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fastapi.standard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"python_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.12.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"installed_modules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jwt-auth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redis-cache"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rapidkit_cli_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.25.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rapidkit_core_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.3.9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AttributeError: 'NoneType' object ..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/users/services/user_service.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"line"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"workspace_health"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warning: Redis not running"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not raw text. Structured context. The model's first response is already grounded in your setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two Editor Surfaces
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;In any Python, TypeScript, JavaScript, or Go file with diagnostics:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Click the lightbulb → you'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;✦ Debug with Workspai AI&lt;/strong&gt; — opens AI modal with error + full workspace context pre-filled&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;✦ Explain error with AI&lt;/strong&gt; — plain-language explanation tailored to your stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both appear in the standard VS Code Code Actions menu — no new panel, no context switch.&lt;/p&gt;




&lt;h2&gt;
  
  
  Doctor Fix with AI
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Workspace Health&lt;/strong&gt; sidebar runs a system check. When it finds an issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;⚠️ &lt;span class="n"&gt;Redis&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;reachable&lt;/span&gt;
&lt;span class="n"&gt;Module&lt;/span&gt;: &lt;span class="n"&gt;redis&lt;/span&gt;-&lt;span class="n"&gt;cache&lt;/span&gt; (&lt;span class="n"&gt;installed&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;-&lt;span class="n"&gt;api&lt;/span&gt;)
&lt;span class="n"&gt;Expected&lt;/span&gt;: &lt;span class="n"&gt;localhost&lt;/span&gt;:&lt;span class="m"&gt;6379&lt;/span&gt;
&lt;span class="n"&gt;Status&lt;/span&gt;: &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="n"&gt;refused&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's now a ✨ button. Click it. The AI gets the full failure context — module name, expected config, error type — and tells you exactly how to fix it for your specific workspace setup.&lt;/p&gt;

&lt;p&gt;No more: Google → StackOverflow → "does this apply to me?" → iterate.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tech
&lt;/h2&gt;

&lt;p&gt;Uses &lt;strong&gt;GitHub Copilot's &lt;code&gt;vscode.lm&lt;/code&gt; API&lt;/strong&gt; locally. No separate key. No data beyond what Copilot normally sends. Configurable model (modern Copilot/GitHub lineup, including GPT-5 family, GPT-4.1/4o, and Claude Sonnet family, depending on account access).&lt;/p&gt;




&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;Search &lt;code&gt;Workspai&lt;/code&gt; in VS Code Extensions.&lt;br&gt;&lt;br&gt;
Publisher: &lt;code&gt;rapidkit&lt;/code&gt; | Requires GitHub Copilot.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://www.workspai.com/" rel="noopener noreferrer"&gt;workspai.com&lt;/a&gt; · &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;Marketplace&lt;/a&gt; · &lt;a href="https://github.com/getrapidkit/rapidkit-vscode" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://getrapidkit.com" rel="noopener noreferrer"&gt;getrapidkit.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>vscode</category>
      <category>workspai</category>
      <category>debugging</category>
    </item>
    <item>
      <title>We Rebuilt Our VS Code Extension with AI — Meet Workspai</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Fri, 17 Apr 2026 16:23:25 +0000</pubDate>
      <link>https://dev.to/rapidkit/we-rebuilt-our-vs-code-extension-with-ai-meet-workspai-347i</link>
      <guid>https://dev.to/rapidkit/we-rebuilt-our-vs-code-extension-with-ai-meet-workspai-347i</guid>
      <description>&lt;h2&gt;
  
  
  The Problem with Generic AI Assistants
&lt;/h2&gt;

&lt;p&gt;Every AI tool I've used in the past year has the same blind spot:&lt;/p&gt;

&lt;p&gt;It doesn't know what I'm building.&lt;/p&gt;

&lt;p&gt;Ask GitHub Copilot to help debug a FastAPI error and it gives you a correct-but-generic answer. It doesn't know you're running inside a RapidKit workspace. It doesn't know which modules you've installed. It doesn't know your project uses DDD architecture.&lt;/p&gt;

&lt;p&gt;You end up spending as much time explaining context as you save generating code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's what we wanted to fix.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Workspai?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Workspai&lt;/strong&gt; is the AI-powered VS Code extension built on top of &lt;a href="https://getrapidkit.com" rel="noopener noreferrer"&gt;RapidKit&lt;/a&gt; — the open-source workspace platform for backend development. Learn more at &lt;a href="https://www.workspai.com/" rel="noopener noreferrer"&gt;workspai.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Think of it as: your workspace knows everything about your backend setup, and the AI taps into that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Four AI Features That Use Your Workspace Context
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✦ AI Create
&lt;/h3&gt;

&lt;p&gt;Describe a project in plain language. Workspai selects the right kit, suggests relevant modules, pre-fills configuration. Works for FastAPI, NestJS, Go.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"A FastAPI authentication service with JWT, Redis sessions, and email verification"
→ Kit: fastapi.standard
→ Suggested modules: jwt-auth, redis-cache, email-smtp
→ Project scaffolded with modules pre-selected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✦ AI Debug Actions
&lt;/h3&gt;

&lt;p&gt;See a diagnostic error in your Python/TypeScript/Go file? The lightbulb now includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;✦ Debug with Workspai AI&lt;/strong&gt; — pre-fills the error + workspace context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;✦ Explain error with AI&lt;/strong&gt; — plain language explanation with fix suggestions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference: it knows you're on FastAPI 0.115 in a RapidKit workspace on Python 3.12. The fix it gives you actually applies.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✦ Doctor Fix with AI
&lt;/h3&gt;

&lt;p&gt;The Workspace Health sidebar runs a system check. When it finds an issue, a ✨ button appears next to it.&lt;/p&gt;

&lt;p&gt;Click → AI gets the full issue context → suggests exact fix steps.&lt;/p&gt;

&lt;p&gt;No more copy-pasting error messages into ChatGPT.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✦ Module Advisor
&lt;/h3&gt;

&lt;p&gt;When creating a project, describe what you're building. Workspai suggests which modules fit your stack, which are compatible, which are already installed elsewhere in your workspace.&lt;/p&gt;




&lt;h2&gt;
  
  
  Under the Hood
&lt;/h2&gt;

&lt;p&gt;Uses &lt;strong&gt;GitHub Copilot's local language model API&lt;/strong&gt; (&lt;code&gt;vscode.lm&lt;/code&gt;). No separate API key. No data beyond what Copilot normally sends. Works with GPT-4o, Claude Sonnet, or whatever model you have access to.&lt;/p&gt;

&lt;p&gt;The AI receives structured workspace context plus targeted file excerpts. Project types, installed modules, health status, selected errors, and key entry files. Focused, not noisy.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Stayed Unchanged
&lt;/h2&gt;

&lt;p&gt;RapidKit's workspace platform is exactly the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx rapidkit create workspace my-backend
&lt;span class="nb"&gt;cd &lt;/span&gt;my-backend
npx rapidkit create project fastapi.standard auth-api
npx rapidkit create project nestjs.standard notifications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All kits. All modules. All CLI commands. Unchanged.&lt;/p&gt;

&lt;p&gt;Workspai is a product layer built on top — specifically for VS Code users who want the AI layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;Search &lt;code&gt;Workspai&lt;/code&gt; in VS Code Extensions, or:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Publisher:&lt;/strong&gt; &lt;code&gt;rapidkit&lt;/code&gt; · &lt;strong&gt;Extension ID:&lt;/strong&gt; &lt;code&gt;rapidkit.rapidkit-vscode&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Requires GitHub Copilot for AI features.&lt;/p&gt;




&lt;p&gt;🔗 &lt;a href="https://www.workspai.com/" rel="noopener noreferrer"&gt;workspai.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;VS Code Marketplace&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://getrapidkit.com" rel="noopener noreferrer"&gt;getrapidkit.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 &lt;a href="https://github.com/getrapidkit/rapidkit-vscode" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rapidkit</category>
      <category>workspai</category>
      <category>ai</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Stop Managing 10 Virtual Environments. Use a Workspace.</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Sat, 21 Feb 2026 07:56:28 +0000</pubDate>
      <link>https://dev.to/rapidkit/stop-managing-10-virtual-environments-use-a-workspace-49gk</link>
      <guid>https://dev.to/rapidkit/stop-managing-10-virtual-environments-use-a-workspace-49gk</guid>
      <description>&lt;p&gt;How RapidKit's workspace architecture eliminates environment drift, cuts setup time to minutes, and lets you manage FastAPI, NestJS, and Go services from a single shared environment.&lt;/p&gt;

&lt;p&gt;I used to manage backend projects like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/projects/
  auth-api/       ← Python 3.10, venv, poetry
  billing-api/    ← Python 3.11, venv, pip
  user-service/   ← Python 3.10, venv, poetry (different poetry version)
  ai-agent/       ← Python 3.11, conda (someone on the team liked conda)
  notifications/  ← NestJS (fine, no env problem here)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every project had its own environment. Every new service meant 20–30 minutes of setup. Every &lt;code&gt;git clone&lt;/code&gt; from a teammate ended in "it works on my machine."&lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fix: Shared Workspace Environment
&lt;/h2&gt;

&lt;p&gt;The concept is simple: &lt;strong&gt;one environment hosts multiple services.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-workspace/
├── .venv/                  ← shared Python env (~150 MB, once)
├── pyproject.toml          ← shared dependency config
├── .rapidkit-workspace     ← workspace marker
├── auth-api/               ← FastAPI project
├── billing-api/            ← FastAPI DDD project  
├── notifications/          ← NestJS project
└── ai-agent/               ← FastAPI + AI module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All services share the same Python version, the same virtualenv, the same tooling. But each service is independently deployable with its own &lt;code&gt;Dockerfile&lt;/code&gt;, &lt;code&gt;pyproject.toml&lt;/code&gt;, and CI pipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  From Zero to Multi-Service Backend
&lt;/h2&gt;

&lt;p&gt;Here's how fast this actually is with &lt;a href="https://getrapidkit.com" rel="noopener noreferrer"&gt;RapidKit&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Create the workspace&lt;/span&gt;
npx rapidkit create workspace my-workspace
&lt;span class="nb"&gt;cd &lt;/span&gt;my-workspace

&lt;span class="c"&gt;# 2. Scaffold services (pick your kits)&lt;/span&gt;
npx rapidkit create project fastapi.standard auth-api
npx rapidkit create project fastapi.ddd billing-api
npx rapidkit create project nestjs.standard notifications
npx rapidkit create project gofiber.standard high-perf-proxy

&lt;span class="c"&gt;# 3. Init all services at once (from workspace root)&lt;/span&gt;
npx rapidkit init

&lt;span class="c"&gt;# 4. Check everything&lt;/span&gt;
npx rapidkit doctor &lt;span class="nt"&gt;--workspace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last command gives you this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📊 Health Score:
   100% ████████████████████
   ✅ 12 passed | ⚠️ 0 warnings | ❌ 0 errors

System Tools:
✅ Python: Python 3.11.8
✅ Poetry: Poetry 2.3.1
✅ Go: Go 1.24.4
✅ RapidKit Core: 0.3.8

Projects:
✅ auth-api          FastAPI Standard  | Tests ✅ | Docker ✅ | Deps ✅
✅ billing-api       FastAPI DDD       | Tests ✅ | Docker ✅ | Deps ✅
✅ notifications     NestJS Standard   | Tests ✅ | Docker ✅ | Deps ✅
✅ high-perf-proxy   Go/Fiber Standard | Tests ✅ | Docker ✅ | Deps ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command. Full workspace health report.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Each Scaffolded Project Includes
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;rapidkit create project&lt;/code&gt; gives you a production-ready base:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;FastAPI Standard&lt;/th&gt;
&lt;th&gt;FastAPI DDD&lt;/th&gt;
&lt;th&gt;NestJS Standard&lt;/th&gt;
&lt;th&gt;Go/Fiber Standard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Clean Architecture&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ DDD layers&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker + Compose&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ multi-stage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions CI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;✅ pytest&lt;/td&gt;
&lt;td&gt;✅ pytest&lt;/td&gt;
&lt;td&gt;✅ Jest&lt;/td&gt;
&lt;td&gt;✅ Go test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linting&lt;/td&gt;
&lt;td&gt;✅ ruff&lt;/td&gt;
&lt;td&gt;✅ ruff&lt;/td&gt;
&lt;td&gt;✅ ESLint&lt;/td&gt;
&lt;td&gt;✅ golangci-lint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.env handling&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health endpoint&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Makefile&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Zero config. All baked in.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Module System: Composable Features
&lt;/h2&gt;

&lt;p&gt;Once your project exists, add features with one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;auth-api
rapidkit add module auth          &lt;span class="c"&gt;# JWT/session auth&lt;/span&gt;
rapidkit add module db_postgres   &lt;span class="c"&gt;# async SQLAlchemy + Alembic&lt;/span&gt;
rapidkit add module redis         &lt;span class="c"&gt;# caching layer&lt;/span&gt;
rapidkit add module rate_limiting &lt;span class="c"&gt;# route-level rate limits&lt;/span&gt;
rapidkit add module observability &lt;span class="c"&gt;# Prometheus metrics + tracing&lt;/span&gt;

&lt;span class="nb"&gt;cd &lt;/span&gt;billing-api
rapidkit add module auth          &lt;span class="c"&gt;# same auth module, same interface&lt;/span&gt;
rapidkit add module stripe        &lt;span class="c"&gt;# Stripe webhooks + billing logic&lt;/span&gt;

&lt;span class="nb"&gt;cd &lt;/span&gt;ai-agent
rapidkit add module ai_assistant  &lt;span class="c"&gt;# multi-provider AI (OpenAI, local)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;27+ modules available.&lt;/strong&gt; Each module:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adds pre-configured code in the right layers&lt;/li&gt;
&lt;li&gt;Updates &lt;code&gt;pyproject.toml&lt;/code&gt; / &lt;code&gt;package.json&lt;/code&gt; automatically&lt;/li&gt;
&lt;li&gt;Includes tests&lt;/li&gt;
&lt;li&gt;Follows the same clean architecture conventions&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Live Example: AI Workspace
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;my-ai-workspace&lt;/code&gt; in &lt;a href="https://github.com/getrapidkit/rapidkit-examples" rel="noopener noreferrer"&gt;rapidkit-examples&lt;/a&gt; has two services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ai-agent&lt;/code&gt; — FastAPI with &lt;code&gt;ai_assistant&lt;/code&gt; module (multi-provider: OpenAI, echo, support)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ai-agent-nest&lt;/code&gt; — NestJS equivalent
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone and run the example&lt;/span&gt;
git clone https://github.com/getrapidkit/rapidkit-examples
&lt;span class="nb"&gt;cd &lt;/span&gt;rapidkit-examples/my-ai-workspace

&lt;span class="c"&gt;# One command to init everything&lt;/span&gt;
npx rapidkit init

&lt;span class="c"&gt;# Run the AI agent&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;ai-agent &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit dev

&lt;span class="c"&gt;# Test it&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:8000/ai/assistant/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"prompt": "What is RapidKit?", "provider": "echo"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Works without an OpenAI key — falls back to local providers automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  The VS Code Extension: Workspace Without the Terminal
&lt;/h2&gt;

&lt;p&gt;If CLI isn't your primary workflow, the &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;RapidKit VS Code Extension&lt;/a&gt; gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workspace Explorer tree&lt;/strong&gt; — all services visible at a glance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-click service creation&lt;/strong&gt; — no &lt;code&gt;npx&lt;/code&gt; needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module browser&lt;/strong&gt; — search, preview, install from the UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live health indicators&lt;/strong&gt; — real-time service status&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrated doctor output&lt;/strong&gt; — health checks without leaving the editor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open workspace folder → see all services → click to create/manage. That's it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters for Scaling
&lt;/h2&gt;

&lt;p&gt;The workspace model pays off exponentially as you grow:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Services&lt;/th&gt;
&lt;th&gt;Traditional (separate envs)&lt;/th&gt;
&lt;th&gt;Workspace&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;30 min setup&lt;/td&gt;
&lt;td&gt;2 min setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;90 min + env drift&lt;/td&gt;
&lt;td&gt;5 min, zero drift&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;150 min + conflict debugging&lt;/td&gt;
&lt;td&gt;8 min, single health check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Week of onboarding per engineer&lt;/td&gt;
&lt;td&gt;1 day onboarding for all services&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Onboarding a new engineer to the entire workspace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &amp;lt;workspace-repo&amp;gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;my-workspace
npx rapidkit init  &lt;span class="c"&gt;# installs shared env + all project deps&lt;/span&gt;
npx rapidkit doctor &lt;span class="nt"&gt;--workspace&lt;/span&gt;  &lt;span class="c"&gt;# ✅ everything green&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. One command. Full environment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workspace = one venv, many services&lt;/strong&gt; — no environment drift, consistent tooling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;npx rapidkit create project &amp;lt;kit&amp;gt; &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/strong&gt; — production-ready service in under 2 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;rapidkit add module &amp;lt;slug&amp;gt;&lt;/code&gt;&lt;/strong&gt; — features composed consistently across services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;npx rapidkit doctor --workspace&lt;/code&gt;&lt;/strong&gt; — full workspace health in one command&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supports FastAPI, FastAPI DDD, NestJS, Go/Fiber&lt;/strong&gt; — mixed-language workspaces supported&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VS Code Extension&lt;/strong&gt; — visual interface for the full workflow&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx rapidkit create workspace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;→ &lt;a href="https://getrapidkit.com" rel="noopener noreferrer"&gt;getrapidkit.com&lt;/a&gt;&lt;br&gt;
→ &lt;a href="https://github.com/getrapidkit/rapidkit-examples" rel="noopener noreferrer"&gt;Examples repo&lt;/a&gt;&lt;br&gt;
→ &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;VS Code Extension&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have you dealt with environment drift in a multi-service backend? What was your solution? Drop it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rapidkit</category>
      <category>devtools</category>
      <category>backend</category>
      <category>python</category>
    </item>
    <item>
      <title>Build a Production-Ready FastAPI E-Commerce API with RapidKit (Step-by-Step)</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Tue, 17 Feb 2026 07:44:56 +0000</pubDate>
      <link>https://dev.to/rapidkit/build-a-production-ready-fastapi-e-commerce-api-with-rapidkit-step-by-step-llm</link>
      <guid>https://dev.to/rapidkit/build-a-production-ready-fastapi-e-commerce-api-with-rapidkit-step-by-step-llm</guid>
      <description>&lt;h2&gt;
  
  
  Let's Build Something Real
&lt;/h2&gt;

&lt;p&gt;Not a hello-world demo. A &lt;strong&gt;real FastAPI project&lt;/strong&gt; you can deploy.&lt;/p&gt;

&lt;p&gt;We'll build a &lt;strong&gt;Product Management API&lt;/strong&gt; with:&lt;br&gt;
• Authentication&lt;br&gt;
• PostgreSQL database&lt;br&gt;
• Redis caching&lt;br&gt;
• Email notifications&lt;br&gt;
• Production deployment&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's begin.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Before We Begin: Three Ways to Create Projects
&lt;/h2&gt;
&lt;h3&gt;
  
  
  🎯 Approach 1: Workspace-First (Recommended)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx rapidkit my-workspace
&lt;span class="nb"&gt;cd &lt;/span&gt;my-workspace
rapidkit create project fastapi.standard product-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Teams, multiple services, production&lt;/p&gt;


&lt;h3&gt;
  
  
  🚀 Approach 2: Direct Project Creation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx rapidkit create project fastapi.standard product-api
&lt;span class="nb"&gt;cd &lt;/span&gt;product-api
npx rapidkit init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Single project, learning, prototyping&lt;/p&gt;


&lt;h3&gt;
  
  
  🎨 Approach 3: VS Code Extension
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install extension&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+Shift+P&lt;/code&gt; → "RapidKit: Create Project"&lt;/li&gt;
&lt;li&gt;Choose FastAPI&lt;/li&gt;
&lt;li&gt;Enter name&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Visual learners, GUI preference&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;We'll use Approach 1 (workspace)&lt;/strong&gt; for this tutorial.&lt;/p&gt;


&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You need:&lt;br&gt;
• Node.js 20+&lt;br&gt;
• Python 3.10+&lt;br&gt;
• Docker (for PostgreSQL/Redis)&lt;/p&gt;

&lt;p&gt;That's it. RapidKit handles the rest.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 1: Create Workspace and Project
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create workspace&lt;/span&gt;
npx rapidkit my-workspace
&lt;span class="nb"&gt;cd &lt;/span&gt;my-workspace

&lt;span class="c"&gt;# Create FastAPI project&lt;/span&gt;
rapidkit create project fastapi.standard product-api
&lt;span class="nb"&gt;cd &lt;/span&gt;product-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;What you get:&lt;/strong&gt;&lt;br&gt;
• Clean &lt;code&gt;src/&lt;/code&gt; architecture&lt;br&gt;
• Health check endpoint (&lt;code&gt;/health&lt;/code&gt;)&lt;br&gt;
• Testing setup (pytest)&lt;br&gt;
• Docker configs&lt;br&gt;
• CI/CD templates&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 2: Initialize Project
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;This installs:&lt;/strong&gt;&lt;br&gt;
• Poetry (if needed)&lt;br&gt;
• All dependencies&lt;br&gt;
• Development tools&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then start the server:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO: Uvicorn running on http://127.0.0.1:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Visit:&lt;/strong&gt; &lt;a href="http://localhost:8000/docs" rel="noopener noreferrer"&gt;http://localhost:8000/docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see &lt;strong&gt;Swagger UI&lt;/strong&gt; with &lt;code&gt;/health&lt;/code&gt; endpoint.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add Configuration Module
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module settings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Settings module provides:&lt;/strong&gt;&lt;br&gt;
• Multi-source config (&lt;code&gt;.env&lt;/code&gt;, env vars, CLI)&lt;br&gt;
• Type-safe with Pydantic&lt;br&gt;
• Environment-specific overrides&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create &lt;code&gt;.env&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Product API
&lt;span class="nv"&gt;APP_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;development
&lt;span class="nv"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;INFO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Health check now shows:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"modules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Add Database (PostgreSQL)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module db_postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Update &lt;code&gt;.env&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;POSTGRES_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;localhost
&lt;span class="nv"&gt;POSTGRES_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5432
&lt;span class="nv"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myuser
&lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mypass
&lt;span class="nv"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;productdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Start PostgreSQL:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt; postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The module provides:&lt;/strong&gt;&lt;br&gt;
• Async SQLAlchemy setup&lt;br&gt;
• Connection pooling&lt;br&gt;
• Health checks&lt;br&gt;
• Alembic migrations&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test connection:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8000/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"modules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"db_postgres"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 5: Create Product Model
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/app/models/product.py&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Boolean&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.ext.declarative&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;declarative_base&lt;/span&gt;

&lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;declarative_base&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run migration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit db migrate &lt;span class="s2"&gt;"Create products table"&lt;/span&gt;
rapidkit db upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 6: Add Redis Caching
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Update &lt;code&gt;.env&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;REDIS_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;redis://localhost:6379
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Start Redis:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt; redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use for caching:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.modules.redis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_redis&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_product_cached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;get_redis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Fetch from DB
&lt;/span&gt;    &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Cache for 5 minutes
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&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="n"&gt;product&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 7: Add Authentication
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module auth_core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;br&gt;
• PBKDF2 password hashing&lt;br&gt;
• JWT token generation&lt;br&gt;
• Token validation middleware&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create user:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.modules.auth_core&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hash_password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create_token&lt;/span&gt;

&lt;span class="c1"&gt;# Hash password
&lt;/span&gt;&lt;span class="n"&gt;hashed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hash_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secure123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Store in DB
&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user@example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;hashed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Generate token
&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_token&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Protected endpoint:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.modules.auth_core&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;require_auth&lt;/span&gt;

&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@require_auth&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ProductCreate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_current_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Only authenticated users can create
&lt;/span&gt;    &lt;span class="n"&gt;new_product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_product&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 8: Add Email Module
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module email
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Update &lt;code&gt;.env&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SMTP_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;smtp.gmail.com
&lt;span class="nv"&gt;SMTP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;587
&lt;span class="nv"&gt;SMTP_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-email@gmail.com
&lt;span class="nv"&gt;SMTP_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-app-password
&lt;span class="nv"&gt;SMTP_FROM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;noreply@productapi.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Send email:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.modules.email&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;send_email&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer@example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product Added to Cart&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your product is ready!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 9: Add Security Headers &amp;amp; CORS
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module cors
rapidkit add module security_headers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Update &lt;code&gt;.env&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CORS_ORIGINS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:3000,https://yourapp.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Your API now has:&lt;/strong&gt;&lt;br&gt;
• CSP, HSTS, X-Frame-Options&lt;br&gt;
• Origin whitelisting&lt;br&gt;
• Credential support&lt;br&gt;
• Preflight handling&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 10: Add Logging
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module logging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;br&gt;
• Structured JSON logs&lt;br&gt;
• Correlation IDs&lt;br&gt;
• Multi-sink (console, file, HTTP)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logs look like:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-02-14T10:30:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Product created"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"correlation_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"product_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 11: Run Tests
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;===== test session starts =====
collected 24 items

tests/test_products.py ........
tests/test_auth.py ....
tests/test_cache.py ....
tests/test_health.py ....

===== 24 passed in 3.2s =====
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Every module includes tests.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 12: Deploy
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Build Docker image:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; product-api &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run container:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;db.example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;REDIS_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;redis://cache.example.com &lt;span class="se"&gt;\&lt;/span&gt;
  product-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Or use GitHub Actions&lt;/strong&gt; (already configured in &lt;code&gt;.github/workflows/&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Structure (Final)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;product-api/
├── src/
│   ├── app/
│   │   ├── main.py
│   │   ├── models/
│   │   │   └── product.py
│   │   ├── routes/
│   │   │   └── products.py
│   │   └── modules/
│   │       ├── settings/
│   │       ├── db_postgres/
│   │       ├── redis/
│   │       ├── auth_core/
│   │       ├── email/
│   │       ├── cors/
│   │       ├── security_headers/
│   │       └── logging/
│   └── tests/
├── docker-compose.yml
├── Dockerfile
├── .env
└── pyproject.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What You Built
&lt;/h2&gt;

&lt;p&gt;✅ Product CRUD API&lt;br&gt;&lt;br&gt;
✅ PostgreSQL database&lt;br&gt;&lt;br&gt;
✅ Redis caching&lt;br&gt;&lt;br&gt;
✅ JWT authentication&lt;br&gt;&lt;br&gt;
✅ Email notifications&lt;br&gt;&lt;br&gt;
✅ CORS protection&lt;br&gt;&lt;br&gt;
✅ Security headers&lt;br&gt;&lt;br&gt;
✅ Structured logging&lt;br&gt;&lt;br&gt;
✅ Docker deployment&lt;br&gt;&lt;br&gt;
✅ CI/CD ready&lt;br&gt;&lt;br&gt;
✅ Tests passing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time spent:&lt;/strong&gt; ~2 hours&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Lines written:&lt;/strong&gt; ~200&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Lines generated:&lt;/strong&gt; ~3,000&lt;/p&gt;


&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Modules are composable&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module X
rapidkit add module Y
&lt;span class="c"&gt;# They work together automatically&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Everything is configurable&lt;/strong&gt;&lt;br&gt;
All settings via &lt;code&gt;.env&lt;/code&gt; — no code changes needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Health checks included&lt;/strong&gt;&lt;br&gt;
Every module reports health at &lt;code&gt;/health&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Tests included&lt;/strong&gt;&lt;br&gt;
Every module brings its own tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Standard FastAPI code&lt;/strong&gt;&lt;br&gt;
No lock-in. Modify anything. It's your code.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧩 Explore More Modules
&lt;/h2&gt;

&lt;p&gt;This tutorial used &lt;strong&gt;8 modules&lt;/strong&gt;, but RapidKit offers &lt;strong&gt;27 free modules&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication &amp;amp; Security (9):&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;auth_core&lt;/code&gt;, &lt;code&gt;api_keys&lt;/code&gt;, &lt;code&gt;oauth&lt;/code&gt;, &lt;code&gt;passwordless&lt;/code&gt;, &lt;code&gt;session&lt;/code&gt;, &lt;code&gt;rbac&lt;/code&gt;, &lt;code&gt;cors&lt;/code&gt;, &lt;code&gt;security_headers&lt;/code&gt;, &lt;code&gt;rate_limiting&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database &amp;amp; Caching (4):&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;db_postgres&lt;/code&gt;, &lt;code&gt;db_mongodb&lt;/code&gt;, &lt;code&gt;db_mysql&lt;/code&gt;, &lt;code&gt;redis&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payments &amp;amp; E-commerce (3):&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;stripe_payment&lt;/code&gt;, &lt;code&gt;paypal_payment&lt;/code&gt;, &lt;code&gt;cart&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Communication (2):&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;email&lt;/code&gt;, &lt;code&gt;email_templates&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business (3):&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;storage&lt;/code&gt; (S3/MinIO), &lt;code&gt;deployment&lt;/code&gt;, &lt;code&gt;observability_core&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Essentials (4):&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;settings&lt;/code&gt;, &lt;code&gt;logging&lt;/code&gt;, &lt;code&gt;celery&lt;/code&gt;, &lt;code&gt;users_core&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI (1):&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;ai_recommender&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't know which module?&lt;/strong&gt;&lt;br&gt;
🤖 Use AI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx rapidkit modules recommend &lt;span class="s2"&gt;"I need user authentication and email"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://dev.tolink"&gt;Read full AI guide →&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Clone Example Projects
&lt;/h2&gt;

&lt;p&gt;RapidKit VS Code Extension connects to real production-style workspaces:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Quickstart Product API&lt;/strong&gt; (&lt;code&gt;quickstart-workspace/product-api&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-Commerce API&lt;/strong&gt; (&lt;code&gt;quickstart-workspace/ecommerce-api&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Agent Workspace&lt;/strong&gt; (&lt;code&gt;my-ai-workspace&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SaaS Starter Workspace&lt;/strong&gt; (&lt;code&gt;saas-starter-workspace&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Clone from VS Code:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Welcome Panel → &lt;strong&gt;Example Workspaces&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select workspace&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;rapidkit init &amp;amp;&amp;amp; rapidkit dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Clone from terminal:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/getrapidkit/rapidkit-examples
&lt;span class="nb"&gt;cd &lt;/span&gt;rapidkit-examples/quickstart-workspace/ecommerce-api
&lt;span class="nb"&gt;source&lt;/span&gt; .rapidkit/activate
rapidkit init
rapidkit dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  E-Commerce Flow (Visual Summary)
&lt;/h2&gt;

&lt;p&gt;If you run &lt;code&gt;quickstart-workspace/ecommerce-api&lt;/code&gt;, this is the core payment lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stateDiagram-v2
  [*] --&amp;gt; Cart
  Cart --&amp;gt; Confirmed: POST /checkout
  Confirmed --&amp;gt; Paid: POST /payments/intents/{id}/confirm
  Confirmed --&amp;gt; Paid: webhook payment.succeeded
  Confirmed --&amp;gt; PaymentFailed: webhook payment.failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the request sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sequenceDiagram
  participant C as Client
  participant A as ecommerce-api
  participant P as Payment Provider (Mock)

  C-&amp;gt;&amp;gt;A: Add items to cart
  C-&amp;gt;&amp;gt;A: POST /checkout
  A--&amp;gt;&amp;gt;C: order.status=confirmed

  C-&amp;gt;&amp;gt;A: POST /payments/intents
  C-&amp;gt;&amp;gt;A: POST /payments/intents/{id}/confirm
  A--&amp;gt;&amp;gt;C: order.status=paid

  P-&amp;gt;&amp;gt;A: POST /webhooks/payments
  A--&amp;gt;&amp;gt;P: 202 accepted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Next: Build a &lt;strong&gt;NestJS microservice&lt;/strong&gt; and see how it compares to FastAPI.&lt;/p&gt;

&lt;p&gt;After that: New AI tracks (support triage, provider failover, cost control).&lt;/p&gt;




&lt;h3&gt;
  
  
  Learn More
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;a href="https://www.getrapidkit.com" rel="noopener noreferrer"&gt;getrapidkit.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;a href="https://www.npmjs.com/package/rapidkit" rel="noopener noreferrer"&gt;npm: rapidkit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐍 &lt;a href="https://pypi.org/project/rapidkit-core/" rel="noopener noreferrer"&gt;PyPI: rapidkit-core&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧩 &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;VS Code Extension&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;You just built a production API.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now ship it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  rapidkit #fastapi #tutorial #python #backend #api #postgresql #redis #docker #beginners
&lt;/h1&gt;

</description>
      <category>webdev</category>
      <category>backend</category>
      <category>fastapi</category>
      <category>rapidkit</category>
    </item>
    <item>
      <title>Build Production SaaS: Code Walkthrough</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Mon, 16 Feb 2026 08:18:49 +0000</pubDate>
      <link>https://dev.to/rapidkit/build-production-saas-code-walkthrough-4c7c</link>
      <guid>https://dev.to/rapidkit/build-production-saas-code-walkthrough-4c7c</guid>
      <description>&lt;p&gt;Most tutorials show you &lt;strong&gt;how to run&lt;/strong&gt; commands.&lt;br&gt;&lt;br&gt;
This one shows you &lt;strong&gt;how the code works&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We'll build and dissect a 4-service SaaS backend with real implementation patterns used in production.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📦 &lt;strong&gt;Get the code:&lt;/strong&gt; &lt;a href="https://github.com/getrapidkit/rapidkit-examples/tree/main/saas-starter-workspace" rel="noopener noreferrer"&gt;saas-starter-workspace&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  What We're Building
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;4 microservices with clear separation:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;saas-api&lt;/code&gt; (FastAPI) — Product API&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;saas-admin&lt;/code&gt; (FastAPI) — Admin ops&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;saas-nest&lt;/code&gt; (NestJS) — Polyglot service&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;saas-webhooks&lt;/code&gt; (FastAPI) — Billing events + replay&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Key features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dual auth (JWT + session cookies)&lt;/li&gt;
&lt;li&gt;Webhook signature verification&lt;/li&gt;
&lt;li&gt;Event replay for billing corrections&lt;/li&gt;
&lt;li&gt;DDD structure with module injection&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;--version&lt;/span&gt;  &lt;span class="c"&gt;# 3.10+&lt;/span&gt;
node &lt;span class="nt"&gt;--version&lt;/span&gt;     &lt;span class="c"&gt;# 20+&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;poetry
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; rapidkit
git clone https://github.com/getrapidkit/rapidkit-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;rapidkit-examples/saas-starter-workspace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  💡 Faster Setup: RapidKit VS Code Extension
&lt;/h3&gt;

&lt;p&gt;Skip manual cloning. Install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;RapidKit VS Code Extension&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you get:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone workspaces from GitHub with one click (Welcome Page → Example Workspaces)&lt;/li&gt;
&lt;li&gt;Download &amp;amp; import workspaces directly&lt;/li&gt;
&lt;li&gt;Run/test projects from the sidebar&lt;/li&gt;
&lt;li&gt;Install modules via GUI&lt;/li&gt;
&lt;li&gt;Integrated terminal with RapidKit commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Install:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;code &lt;span class="nt"&gt;--install-extension&lt;/span&gt; rapidkit.rapidkit-vscode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open Command Palette (&lt;code&gt;Cmd/Ctrl+Shift+P&lt;/code&gt;) → &lt;strong&gt;RapidKit: Import Workspace&lt;/strong&gt; → done.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Pattern: DDD with Injection Markers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Project structure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;saas-api/src/
├── main.py              # Entry point with injection markers
├── app/main.py          # FastAPI factory
├── routing/
│   └── saas.py          # Business logic (485 lines)
└── modules/free/        # RapidKit modules
    ├── auth/core/       # Password hashing + JWT
    ├── auth/session/    # Cookie sessions
    ├── users/users_core/
    └── security/rate_limiting/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Entry point pattern (&lt;code&gt;main.py&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@asynccontextmanager&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lifespan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;AsyncIterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="c1"&gt;# &amp;lt;&amp;lt;&amp;lt;inject:startup&amp;gt;&amp;gt;&amp;gt; — modules add startup hooks here
&lt;/span&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# &amp;lt;&amp;lt;&amp;lt;inject:shutdown&amp;gt;&amp;gt;&amp;gt; — cleanup hooks
&lt;/span&gt;        &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;saas-api&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;lifespan&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lifespan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# &amp;lt;&amp;lt;&amp;lt;inject:routes&amp;gt;&amp;gt;&amp;gt; — modules mount routes here
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modules inject code at generation time&lt;/li&gt;
&lt;li&gt;Clean separation of concerns&lt;/li&gt;
&lt;li&gt;Easy to add/remove features&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code Deep Dive 1: Authentication Flow
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Register endpoint (&lt;code&gt;routing/saas.py&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@router.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/auth/register&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RegisterRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;users_service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UsersService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_users_service&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;auth_runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AuthCoreRuntime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_auth_core_runtime&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rate_limit_dependency&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Hash password (PBKDF2, 100K iterations)
&lt;/span&gt;    &lt;span class="n"&gt;password_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth_runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Create user in database
&lt;/span&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user_dto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserCreateDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;password_hash&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;password_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;full_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;full_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;created_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;users_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_dto&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;UserEmailConflictError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;409&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email already registered&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. Issue JWT token
&lt;/span&gt;    &lt;span class="n"&gt;token_payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sub&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;created_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;created_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth_runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;issue_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token_payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. Create session + set cookie
&lt;/span&gt;    &lt;span class="n"&gt;session_runtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_get_session_runtime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;session_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session_runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;created_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;_set_session_cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_runtime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_token&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;created_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;access_token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bearer&lt;/span&gt;&lt;span class="sh"&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;&lt;strong&gt;Pattern breakdown:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PBKDF2 hashing:&lt;/strong&gt; 100K iterations prevents brute force&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service layer:&lt;/strong&gt; Business logic isolated from HTTP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual auth:&lt;/strong&gt; JWT (stateless) + session (server-side validation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting:&lt;/strong&gt; Dependency injection pattern&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code Deep Dive 2: Authentication Resolution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How we resolve users from JWT OR cookies:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_current_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;users_service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;auth_runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AuthCoreRuntime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;session_runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SessionRuntime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserDTO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;auth_header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Strategy 1: JWT Bearer Token
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;auth_header&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;auth_header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bearer &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;bearer_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth_header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth_runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bearer_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sub&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Strategy 2: Session Cookie
&lt;/span&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;session_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session_runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;session_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authentication required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session_runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify_session_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;

    &lt;span class="c1"&gt;# Fetch user from database
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;UserDTO&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;users_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why dual auth?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mobile apps → JWT (stateless, offline validation)&lt;/li&gt;
&lt;li&gt;Web browsers → Cookies (server-side revocation)&lt;/li&gt;
&lt;li&gt;Single function handles both&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Usage in protected routes:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@router.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/auth/me&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UsersService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_users_service&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AuthCoreRuntime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_auth_core_runtime&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SessionRuntime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_get_session_runtime&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;_get_current_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Code Deep Dive 3: Webhook Processing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Signature verification (&lt;code&gt;saas-webhooks/routing/webhooks.py&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_verify_signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Verify Stripe webhook signature using HMAC-SHA256.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_parse_signature_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# Reconstruct: "{timestamp}.{body}"
&lt;/span&gt;    &lt;span class="n"&gt;signed_payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;signed_payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Constant-time comparison (prevents timing attacks)
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare_digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ingestion endpoint:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@router.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/stripe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;202&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;receive_webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;StripeWebhookRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BackgroundTasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Verify signature
&lt;/span&gt;    &lt;span class="n"&gt;raw_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stripe-signature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;_verify_signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WEBHOOK_SECRET&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid signature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Check idempotency
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_EVENTS&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duplicate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. Persist log
&lt;/span&gt;    &lt;span class="n"&gt;_EVENTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WebhookLogEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;event_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queued&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;received_at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;_utc_now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. Queue background processing
&lt;/span&gt;    &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_process_event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accepted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this pattern?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signature first → reject fakes immediately&lt;/li&gt;
&lt;li&gt;Idempotency → Stripe sends duplicates&lt;/li&gt;
&lt;li&gt;Background tasks → don't block response&lt;/li&gt;
&lt;li&gt;Logs → audit trail for billing events&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code Deep Dive 4: Webhook Replay
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Critical for billing correctness:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@router.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/replay/{event_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;replay_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BackgroundTasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Reprocess failed event without calling Stripe.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_EVENTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Event not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replay_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replay_queued&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Reconstruct payload from stored data
&lt;/span&gt;    &lt;span class="n"&gt;replay_payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StripeWebhookRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Queue for processing
&lt;/span&gt;    &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_process_event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replay_payload&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replay_accepted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replay_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replay_count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When you need replay:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handler had a bug → fix code, replay events&lt;/li&gt;
&lt;li&gt;Database was down → replay after recovery&lt;/li&gt;
&lt;li&gt;Need to backfill subscription states&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Production upgrade:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;_EVENTS&lt;/code&gt; dict with PostgreSQL&lt;/li&gt;
&lt;li&gt;Add exponential backoff for retries&lt;/li&gt;
&lt;li&gt;Implement dead-letter queue&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code Deep Dive 5: NestJS Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Auth service (&lt;code&gt;saas-nest/src/auth/auth.service.ts&lt;/code&gt;):&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;usersByEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UserRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersByEmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email already registered&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`user_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;passwordHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usersByEmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;issueToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publicUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;token_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bearer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;issueToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&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;&lt;strong&gt;Controller:&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CONFLICT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;me&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractBearer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Auth required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UNAUTHORIZED&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;me&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&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;&lt;strong&gt;Comparison with FastAPI version:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same flow: hash → store → issue token&lt;/li&gt;
&lt;li&gt;NestJS: TypeScript types + dependency injection&lt;/li&gt;
&lt;li&gt;FastAPI: Async/await + Pydantic validation&lt;/li&gt;
&lt;li&gt;Both: Service pattern isolates business logic&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Run the Complete System
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Terminal 1 — Product API:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;saas-api &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; poetry shell &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit dev
&lt;span class="c"&gt;# → http://127.0.0.1:8000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Terminal 2 — Admin API:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;saas-admin &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; poetry shell &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit dev &lt;span class="nt"&gt;--port&lt;/span&gt; 8001
&lt;span class="c"&gt;# → http://127.0.0.1:8001&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Terminal 3 — NestJS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;saas-nest &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit dev &lt;span class="nt"&gt;--port&lt;/span&gt; 8002
&lt;span class="c"&gt;# → http://127.0.0.1:8002&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Terminal 4 — Webhooks:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;saas-webhooks &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; poetry shell &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit dev &lt;span class="nt"&gt;--port&lt;/span&gt; 8003
&lt;span class="c"&gt;# → http://127.0.0.1:8003&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Test the Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Auth flow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="c1"&gt;# Register
&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:8000/api/auth/register&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dev@example.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SecurePass123!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;access_token&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Get profile
&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;me&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:8000/api/auth/me&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Webhook flow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Send event&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:8003/api/webhooks/stripe &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"id":"evt_test","type":"customer.subscription.updated","data":{}}'&lt;/span&gt;

&lt;span class="c"&gt;# View logs&lt;/span&gt;
curl http://127.0.0.1:8003/api/webhooks/logs | jq

&lt;span class="c"&gt;# Replay&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:8003/api/webhooks/replay/evt_test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Patterns You Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Injection Marker System&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# &amp;lt;&amp;lt;&amp;lt;inject:startup&amp;gt;&amp;gt;&amp;gt; — modules contribute code here
# &amp;lt;&amp;lt;&amp;lt;inject:routes&amp;gt;&amp;gt;&amp;gt; — dynamic route mounting
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Service Layer Pattern&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Controller → calls → Service → calls → Repository
# Keeps business logic testable and framework-independent
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Dependency Injection&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_service&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_auth&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# FastAPI resolves dependencies automatically
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Background Processing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;process_event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accepted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;# Immediate response
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Dual Authentication&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Check Bearer token first, fall back to session cookie
# Enables mobile (JWT) + web (session) clients
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Production Hardening
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before going live:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Replace in-memory storage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Current: _EVENTS = {}
# Production: PostgreSQL with SQLAlchemy
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Add retry logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Implement dead-letter queue:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;send_to_dlq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Add observability:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structured logging with request IDs&lt;/li&gt;
&lt;li&gt;APM (Sentry/DataDog)&lt;/li&gt;
&lt;li&gt;Prometheus metrics&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What You Built
&lt;/h2&gt;

&lt;p&gt;✅ &lt;strong&gt;Multi-service architecture&lt;/strong&gt; (4 services, independent scaling)&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Dual authentication&lt;/strong&gt; (JWT + session cookies)&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Secure webhooks&lt;/strong&gt; (signature verification + replay)&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;DDD structure&lt;/strong&gt; (clean separation of concerns)&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Polyglot support&lt;/strong&gt; (FastAPI + NestJS coexist)&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Production patterns&lt;/strong&gt; (background tasks, rate limiting, error handling)  &lt;/p&gt;

&lt;p&gt;This is the foundation real SaaS companies use to process millions in ARR.&lt;/p&gt;




&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Want &lt;strong&gt;Part 2 - Production Deployment&lt;/strong&gt;?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker Compose orchestration&lt;/li&gt;
&lt;li&gt;PostgreSQL + Redis setup&lt;/li&gt;
&lt;li&gt;CI/CD with GitHub Actions&lt;/li&gt;
&lt;li&gt;Kubernetes manifests&lt;/li&gt;
&lt;li&gt;Secrets management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Drop a comment if interested 👇&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/getrapidkit/rapidkit-examples/tree/main/saas-starter-workspace" rel="noopener noreferrer"&gt;Example Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;RapidKit VS Code Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getrapidkit.com/docs" rel="noopener noreferrer"&gt;RapidKit Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fastapi.tiangolo.com" rel="noopener noreferrer"&gt;FastAPI Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.nestjs.com" rel="noopener noreferrer"&gt;NestJS Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Found this useful? Follow for more production engineering patterns.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>microservices</category>
      <category>saas</category>
      <category>rapidkit</category>
    </item>
    <item>
      <title>The Hidden Cost of Backend Boilerplate (And How to Eliminate It)</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Sun, 15 Feb 2026 07:39:17 +0000</pubDate>
      <link>https://dev.to/rapidkit/the-hidden-cost-of-backend-boilerplate-and-how-to-eliminate-it-4c01</link>
      <guid>https://dev.to/rapidkit/the-hidden-cost-of-backend-boilerplate-and-how-to-eliminate-it-4c01</guid>
      <description>&lt;h2&gt;
  
  
  Everyone Counts the Same Cost
&lt;/h2&gt;

&lt;p&gt;Ask any backend developer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"How long to start a new API project?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Answer:&lt;br&gt;
&lt;em&gt;"30 minutes with a template."&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"A few hours from scratch."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But that's not the real cost.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's just &lt;strong&gt;Day 1&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Real Cost Shows Up Later
&lt;/h2&gt;

&lt;p&gt;Let me show you what actually happens.&lt;/p&gt;


&lt;h2&gt;
  
  
  Week 1: The Setup
&lt;/h2&gt;

&lt;p&gt;You start a new FastAPI project.&lt;/p&gt;

&lt;p&gt;You copy your "starter template":&lt;br&gt;
• Project structure&lt;br&gt;
• Docker configs&lt;br&gt;
• CI/CD workflows&lt;br&gt;
• Auth boilerplate&lt;br&gt;
• Database setup&lt;br&gt;
• Logging config&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; 2 hours (not bad!)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you don't notice:&lt;/strong&gt;&lt;br&gt;
• JWT v1 from 6 months ago (now there's v2)&lt;br&gt;
• Database pool settings from different project&lt;br&gt;
• Logging format doesn't match team's new standard&lt;br&gt;
• Docker compose has hardcoded values from old project&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost so far:&lt;/strong&gt; 2 hours + unknown future bugs&lt;/p&gt;


&lt;h2&gt;
  
  
  Week 3: The Divergence
&lt;/h2&gt;

&lt;p&gt;Your teammate starts another project.&lt;/p&gt;

&lt;p&gt;They &lt;strong&gt;copy YOUR template&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But make "improvements":&lt;br&gt;
• Different folder structure (&lt;code&gt;src/&lt;/code&gt; vs &lt;code&gt;app/&lt;/code&gt;)&lt;br&gt;
• Different error handling&lt;br&gt;
• Different env variable naming&lt;br&gt;
• Updated packages (breaking changes!)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now you have &lt;strong&gt;two projects that look similar but work differently&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you fix a bug in Project A, do you remember to fix it in Project B?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Code duplication + inconsistency tax&lt;/p&gt;


&lt;h2&gt;
  
  
  Month 2: The Onboarding
&lt;/h2&gt;

&lt;p&gt;A new developer joins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; "Just look at user-api to understand our structure."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New Dev:&lt;/strong&gt; &lt;em&gt;(Looks at user-api, then payment-api)&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;New Dev:&lt;/strong&gt; "These structure auth differently. Which is correct?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; "Uh... let me check."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Confusion + lost productivity + rework&lt;/p&gt;


&lt;h2&gt;
  
  
  Month 4: The Maintenance Nightmare
&lt;/h2&gt;

&lt;p&gt;You discover a security issue in auth logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; Which projects have this issue?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search codebase (30 minutes)&lt;/li&gt;
&lt;li&gt;Find 6 projects with copied auth&lt;/li&gt;
&lt;li&gt;Each has slightly different implementation&lt;/li&gt;
&lt;li&gt;Fix takes 4 hours (not 30 minutes)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; 4+ hours + risk you missed one&lt;/p&gt;


&lt;h2&gt;
  
  
  Month 6: The "Which Version?" Problem
&lt;/h2&gt;

&lt;p&gt;You have 8 APIs now:&lt;br&gt;
• 3 use Pydantic v1&lt;br&gt;
• 4 use Pydantic v2&lt;br&gt;
• 1 nobody knows&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Templates capture a &lt;strong&gt;snapshot in time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They don't evolve.&lt;/p&gt;

&lt;p&gt;Each copy drifts further from the source.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Hidden Costs (Quantified)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Setup cost&lt;/strong&gt; (what you measure):&lt;br&gt;
• Template: 2 hours&lt;br&gt;
• From scratch: 6 hours&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drift cost&lt;/strong&gt; (what you miss):&lt;br&gt;
• Fixing bugs across 8 copies: 4 hours × 8 = 32 hours&lt;br&gt;
• Onboarding confusion: 2 hours per developer × 5 devs = 10 hours&lt;br&gt;
• "Which version?" debugging: 6 hours&lt;br&gt;
• Architectural inconsistency: Ongoing pain&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real cost:&lt;/strong&gt;&lt;br&gt;
• Initial: 2 hours&lt;br&gt;
• Ongoing: 48+ hours over 6 months&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's 24× the initial cost.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem Isn't Templates
&lt;/h2&gt;

&lt;p&gt;Templates are great for:&lt;br&gt;
• UI components&lt;br&gt;
• Boilerplate-free tools (like Swagger)&lt;br&gt;
• One-time setups&lt;/p&gt;

&lt;p&gt;Templates fail for:&lt;br&gt;
• Evolving codebases&lt;br&gt;
• Team consistency&lt;br&gt;
• Bug fixes and updates&lt;br&gt;
• Architectural standards&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Because once you copy a template, you're on your own.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What If You Could Eliminate Drift?
&lt;/h2&gt;

&lt;p&gt;Imagine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a project&lt;/li&gt;
&lt;li&gt;A bug is found in auth logic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One command updates all projects&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;No searching, no manual fixes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is what &lt;strong&gt;RapidKit modules&lt;/strong&gt; solve.&lt;/p&gt;


&lt;h2&gt;
  
  
  How RapidKit Changes This
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Traditional approach:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Copy template&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; starter-template/ new-api/
&lt;span class="nb"&gt;cd &lt;/span&gt;new-api

&lt;span class="c"&gt;# Modify everything&lt;/span&gt;
&lt;span class="c"&gt;# (Hope you remember what to change)&lt;/span&gt;

&lt;span class="c"&gt;# 6 months later: bug found in auth&lt;/span&gt;
&lt;span class="c"&gt;# Fix manually in 8 projects&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;RapidKit approach:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create project&lt;/span&gt;
rapidkit create project fastapi.standard new-api
&lt;span class="nb"&gt;cd &lt;/span&gt;new-api

&lt;span class="c"&gt;# Add modules&lt;/span&gt;
rapidkit add module auth_core
rapidkit add module db_postgres
rapidkit add module logging

&lt;span class="c"&gt;# 6 months later: auth bug fixed in module&lt;/span&gt;
rapidkit upgrade
&lt;span class="c"&gt;# ↳ Fixed across all projects&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Difference: Managed vs Copied
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Templates:&lt;/strong&gt;&lt;br&gt;
• Copied code&lt;br&gt;
• No connection to source&lt;br&gt;
• Manual updates&lt;br&gt;
• Drift inevitable&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RapidKit Modules:&lt;/strong&gt;&lt;br&gt;
• Versioned modules&lt;br&gt;
• Tracked installations&lt;br&gt;
• Automatic updates&lt;br&gt;
• Consistency enforced&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think:&lt;/strong&gt;&lt;br&gt;
• Templates = copy-paste code&lt;br&gt;
• Modules = npm packages for backend&lt;/p&gt;


&lt;h2&gt;
  
  
  Real Example: Auth Bug Fix
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Security vulnerability in JWT validation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Template approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify affected projects (30 min)&lt;/li&gt;
&lt;li&gt;Fix project 1 (30 min)&lt;/li&gt;
&lt;li&gt;Fix project 2 (30 min)&lt;/li&gt;
&lt;li&gt;Fix project 3 (30 min)&lt;/li&gt;
&lt;li&gt;...repeat for 8 projects&lt;/li&gt;
&lt;li&gt;Test each (2 hours)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Total:&lt;/strong&gt; 6+ hours&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;RapidKit approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fix auth_core module&lt;/li&gt;
&lt;li&gt;Release v0.1.5&lt;/li&gt;
&lt;li&gt;Run in each project:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   rapidkit upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Module updates automatically&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Total:&lt;/strong&gt; 30 minutes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Saved:&lt;/strong&gt; 5.5 hours (per bug!)&lt;/p&gt;


&lt;h2&gt;
  
  
  The Compounding Effect
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;After 1 year:&lt;/strong&gt;&lt;br&gt;
• 12 bug fixes in shared modules&lt;br&gt;
• 5.5 hours saved × 12 = &lt;strong&gt;66 hours saved&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After 2 years:&lt;/strong&gt;&lt;br&gt;
• 24 bug fixes&lt;br&gt;
• &lt;strong&gt;132 hours saved&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plus:&lt;/strong&gt;&lt;br&gt;
• Zero onboarding confusion&lt;br&gt;
• Zero "which version?" problems&lt;br&gt;
• Zero architectural drift&lt;/p&gt;


&lt;h2&gt;
  
  
  But Isn't This Lock-In?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RapidKit generates &lt;strong&gt;standard FastAPI/NestJS code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can:&lt;br&gt;
• Modify any file&lt;br&gt;
• Remove RapidKit entirely&lt;br&gt;
• Continue without it&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You own the code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RapidKit just &lt;strong&gt;manages the boring parts&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  What About Customization?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Templates:&lt;/strong&gt; Everything is customizable (because everything is yours)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RapidKit:&lt;/strong&gt; Everything is customizable too:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Modify generated code&lt;/li&gt;
&lt;li&gt;RapidKit tracks your changes&lt;/li&gt;
&lt;li&gt;When upgrading, it:
• Shows diffs
• Preserves your customizations
• Merges updates safely&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Best of both worlds:&lt;/strong&gt;&lt;br&gt;
• Evolution without drift&lt;br&gt;
• Customization without chaos&lt;/p&gt;


&lt;h2&gt;
  
  
  The Mental Model Shift
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Old way:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;"Copy this template and make it yours."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New way:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;"Install these modules and add your features."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Old way:&lt;/strong&gt; Start by &lt;strong&gt;deleting/modifying&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;New way:&lt;/strong&gt; Start by &lt;strong&gt;building features&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Create two projects with templates:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Project 1&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; template/ api-1/
&lt;span class="nb"&gt;cd &lt;/span&gt;api-1
&lt;span class="c"&gt;# Spend 2 hours customizing&lt;/span&gt;

&lt;span class="c"&gt;# Project 2&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; template/ api-2/
&lt;span class="nb"&gt;cd &lt;/span&gt;api-2
&lt;span class="c"&gt;# Spend 2 hours customizing&lt;/span&gt;

&lt;span class="c"&gt;# 3 months later: find a bug in template&lt;/span&gt;
&lt;span class="c"&gt;# Now fix it manually in both&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create two projects with RapidKit:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Project 1&lt;/span&gt;
rapidkit create project fastapi.standard api-1
&lt;span class="nb"&gt;cd &lt;/span&gt;api-1
rapidkit add module auth_core db_postgres

&lt;span class="c"&gt;# Project 2&lt;/span&gt;
rapidkit create project fastapi.standard api-2
&lt;span class="nb"&gt;cd &lt;/span&gt;api-2
rapidkit add module auth_core db_postgres

&lt;span class="c"&gt;# 3 months later: bug fixed in auth_core&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;api-1 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit upgrade
&lt;span class="nb"&gt;cd &lt;/span&gt;api-2 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rapidkit upgrade
&lt;span class="c"&gt;# Done.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Real Cost of Boilerplate
&lt;/h2&gt;

&lt;p&gt;It's not the initial setup time.&lt;/p&gt;

&lt;p&gt;It's:&lt;br&gt;
• &lt;strong&gt;Drift&lt;/strong&gt; (projects become inconsistent)&lt;br&gt;
• &lt;strong&gt;Duplication&lt;/strong&gt; (fix same bugs multiple times)&lt;br&gt;
• &lt;strong&gt;Confusion&lt;/strong&gt; (teammates don't know which is canonical)&lt;br&gt;
• &lt;strong&gt;Maintenance&lt;/strong&gt; (updates take forever)&lt;br&gt;
• &lt;strong&gt;Onboarding&lt;/strong&gt; (new devs lost in inconsistency)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RapidKit eliminates all of these.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Next article: &lt;strong&gt;"Your First FastAPI Project with RapidKit"&lt;/strong&gt; — a complete tutorial building a real API.&lt;/p&gt;




&lt;h3&gt;
  
  
  Learn More
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;a href="https://www.getrapidkit.com" rel="noopener noreferrer"&gt;getrapidkit.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;a href="https://www.npmjs.com/package/rapidkit" rel="noopener noreferrer"&gt;npm: rapidkit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐍 &lt;a href="https://pypi.org/project/rapidkit-core/" rel="noopener noreferrer"&gt;PyPI: rapidkit-core&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧩 &lt;a href="https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode" rel="noopener noreferrer"&gt;VS Code Extension&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Stop copying templates.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start managing modules.&lt;/p&gt;

</description>
      <category>rapidkit</category>
      <category>backend</category>
      <category>productivity</category>
      <category>architecture</category>
    </item>
    <item>
      <title>From Zero to Production API in 5 Minutes</title>
      <dc:creator>RapidKit </dc:creator>
      <pubDate>Sat, 14 Feb 2026 20:04:33 +0000</pubDate>
      <link>https://dev.to/rapidkit/from-zero-to-production-api-in-5-minutes-2ehl</link>
      <guid>https://dev.to/rapidkit/from-zero-to-production-api-in-5-minutes-2ehl</guid>
      <description>&lt;h2&gt;
  
  
  Let's Stop Talking. Let's Build.
&lt;/h2&gt;

&lt;p&gt;Enough theory. We're building a &lt;strong&gt;real, production-ready FastAPI project&lt;/strong&gt; from absolute zero.&lt;/p&gt;

&lt;p&gt;Not a toy example. Not a template.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Timer starts now.&lt;/strong&gt; ⏱️&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📌 &lt;strong&gt;Source Code:&lt;/strong&gt; &lt;a href="https://github.com/getrapidkit/rapidkit-examples/tree/main/quickstart-workspace" rel="noopener noreferrer"&gt;github.com/getrapidkit/rapidkit-examples/tree/main/quickstart-workspace&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Minute 0:00 — Prerequisites Check
&lt;/h2&gt;

&lt;p&gt;You need:&lt;br&gt;
• Node.js 20+&lt;br&gt;
• Python 3.10+&lt;br&gt;
• 5 minutes&lt;/p&gt;

&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;RapidKit handles:&lt;br&gt;
• Poetry (auto-installed)&lt;br&gt;
• Docker (configs provided)&lt;br&gt;
• Dependencies (auto-managed)&lt;/p&gt;


&lt;h2&gt;
  
  
  Minute 0:30 — Create the Workspace
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Workspace-based approach&lt;/strong&gt; (recommended for multiple projects):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx rapidkit quickstart-workspace
&lt;span class="nb"&gt;cd &lt;/span&gt;quickstart-workspace
npx rapidkit create project fastapi.standard product-api
&lt;span class="nb"&gt;cd &lt;/span&gt;product-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What you get:&lt;/strong&gt;&lt;br&gt;
• Clean &lt;code&gt;src/&lt;/code&gt; architecture&lt;br&gt;
• Health check endpoint&lt;br&gt;
• Docker &amp;amp; docker-compose ready&lt;br&gt;
• CI/CD templates (GitHub Actions)&lt;br&gt;
• Testing setup (pytest)&lt;br&gt;
• Environment management (&lt;code&gt;.env.example&lt;/code&gt;)&lt;br&gt;
• Makefile for common tasks&lt;br&gt;
• Shared &lt;code&gt;.venv&lt;/code&gt; for all workspace projects&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generated code&lt;/strong&gt;, not templates.&lt;/p&gt;


&lt;h2&gt;
  
  
  Minute 1:00 — Install Dependencies
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Activate workspace environment&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; .rapidkit/activate

&lt;span class="c"&gt;# Initialize project&lt;/span&gt;
rapidkit init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;What happens:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Detects workspace environment&lt;/li&gt;
&lt;li&gt;Installs Poetry (if needed)&lt;/li&gt;
&lt;li&gt;Uses shared workspace &lt;code&gt;.venv/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Installs all project dependencies&lt;/li&gt;
&lt;li&gt;Sets up pre-commit hooks&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Poetry detected
✓ Using workspace virtualenv
✓ Installing dependencies
✓ Project ready!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Minute 1:30 — First Run
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO: Uvicorn running on http://127.0.0.1:8000
INFO: Application startup complete.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Open browser:&lt;/strong&gt; &lt;a href="http://localhost:8000/docs" rel="noopener noreferrer"&gt;http://localhost:8000/docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see &lt;strong&gt;Swagger UI&lt;/strong&gt; with health endpoints:&lt;br&gt;
• &lt;code&gt;GET /health&lt;/code&gt; — Overall health check&lt;br&gt;
• &lt;code&gt;GET /api/health/livez&lt;/code&gt; — Liveness probe&lt;br&gt;
• &lt;code&gt;GET /api/health/readyz&lt;/code&gt; — Readiness probe&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your API is running.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Minute 2:00 — Add Essential Modules
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module settings
rapidkit add module auth_core  
rapidkit add module logging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Settings module:&lt;/strong&gt;&lt;br&gt;
• Multi-source config (&lt;code&gt;.env&lt;/code&gt;, env vars, YAML)&lt;br&gt;
• Type-safe with Pydantic&lt;br&gt;
• Environment-specific overrides&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auth Core module:&lt;/strong&gt;&lt;br&gt;
• PBKDF2 password hashing&lt;br&gt;
• HMAC token signing&lt;br&gt;
• Secure credential management&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logging module:&lt;/strong&gt;&lt;br&gt;
• Structured JSON logs&lt;br&gt;
• Request/correlation tracking&lt;br&gt;
• Configurable log levels&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check health endpoints:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-02-14T..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"modules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"auth_core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthy"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Minute 2:30 — Add Database
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rapidkit add module db_postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What you get:&lt;/strong&gt;&lt;br&gt;
• Async &amp;amp; sync SQLAlchemy engines&lt;br&gt;
• Connection pooling with configurable limits&lt;br&gt;
• Health checks with connection testing&lt;br&gt;
• Alembic migrations ready&lt;br&gt;
• Docker Compose with Postgres service&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment configured in &lt;code&gt;.env&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;RAPIDKIT_DB_POSTGRES_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql://postgres:postgres@localhost:5432/app_db
&lt;span class="nv"&gt;RAPIDKIT_DB_POSTGRES_TEST_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql://postgres:postgres@localhost:5433/app_db_test
&lt;span class="nv"&gt;RAPIDKIT_DB_POSTGRES_POOL_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10
&lt;span class="nv"&gt;RAPIDKIT_DB_POSTGRES_MAX_OVERFLOW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Start database:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt; postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Check health:&lt;/strong&gt;&lt;br&gt;
&lt;a href="http://localhost:8000/api/health/module/postgres" rel="noopener noreferrer"&gt;http://localhost:8000/api/health/module/postgres&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
---

## Minute 3:00 — Add Redis Caching

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;br&gt;
rapidkit add module redis&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Redis features:**
• Async Redis client with connection pooling
• Automatic retry logic with exponential backoff
• Health monitoring with connection testing
• Configurable TTL and preconnection

**Environment configured in `.env`:**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;br&gt;
REDIS_URL=redis://localhost:6379/0&lt;br&gt;
REDIS_HOST=localhost&lt;br&gt;
REDIS_PORT=6379&lt;br&gt;
REDIS_DB=0&lt;br&gt;
CACHE_TTL=3600&lt;br&gt;
REDIS_CONNECT_RETRIES=3&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Start Redis:**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;br&gt;
docker-compose up -d redis&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Check health:**
http://localhost:8000/api/health/module/redis

---

## Minute 3:30 — Add Security &amp;amp; Middleware

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;br&gt;
rapidkit add module cors&lt;br&gt;
rapidkit add module security_headers&lt;br&gt;
rapidkit add module middleware&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**CORS:**
• Whitelist origins for production
• Credential support enabled
• Preflight request handling

**Security Headers:**
• CSP, HSTS, X-Frame-Options configured
• Production-ready secure defaults

**Middleware:**
• Request ID tracking
• Response time recording
• Custom middleware support

**Your API now has enterprise-grade security.**

---

## Minute 4:00 — Add Deployment Config

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;br&gt;
rapidkit add module deployment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Deployment features:**
• Production-ready Dockerfile (multi-stage builds)
• Docker Compose with all services
• GitHub Actions CI/CD workflows
• Makefile with common tasks
• Health check integration
• Environment-based configuration

---

## Minute 4:30 — Run Tests

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;br&gt;
rapidkit test&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Output:**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;===== test session starts =====&lt;br&gt;
collected 15 items&lt;/p&gt;

&lt;p&gt;tests/test_health.py ✓✓✓✓&lt;br&gt;
tests/test_auth_core.py ✓✓✓&lt;br&gt;
tests/test_db.py ✓✓✓✓&lt;br&gt;
tests/test_redis.py ✓✓&lt;br&gt;
tests/test_integration.py ✓✓&lt;/p&gt;

&lt;p&gt;===== 15 passed in 3.2s =====&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**All modules have tests included automatically.**

---

## Minute 5:00 — Deploy

**Using Makefile commands:**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;/p&gt;
&lt;h1&gt;
  
  
  Build Docker image
&lt;/h1&gt;

&lt;p&gt;make docker-build&lt;/p&gt;
&lt;h1&gt;
  
  
  Run with docker-compose (all services)
&lt;/h1&gt;

&lt;p&gt;make docker-up&lt;/p&gt;
&lt;h1&gt;
  
  
  Or manual Docker build
&lt;/h1&gt;

&lt;p&gt;docker build -t product-api .&lt;br&gt;
docker run -p 8000:8000 --env-file .env product-api&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Production deployment:**
• GitHub Actions workflows (auto-generated by deployment module)
• Multi-stage Dockerfile (optimized for production)
• Docker Compose with all services
• Health checks integrated
• Environment-based configuration

**Your API is production-ready.**

---

## ⏱️ Timer: 5:00

**What you built:**
✅ Workspace-based FastAPI project with clean architecture  
✅ JWT Authentication (register, login, refresh)  
✅ Database (PostgreSQL with async + sync engines)  
✅ Caching (Redis with retry logic)  
✅ Security (CORS + security headers)  
✅ Middleware (request tracking)  
✅ Logging (structured JSON with correlation IDs)  
✅ Configuration (multi-source with type safety)  
✅ Tests (passing with 15 test cases)  
✅ Docker (production-ready multi-stage builds)  
✅ CI/CD (GitHub Actions workflows)

**Lines of code written by you:** ~60 (configs)  
**Lines of code generated:** ~2,500+

---

## Project Structure

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;quickstart-workspace/&lt;br&gt;
├── .rapidkit/&lt;br&gt;
│   ├── activate                 # Workspace activation script&lt;br&gt;
│   └── .venv/                   # Shared virtual environment&lt;br&gt;
├── product-api/&lt;br&gt;
│   ├── src/&lt;br&gt;
│   │   ├── main.py              # FastAPI app entrypoint&lt;br&gt;
│   │   ├── cli.py               # CLI commands&lt;br&gt;
│   │   ├── health/              # Health check routes&lt;br&gt;
│   │   ├── routing/             # API routes&lt;br&gt;
│   │   └── modules/             # Installed modules&lt;br&gt;
│   │       ├── settings/&lt;br&gt;
│   │       ├── auth_core/&lt;br&gt;
│   │       ├── db_postgres/&lt;br&gt;
│   │       ├── redis/&lt;br&gt;
│   │       ├── cors/&lt;br&gt;
│   │       ├── security_headers/&lt;br&gt;
│   │       ├── logging/&lt;br&gt;
│   │       ├── deployment/&lt;br&gt;
│   │       └── middleware/&lt;br&gt;
│   ├── tests/                   # Tests for all modules&lt;br&gt;
│   ├── docker-compose.yml       # Postgres + Redis services&lt;br&gt;
│   ├── Dockerfile               # Production multi-stage image&lt;br&gt;
│   ├── pyproject.toml           # Project dependencies&lt;br&gt;
│   ├── .env.example             # Environment template&lt;br&gt;
│   └── Makefile                 # Common development tasks&lt;br&gt;
└── README.md                    # Workspace documentation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Every module:**
• Has its own directory
• Brings tests
• Updates health endpoint
• Configurable via `.env`

---

## What Makes This Different?

**Templates give you:**
• Example files
• You modify everything
• No upgrade path

**RapidKit gives you:**
• Production code
• Working integrations
• Upgradable modules
• Health checks included
• Tests included

**Key difference:**

Templates = **delete and modify**  
RapidKit = **add and build**

---

## Next Steps

**Add more features:**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;/p&gt;
&lt;h1&gt;
  
  
  Email sending
&lt;/h1&gt;

&lt;p&gt;rapidkit add module email&lt;/p&gt;
&lt;h1&gt;
  
  
  Background tasks
&lt;/h1&gt;

&lt;p&gt;rapidkit add module celery&lt;/p&gt;
&lt;h1&gt;
  
  
  File storage
&lt;/h1&gt;

&lt;p&gt;rapidkit add module storage&lt;/p&gt;
&lt;h1&gt;
  
  
  Observability
&lt;/h1&gt;

&lt;p&gt;rapidkit add module observability_core&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Each module integrates cleanly** — working together seamlessly.

---

## Troubleshooting: Health Check

**Something not working?**

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;br&gt;
npx rapidkit doctor&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Checks:**
• Python version
• Poetry installation
• RapidKit Core version
• Dependencies status

**Example output:**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Python: Python 3.10.19&lt;br&gt;
✅ Poetry: Poetry 2.3.2&lt;br&gt;
✅ pipx: pipx 1.8.0&lt;br&gt;
✅ RapidKit Core: RapidKit Core 0.3.2&lt;br&gt;
   • Global (pipx): /home/user/.local/bin/rapidkit -&amp;gt; 0.3.2&lt;/p&gt;

&lt;p&gt;✅ All required tools are installed!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Instant diagnosis.** For detailed project checks, use `rapidkit doctor --workspace`.

---

## Try It Yourself

**Clone the example:**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;br&gt;
git clone &lt;a href="https://github.com/getrapidkit/rapidkit-examples.git" rel="noopener noreferrer"&gt;https://github.com/getrapidkit/rapidkit-examples.git&lt;/a&gt;&lt;br&gt;
cd rapidkit-examples/quickstart-workspace/product-api&lt;br&gt;
source ../.rapidkit/activate&lt;br&gt;
rapidkit init&lt;br&gt;
rapidkit dev&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
**Or create from scratch:**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;br&gt;
time npx rapidkit create workspace my-workspace&lt;br&gt;
cd my-workspace&lt;br&gt;
time npx rapidkit create project fastapi.standard my-api&lt;br&gt;
cd my-api&lt;br&gt;
source ../.rapidkit/activate&lt;br&gt;
time rapidkit init&lt;br&gt;
time rapidkit dev&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


**Challenge:** Can you beat 5 minutes?

---

## FAQs

**Q: Is this production-ready?**  
Yes. Companies use generated projects in production.

**Q: Can I customize the code?**  
Yes. It's your code. Modify anything. RapidKit tracks changes and helps merge updates.

**Q: What if I add a module later?**  
RapidKit integrates it cleanly, preserving your custom code.

**Q: Do I need to learn RapidKit patterns?**  
No. It's **standard FastAPI code**. If you know FastAPI, you know this code.

---

## What's Next?

Next article: **"The Hidden Cost of Backend Boilerplate"** — why "just use a template" isn't good enough.

---

### Learn More

* 🌐 [getrapidkit.com](https://www.getrapidkit.com)
* 📦 [npm: rapidkit](https://www.npmjs.com/package/rapidkit)
* 🐍 [PyPI: rapidkit-core](https://pypi.org/project/rapidkit-core/)
* 🧩 [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=rapidkit.rapidkit-vscode)
* 📂 [GitHub: rapidkit-examples](https://github.com/getrapidkit/rapidkit-examples)

---

**You just built a production-ready API in 5 minutes.**

Now go ship something.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>rapidkit</category>
      <category>quickstart</category>
      <category>python</category>
      <category>fastapi</category>
    </item>
  </channel>
</rss>
