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/
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
<link rel="prev" href="..">
|
||||
|
||||
|
||||
<link rel="next" href="../10_testing/">
|
||||
<link rel="next" href="../02_components/">
|
||||
|
||||
|
||||
<link rel="icon" href="../assets/images/favicon.png">
|
||||
@@ -297,18 +297,18 @@
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#summary" class="md-nav__link">
|
||||
<a href="#architecture" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Summary
|
||||
🏗️ Architecture
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#the-three-layers" class="md-nav__link">
|
||||
<a href="#the-one-way-dependency-rule" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
The three layers
|
||||
🔄 The one-way dependency rule
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -317,7 +317,7 @@
|
||||
<li class="md-nav__item">
|
||||
<a href="#core-principles" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Core principles
|
||||
🧭 Core principles
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -326,7 +326,16 @@
|
||||
<li class="md-nav__item">
|
||||
<a href="#runtime-processes" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Runtime processes
|
||||
⚙️ Runtime processes
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#read-next" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
➡️ Read Next
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -347,12 +356,12 @@
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../10_testing/" class="md-nav__link">
|
||||
<a href="../02_components/" class="md-nav__link">
|
||||
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Testing
|
||||
App Components
|
||||
|
||||
</span>
|
||||
|
||||
@@ -369,7 +378,7 @@
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../11_build_recipe/" class="md-nav__link">
|
||||
<a href="../03_build_recipe/" class="md-nav__link">
|
||||
|
||||
|
||||
|
||||
@@ -384,6 +393,28 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<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>
|
||||
@@ -411,18 +442,18 @@
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#summary" class="md-nav__link">
|
||||
<a href="#architecture" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Summary
|
||||
🏗️ Architecture
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#the-three-layers" class="md-nav__link">
|
||||
<a href="#the-one-way-dependency-rule" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
The three layers
|
||||
🔄 The one-way dependency rule
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -431,7 +462,7 @@
|
||||
<li class="md-nav__item">
|
||||
<a href="#core-principles" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Core principles
|
||||
🧭 Core principles
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -440,7 +471,16 @@
|
||||
<li class="md-nav__item">
|
||||
<a href="#runtime-processes" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Runtime processes
|
||||
⚙️ Runtime processes
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#read-next" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
➡️ Read Next
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -463,45 +503,104 @@
|
||||
|
||||
|
||||
<h1 id="overview">Overview</h1>
|
||||
<h2 id="summary">Summary</h2>
|
||||
<p>The blueprint is a <strong>hexagonal (ports and adapters) application</strong> with a
|
||||
<p>The blueprint is a <strong>hexagonal (ports & adapters) application</strong> with a
|
||||
<strong>spec-first</strong> web edge and a <strong>single composition root</strong>. It favors explicit
|
||||
wiring over implicit magic, and it prefers existing internal libraries over
|
||||
hand-written infrastructure.</p>
|
||||
wiring over implicit magic and existing internal libraries over hand-written
|
||||
infrastructure. Start here to build the mental model; the enforceable details
|
||||
live in the reference pages.</p>
|
||||
<hr />
|
||||
<h2 id="the-three-layers">The three layers</h2>
|
||||
<div class="language-text 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>interfaces/ ← HTTP edge: thin handlers bound to an OpenAPI operationId
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a>domain/ ← business core: models, ports (interfaces), services, orchestrators
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a>infra/ ← adapters: databases, caches, external clients, hardware
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
<p>Plus two optional layers:</p>
|
||||
<div class="language-text 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></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>pipelines/ ← data-driven transformation graphs (extraction, enrichment)
|
||||
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2"></a>scripts/ ← operator scripts that reuse the composition root
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
<h2 id="core-principles">Core principles</h2>
|
||||
<h2 id="architecture">🏗️ Architecture</h2>
|
||||
<pre class="mermaid"><code>flowchart LR
|
||||
subgraph EDGE["interfaces/ — HTTP edge"]
|
||||
OAS["openapi.yaml<br/>operationId contract"]
|
||||
RT["<resource>/routes.py<br/>thin handlers"]
|
||||
end
|
||||
|
||||
subgraph CORE["domain/ — pure business core"]
|
||||
MD["models"]
|
||||
PT["ports (abstract)"]
|
||||
SV["services"]
|
||||
end
|
||||
|
||||
subgraph INFRA["infra/ — adapters"]
|
||||
RP["mongo repos (mongo-ops)"]
|
||||
AD["cache · stores · llm · mail"]
|
||||
DB[("MongoDB")]
|
||||
end
|
||||
|
||||
CR["init.py<br/>composition root"]
|
||||
|
||||
OAS --> RT
|
||||
RT --> SV
|
||||
SV --> PT
|
||||
SV --> RP
|
||||
PT -. depends on .- RP
|
||||
CR --- RT
|
||||
CR --- SV
|
||||
CR --- RP
|
||||
RP --> DB
|
||||
AD --- CR</code></pre>
|
||||
<p>The rule holds at every edge: code in an outer ring may depend on a ring closer
|
||||
to the core, never the reverse. <code>domain/</code> never imports a web framework or a
|
||||
database driver.</p>
|
||||
<blockquote>
|
||||
<p><strong>Legend</strong> — solid arrows are compile-time calls; dotted arrows are the
|
||||
port/adapter contract, resolved by the composition root at startup.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="the-one-way-dependency-rule">🔄 The one-way dependency rule</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ring</th>
|
||||
<th>May import</th>
|
||||
<th>Never imports</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>interfaces/</code></td>
|
||||
<td><code>domain</code>, framework glue (glue only)</td>
|
||||
<td>business logic, <code>infra</code> directly</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>domain/</code></td>
|
||||
<td>nothing but its own ports</td>
|
||||
<td>web frameworks, drivers, <code>infra</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>infra/</code></td>
|
||||
<td><code>domain</code> ports, drivers, libraries</td>
|
||||
<td>—</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>init.py</code></td>
|
||||
<td>everything (the wiring point)</td>
|
||||
<td>—</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="core-principles">🧭 Core principles</h2>
|
||||
<ol>
|
||||
<li><strong>One-way dependencies.</strong> <code>interfaces -> domain -> infra</code> is allowed;
|
||||
the reverse is forbidden. The domain never imports a framework it does not
|
||||
own.</li>
|
||||
<li><strong>Ports in the domain, adapters in infra.</strong> A service depends on an
|
||||
abstract port; the composition root injects a concrete adapter.</li>
|
||||
<li><strong>One-way dependencies.</strong> <code>interfaces -> domain -> infra</code> is allowed; the
|
||||
reverse is forbidden.</li>
|
||||
<li><strong>Ports in the domain, adapters in infra.</strong> A service depends on an abstract
|
||||
port; the composition root injects a concrete adapter.</li>
|
||||
<li><strong>One composition root.</strong> Nothing constructs its own dependencies. All
|
||||
wiring lives in one module (<code>init.py</code>) and is exposed as a flat resource
|
||||
registry.</li>
|
||||
<li><strong>Spec-first.</strong> The HTTP contract is declared in an OpenAPI document. Route
|
||||
wiring lives in one module (<code>init.py</code>) exposed as a flat resource registry.</li>
|
||||
<li><strong>Spec-first.</strong> The HTTP contract is declared in <code>openapi.yaml</code>; route
|
||||
handlers are looked up by <code>operationId</code>. There are no decorator routers.</li>
|
||||
<li><strong>Reuse the libraries.</strong> Pipeline orchestration, DI, Mongo repositories,
|
||||
ingestion, auth, and docs are provided by internal libraries. Do not
|
||||
reimplement them — see the library registry.</li>
|
||||
<li><strong>Reuse the libraries.</strong> Orchestration, DI, Mongo repositories, ingestion,
|
||||
auth, and docs come from internal libraries — see the <a href="../lib/13_library_registry/">Library
|
||||
Registry</a>.</li>
|
||||
<li><strong>Explicit state machines.</strong> Long-running work moves through explicit,
|
||||
durable statuses and can pause for human input.</li>
|
||||
</ol>
|
||||
<h2 id="runtime-processes">Runtime processes</h2>
|
||||
<p>A standard app may run as up to three processes that share the same
|
||||
composition root:</p>
|
||||
<hr />
|
||||
<h2 id="runtime-processes">⚙️ Runtime processes</h2>
|
||||
<p>A standard app may run as up to three processes that share the same composition
|
||||
root:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -528,6 +627,11 @@ composition root:</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="read-next">➡️ Read Next</h2>
|
||||
<ul>
|
||||
<li><a href="../02_components/">02 – App Components</a> · <a href="../03_build_recipe/">03 – Build Recipe</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
@@ -589,6 +693,8 @@ composition root:</p>
|
||||
|
||||
<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>
|
||||
Reference in New Issue
Block a user