Discover and share modules for DOCSight.
DOCSight can install catalog modules from Settings > Extensions > Community Modules. The catalog is defined in registry.json.
| Module | Type | What it adds | Requirements |
|---|---|---|---|
| VF Kabel Deutschland Community Thresholds | analysis |
Regional signal thresholds based on community recommendations for Vodafone/Kabel Deutschland cable connections | DOCSight 2026.2+ |
| UDM WAN-Monitor | integration |
WAN1/WAN2 status collection for Ubiquiti UDM Pro/SE setups, with DOCSight events and dashboard surfaces | DOCSight 2026.2+, UDM access on the local network |
The catalog is curated, but modules can be maintained either in this repository or in an external contributor repository. See Submitting a Module for the registry format and review checklist.
- Copy the
TEMPLATE/directory - Rename the directory to your module name
- Edit
manifest.jsonwith your module's details - Add your code
- Test locally
- Submit to the registry
A DOCSight module is a directory with a manifest.json at its root:
my-module/
├── manifest.json # Required — module metadata
├── __init__.py # Required — Python package marker
├── routes.py # Optional — Flask Blueprint (API endpoints / pages)
├── collector.py # Optional — data collector class
├── storage.py # Optional — SQLite storage helper
├── i18n/ # Optional — translation files
│ ├── en.json
│ ├── de.json
│ ├── es.json
│ └── fr.json
├── static/ # Optional — CSS/JS assets
│ ├── style.css # Auto-loaded if present
│ └── main.js # Auto-loaded if present
└── templates/ # Optional — Jinja2 templates
└── my_settings.html # Settings panel template
Every module needs a manifest.json:
{
"id": "community.mymodule",
"name": "My Module",
"description": "What this module does in one sentence",
"version": "1.0.0",
"author": "your-github-username",
"minAppVersion": "2026.2",
"type": "integration",
"contributes": {
"routes": "routes.py",
"i18n": "i18n/"
}
}| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier. Must match ^[a-z][a-z0-9_.]+$. Use community. or your username as prefix. |
name |
string | Human-readable name shown in the UI |
description |
string | One-line description |
version |
string | Semantic version (major.minor.patch) |
author |
string | Your GitHub username |
minAppVersion |
string | Minimum DOCSight version (currently 2026.2) |
type |
string | One of: integration, analysis, theme |
contributes |
object | What this module provides (see Contribution Types) |
| Field | Type | Description |
|---|---|---|
homepage |
string | URL to module documentation or repo |
license |
string | SPDX license identifier (e.g., MIT) |
config |
object | Default configuration values (details) |
config_secrets |
array | Module-owned sensitive config keys (details) |
menu |
object | Sidebar navigation entry (details) |
Add a sidebar link for your module:
"menu": {
"label_key": "community.mymodule.nav_title",
"icon": "puzzle",
"order": 50
}label_key— i18n key for the label (namespaced with your module ID)icon— Lucide icon nameorder— Sort position in sidebar (higher = lower; built-in modules use 10–30)
Declare default values and they are automatically registered in DOCSight's config system:
{
"config": {
"mymodule_enabled": false,
"mymodule_api_url": "",
"mymodule_api_token": "",
"mymodule_interval": 300
},
"config_secrets": [
"mymodule_api_token"
]
}- Boolean values are auto-added to
BOOL_KEYS(parsed from checkbox forms) - Integer values are auto-added to
INT_KEYS(parsed from text inputs) - String values are stored as-is
- Keys must not conflict with existing core config keys
Use config_secrets for module passwords, API tokens, and other sensitive settings:
- Every key in
config_secretsmust also exist in the same manifest'sconfigobject with a string default, normally""; non-string defaults are rejected so encrypted values never enter scalar coercion. config_secretsmust be a list of unique strings.- Secret keys are encrypted at rest and masked in Settings after they are saved.
- Community collectors can read only their own declared secret keys; they still cannot read DOCSight core secrets such as modem passwords or global API tokens.
- Settings templates should render secret fields as empty password/token inputs with
data-config-secret="true". Adddata-saved-secret="true"only when the masked config value indicates an existing saved secret. This explicit metadata makes an untouched field post the mask while an edited field posts the new value. Do not write saved secret values back into HTMLvalueattributes.
The manifest capability contract is owned by DOCSight core rather than duplicated in this catalog. With sibling checkouts, run python3 ../docsight/app/manifest_contract.py .; catalog CI performs the same check against current core before running the registry-specific validator.
The contributes object declares what your module provides. All keys are optional — include only what you need.
"contributes": { "routes": "routes.py" }Your routes.py must export a Flask Blueprint named bp or blueprint:
from flask import Blueprint, jsonify
bp = Blueprint("mymodule_bp", __name__)
@bp.route("/api/mymodule/data")
def api_data():
return jsonify({"status": "ok"})The Blueprint is automatically registered with the Flask app. No URL prefix is added — you control the full path.
Accessing core services in routes:
from app.web import get_storage, get_config_manager
@bp.route("/api/mymodule/data")
def api_data():
storage = get_storage() # SQLite storage instance
config = get_config_manager() # Config manager instance
return jsonify({...})"contributes": { "collector": "collector.py:MyCollector" }Format: filename.py:ClassName. Your collector must extend the base class:
from app.collectors.base import Collector, CollectorResult
class MyCollector(Collector):
name = "mymodule"
def __init__(self, config_mgr, storage, web, poll_interval=300, **kwargs):
super().__init__(poll_interval)
self._config = config_mgr
self._storage = storage # core SnapshotStorage instance
self._web = web # web state manager
def is_enabled(self):
return self._config.get("mymodule_enabled", False)
def collect(self):
data = {"value": 42}
return CollectorResult(source=self.name, data=data)DOCSight passes config_mgr, storage, and web to every module collector. The base class provides exponential backoff on repeated failures (30s to 3600s max, auto-reset after 24h idle).
Note: Community modules receive a
_ModuleConfigProxyinstead of the rawConfigManager. This proxy hides DOCSight core secret keys such as modem passwords and API tokens. Declare module-owned passwords or tokens inconfig_secrets; only those declared keys are readable by that module's collector. Keep saved secret values out of rendered HTML and handle them through dedicated password/token fields.
"contributes": { "publisher": "publisher.py:MyPublisher" }Format: filename.py:ClassName. Publisher classes receive collected data and export it to external services.
"contributes": { "settings": "templates/mymodule_settings.html" }Your settings template is rendered in the Settings page under the Modules section. The panel ID must follow the pattern panel-mod-{module_id_with_dots_replaced_by_underscores}:
<div class="settings-panel" id="panel-mod-community_mymodule">
<div class="settings-card glass">
<div class="card-header">
<div class="card-title-group">
<div class="card-icon blue"><i data-lucide="puzzle"></i></div>
<div>
<div class="card-title">{{ t.get('community.mymodule.title', 'My Module') }}</div>
<div class="card-subtitle">{{ t.get('community.mymodule.desc', 'Module description') }}</div>
</div>
</div>
</div>
<div class="form-grid cols-2">
<div class="form-group">
<label for="mymodule_api_url">{{ t.get('community.mymodule.api_url', 'API URL') }}</label>
<input type="text" id="mymodule_api_url" name="mymodule_api_url"
value="{{ config.get('mymodule_api_url', '') }}"
placeholder="https://api.example.com">
</div>
<div class="form-group full-width">
<label class="toggle">
<input type="checkbox" name="mymodule_enabled"
{{ 'checked' if config.get('mymodule_enabled') }}>
<span class="toggle-slider"></span>
</label>
<label style="margin-left:8px;">{{ t.get('community.mymodule.enable', 'Enable') }}</label>
</div>
</div>
</div>
</div>Important: Template filename must be unique. Do not name it
settings.html(conflicts with core). Usemymodule_settings.html.
Available CSS classes:
settings-card glass- card container with glass effectcard-header,card-title-group,card-icon {color},card-title,card-subtitle- card headerform-grid cols-2- two-column form layoutform-group- single form field (label + input)form-group full-width- full-width field spanning both columnsform-hint- hint text below an inputtoggle,toggle-slider- toggle switch (replaces checkbox)
Icon colors: blue, purple, amber, green
"contributes": { "i18n": "i18n/" }Place JSON files in the i18n/ directory:
i18n/
├── en.json # English (required)
├── de.json # German (recommended)
├── es.json # Spanish (recommended)
└── fr.json # French (recommended)
Keys are automatically namespaced with your module ID:
{
"nav_title": "My Module",
"api_url": "API URL"
}Access in templates: {{ t['community.mymodule.nav_title'] }}
"contributes": { "tab": "templates/mymodule_tab.html" }Adds a tab to the main dashboard view switcher.
"contributes": { "card": "templates/mymodule_card.html" }Adds a card widget to the dashboard overview.
"contributes": { "thresholds": "thresholds.json" }A threshold module provides regional signal quality thresholds for DOCSight's health assessment. Only one threshold profile can be active at a time — enabling a new one automatically disables the previous one.
Use the TEMPLATE-THRESHOLDS/ directory as a starting point.
The thresholds.json file must contain these three sections, each with a _default key:
| Section | Keys | Format |
|---|---|---|
downstream_power |
Modulation names (e.g., 256QAM, 4096QAM) |
{ "good": [min, max], "warning": [min, max], "critical": [min, max] } |
upstream_power |
Channel types: sc_qam, ofdma |
Same [min, max] array format |
snr |
Modulation names | { "good_min": N, "warning_min": N, "critical_min": N } |
| Section | Purpose |
|---|---|
_meta |
Metadata (region, operator, docsis_variant, source, notes) |
upstream_modulation |
QAM order thresholds (critical_max_qam, warning_max_qam) |
errors |
Uncorrectable error rate (uncorrectable_pct: { warning: %, critical: % }) |
"contributes": { "theme": "theme.json" }A theme module provides dark and light color schemes. The theme.json must contain exactly two sections (dark and light), each with CSS custom property overrides:
{
"meta": { "family": "dark-first" },
"dark": {
"--bg": "#1a1b26",
"--surface": "#1f2335",
"--text": "#c0caf5",
"--accent": "#7aa2f7",
"--good": "#9ece6a",
"--warn": "#e0af68",
"--crit": "#f7768e",
"--muted": "#565f89"
},
"light": {
"--bg": "#f0f0f0",
"--surface": "#ffffff",
"--text": "#1a1b26",
"--accent": "#2e7de9"
}
}Only one theme can be active at a time. Users select themes in Settings > Appearance.
Security restriction: Theme modules cannot contribute collector, routes, or publisher.
"contributes": { "static": "static/" }Files are served at /modules/<module-id>/static/. Two files are auto-detected and loaded on every page:
style.css— stylesheetmain.js— JavaScript
Other static files (images, fonts, etc.) are accessible at their path but not auto-loaded.
Module collectors can integrate with DOCSight's Smart Capture engine to trigger automated measurements when module-specific events are detected.
Pattern: Your collector receives the Smart Capture engine via post-construction injection and evaluates events through it after saving them:
class MyCollector(Collector):
name = "mymodule"
def __init__(self, config_mgr, storage, web, **kwargs):
super().__init__(300)
self._storage = storage
self._smart_capture = None
def set_smart_capture(self, smart_capture):
"""Inject Smart Capture engine for event evaluation."""
self._smart_capture = smart_capture
def collect(self):
events = self._detect_events()
if events and hasattr(self._storage, "save_events_with_ids"):
self._storage.save_events_with_ids(events)
if self._smart_capture:
self._smart_capture.evaluate(events)
return CollectorResult(source=self.name)Use save_events_with_ids() (not save_events()) so each event gets annotated with its database row ID for execution correlation.
The Smart Capture engine is wired to your collector in main.py after discover_collectors() returns. See the Connection Monitor module for a working example.
-
Mount the modules directory in your Docker setup:
# docker-compose.yml services: docsight: image: ghcr.io/itsdnns/docsight:latest volumes: - docsight_data:/data - ./modules:/modules # <-- add this line ports: - "8765:8765"
-
Place your module in the
modules/directory:mkdir -p modules cp -r TEMPLATE modules/my-module # Edit modules/my-module/manifest.json and code -
Restart DOCSight to discover the new module:
docker compose restart docsight
-
Verify in Settings > Modules — your module should appear with a "Community" badge.
-
Check logs for any loading errors:
docker compose logs docsight | grep -i module
DOCSight never crashes due to a broken module:
- Invalid manifests are skipped with a warning
- Load failures are caught per-module and stored as error state
- Broken modules show an error badge in Settings > Modules
- Core functionality is never affected
The catalog supports two contribution styles:
- Curated in-repo modules: Small, reviewed modules can live directly in this repository under their own directory.
- External modules: Larger modules can stay in a contributor-owned GitHub repository and be referenced from
registry.json.
In both cases, the registry entry must point to an installable module directory through download_url.
- Your module works locally with DOCSight
- Your module has a README with setup, requirements, and support notes
- Your
manifest.jsonuses a unique ID that does not conflict with built-in DOCSight modules - Routes, collectors, settings forms, and stored configuration follow the safety checklist below
-
Fork this repository
-
Add or update your module files if the module lives in this catalog repository
-
Add your module to
registry.json:{ "id": "community.mymodule", "name": "My Module", "description": "What it does in one sentence", "author": "your-github-username", "repo": "https://github.com/your-username/docsight-mymodule", "version": "1.0.0", "min_app_version": "2026.2", "type": "integration", "download_url": "https://api.github.com/repos/your-username/docsight-mymodule/contents/my-module?ref=main", "verified": false } -
Open a Pull Request
-
We review: valid manifest, basic functionality, clear setup docs, and no malicious or unsafe behavior
-
After merge, your module appears in the catalog
Modules reviewed and tested by the DOCSight team receive "verified": true. Unverified modules are functional but marked accordingly in the catalog.
Before opening your PR, verify:
- Auth on all routes — every
@bp.routemust have@require_auth(import fromapp.web) - No credentials in HTML — password/token fields must use
value="",data-config-secret="true", and conditionaldata-saved-secret="true"metadata, nevervalue="{{ config.password }}" - Escape dynamic content — any value from API responses inserted via
innerHTMLmust be HTML-escaped; usetextContentwhere possible - English API errors — error messages returned by API endpoints must be English (UI translations go in i18n files)
- No exception details in responses — use generic error messages ("Connection failed"), log details server-side with
logger.exception() - i18n parity — all language files (EN, DE, FR, ES) must have identical keys; include a
template.jsonwith empty values - Validate user input — config values used in URLs or paths must be sanitized (e.g. site names: alphanumeric only)
- Trailing newlines — all JSON files must end with a newline
- Version consistency — version string in
manifest.jsonmust match any version shown in docstrings or templates
- One module per repository — keep it focused
- Semantic versioning — update
versionin both your manifest and the registry entry - No
docsight.*IDs — this prefix is reserved for built-in modules - English README required — additional languages welcome
| Type | Purpose | Example |
|---|---|---|
integration |
External service connection | Ping test, uptime monitor, API bridge |
analysis |
Data analysis/visualization | Custom charts, reports, threshold profiles |
theme |
UI customization | Color schemes, layouts |
These built-in DOCSight modules serve as examples:
| Module | Type | Contributes | Complexity |
|---|---|---|---|
| Reports | analysis | routes, i18n | Minimal |
| Journal | analysis | routes, i18n | Medium |
| Weather | integration | collector, routes, settings, i18n | Full |
| Backup | integration | collector, routes, settings, i18n | Full |
| Connection Monitor | integration | collector, routes, settings, i18n | Full + Smart Capture |
| Speedtest | integration | collector, routes, settings, i18n | Full |
| MQTT | integration | publisher, settings, i18n | Publisher |
| VFKD Thresholds | analysis | thresholds | Minimal |
| Classic Theme | theme | theme | Minimal |
MIT — same as DOCSight.