docs: document backend architecture and checks

This commit is contained in:
Dariusz L
2026-08-02 03:31:01 +02:00
parent e489c3fac7
commit 8eca219420
3 changed files with 64 additions and 5 deletions
+9
View File
@@ -186,6 +186,15 @@ Configure credentials and API keys in the Settings panel to authenticate gated d
* Libraries: `requests`, `aiohttp`, `rapidfuzz`, `huggingface-hub`
* Modern web browser with JS support (Chrome, Edge, Firefox, Brave)
## 🧱 Backend Architecture
The ComfyUI entry point is intentionally thin. Runtime state lives in
`core/extension.py`, route registration is centralized in
`core/routes/registry.py`, HTTP adapters live in `core/routes/`, and reusable
feature behavior lives in `core/services/`. See
[`docs/architecture.md`](docs/architecture.md) for the dependency flow and
local verification commands.
---
## 📜 License
+47
View File
@@ -0,0 +1,47 @@
# Backend architecture
Model Resolver keeps the ComfyUI entry point small and separates HTTP wiring from
the feature logic that powers each route.
## Runtime flow
1. `__init__.py` exposes the ComfyUI compatibility exports and initializes the
extension.
2. `core/extension.py` owns runtime state such as progress trackers and starts
route registration.
3. `core/routes/registry.py` loads the available integrations and builds a
`RouteContext` with explicit dependencies.
4. Modules in `core/routes/` adapt HTTP requests and responses to service calls.
5. Services in `core/services/` contain feature behavior and receive their
dependencies through `RouteContext`.
The grouping modules `core/routes/model_info.py`, `core/routes/search.py`, and
`core/routes/workflow.py` remain compatibility entry points for related route
families. The actual handlers live in focused route adapters and services.
## Adding a route
When adding a feature, keep the request parsing, status codes, and JSON response
in a route adapter. Put reusable behavior in a service and add its dependency to
`RouteContext` explicitly. Use `json_api_endpoint` for the common error boundary,
and preserve deliberate `aiohttp.web.HTTPException` statuses when returning
client errors.
Add a focused route/service test before changing behavior. For changes that touch
route registration or shared backend code, run the complete Python suite as well.
## Local verification
Run these commands with the same Python interpreter used by ComfyUI:
```powershell
python -m pytest
python -m ruff check __init__.py core
python -m compileall -q __init__.py core
python -m coverage run -m pytest
python -m coverage report -m
```
The development tools are declared in the `dev` optional dependency group in
`pyproject.toml`. Coverage configuration is kept there as well, with branch
coverage enabled and `core/` as the measured source.
+8 -5
View File
@@ -106,9 +106,9 @@ test('Missing Models rows use fixed-size virtualization for smooth stable scroll
assert.ok(rowRule, 'Expected the Missing Models row style');
assert.match(rowRule[1], /content-visibility\s*:\s*auto/);
assert.match(rowRule[1], /contain-intrinsic-size\s*:\s*70px/);
assert.match(rowRule[1], /height\s*:\s*70px/);
assert.match(rowRule[1], /min-height\s*:\s*70px/);
assert.match(rowRule[1], /contain-intrinsic-size\s*:\s*var\(--mr-missing-row-height\)/);
assert.match(rowRule[1], /height\s*:\s*var\(--mr-missing-row-height\)/);
assert.match(rowRule[1], /min-height\s*:\s*var\(--mr-missing-row-height\)/);
assert.match(rowRule[1], /box-sizing\s*:\s*border-box/);
assert.match(rowRule[1], /contain\s*:\s*layout paint style/);
});
@@ -138,7 +138,7 @@ test('manual model selection uses the two-line status card layout', () => {
);
assert.match(
resolverMainCssSource,
/\.mr-missing-detail-pane \.model-resolver-selected\s*\{[^}]*height:\s*70px[^}]*border-radius:\s*0/s
/\.mr-missing-detail-pane \.model-resolver-selected\s*\{[^}]*height:\s*var\(--mr-missing-row-height\)[^}]*border-radius:\s*0/s
);
assert.match(
resolverMainCssSource,
@@ -148,7 +148,10 @@ test('manual model selection uses the two-line status card layout', () => {
resolverMainCssSource,
/\.mr-missing-detail-pane \.mr-selected-bar-inner\s*\{[^}]*flex-direction:\s*column/s
);
assert.match(resolverMainCssSource, /\.mr-btn-danger\s*\{[^}]*rgba\(239,\s*68,\s*68/s);
assert.match(
resolverMainCssSource,
/\.mr-missing-detail-pane \.model-resolver-selected \.mr-btn-danger:hover[^}]*background:\s*rgba\(239,\s*68,\s*68/s
);
});
test('floating dialog drag stays on the compositor without forced style reads', () => {