refactor: conform standards docs to doc-forge wiki/lib layout; generic build.py; static kind links

This commit is contained in:
2026-10-11 23:04:56 +05:30
parent 1208945e1d
commit 74aaf2f53e
181 changed files with 8649 additions and 1873 deletions

View File

@@ -6,12 +6,12 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
<link rel="prev" href="../01_overview/">
<link rel="prev" href="..">
<link rel="next" href="../03_composition_root/">
@@ -22,7 +22,7 @@
<title>Layering Rules - Aetos Standards</title>
<title>Layering Rules - Aetos Standards — Reference</title>
@@ -90,7 +90,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -104,7 +104,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -207,13 +207,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -244,28 +244,6 @@
<li class="md-nav__item">
<a href="../01_overview/" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
</li>
@@ -540,50 +518,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix/" class="md-nav__link">

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
@@ -22,7 +22,7 @@
<title>Composition Root - Aetos Standards</title>
<title>Composition Root - Aetos Standards — Reference</title>
@@ -90,7 +90,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -104,7 +104,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -207,13 +207,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -246,28 +246,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -531,50 +509,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix/" class="md-nav__link">

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
@@ -22,7 +22,7 @@
<title>Spec-First Routing - Aetos Standards</title>
<title>Spec-First Routing - Aetos Standards — Reference</title>
@@ -90,7 +90,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -104,7 +104,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -207,13 +207,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -246,28 +246,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -549,50 +527,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix/" class="md-nav__link">

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
@@ -22,7 +22,7 @@
<title>CRUD Template - Aetos Standards</title>
<title>CRUD Template - Aetos Standards — Reference</title>
@@ -90,7 +90,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -104,7 +104,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -207,13 +207,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -246,28 +246,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -549,50 +527,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix/" class="md-nav__link">

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
@@ -22,7 +22,7 @@
<title>Pipeline Scaffold - Aetos Standards</title>
<title>Pipeline Scaffold - Aetos Standards — Reference</title>
@@ -90,7 +90,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -104,7 +104,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -207,13 +207,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -246,28 +246,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -558,50 +536,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix/" class="md-nav__link">

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
@@ -22,7 +22,7 @@
<title>Worker & Progress - Aetos Standards</title>
<title>Worker & Progress - Aetos Standards — Reference</title>
@@ -90,7 +90,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -104,7 +104,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -207,13 +207,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -246,28 +246,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -531,50 +509,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix/" class="md-nav__link">

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
@@ -22,7 +22,7 @@
<title>Human-in-the-Loop - Aetos Standards</title>
<title>Human-in-the-Loop - Aetos Standards — Reference</title>
@@ -90,7 +90,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -104,7 +104,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -207,13 +207,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -246,28 +246,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -540,50 +518,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix/" class="md-nav__link">

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
@@ -14,7 +14,7 @@
<link rel="prev" href="../08_human_in_loop/">
<link rel="next" href="../10_testing/">
<link rel="next" href="../12_genericity_matrix/">
<link rel="icon" href="../assets/images/favicon.png">
@@ -22,7 +22,7 @@
<title>Infra Adapters - Aetos Standards</title>
<title>Infra Adapters - Aetos Standards — Reference</title>
@@ -90,7 +90,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -104,7 +104,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -207,13 +207,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -246,28 +246,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -558,50 +536,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix/" class="md-nav__link">

View File

@@ -6,12 +6,12 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
<link rel="prev" href="../11_build_recipe/">
<link rel="prev" href="../09_infra_adaptors/">
<link rel="next" href="../13_library_registry/">
@@ -22,7 +22,7 @@
<title>Genericity Matrix - Aetos Standards</title>
<title>Genericity Matrix - Aetos Standards — Reference</title>
@@ -90,7 +90,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -104,7 +104,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -207,13 +207,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -246,28 +246,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -442,50 +420,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
@@ -20,7 +20,7 @@
<title>Library Registry - Aetos Standards</title>
<title>Library Registry - Aetos Standards — Reference</title>
@@ -88,7 +88,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -102,7 +102,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -205,13 +205,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -244,28 +244,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -442,50 +420,6 @@
<li class="md-nav__item">
<a href="../10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix/" class="md-nav__link">

View File

@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The standardized application blueprint and library registry.">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
@@ -18,7 +18,7 @@
<title>Aetos Standards</title>
<title>Aetos Standards — Reference</title>
@@ -81,7 +81,7 @@
<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" class="md-header__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href="/." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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>
@@ -95,7 +95,7 @@
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
@@ -198,13 +198,13 @@
<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" class="md-nav__button md-logo" aria-label="Aetos Standards" data-md-component="logo">
<a href="/." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
@@ -237,28 +237,6 @@
<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_layering_rules/" class="md-nav__link">
@@ -435,50 +413,6 @@
<li class="md-nav__item">
<a href="/10_testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="/11_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="/12_genericity_matrix/" class="md-nav__link">

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

587
standards/lib/index.html Normal file
View File

@@ -0,0 +1,587 @@
<!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 rules and library registry of the standardized application blueprint.">
<link rel="next" href="02_layering_rules/">
<link rel="icon" href="assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.23">
<title>Aetos Standards — Reference</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="#standards-reference" 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 — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" 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 — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Home
</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 — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" 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 — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<a href="." class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="02_layering_rules/" class="md-nav__link">
<span class="md-ellipsis">
Layering Rules
</span>
</a>
</li>
<li class="md-nav__item">
<a href="03_composition_root/" class="md-nav__link">
<span class="md-ellipsis">
Composition Root
</span>
</a>
</li>
<li class="md-nav__item">
<a href="04_spec_first_routing/" class="md-nav__link">
<span class="md-ellipsis">
Spec-First Routing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="05_crud_template/" class="md-nav__link">
<span class="md-ellipsis">
CRUD Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="06_pipeline_scaffold/" class="md-nav__link">
<span class="md-ellipsis">
Pipeline Scaffold
</span>
</a>
</li>
<li class="md-nav__item">
<a href="07_worker_and_progress/" class="md-nav__link">
<span class="md-ellipsis">
Worker & Progress
</span>
</a>
</li>
<li class="md-nav__item">
<a href="08_human_in_loop/" class="md-nav__link">
<span class="md-ellipsis">
Human-in-the-Loop
</span>
</a>
</li>
<li class="md-nav__item">
<a href="09_infra_adaptors/" class="md-nav__link">
<span class="md-ellipsis">
Infra Adapters
</span>
</a>
</li>
<li class="md-nav__item">
<a href="12_genericity_matrix/" class="md-nav__link">
<span class="md-ellipsis">
Genericity Matrix
</span>
</a>
</li>
<li class="md-nav__item">
<a href="13_library_registry/" class="md-nav__link">
<span class="md-ellipsis">
Library Registry
</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">
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="standards-reference">Standards Reference</h1>
<p>The reference half of the Standards description: the enforceable rules,
patterns, and the internal library catalog that agents consult while coding.</p>
<ul>
<li><strong>Layering Rules</strong> — the strict request → domain → repository layering and
the rules that enforce it.</li>
<li><strong>Composition Root</strong> — a single composition point wiring the whole app.</li>
<li><strong>Spec-First Routing</strong> — the OpenAPI contract as the routing source of truth.</li>
<li><strong>CRUD Template</strong> — the standardized generic resource endpoint scaffold.</li>
<li><strong>Pipeline Scaffold</strong> — the deterministic pipeline skeleton for multi-stage
jobs.</li>
<li><strong>Worker &amp; Progress</strong> — queued work, progress reporting, and visibility.</li>
<li><strong>Human-in-the-Loop</strong> — guardrails and approvals inside automations.</li>
<li><strong>Infra Adapters</strong> — how infrastructure connects without leaking into domain.</li>
<li><strong>Genericity Matrix</strong> — what is generic vs app-specific.</li>
<li><strong>Library Registry</strong> — the catalog of internal libraries behind all of it.</li>
</ul>
<p>Read the <strong>Wiki</strong> for the philosophy and rationale; these pages are the
reference that mirrors the <code>standards</code> MCP bundle.</p>
</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>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,53 @@
# Layering Rules
## Summary
The dependency direction is fixed. Violating it is a design defect.
---
## Allowed imports
```
interfaces/* -> domain/* (services, ports, models)
interfaces/* -> infra/adapters/* (only read-only value objects)
domain/* -> domain/* (same layer)
domain/* -> pipelines/* (call a pipeline via a port)
infra/adapters/* -> domain/ports/* (implement the interface)
main.py/init.py -> everything (composition root only)
```
## Forbidden imports
```
domain/* -> interfaces/* (never)
domain/* -> fastapi/starlette (never)
infra/adapters/* -> interfaces/* (never)
interfaces/* -> infra/db/* (state lives in resources, not imports)
```
## Why
- A pure domain is testable without a server, a database, or an event loop.
- Adapters can be swapped (in-memory fake, real database) without touching
business logic.
- The HTTP edge stays thin and replaceable.
## The port/adapter contract
A **port** is an abstract class or protocol declared in `domain/<x>/ports/`.
An **adapter** implements it in `infra/adapters/`. The composition root binds
the two.
```
domain/<resource>/ports/db.py -> repository port + document model
domain/<resource>/ports/service.py -> service + factory
infra/db/repos/<vendor>.py -> repository adapter factory
infra/adapters/service.py -> generic CRUD service base
```
## Enforcement
- Keep every domain module importable with only the standard library and
Pydantic. If a domain import pulls in `fastapi`, the layering is broken.
- Reviewers (and CI) reject `import fastapi` inside `domain/` or `infra/`.

View File

@@ -0,0 +1,89 @@
# Composition Root
## Summary
All wiring happens in exactly one module. It builds a **flat resource
registry** and exposes it to the HTTP layer and to scripts.
---
## The resource registry
`init.py` returns a plain `dict[str, Any]`. Keys follow two conventions:
- `<resource>_repo` — a repository adapter for a resource.
- `<resource>_svc` — a service for a resource.
Plus named infrastructure adaptors:
- `http_cache_store` — response cache backend.
- `progress_bus` — progress/event bus.
- `<vendor>_<kind>` — fetchers, clients, stores.
The API stores the dict on `app.state.resources` during lifespan startup.
Handlers read from it; nothing imports concrete adapters.
## Shape
```python
_resources: dict = {}
_initialized = False
async def init(settings=None) -> dict:
global _initialized
if _initialized:
return _resources
await setup_database(uri=settings.mongo_uri, db_name=settings.mongo_db)
# 1. leaf repositories
user_repo = create_user_repo()
# 2. dependent repositories (dependencies passed by keyword)
wallet_repo = create_wallet_repo(user_repo=user_repo)
# 3. services (build via the DI library, injecting the repo)
_resources["user_repo"] = user_repo
_resources["wallet_repo"] = wallet_repo
_resources["user_svc"] = get_user_service(user_repo)
_resources["wallet_svc"] = get_wallet_service(wallet_repo)
# 4. infrastructure adaptors (optional)
_resources["http_cache_store"] = HttpCacheStore(...)
_resources["progress_bus"] = ProgressEventBus()
_initialized = True
return _resources
async def shutdown() -> None:
global _initialized
await close_stores(_resources)
await shutdown_database()
_resources.clear()
_initialized = False
```
## Typed accessors
Expose a `get_svc(name)` helper with one `@overload` per key so scripts get
typing without importing concrete classes:
```python
@overload
def get_svc(name: Literal["user_svc"]) -> UserService: ...
@overload
def get_svc(name: Literal["wallet_svc"]) -> WalletService: ...
def get_svc(name: str):
return _resources[name]
```
Also expose `get_db()` (raw database handle) and pure helpers such as
`compute_fingerprint(payload)` (canonical hash used for deduplication).
## Rules
- `init()` is **idempotent**.
- The composition root is the only place that imports concrete adapters.
- Handlers never call `init()`; they read `request.app.state.resources`.
- Scripts call `init()` / `shutdown()` around their work.

View File

@@ -0,0 +1,77 @@
# Spec-First Routing
## Summary
The OpenAPI document is the single source of truth for the HTTP contract.
Handlers are bound to it by name; there is no decorator router.
---
## The contract
- `openapi.yaml` (or `.json`) declares paths, schemas, parameters, responses,
and security.
- A custom `operationId` names the handler function.
- The framework (`openapi_first`) validates requests/responses against the
spec and dispatches to the handler whose name equals `operationId`.
## App bootstrap
```python
# main.py
from openapi_first.app import OpenAPIFirstApp
app = OpenAPIFirstApp(
openapi_path="openapi.yaml",
routes_module=interfaces.openapi, # module whose namespace holds handlers
title="<App> API",
version="0.1.0",
lifespan=lifespan,
)
```
`lifespan` calls the composition root:
```python
@asynccontextmanager
async def lifespan(app):
app.state.resources = await init()
yield
await shutdown()
```
## Handler registry
`interfaces/openapi.py` is a flat re-export of every handler, so the framework
can resolve `operationId` across the whole app:
```python
from interfaces.item.routes import *
from interfaces.wallet.routes import *
from interfaces.progress.sse import *
```
## Handler shape
Handlers are thin and synchronous with respect to business logic:
```python
async def create_item(request: Request, body: dict):
svc = request.app.state.resources["item_svc"]
return await svc.create(Item.model_validate(body))
```
## Conventions
- `operationId` naming: `list_<resource>`, `create_<resource>`,
`get_<resource>`, `update_<resource>`, `delete_<resource>`.
- Read-only endpoints may use a cache decorator keyed on path + query + user.
- Validation errors -> `400`; not found -> `404`; delete -> `204`.
- Security is declared once in the spec and enforced by the framework; handlers
contain no auth code.
## Codegen
The `openapi_first` library can scaffold models and route stubs from the spec,
and ships app templates (CRUD app, model app, service). Prefer codegen over
hand-writing boilerplate.

View File

@@ -0,0 +1,79 @@
# CRUD Template
## Summary
Every resource follows the same four-file slice. Repetition is intentional: it
makes the codebase predictable and generatable.
---
## The slice
```
domain/<resource>/
models.py # pure Pydantic model (no DB fields)
ports/
db.py # document model + repository factory
service.py # service class + factory
converters.py # (optional) transforms
```
## models.py
A framework-free Pydantic model describing the business shape.
```python
class Item(BaseModel):
name: str
quantity: int = 0
```
## ports/db.py
The persistence model extends the business model and adds database concerns.
The repository factory selects the right repository flavour.
```python
class ItemDocument(Item, BaseDocument): # BaseDocument adds id/created_at/...
pass
def create_item_repo(*, owner_repo=None) -> ItemRepository:
return repo_factory(
collection="items",
document=ItemDocument,
populate_rules=[PopulateRule(field="owner", collection="users")],
cache=None, # or a CachedBaseRepository config
)
```
## ports/service.py
The service is built through the DI library, injecting the repository. The
generic CRUD base provides `create/read/update/patch/delete/search/...`.
```python
class ItemService(CrudsServiceAdaptor[Item, ItemDocument]):
model = Item
schema = ItemDocument
def get_item_service(repo) -> ItemService:
return build(ItemService, instances={"repo": repo})
```
## Naming conventions
| Concept | Convention |
|---|---|
| collection | plural snake case (`items`) |
| document | `<Resource>Document` |
| repository factory | `create_<resource>_repo` |
| service | `<Resource>Service` |
| service factory | `get_<resource>_service` |
| resource key | `<resource>_svc` |
| operationId | `list_items`, `create_item`, ... |
## Optional files
- `converters.py` — pure functions mapping between domain types.
- `ports/enrichment.py` — adapts a pipeline into an async callable the service
can invoke (used when a resource is populated by a pipeline).

View File

@@ -0,0 +1,84 @@
# Pipeline Scaffold
## Summary
Data-driven processing is expressed as a **composition graph**. The graph is
built by a DI library; execution is driven by a DAG engine. Stages are pure and
individually testable.
---
## When to use a pipeline
Use a pipeline when a resource is produced by a **multi-step transformation**
of an input (a document, a file, a message) rather than by a simple CRUD write.
## Structure of a family
A **family** is one input shape (e.g. a file format or a message kind). Each
family has the same skeleton:
```
pipelines/<family>/
abc.py # port contracts (stage interfaces + root interface)
impl.py # concrete stages + root implementation
pipeline.yaml # graph spec: nodes, edges, roots, schema
resources/
pipeline.yaml # runtime spec consumed by the loader
patterns/*.yaml # rule fragments (pattern registry)
banks/<variant>.py # optional variants that re-pin a few slots
```
## Shared scaffolding
```
pipelines/shared/
ports.py # RegistryPort, FinalizePort, etc.
loader.py # build(root_cls) -> wires the graph + engine
registry.py # resolve_root(...) -> root class for a (kind, variant)
```
## The loader
```python
def build(root_cls, *, instances=None, config=None):
# merge resources/patterns/*.yaml into a pattern registry
# bind registry/config into each graph node by id
# build the schema (state) class and the engine
root = root_cls()
root._engine = Engine(graph, state_cls, payload_cls)
return root
```
## The registry
A single lookup replaces hand-rolled `if/else` selection:
```python
_FAMILIES = {
"csv": {"acme": {"heuristic": AcmeCsvPipeline}},
"json": {"globex": {"heuristic": GlobexJsonPipeline}},
}
def resolve_root(kind, variant, mode="heuristic"):
return _FAMILIES[kind][variant][mode]
```
Adding a new variant means adding one class and one registry entry.
## Driving a pipeline
Stages are driven explicitly so intermediate state can be persisted:
```python
pipeline = build(resolve_root(kind, variant))
content = pipeline.ingest.materialize(raw_bytes)
records = pipeline.reader.read(content)
items = pipeline.normalize.build(records)
```
## Testing
Because stages are pure, test each stage in isolation and test the assembled
root against **fixture inputs** whose expected outputs are stored as golden
files. A parity test replays fixtures headlessly.

View File

@@ -0,0 +1,95 @@
# Worker & Progress
## Summary
Long-running work runs in a background worker. Jobs are durable documents that
move through an explicit status machine. Progress is streamed to clients.
---
## The status machine
```
pending -> processing -> completed
\-> failed (retried up to N times)
\-> paused (waiting for human input)
```
- `pending` — queued, eligible for pickup.
- `processing` — claimed by a worker.
- `paused` — blocked on a human-in-the-loop question.
- `failed` — error; `retry_count` increments until a max, then skipped.
- `completed` — terminal success.
## The poll loop
```python
async def poll(resources):
backoff = MIN_POLL
while True:
jobs = await job_svc.search(filter={"status": "pending"}, limit=100)
backoff = MIN_POLL if jobs else min(backoff * 2, MAX_POLL)
for job in jobs:
if (job.retry_count or 0) >= MAX_RETRIES:
continue
await job_svc.update_status(job.id, "processing")
try:
await process(job, resources)
except PauseForResolution:
await job_svc.update_status(job.id, "paused")
except Exception as e:
await job_svc.update_status(
job.id, "failed", error=str(e),
retry_count=(job.retry_count or 0) + 1,
)
await asyncio.sleep(backoff)
```
Tunables live in environment variables: `WORKER_POLL_MIN`, `WORKER_POLL_MAX`,
`WORKER_MAX_RETRIES`.
## Progress events
A worker publishes structured progress events to a **bus** (a port). The HTTP
edge exposes a streaming endpoint that replays events for a given job id.
```python
class ProgressEvent(BaseModel):
job_id: str
step: str
status: str # started | progress | completed | skipped | paused
message: dict | None = None
```
The bus is an in-memory adapter by default; because it is a port, it can be
swapped for a durable broker. Emit from the orchestrator at each stage:
```python
await self.bus.publish(ProgressEvent(job_id=jid, step="normalize",
status="completed", message={"count": n}))
```
## Streaming endpoint
```python
async def stream_job_events(request, id):
bus = request.app.state.resources.get("progress_bus")
if bus is None:
return {"events": []}
async def gen():
sent = 0
while True:
events = bus.get_events(id)
for e in events[sent:]:
yield f"data: {e.model_dump_json(exclude_none=True)}\n\n"
sent += 1
await asyncio.sleep(0.5)
return StreamingResponse(gen(), media_type="text/event-stream")
```
> **Known limitation.** The default in-memory bus is per-process. If the worker
> and the API run as separate processes, events published by the worker are not
> visible to the API. For production, back the bus with a shared broker. The
> port boundary makes this a one-adapter change.

View File

@@ -0,0 +1,87 @@
# Human-in-the-Loop
## Summary
Some inputs are ambiguous and must be resolved by a human before processing can
continue. The blueprint models this as a **durable pause**: an exception is
raised, a question is recorded, the job pauses, and later resumes.
---
## The mechanism
1. During processing, a stage raises a domain exception carrying the context
needed to ask the question:
```python
raise PauseForResolution(
job_id=jid,
reference="<stable key for this decision>",
options=[...],
context={...},
)
```
2. The orchestrator catches it, records a **question document**, and re-raises
so the worker marks the job `paused`.
3. A client lists pending questions and answers one:
```
GET /jobs/{id}/questions -> list pending questions
POST /questions/{qid}/resolve {choice} -> record the choice
```
4. When the **last** pending question is resolved, the resolve endpoint flips
the parent job back to `pending`.
5. The worker picks it up again, rebuilds a **resolution map** from previously
answered questions, and seeds it into the pipeline so the same decision is
not asked twice.
## The question document
```python
class Question(BaseDocument):
job_id: str
reference: str # stable key: stage|field|value
status: str # pending | resolved
options: list[dict]
context: dict
chosen: dict | None = None
resolved_at: str | None = None
```
## Resume map
The worker turns answered questions into a lookup keyed by `reference`, then
injects it into the pipeline so that stage can skip re-raising:
```python
resolved = {q.reference: q.chosen for q in await svc.search(
filter={"job_id": jid, "status": "resolved"})}
pipeline = build(root, instances={"pause": handler}, config={"resolved": resolved})
```
## Resolve endpoint
```python
async def resolve_question(request, id, body):
svc = request.app.state.resources["question_svc"]
q = await svc.read(id)
await svc.update(id, {"chosen": body["chosen"], "status": "resolved",
"resolved_at": now()})
pending = await svc.search(filter={"job_id": q.job_id, "status": "pending"},
limit=1)
if not pending:
jobs = request.app.state.resources["job_svc"]
job = await jobs.read(q.job_id)
if job and job.status == "paused":
await jobs.update_status(q.job_id, "pending")
return q
```
## CLI parity
The same flow is available through scripts/CLI: `list`, `get`, `create`,
`questions`, `resolve`, `retry`.

View File

@@ -0,0 +1,84 @@
# Infra Adapters
## Summary
All external systems are reached through adapters in `infra/`. Prefer an
existing internal library over writing a new adapter.
---
## Database (MongoDB)
- A single connection manager owns the client lifecycle.
`setup_database(uri, db_name)` / `shutdown_database()`.
- A repository **factory** selects the repository flavour:
```python
repo_factory(collection, document, engine=None,
populate_rules=None, cache=None)
```
- base repository — plain CRUD;
- populating repository — resolves referenced documents (foreign keys);
- cached repository — an LRU/TTL cache in front of reads.
- Referenced documents are described declaratively:
```python
PopulateRule(field="owner", collection="users",
nested_rules=[], max_depth=2, projection=None)
```
- Transactions use a session context manager provided by the library.
**Library:** the Mongo operations library (see registry). Do not write raw
Motor calls in the domain.
## HTTP response cache
A generic GET cache sits behind a decorator.
```python
@cache_response(ttl=60)
async def list_items(request): ...
```
- Keyed on path + query + user.
- No-op when no store is wired.
- `invalidate(*resources)` bumps a generation counter for write-triggered
invalidation.
## Event / progress bus
A port with an in-memory default adapter (`publish`, `get_events`). Swap for a
durable broker in production (see Worker & Progress).
## External clients (ingestion)
External fetchers (files, mail, HTTP) are adapters that wrap ingestion
libraries. Construct them in the composition root and inject into
orchestrators.
**Libraries:** the ingestion library (formats) and the mail library (email).
## LLM clients
When a pipeline calls a model provider, route through a pool adaptor that
handles provider selection, retries, and client lifecycle:
```python
pool = setup_async_pool(provider=settings.llm_provider)
result = await pool.complete(model="...", messages=[...])
```
Providers are selected by `LLM_PROVIDER` and configured by environment.
## Key-value store
For report/snapshot storage, provide a pluggable store port with a Redis
adapter and an in-memory fallback.
## Rule
If a capability already exists as a library (DB, DI, ingestion, mail, auth,
docs), **use it**. Writing a private copy of a library is a defect.

View File

@@ -0,0 +1,57 @@
# Genericity Matrix
## Summary
This page states precisely what is **reusable as-is**, what is a **template to
adapt**, and what is **app-specific and must be authored**. Use it to scope a
new build.
---
## Reusable as-is (do not rewrite)
| Area | Artifact |
|---|---|
| Layering & dependency rule | the package layout and import rules |
| Composition root | the `init.py` shape, idempotency, `get_svc` overloading |
| Web edge | `OpenAPIFirstApp` bootstrap, handler-name = `operationId`, thin handlers |
| CRUD slice | the four-file pattern (model / ports-db / ports-service / converters) |
| Generic CRUD service | the base service adaptor |
| Repository factory | base / populating / cached selection |
| Worker | the poll loop, backoff, retry, status machine |
| Progress bus | the bus port + in-memory adapter + streaming endpoint |
| Human-in-the-loop | the durable pause + question document + resolve endpoint + resume map |
| Infra adaptors | HTTP cache decorator, KV store port, LLM pool scaffold |
| Testing | integration harness with fakes, fixture-parity pattern |
| Docs | GSDFC + generated stubs + MCP bundle pipeline |
## Template to adapt (copy, then change names)
| Artifact | Change |
|---|---|
| `pyproject.toml` | project name, dependencies |
| `Dockerfile` / `docker-compose.yaml` | service name, ports, services |
| `.env.example` | connection strings, provider keys |
| `openapi.yaml` | every path/schema/operationId |
| `scripts/` | seed and operator tasks |
## App-specific (must be authored)
| Artifact | Why |
|---|---|
| Resource models | the business shape |
| Repository populate/cache rules | the relationships |
| Service business logic | domain behaviour |
| Pipeline families (if any) | the transformation graph |
| Pattern/rule resources | data-driven policy |
| Fixtures & golden outputs | test data |
## The two axes
Everything app-specific reduces to **two axes**:
1. **Resource model** — the set of resources, their fields, relationships, and
the OpenAPI contract.
2. **Pipeline family** — only if inputs require multi-step transformation.
If you can specify those two axes, the rest of the app follows mechanically.

View File

@@ -0,0 +1,54 @@
# Library Registry
## Summary
The Aetos ecosystem provides internal libraries for the shared concerns of
every application. **Use them.** Writing a private copy of any capability below
is a defect.
Each library also exposes its own documentation as an MCP server. An AI agent
can read a library's full API by connecting to its MCP and reading
`docs://index`, `docs://nav`, and `docs://modules/{module}`.
---
## Catalog
| Library | Import | Purpose | Use instead of | MCP |
|---|---|---|---|---|
| DAG Pipe | `dagpipe` | Deterministic state-transformation DAG engine | hand-rolled orchestration/topological ordering | `:8006` |
| Hexa | `hexa` | Declarative DI / composition-root tooling | manual wiring, hand-written factories | *(see note)* |
| Mongo Ops | `mongo_ops` | Async MongoDB repositories, cache, populate, transactions | raw Motor CRUD and connection lifecycle | `:8007` |
| Omniread | `omniread` | Format-agnostic fetch + parse (HTML, PDF, CSV, XLSX) | custom scrapers/parsers | `:8003` |
| OpenAPI First | `openapi_first` | Spec-first FastAPI bootstrap, client, codegen | decorator routers and hand-written clients | `:8004` |
| Mail Intake | `mail_intake` | Provider-agnostic read-only email ingestion | Gmail OAuth + MIME parsing | `:8002` |
| Py JWT | `jwtlib` | JWT auth primitives (register/login/introspect) | password hashing + token code | `:8005` |
| Doc Forge | `docforge` | Docstring compiler → MkDocs + MCP docs | custom doc generators | `:8001` |
| Auth Server | *(service)* | Central identity service (register/login/me/introspect) | building auth endpoints yourself | — |
## How to choose
| You need to… | Use |
|---|---|
| persist and query documents | Mongo Ops |
| compose dependencies | Hexa |
| run a multi-step transformation | DAG Pipe |
| read/parse an arbitrary input format | Omniread |
| expose a contract-first HTTP API | OpenAPI First |
| ingest email | Mail Intake |
| authenticate users / verify tokens | Py JWT (+ Auth Server) |
| generate documentation | Doc Forge |
## Discovery
A single **standards MCP** exposes `find_library(capability)`, which returns the
matching library, its import name, its "use instead of" guidance, and its MCP
endpoint. Query it before writing any infrastructure.
## Notes
- **Hexa** ships an MCP bundle but is not yet assigned a dedicated port in the
hub config; it is reachable via the standards registry entry and will be
wired to a port.
- Library MCP servers expose **documentation resources** (not executable tools):
they tell an agent the available API surface so it does not invent code.

View File

@@ -0,0 +1,20 @@
# Standards Reference
The reference half of the Standards description: the enforceable rules,
patterns, and the internal library catalog that agents consult while coding.
- **Layering Rules** — the strict request → domain → repository layering and
the rules that enforce it.
- **Composition Root** — a single composition point wiring the whole app.
- **Spec-First Routing** — the OpenAPI contract as the routing source of truth.
- **CRUD Template** — the standardized generic resource endpoint scaffold.
- **Pipeline Scaffold** — the deterministic pipeline skeleton for multi-stage
jobs.
- **Worker & Progress** — queued work, progress reporting, and visibility.
- **Human-in-the-Loop** — guardrails and approvals inside automations.
- **Infra Adapters** — how infrastructure connects without leaking into domain.
- **Genericity Matrix** — what is generic vs app-specific.
- **Library Registry** — the catalog of internal libraries behind all of it.
Read the **Wiki** for the philosophy and rationale; these pages are the
reference that mirrors the `standards` MCP bundle.

View File

@@ -0,0 +1,66 @@
site_name: Aetos Standards — Reference
site_description: The rules and library registry of the standardized application blueprint.
docs_dir: lib
site_dir: ../lib
use_directory_urls: true
theme:
name: material
palette:
- scheme: slate
primary: deep purple
accent: cyan
font:
text: Inter
code: JetBrains Mono
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
markdown_extensions:
- pymdownx.superfences
- pymdownx.inlinehilite
- pymdownx.snippets
- admonition
- pymdownx.details
- pymdownx.highlight:
linenums: true
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.tabbed:
alternate_style: true
- pymdownx.tasklist:
custom_checkbox: true
- tables
- footnotes
- pymdownx.caret
- pymdownx.tilde
- pymdownx.mark
plugins:
- search
nav:
- Home: index.md
- Layering Rules: 02_layering_rules.md
- Composition Root: 03_composition_root.md
- Spec-First Routing: 04_spec_first_routing.md
- CRUD Template: 05_crud_template.md
- Pipeline Scaffold: 06_pipeline_scaffold.md
- Worker & Progress: 07_worker_and_progress.md
- Human-in-the-Loop: 08_human_in_loop.md
- Infra Adapters: 09_infra_adaptors.md
- Genericity Matrix: 12_genericity_matrix.md
- Library Registry: 13_library_registry.md

View File

@@ -0,0 +1,59 @@
site_name: Aetos Standards — Wiki
site_description: The philosophy and prompts behind the standardized application blueprint.
docs_dir: wiki
site_dir: ../wiki
use_directory_urls: true
theme:
name: material
palette:
- scheme: slate
primary: deep purple
accent: cyan
font:
text: Inter
code: JetBrains Mono
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
markdown_extensions:
- pymdownx.superfences
- pymdownx.inlinehilite
- pymdownx.snippets
- admonition
- pymdownx.details
- pymdownx.highlight:
linenums: true
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.tabbed:
alternate_style: true
- pymdownx.tasklist:
custom_checkbox: true
- tables
- footnotes
- pymdownx.caret
- pymdownx.tilde
- pymdownx.mark
plugins:
- search
nav:
- Home: index.md
- Overview: 01_overview.md
- Testing: 10_testing.md
- Build Recipe: 11_build_recipe.md

View File

@@ -0,0 +1,54 @@
# Overview
## Summary
The blueprint is a **hexagonal (ports and adapters) application** with a
**spec-first** web edge and a **single composition root**. It favors explicit
wiring over implicit magic, and it prefers existing internal libraries over
hand-written infrastructure.
---
## The three layers
```
interfaces/ ← HTTP edge: thin handlers bound to an OpenAPI operationId
domain/ ← business core: models, ports (interfaces), services, orchestrators
infra/ ← adapters: databases, caches, external clients, hardware
```
Plus two optional layers:
```
pipelines/ ← data-driven transformation graphs (extraction, enrichment)
scripts/ ← operator scripts that reuse the composition root
```
## Core principles
1. **One-way dependencies.** `interfaces -> domain -> infra` is allowed;
the reverse is forbidden. The domain never imports a framework it does not
own.
2. **Ports in the domain, adapters in infra.** A service depends on an
abstract port; the composition root injects a concrete adapter.
3. **One composition root.** Nothing constructs its own dependencies. All
wiring lives in one module (`init.py`) and is exposed as a flat resource
registry.
4. **Spec-first.** The HTTP contract is declared in an OpenAPI document. Route
handlers are looked up by `operationId`. There are no decorator routers.
5. **Reuse the libraries.** Pipeline orchestration, DI, Mongo repositories,
ingestion, auth, and docs are provided by internal libraries. Do not
reimplement them — see the library registry.
6. **Explicit state machines.** Long-running work moves through explicit,
durable statuses and can pause for human input.
## Runtime processes
A standard app may run as up to three processes that share the same
composition root:
| Process | Entry point | Responsibility |
|---|---|---|
| API | `main.py` | serve HTTP; start/stop resources via lifespan |
| Worker | `worker.py` | poll durable jobs, run pipelines, publish progress |
| Scripts | `python -m scripts.<name>` | one-shot operator tasks |

View File

@@ -0,0 +1,56 @@
# Testing
## Summary
Two test suites: **integration** (the HTTP edge with fakes) and **unit** (pure
domain and pipeline logic). Both run under pytest with asyncio auto mode.
---
## Layout
```
tests/
integration/ # TestClient(app) + mocked resources
unit/ # models, converters, pipeline stages/roots
conftest.py # fixtures
```
## Integration tests
- Build the app with `TestClient`.
- Replace `app.state.resources` with fake repositories/services so no database
is required.
- Patch the auth introspection call (`httpx.AsyncClient.post`) to return a
canned identity.
- Assert status codes and bodies for list/get/create/update/delete, plus
`400`, `404`, `204`, and the streaming endpoint's fallback.
```python
client = TestClient(app)
app.state.resources = {"item_svc": FakeItemService(), ...}
def test_create_item():
r = client.post("/items", json={"name": "x"})
assert r.status_code == 200
```
## Unit tests
- Domain models and converters: pure, no I/O.
- Pipeline stages: feed a fixture state, assert the transformed state.
- Assembled pipeline roots: **fixture parity** — replay a stored fixture input
and compare against a golden output file.
## Config-consistency tests
For rule-driven pipelines, add a test that cross-references rules against the
declared pattern registry: every flag emitted must be defined; every defined
flag must be reachable. This catches drift without running the pipeline.
## Conventions
- `asyncio_mode = "auto"`; no manual event loops.
- Fixtures are checked into the repo (inputs + golden outputs).
- Tests skip (not fail) when a required fixture is absent.
- Do not mock the domain; mock only the infrastructure edge.

View File

@@ -0,0 +1,82 @@
# Build Recipe
## Summary
Follow this ordered checklist to generate a new application of the standard
shape. Every step is deterministic; only steps 2 and 7 require app-specific
authoring.
---
## 0. Query the registry
Before writing anything, read the **library registry** and note which internal
libraries provide DB, DI, routing, ingestion, auth, and docs. Do not
reimplement them.
## 1. Scaffold the repository
Copy the `templates/` skeleton. It provides: `pyproject.toml`, `openapi.yaml`,
`main.py`, `init.py`, `worker.py`, `config.py`, `Dockerfile`,
`docker-compose.yaml`, `.env.example`, and the package tree
(`domain/ infra/ interfaces/ pipelines/ tests/ scripts/`).
## 2. Author the spec *(app-specific)*
Write `openapi.yaml`: resources, schemas, `operationId`s, security, and any
extension metadata. This is the contract.
## 3. Write each CRUD slice *(app-specific)*
For each resource, create the four-file slice (see **CRUD Template**):
`models.py`, `ports/db.py`, `ports/service.py`, optional `converters.py`.
## 4. Wire the composition root
In `init.py`: build leaf repositories, then dependent repositories, then
services; add infrastructure adaptors (cache store, progress bus, stores,
fetchers). Add `get_svc` overloads.
## 5. Add routes
Create `interfaces/<resource>/routes.py` (thin handlers) and re-export them in
`interfaces/openapi.py`. Add a cache decorator to read endpoints.
## 6. Bootstrap the app and worker
Confirm `main.py` wires the OpenAPI-first app with the lifespan. If the app has
long-running jobs, adapt `worker.py` to poll the relevant job collection.
## 7. Add a pipeline family *(only if data-driven)*
Create `pipelines/<family>/` with `abc.py`, `impl.py`, `pipeline.yaml`,
`resources/`, and register the root in `registry.py`. Add fixtures and a parity
test.
## 8. Add infrastructure as needed
Only where the standard adaptors do not cover the need. Prefer library-backed
adapters.
## 9. Tests
Add integration tests with fakes and unit tests for domain/pipeline logic; add
a config-consistency test if using rule-driven pipelines.
## 10. Scripts and seeds
Add operator scripts under `scripts/` that use `init()` / `get_svc()` /
`shutdown()`.
## 11. Docs
Author GSDFC docstrings, generate the type stubs (`.pyi`), mark the package
`py.typed`, and build docs.
## Definition of done
- `python -c "import main"` succeeds.
- `pytest` passes.
- The app serves the spec's operations; the worker drains its queue.
- No domain module imports a web framework.
- No infrastructure was reimplemented that a library already provides.

View File

@@ -0,0 +1,45 @@
# The Aetos Standard App Blueprint
A single, reusable architecture for backend applications in the Aetos ecosystem.
Every application built with this blueprint has the same shape:
- a **spec-first HTTP layer** driven by an OpenAPI document;
- a **domain layer** of pure models, ports, and services;
- an **infrastructure layer** of adapters (MongoDB, cache, workers, LLM, mail);
- a **composition root** that wires everything in exactly one place;
- an optional **pipeline layer** for data-driven extraction/enrichment;
- an optional **background worker** that runs long-running jobs and reports progress.
> This blueprints is deliberately **app-agnostic**. It never names a concrete
> business domain. Any application — expenses, health metrics, inventory,
> analytics — is produced by filling in **two axes only**: the resource model
> and (if needed) the pipeline family.
## How to read this
| Page | What it covers |
|---|---|
| Overview | The philosophy and the one-way dependency rule |
| Layering Rules | Which package may import which |
| Composition Root | The single wiring point |
| Spec-First Routing | OpenAPI as the source of truth |
| CRUD Template | The canonical resource slice |
| Pipeline Scaffold | Data-driven processing families |
| Worker & Progress | Async jobs, status machine, streaming progress |
| Human-in-the-Loop | Pausing a job to ask a question |
| Infra Adapters | MongoDB, cache, stores, LLM, mail |
| Testing | Integration + unit conventions |
| Build Recipe | The ordered checklist to generate a new app |
| Genericity Matrix | What is reusable vs what you must write |
## For AI agents
This content is served as MCP resources under `docs://index`, `docs://nav`,
and `docs://modules/{module}`. To build a new app:
1. Read `build_recipe` first.
2. Read `genericity_matrix` to know what you must author.
3. Query the **library registry** (`find_library`) before writing any
infrastructure yourself.
4. Copy the `templates/` skeleton and fill the two app-specific axes.

View File

@@ -0,0 +1,54 @@
# Application Template
A minimal, runnable skeleton of the standardized architecture. It demonstrates
both axes of the blueprint (see `standards`):
1. **Resource axis** — items and jobs, each a Claude-style generic CRUD slice
(model → document → repo → service → route), all driven from `openapi.yaml`.
2. **Pipeline axis** — a background `worker.py` that polls pending jobs and runs
`pipelines/item_sync.py`, a deterministic async step chain.
Everything here is deliberately small so an agent can rewrite each file rather
than delete unused code. The domain is a neutral "item", not an app noun.
## Instantiate a new app
cp -r templates/app apps/<your-app>
cd apps/<your-app>
1. `pyproject.toml` — rename the package; keep the internal library pins.
2. `config.py` — replace/add settings consumed by your domain.
3. `openapi.yaml` — replace the `Item`/`Job` resources with your resources.
4. `domain/` — rename `item` and `job` slices to your aggregates.
5. `pipelines/item_sync.py` — replace the demo steps with your pipeline.
6. `tests/` — keep the two test files as the pattern for your own.
Run the API:
pip install -e ".[dev]"
uvicorn main:app --reload
Run the worker:
python worker.py
## What to keep, what to replace
| Keep | Replace / rename |
|------------------------------|---------------------------------------|
| `config.py` shape | Settings fields |
| `init.py` wiring pattern | Resource names |
| openapi-first routing | Paths, schemas, operationIds |
| mongo-ops repo factory | Collections, doc models |
| generic CRUD adaptor | Nothing (reuse as-is) |
| worker poll + status loop | Job payloads, pipeline steps |
## Where the internal libraries slot in
- `openapi_first.app.OpenAPIFirstApp` — main.py, interfaces/openapi.py
- `mongo_ops` — infra/db/setup.py, infra/db/repos/mongo.py, domain/*/ports/db.py
- `hexa.build` — domain/*/ports/service.py
- `dagpipe` — pipelines/ (wrap step chains in a DAG once they branch)
Confirm current endpoints and ownership with the `standards` registry MCP tool:
`find_library("pipeline")`, `find_library("auth")`, etc.

View File

@@ -0,0 +1,8 @@
.venv/
__pycache__/
*.pyc
.env
.git/
docs/
dist/
build/

View File

@@ -0,0 +1,5 @@
DEBUG=false
MONGO_URI=mongodb://localhost:27017
MONGO_DB=app_template
WORKER_POLL_SECONDS=30
WORKER_MAX_RETRIES=3

View File

@@ -0,0 +1,15 @@
FROM python:3.11-slim
WORKDIR /app
COPY pyproject.toml ./
COPY . .
RUN pip install --no-cache-dir --upgrade pip \
&& pip install --no-cache-dir .
EXPOSE 8000
# Two processes, per the two axes:
# - main.py : the spec-first FastAPI application
# - worker.py : the pipeline consumer polling pending jobs
CMD ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port 8000 & exec python worker.py"]

View File

@@ -0,0 +1,36 @@
"""# Summary
App configuration loaded from environment — a Settings dataclass with defaults
plus a singleton settings instance populated from OS environment variables at
import time.
"""
import os
from dataclasses import dataclass
@dataclass
class Settings:
"""Runtime configuration settings for the application.
Attributes:
debug (bool): Enable debug behavior. Defaults to False.
mongo_uri (str): MongoDB connection URI. Defaults to mongodb://localhost:27017.
mongo_db (str): MongoDB database name. Defaults to app_template.
worker_poll_seconds (int): Worker poll interval in seconds. Defaults to 30.
worker_max_retries (int): Maximum job retries before skipping. Defaults to 3.
"""
debug: bool = False
mongo_uri: str = "mongodb://localhost:27017"
mongo_db: str = "app_template"
worker_poll_seconds: int = 30
worker_max_retries: int = 3
settings = Settings(
debug=os.environ.get("DEBUG", "").lower() in ("1", "true", "yes"),
mongo_uri=os.environ.get("MONGO_URI", "mongodb://localhost:27017"),
mongo_db=os.environ.get("MONGO_DB", "app_template"),
worker_poll_seconds=int(os.environ.get("WORKER_POLL_SECONDS", "30")),
worker_max_retries=int(os.environ.get("WORKER_MAX_RETRIES", "3")),
)

View File

@@ -0,0 +1,21 @@
services:
api:
build: .
command: uvicorn main:app --host 0.0.0.0 --port 8000
env_file: .env
ports:
- "8000:8000"
depends_on:
- mongo
worker:
build: .
command: python worker.py
env_file: .env
depends_on:
- mongo
mongo:
image: mongo:7
ports:
- "27017:27017"

View File

@@ -0,0 +1,19 @@
"""# Summary
Item domain model — the neutral resource used throughout the template.
"""
from pydantic import BaseModel, Field
class Item(BaseModel):
"""A single countable resource.
Attributes:
name (str): Item name.
quantity (int): Item quantity. Defaults to 1.
"""
name: str
quantity: int = Field(default=1)
model_config = {"extra": "ignore"}

View File

@@ -0,0 +1,20 @@
"""# Summary
Mongo persistence for items: document schema and repository factory.
"""
from domain.item.models import Item
from infra.db.repos.mongo import _repo_factory as mongo_repo_factory
from mongo_ops import BaseDocument, BaseRepository
class ItemDocument(Item, BaseDocument):
"""Mongo document form of :class:`Item`."""
def create_item_repo() -> BaseRepository:
"""Create the Mongo-backed item repository.
Returns:
BaseRepository: Repository wired to the ``items`` collection.
"""
return mongo_repo_factory("items", ItemDocument)

View File

@@ -0,0 +1,33 @@
"""# Summary
CRUD service wiring for the item aggregate via the hexa container.
"""
from hexa import build
from domain.item.models import Item
from domain.item.ports.db import ItemDocument
from infra.adapters.service import CrudsServiceAdaptor
class ItemCrudsService(CrudsServiceAdaptor[Item, ItemDocument]):
"""Item CRUD service resolving :class:`ItemDocument` from a repo.
Notes:
Instances are created by :func:`get_item_service`. The ``model`` and
``schema`` class attributes bind the domain model and its document type.
"""
model = Item
schema = ItemDocument
def get_item_service(repo) -> ItemCrudsService:
"""Build an item CRUD service wired to ``repo``.
Args:
repo (Any): Mongo-backed item repository from :func:`create_item_repo`.
Returns:
ItemCrudsService: Ready-to-use item CRUD service.
"""
return build(ItemCrudsService, instances={"repo": repo})

View File

@@ -0,0 +1,26 @@
"""# Summary
Job domain model — a pipeline work item consumed by the background worker.
"""
from typing import Literal
from pydantic import BaseModel, Field
class Job(BaseModel):
"""A unit of background work.
Attributes:
name (str): Job name.
status (str): Lifecycle status. Defaults to "pending".
retry_count (int): Times the job failed. Defaults to 0.
error_message (str | None): Last failure message. Defaults to None.
payload (dict | None): Arbitrary job payload. Defaults to None.
"""
name: str
status: Literal["pending", "processing", "done", "failed"] = "pending"
retry_count: int = Field(default=0)
error_message: str | None = None
payload: dict | None = None
model_config = {"extra": "ignore"}

View File

@@ -0,0 +1,20 @@
"""# Summary
Mongo persistence for jobs: document schema and repository factory.
"""
from domain.job.models import Job
from infra.db.repos.mongo import _repo_factory as mongo_repo_factory
from mongo_ops import BaseDocument, BaseRepository
class JobDocument(Job, BaseDocument):
"""Mongo document form of :class:`Job`."""
def create_job_repo() -> BaseRepository:
"""Create the Mongo-backed job repository.
Returns:
BaseRepository: Repository wired to the ``jobs`` collection.
"""
return mongo_repo_factory("jobs", JobDocument)

View File

@@ -0,0 +1,33 @@
"""# Summary
CRUD service wiring for the job aggregate via the hexa container.
"""
from hexa import build
from domain.job.models import Job
from domain.job.ports.db import JobDocument
from infra.adapters.service import CrudsServiceAdaptor
class JobCrudsService(CrudsServiceAdaptor[Job, JobDocument]):
"""Job CRUD service resolving :class:`JobDocument` from a repo.
Notes:
Instances are created by :func:`get_job_service`. The ``model`` and
``schema`` class attributes bind the domain model and its document type.
"""
model = Job
schema = JobDocument
def get_job_service(repo) -> JobCrudsService:
"""Build a job CRUD service wired to ``repo``.
Args:
repo (Any): Mongo-backed job repository from :func:`create_job_repo`.
Returns:
JobCrudsService: Ready-to-use job CRUD service.
"""
return build(JobCrudsService, instances={"repo": repo})

View File

@@ -0,0 +1,128 @@
"""# Summary
Generic CRUD service adaptor over a Mongo repository.
Bridge pydantic models and mongo-ops documents, exposing create, read, update,
patch, delete, and search operations for every domain that needs them.
"""
from typing import Generic, Type, TypeVar
from infra.db.repos import mongo
from pydantic import BaseModel
from mongo_ops import BaseDocument
from mongo_ops.models import PyObjectId
Model = TypeVar("Model", bound=BaseModel)
Schema = TypeVar("Schema", bound=BaseDocument)
class CrudsServiceAdaptor(Generic[Model, Schema]):
"""Adapt a generic Mongo repository to a model/schema CRUD service.
Attributes:
repo (mongo.BaseRepository): Repository backing all CRUD operations.
model (Type[Model]): Pydantic model type handled by this service.
schema (Type[Schema]): Document schema type persisted by the repository.
"""
repo: mongo.BaseRepository
model: Type[Model]
schema: Type[Schema]
def __init__(self, *, repo=None):
"""Initialize the adaptor with a backing repository.
Args:
repo (mongo.BaseRepository): Repository used for all operations.
"""
self.repo = repo
@staticmethod
def model_to_dict(model_obj: Model) -> dict:
"""Serialize a model into a sparse dictionary.
Args:
model_obj (Model): Model instance to serialize.
Returns:
dict: Fields that are set and not ``None``.
"""
return model_obj.model_dump(exclude_unset=True, exclude_none=True)
async def create(self, data: Model | dict) -> Schema:
"""Create a document from a model or raw mapping.
Args:
data (Model | dict): Model instance or field mapping to persist.
Returns:
Schema: Persisted document.
"""
if isinstance(data, dict):
data = self.schema(**data)
return await self.repo.create(data)
async def read(self, id: PyObjectId) -> Schema | None:
"""Read a document by primary key.
Args:
id (PyObjectId): Document identifier.
Returns:
Schema | None: Matching document, or ``None`` when absent.
"""
return await self.repo.get_by_id(id)
async def update(self, id: PyObjectId, data: Model | dict) -> Schema | None:
"""Replace a document by primary key.
Args:
id (PyObjectId): Document identifier.
data (Model | dict): Replacement model or field mapping.
Returns:
Schema | None: Updated document, or ``None`` when absent.
"""
return await self.repo.update(
id,
data if isinstance(data, dict) else self.model_to_dict(data),
)
async def patch(self, id: PyObjectId, data: dict) -> Schema | None:
"""Partially update a document by primary key.
Args:
id (PyObjectId): Document identifier.
data (dict): Fields to patch.
Returns:
Schema | None: Updated document, or ``None`` when absent.
"""
return await self.repo.patch(id, data)
async def delete(self, id: PyObjectId) -> bool:
"""Delete a document by primary key.
Args:
id (PyObjectId): Document identifier.
Returns:
bool: ``True`` when a document was deleted.
"""
return await self.repo.delete(id)
async def search(self, filter: dict | None = None, *args, **kwargs) -> list[Schema]:
"""List documents matching an optional filter.
Args:
filter (dict | None): Query filter passed to the repository.
Returns:
list[Schema]: Matching documents.
Notes:
Extra positional and keyword arguments are forwarded to the
repository.
"""
return await self.repo.get_many(filter=filter, *args, **kwargs)

View File

@@ -0,0 +1,42 @@
"""# Summary
Generic MongoDB CRUD repo — single implementation for all domains.
Select a concrete mongo-ops repository (base, cached, or populating) from the
options supplied to the factory.
"""
from typing import List, Optional, Type
from mongo_ops import BaseRepository, CachedBaseRepository, PopulatingRepository
from mongo_ops.cache import CacheBackend, CacheConfig
from mongo_ops.models import BaseDocument
from mongo_ops.populate import PopulationEngine, PopulateRule
def _repo_factory(
collection: str,
db_model: Type[BaseDocument],
cache_backend: Optional[CacheBackend] = None,
cache_config: Optional[CacheConfig] = None,
engine: Optional[PopulationEngine] = None,
populate_rules: Optional[List[PopulateRule]] = None,
) -> BaseRepository:
"""Build the appropriate mongo-ops repository.
Args:
collection (str): Collection name to operate on.
db_model (Type[BaseDocument]): Document model bound to the collection.
cache_backend (Optional[CacheBackend]): Cache backend enabling cached reads.
cache_config (Optional[CacheConfig]): Cache configuration for the backend.
engine (Optional[PopulationEngine]): Population engine for reference expansion.
populate_rules (Optional[List[PopulateRule]]): Rules applied by the engine.
Returns:
BaseRepository: Repository instance matching the supplied options.
"""
if engine and populate_rules is not None:
return PopulatingRepository(collection, db_model, engine, populate_rules)
elif cache_backend is not None:
return CachedBaseRepository(collection, db_model, cache_backend, cache_config)
else:
return BaseRepository(collection, db_model)

View File

@@ -0,0 +1,23 @@
"""# Summary
Database setup — connection lifecycle only. No domain imports.
Connect and disconnect the shared Mongo connection manager at application
startup and shutdown.
"""
from mongo_ops import MongoConnectionManager
async def setup_database(uri: str, db_name: str):
"""Connect the shared Mongo connection manager.
Args:
uri (str): Mongo connection URI.
db_name (str): Target database name.
"""
await MongoConnectionManager.connect(uri=uri, db_name=db_name)
async def shutdown_database():
"""Disconnect the shared Mongo connection manager."""
await MongoConnectionManager.disconnect()

Some files were not shown because too many files have changed in this diff Show More