Decouple core from plugins; wire widgets hook; drop dead search hook
Architectural pass from the skill review ("plugin is the product" boundary).
Core no longer imports plugin models at module load (was a hard import-time
dependency that broke core if the computers plugin was absent/disabled):
- collector.py, applications.py, reports.py: lazy + guarded imports of the
computers plugin models. Endpoints that need install-tracking now return 503
when the plugin is absent instead of failing at import.
Search honors runtime enable/disable:
- search.py: _require_enabled(name) raises ImportError for a disabled plugin,
so each plugin-scoped block skips it (a disabled plugin's rows leave search).
- Replace hardcoded root/rootpassword employee-DB connection in _search_employees
with the shared env-backed employee_connection helper.
Plugin hooks (integrating-plugin-hooks: every hook needs a consumer):
- get_dashboard_widgets: add the consumer GET /api/dashboard/widgets (5 plugins
already implemented the hook; it had none). Skips disabled, isolates in prod.
- get_searchable_fields: REMOVED. Zero plugins implemented it and there was no
consumer; global search is a core concern over the asset model. Contract
reduction, __contract_version__ 0.3.0 -> 0.4.0.
Docs/contract: PLUGIN-HOOKS.md (widgets consumer note, searchable-fields removal,
0.4.0), PLUGIN-QUICKSTART.md, ADR-001 hook list. Tests: widgets endpoint
aggregate + disabled-skip; contract tests for the removed/added hooks.
151 tests pass, naming/style green, app boots all 6 plugins.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ The contract is locked in [ADR-001](../docs/adr/ADR-001-asset-as-platform-contra
|
||||
The framework declares its contract version in `shopdb/__init__.py`:
|
||||
|
||||
```python
|
||||
__contract_version__ = '0.3.0'
|
||||
__contract_version__ = '0.4.0'
|
||||
```
|
||||
|
||||
Each plugin's `manifest.json` declares the range of contract versions it supports:
|
||||
@@ -166,6 +166,10 @@ class NotificationsPlugin(BasePlugin):
|
||||
}]
|
||||
```
|
||||
|
||||
Consumed by `GET /api/dashboard/widgets`, which merges widgets from all enabled
|
||||
plugins sorted by `position` (disabled plugins are skipped; a broken plugin is
|
||||
isolated in prod, re-raised in dev/test).
|
||||
|
||||
### `get_navigation_items() -> List[Dict]`
|
||||
|
||||
Returns navigation menu items.
|
||||
@@ -181,24 +185,10 @@ class ComputersPlugin(BasePlugin):
|
||||
}]
|
||||
```
|
||||
|
||||
### `get_searchable_fields() -> List[Dict]`
|
||||
|
||||
Declares fields the plugin contributes to global search.
|
||||
|
||||
```python
|
||||
from .models import Computer
|
||||
|
||||
class ComputersPlugin(BasePlugin):
|
||||
def get_searchable_fields(self):
|
||||
return [{
|
||||
'model': Computer,
|
||||
'search_fields': ['hostname', 'serialnumber', 'currentuser'],
|
||||
'result_type': 'computer',
|
||||
'url_template': '/computers/{id}',
|
||||
'title_field': 'hostname',
|
||||
'subtitle_field': 'currentuser',
|
||||
}]
|
||||
```
|
||||
> Removed in contract 0.4.0: `get_searchable_fields`. Global search
|
||||
> (`/api/search`) is a core concern that queries the asset model directly and
|
||||
> already covers every bundled asset type; no plugin ever implemented the hook.
|
||||
> Search honors runtime plugin enable/disable.
|
||||
|
||||
### `get_collector_schema() -> Optional[Dict]`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user