Files
docs/standards/wiki/03_build_recipe/index.html
Vishesh 'ironeagle' Bangotra 06ff5bce6e docs(standards): mirror doc-forge wiki style; mermaid + copyable build prompt
- move templates into src/templates; renumber wiki pages; add app-components page

- embed agentic build prompt as a copyable markdown block; add mermaid diagrams

- build.py writes <name>/mcp; config static bundle -> standards/mcp

- registry reads libraries.json as bytes (committed file was UTF-16LE); normalize to UTF-8

- Dockerfile: drop stale blog copy; per-repo <name>/mcp copies

- drop nested standards/mcp/standards duplicate and empty root mcp/
2026-10-12 00:21:41 +05:30

794 lines
33 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The philosophy and prompts behind the standardized application blueprint.">
<link rel="prev" href="../02_components/">
<link rel="next" href="../04_development/01_testing/">
<link rel="icon" href="../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.23">
<title>Build Recipe - Aetos Standards — Wiki</title>
<link rel="stylesheet" href="../assets/stylesheets/main.84d31ad4.min.css">
<link rel="stylesheet" href="../assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="cyan">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#build-recipe" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href=".." title="Aetos Standards — Wiki" class="md-header__button md-logo" aria-label="Aetos Standards — Wiki" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards — Wiki
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Build Recipe
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="cyan" aria-hidden="true" type="radio" name="__palette" id="__palette_0">
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href=".." title="Aetos Standards — Wiki" class="md-nav__button md-logo" aria-label="Aetos Standards — Wiki" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
Aetos Standards — Wiki
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../01_overview/" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../02_components/" class="md-nav__link">
<span class="md-ellipsis">
App Components
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Build Recipe
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#quick-start" class="md-nav__link">
<span class="md-ellipsis">
🚀 Quick start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#agent-prompt-copyable" class="md-nav__link">
<span class="md-ellipsis">
📋 Agent prompt (copyable)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#where-the-steps-land" class="md-nav__link">
<span class="md-ellipsis">
🧭 Where the steps land
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#definition-of-done" class="md-nav__link">
<span class="md-ellipsis">
⚠️ Definition of done
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#related" class="md-nav__link">
<span class="md-ellipsis">
Related
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../04_development/01_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing & Quality
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#quick-start" class="md-nav__link">
<span class="md-ellipsis">
🚀 Quick start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#agent-prompt-copyable" class="md-nav__link">
<span class="md-ellipsis">
📋 Agent prompt (copyable)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#where-the-steps-land" class="md-nav__link">
<span class="md-ellipsis">
🧭 Where the steps land
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#definition-of-done" class="md-nav__link">
<span class="md-ellipsis">
⚠️ Definition of done
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#related" class="md-nav__link">
<span class="md-ellipsis">
Related
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="build-recipe">Build Recipe</h1>
<p>The ordered, deterministic checklist for generating a new application of the
standard shape. Every step is fixed; only steps 2 and 3 need app-specific
authoring. Give an AI agent the copyable prompt below (or read it from the
<code>standards</code> MCP bundle as <code>doc://modules/build_recipe</code>) and it can produce a
complete app in one pass.</p>
<hr />
<h2 id="quick-start">🚀 Quick start</h2>
<div class="language-bash highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-1">1</a></span>
<span class="normal"><a href="#__codelineno-0-2">2</a></span>
<span class="normal"><a href="#__codelineno-0-3">3</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="c1"># Copy the runnable skeleton (from the standards docs checkout)</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a>cp<span class="w"> </span>-r<span class="w"> </span>&lt;docs&gt;/standards/src/templates/app<span class="w"> </span>apps/&lt;your-app&gt;
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="nb">cd</span><span class="w"> </span>apps/&lt;your-app&gt;
</span></code></pre></div></td></tr></table></div>
<p>Then follow the numbered steps in the prompt.</p>
<hr />
<h2 id="agent-prompt-copyable">📋 Agent prompt (copyable)</h2>
<div class="language-markdown highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-1-1"> 1</a></span>
<span class="normal"><a href="#__codelineno-1-2"> 2</a></span>
<span class="normal"><a href="#__codelineno-1-3"> 3</a></span>
<span class="normal"><a href="#__codelineno-1-4"> 4</a></span>
<span class="normal"><a href="#__codelineno-1-5"> 5</a></span>
<span class="normal"><a href="#__codelineno-1-6"> 6</a></span>
<span class="normal"><a href="#__codelineno-1-7"> 7</a></span>
<span class="normal"><a href="#__codelineno-1-8"> 8</a></span>
<span class="normal"><a href="#__codelineno-1-9"> 9</a></span>
<span class="normal"><a href="#__codelineno-1-10">10</a></span>
<span class="normal"><a href="#__codelineno-1-11">11</a></span>
<span class="normal"><a href="#__codelineno-1-12">12</a></span>
<span class="normal"><a href="#__codelineno-1-13">13</a></span>
<span class="normal"><a href="#__codelineno-1-14">14</a></span>
<span class="normal"><a href="#__codelineno-1-15">15</a></span>
<span class="normal"><a href="#__codelineno-1-16">16</a></span>
<span class="normal"><a href="#__codelineno-1-17">17</a></span>
<span class="normal"><a href="#__codelineno-1-18">18</a></span>
<span class="normal"><a href="#__codelineno-1-19">19</a></span>
<span class="normal"><a href="#__codelineno-1-20">20</a></span>
<span class="normal"><a href="#__codelineno-1-21">21</a></span>
<span class="normal"><a href="#__codelineno-1-22">22</a></span>
<span class="normal"><a href="#__codelineno-1-23">23</a></span>
<span class="normal"><a href="#__codelineno-1-24">24</a></span>
<span class="normal"><a href="#__codelineno-1-25">25</a></span>
<span class="normal"><a href="#__codelineno-1-26">26</a></span>
<span class="normal"><a href="#__codelineno-1-27">27</a></span>
<span class="normal"><a href="#__codelineno-1-28">28</a></span>
<span class="normal"><a href="#__codelineno-1-29">29</a></span>
<span class="normal"><a href="#__codelineno-1-30">30</a></span>
<span class="normal"><a href="#__codelineno-1-31">31</a></span>
<span class="normal"><a href="#__codelineno-1-32">32</a></span>
<span class="normal"><a href="#__codelineno-1-33">33</a></span>
<span class="normal"><a href="#__codelineno-1-34">34</a></span>
<span class="normal"><a href="#__codelineno-1-35">35</a></span>
<span class="normal"><a href="#__codelineno-1-36">36</a></span>
<span class="normal"><a href="#__codelineno-1-37">37</a></span>
<span class="normal"><a href="#__codelineno-1-38">38</a></span>
<span class="normal"><a href="#__codelineno-1-39">39</a></span>
<span class="normal"><a href="#__codelineno-1-40">40</a></span>
<span class="normal"><a href="#__codelineno-1-41">41</a></span>
<span class="normal"><a href="#__codelineno-1-42">42</a></span>
<span class="normal"><a href="#__codelineno-1-43">43</a></span>
<span class="normal"><a href="#__codelineno-1-44">44</a></span>
<span class="normal"><a href="#__codelineno-1-45">45</a></span>
<span class="normal"><a href="#__codelineno-1-46">46</a></span>
<span class="normal"><a href="#__codelineno-1-47">47</a></span>
<span class="normal"><a href="#__codelineno-1-48">48</a></span>
<span class="normal"><a href="#__codelineno-1-49">49</a></span>
<span class="normal"><a href="#__codelineno-1-50">50</a></span>
<span class="normal"><a href="#__codelineno-1-51">51</a></span>
<span class="normal"><a href="#__codelineno-1-52">52</a></span>
<span class="normal"><a href="#__codelineno-1-53">53</a></span>
<span class="normal"><a href="#__codelineno-1-54">54</a></span>
<span class="normal"><a href="#__codelineno-1-55">55</a></span>
<span class="normal"><a href="#__codelineno-1-56">56</a></span>
<span class="normal"><a href="#__codelineno-1-57">57</a></span>
<span class="normal"><a href="#__codelineno-1-58">58</a></span>
<span class="normal"><a href="#__codelineno-1-59">59</a></span>
<span class="normal"><a href="#__codelineno-1-60">60</a></span>
<span class="normal"><a href="#__codelineno-1-61">61</a></span>
<span class="normal"><a href="#__codelineno-1-62">62</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="gh"># Build a new application from the Aetos Standards blueprint</span>
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2"></a>
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3"></a>You are coding a complete new backend application conforming to the Aetos
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4"></a>standard app blueprint. Execute every step in order. Only steps 2 and 3 use the
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5"></a>app-specific details provided by the user; everything else is deterministic.
</span><span id="__span-1-6"><a id="__codelineno-1-6" name="__codelineno-1-6"></a>
</span><span id="__span-1-7"><a id="__codelineno-1-7" name="__codelineno-1-7"></a>Before writing any code, connect to the <span class="sb">`standards`</span> MCP server and read:
</span><span id="__span-1-8"><a id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="k">-</span><span class="w"> </span><span class="sb">`doc://nav`</span> (the module list)
</span><span id="__span-1-9"><a id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="k">-</span><span class="w"> </span><span class="sb">`doc://modules/layering_rules`</span> (the dependency rules)
</span><span id="__span-1-10"><a id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="k">-</span><span class="w"> </span><span class="sb">`doc://modules/genericity_matrix`</span> (what is generic vs app-specific)
</span><span id="__span-1-11"><a id="__codelineno-1-11" name="__codelineno-1-11"></a>Then call <span class="sb">`find_library`</span> with capabilities like <span class="sb">`db`</span>, <span class="sb">`di`</span>, <span class="sb">`routing`</span>,
</span><span id="__span-1-12"><a id="__codelineno-1-12" name="__codelineno-1-12"></a><span class="sb">`ingestion`</span>, <span class="sb">`auth`</span>, <span class="sb">`docs`</span>, <span class="sb">`pipeline`</span>, and note the libraries that already
</span><span id="__span-1-13"><a id="__codelineno-1-13" name="__codelineno-1-13"></a>exist. Never reimplement one.
</span><span id="__span-1-14"><a id="__codelineno-1-14" name="__codelineno-1-14"></a>
</span><span id="__span-1-15"><a id="__codelineno-1-15" name="__codelineno-1-15"></a><span class="k">1.</span> <span class="gs">**Scaffold**</span> — copy <span class="sb">`src/templates/app/`</span> into <span class="sb">`apps/&lt;your-app&gt;/`</span>. Keep the
</span><span id="__span-1-16"><a id="__codelineno-1-16" name="__codelineno-1-16"></a> package tree: <span class="sb">`domain/`</span>, <span class="sb">`infra/`</span>, <span class="sb">`interfaces/`</span>, <span class="sb">`pipelines/`</span>, <span class="sb">`tests/`</span>,
</span><span id="__span-1-17"><a id="__codelineno-1-17" name="__codelineno-1-17"></a> <span class="sb">`scripts/`</span>, plus <span class="sb">`pyproject.toml`</span>, <span class="sb">`openapi.yaml`</span>, <span class="sb">`config.py`</span>, <span class="sb">`init.py`</span>,
</span><span id="__span-1-18"><a id="__codelineno-1-18" name="__codelineno-1-18"></a> <span class="sb">`main.py`</span>, <span class="sb">`worker.py`</span>, <span class="sb">`Dockerfile`</span>, <span class="sb">`docker-compose.yaml`</span>, <span class="sb">`.env.example`</span>.
</span><span id="__span-1-19"><a id="__codelineno-1-19" name="__codelineno-1-19"></a>
</span><span id="__span-1-20"><a id="__codelineno-1-20" name="__codelineno-1-20"></a><span class="k">2.</span> <span class="gs">**Author the spec (app-specific)**</span> — write <span class="sb">`openapi.yaml`</span>: resources,
</span><span id="__span-1-21"><a id="__codelineno-1-21" name="__codelineno-1-21"></a> schemas, <span class="sb">`operationId`</span>s, security, and extension metadata. This is the
</span><span id="__span-1-22"><a id="__codelineno-1-22" name="__codelineno-1-22"></a> contract and drives all routing.
</span><span id="__span-1-23"><a id="__codelineno-1-23" name="__codelineno-1-23"></a>
</span><span id="__span-1-24"><a id="__codelineno-1-24" name="__codelineno-1-24"></a><span class="k">3.</span> <span class="gs">**Write each CRUD slice (app-specific)**</span> — per resource create the
</span><span id="__span-1-25"><a id="__codelineno-1-25" name="__codelineno-1-25"></a> four-file slice: <span class="sb">`models.py`</span>, <span class="sb">`ports/db.py`</span>, <span class="sb">`ports/service.py`</span>, and
</span><span id="__span-1-26"><a id="__codelineno-1-26" name="__codelineno-1-26"></a> optional <span class="sb">`converters.py`</span>. Follow the CRUD template.
</span><span id="__span-1-27"><a id="__codelineno-1-27" name="__codelineno-1-27"></a>
</span><span id="__span-1-28"><a id="__codelineno-1-28" name="__codelineno-1-28"></a><span class="k">4.</span> <span class="gs">**Wire the composition root**</span> — in <span class="sb">`init.py`</span>, build leaf repositories, then
</span><span id="__span-1-29"><a id="__codelineno-1-29" name="__codelineno-1-29"></a> dependent repositories, then services; add infra adapters (db, cache,
</span><span id="__span-1-30"><a id="__codelineno-1-30" name="__codelineno-1-30"></a> stores, progress bus, fetchers). Expose <span class="sb">`get_svc`</span> overloads.
</span><span id="__span-1-31"><a id="__codelineno-1-31" name="__codelineno-1-31"></a>
</span><span id="__span-1-32"><a id="__codelineno-1-32" name="__codelineno-1-32"></a><span class="k">5.</span> <span class="gs">**Add routes**</span> — create <span class="sb">`interfaces/&lt;resource&gt;/routes.py`</span> thin handlers
</span><span id="__span-1-33"><a id="__codelineno-1-33" name="__codelineno-1-33"></a> bound to <span class="sb">`operationId`</span>s and re-export them in <span class="sb">`interfaces/openapi.py`</span>. Add
</span><span id="__span-1-34"><a id="__codelineno-1-34" name="__codelineno-1-34"></a> the cache decorator to read endpoints.
</span><span id="__span-1-35"><a id="__codelineno-1-35" name="__codelineno-1-35"></a>
</span><span id="__span-1-36"><a id="__codelineno-1-36" name="__codelineno-1-36"></a><span class="k">6.</span> <span class="gs">**Bootstrap app and worker**</span> — confirm <span class="sb">`main.py`</span> runs the OpenAPI-first app
</span><span id="__span-1-37"><a id="__codelineno-1-37" name="__codelineno-1-37"></a> with its lifespan. If the app has long-running jobs, adapt <span class="sb">`worker.py`</span> to
</span><span id="__span-1-38"><a id="__codelineno-1-38" name="__codelineno-1-38"></a> poll the job collection, run the pipeline, and publish progress.
</span><span id="__span-1-39"><a id="__codelineno-1-39" name="__codelineno-1-39"></a>
</span><span id="__span-1-40"><a id="__codelineno-1-40" name="__codelineno-1-40"></a><span class="k">7.</span> <span class="gs">**Add pipeline families (only if data-driven)**</span> — create
</span><span id="__span-1-41"><a id="__codelineno-1-41" name="__codelineno-1-41"></a> <span class="sb">`pipelines/&lt;family&gt;/`</span> with <span class="sb">`abc.py`</span>, <span class="sb">`impl.py`</span>, <span class="sb">`pipeline.yaml`</span>,
</span><span id="__span-1-42"><a id="__codelineno-1-42" name="__codelineno-1-42"></a> <span class="sb">`resources/`</span>, and register the root. Add fixtures and a parity test.
</span><span id="__span-1-43"><a id="__codelineno-1-43" name="__codelineno-1-43"></a>
</span><span id="__span-1-44"><a id="__codelineno-1-44" name="__codelineno-1-44"></a><span class="k">8.</span> <span class="gs">**Add infrastructure only where needed**</span> — prefer a library-backed adapter.
</span><span id="__span-1-45"><a id="__codelineno-1-45" name="__codelineno-1-45"></a> Never hand-write what an internal library already provides.
</span><span id="__span-1-46"><a id="__codelineno-1-46" name="__codelineno-1-46"></a>
</span><span id="__span-1-47"><a id="__codelineno-1-47" name="__codelineno-1-47"></a><span class="k">9.</span> <span class="gs">**Tests**</span> — integration tests with fakes at the HTTP edge; unit tests for
</span><span id="__span-1-48"><a id="__codelineno-1-48" name="__codelineno-1-48"></a> domain and pipeline logic; a config-consistency test for rule-driven
</span><span id="__span-1-49"><a id="__codelineno-1-49" name="__codelineno-1-49"></a> pipelines.
</span><span id="__span-1-50"><a id="__codelineno-1-50" name="__codelineno-1-50"></a>
</span><span id="__span-1-51"><a id="__codelineno-1-51" name="__codelineno-1-51"></a><span class="k">10.</span> <span class="gs">**Scripts and seeds**</span> — operator scripts under <span class="sb">`scripts/`</span> using
</span><span id="__span-1-52"><a id="__codelineno-1-52" name="__codelineno-1-52"></a> <span class="sb">`init()`</span> / <span class="sb">`get_svc()`</span> / <span class="sb">`shutdown()`</span>.
</span><span id="__span-1-53"><a id="__codelineno-1-53" name="__codelineno-1-53"></a>
</span><span id="__span-1-54"><a id="__codelineno-1-54" name="__codelineno-1-54"></a><span class="k">11.</span> <span class="gs">**Docs**</span> — author GSDFC docstrings, generate <span class="sb">`.pyi`</span> stubs, mark the package
</span><span id="__span-1-55"><a id="__codelineno-1-55" name="__codelineno-1-55"></a> <span class="sb">`py.typed`</span>, and build the docs.
</span><span id="__span-1-56"><a id="__codelineno-1-56" name="__codelineno-1-56"></a>
</span><span id="__span-1-57"><a id="__codelineno-1-57" name="__codelineno-1-57"></a><span class="gs">**Definition of done:**</span>
</span><span id="__span-1-58"><a id="__codelineno-1-58" name="__codelineno-1-58"></a><span class="k">-</span><span class="w"> </span><span class="sb">`python -c &quot;import main&quot;`</span> succeeds.
</span><span id="__span-1-59"><a id="__codelineno-1-59" name="__codelineno-1-59"></a><span class="k">-</span><span class="w"> </span><span class="sb">`pytest`</span> passes.
</span><span id="__span-1-60"><a id="__codelineno-1-60" name="__codelineno-1-60"></a><span class="k">-</span><span class="w"> </span>The app serves every operation in the spec; the worker drains its queue.
</span><span id="__span-1-61"><a id="__codelineno-1-61" name="__codelineno-1-61"></a><span class="k">-</span><span class="w"> </span>No domain module imports a web framework.
</span><span id="__span-1-62"><a id="__codelineno-1-62" name="__codelineno-1-62"></a><span class="k">-</span><span class="w"> </span>No infrastructure was reimplemented that a library already provides.
</span></code></pre></div></td></tr></table></div>
<hr />
<h2 id="where-the-steps-land">🧭 Where the steps land</h2>
<p>The steps map onto the layers as follows:</p>
<table>
<thead>
<tr>
<th>Step</th>
<th>Package / file</th>
<th>Depends on</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 · Scaffold</td>
<td>whole <code>templates/app/</code></td>
<td>—</td>
</tr>
<tr>
<td>2 · Spec</td>
<td><code>openapi.yaml</code></td>
<td>—</td>
</tr>
<tr>
<td>3 · CRUD slices</td>
<td><code>domain/&lt;resource&gt;/</code></td>
<td>spec, CRUD template</td>
</tr>
<tr>
<td>4 · Wiring</td>
<td><code>init.py</code></td>
<td>every slice</td>
</tr>
<tr>
<td>5 · Routes</td>
<td><code>interfaces/&lt;resource&gt;/</code></td>
<td>services, openapi route registry</td>
</tr>
<tr>
<td>6 · Bootstrap</td>
<td><code>main.py</code>, <code>worker.py</code></td>
<td>composition root</td>
</tr>
<tr>
<td>7 · Pipelines</td>
<td><code>pipelines/&lt;family&gt;/</code></td>
<td>library pipeline engine</td>
</tr>
<tr>
<td>8 · Infra</td>
<td><code>infra/</code></td>
<td>domain ports</td>
</tr>
<tr>
<td>9 · Tests</td>
<td><code>tests/</code></td>
<td>app + fixtures</td>
</tr>
<tr>
<td>10 · Scripts</td>
<td><code>scripts/</code></td>
<td>composition root</td>
</tr>
<tr>
<td>11 · Docs</td>
<td>docstrings + docs build</td>
<td>code, Doc Forge</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="definition-of-done">⚠️ Definition of done</h2>
<ul>
<li><code>python -c "import main"</code> succeeds.</li>
<li><code>pytest</code> passes.</li>
<li>The app serves the spec's operations; the worker drains its queue.</li>
<li>No domain module imports a web framework.</li>
<li>No infrastructure was reimplemented that a library already provides.</li>
</ul>
<hr />
<h2 id="related">Related</h2>
<ul>
<li><a href="../01_overview/">01 – Overview</a> · <a href="../02_components/">02 – App Components</a> · <a href="../04_development/01_testing/">04 – Testing &amp; Quality</a></li>
</ul>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "..", "features": ["navigation.sections", "navigation.expand", "navigation.top", "navigation.instant", "navigation.tracking", "navigation.indexes", "content.code.copy", "content.code.annotate", "content.tabs.link", "content.action.edit", "search.highlight", "search.share", "search.suggest"], "search": "../assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../assets/javascripts/bundle.f55a23d4.min.js"></script>
<script src="https://unpkg.com/mermaid@10.9.1/dist/mermaid.min.js"></script>
</body>
</html>