docs: document backend architecture and checks
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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', () => {
|
||||
|
||||
Reference in New Issue
Block a user