9.2 KiB
Doris Dashboard
Local homepage for John's briefing, glanceable status, and "what matters right now" view.
What it is
Doris Dashboard is the quiet front page for John's local information stack on NOMAD. It is not a general website and it is not meant to be another feed reader with a fresh coat of paint. It exists to turn Doris Digest output and a few homelab/task signals into one page John can open for a fast read.
The dashboard is meant to answer:
- what is worth looking at this morning
- what local or homelab signals need attention
- what chores or Paperless follow-ups are still hanging around
- what topics are surfacing too often and should be tuned down
Why it exists
Without this stack, the raw inputs are noisy:
- Doris Digest candidates are too broad on their own
- Donetick and Paperless are useful but fragmented
- local weather/sky/homelab signals live in separate places
The dashboard turns that into one opinionated, local-only page that Doris can tune over time.
Runtime model
- Repo source:
/home/fizzlepoof/repos/truenas-stacks/home/doris-dashboard - Live runtime:
/opt/doris-dashboard - Generated page:
/opt/doris-dashboard/public/index.html - LAN URL:
http://10.5.1.16:8787/ - Exposure rule: local-only unless John explicitly asks otherwise
What it shows
- top briefing cards from Doris Digest candidates
- space / homelab / local / other signal lanes
- an experimental
New to Youlane for off-profile category sampling - Donetick tasks
- Paperless review queue items
- weather, sky, and homelab pulse cards
- lightweight stats about candidate/source mix
How it works
bin/generate_dashboard.pyreads Doris Digest candidates plus a few local/runtime data files.- It scores, deduplicates, and groups stories into dashboard sections.
- It writes generated JSON artifacts under
data/and the final static page underpublic/. bin/dashboard_server.pyserves the page and handles interactive actions like topic feedback and Paperless review state.
That means the dashboard is static-looking for the reader, but still has enough local interactivity for feedback and review flows.
Live paths
Live runtime path:
/opt/doris-dashboard
Generated page:
/opt/doris-dashboard/public/index.html
Generate manually
cd /opt/doris-dashboard
bin/generate_dashboard.py
Preview locally
cd /opt/doris-dashboard/public
python3 -m http.server 8787
Then open:
http://localhost:8787/
If viewing from another machine on the LAN, use NOMAD’s LAN IP instead of localhost and make sure the firewall allows the port.
Cron refresh
Installed in fizzlepoof’s crontab:
# BEGIN DORIS DASHBOARD
DORIS_DASHBOARD_DIR=/opt/doris-dashboard
DORIS_DIGEST_DIR=/home/fizzlepoof/.openclaw/workspace/doris-digest
# Refresh local dashboard after digest collection windows; wrapper enforces Chicago daytime.
5,35 * * * * cd $DORIS_DASHBOARD_DIR && bin/cron_generate_dashboard.sh >> logs/generate.log 2>&1
# END DORIS DASHBOARD
Inspect with:
crontab -l | sed -n '/# BEGIN DORIS DASHBOARD/,/# END DORIS DASHBOARD/p'
Data inputs
Main news source:
/home/fizzlepoof/.openclaw/workspace/doris-digest/data/candidates.json
/home/fizzlepoof/.openclaw/workspace/doris-digest/data/preferences.json
Local dashboard placeholders:
data/todos.json
data/calendar.json
data/notes.json
These are intentionally simple JSON arrays so calendar/Donetick integrations can be added later without rewriting the page.
Next integrations to add
- Donetick tasks
- Calendar events
- Weather / severe weather
- Moon phase / ISS passes / meteor shower calendar
- Homelab health pulse
- Article feedback buttons or quick links back to Doris
Privacy/deployment note
This dashboard is local-only on NOMAD unless John explicitly asks to expose it. Do not publish it externally without asking.
LAN service
The dashboard is exposed on NOMAD's LAN IP via systemd:
http://10.5.1.16:8787/
Service file:
/etc/systemd/system/doris-dashboard.service
Manage it:
sudo systemctl status doris-dashboard.service
sudo systemctl restart doris-dashboard.service
sudo systemctl stop doris-dashboard.service
The service runs as fizzlepoof, serves public/, binds 0.0.0.0:8787, and regenerates the page before starting.
At setup time UFW was inactive, so no firewall rule was required.
Buildout added 2026-05-12
The dashboard generator now builds a richer local homepage directly on NOMAD.
Added sections/data:
- Weather metrics for Clarksville via Open-Meteo (
data/weather.json) - Moon phase / sky note calculated locally (
data/sky.json) - Homelab pulse checks (
data/homelab.json): dashboard service, cron, digest freshness, workspace disk - Article export from Doris Digest candidates (
data/articles.json) - Dashboard metadata (
data/dashboard.json)
The generated page still lives at:
/opt/doris-dashboard/public/index.html
And the LAN service remains:
http://10.5.1.16:8787/
Verification commands:
cd /opt/doris-dashboard
python3 -m py_compile bin/generate_dashboard.py
bin/generate_dashboard.py
curl -fsS http://127.0.0.1:8787/ | grep 'Doris Dashboard'
systemctl is-active doris-dashboard.service
crontab -l | sed -n '/# BEGIN DORIS DASHBOARD/,/# END DORIS DASHBOARD/p'
Notes:
- Weather.gov and NASA API are not used; Open-Meteo worked reliably without an API key.
- Donetick live task import is still not enabled in the dashboard;
data/todos.jsonremains the safe placeholder until the exact read-only endpoint is confirmed. - Raw secrets are not written to dashboard output.
Compact news layout
2026-05-13: News/article sections were changed from large cards to compact rows so the dashboard can keep plenty of articles without making John scroll forever.
Implementation:
generate_dashboard.pyrenders article sections withcompact-cardrows by default.public/style.csscontains the compact layout rules.- Metrics/weather/homelab pulse remain large cards.
Donetick integration
2026-05-13: The dashboard now imports open Donetick chores read-only during generation.
Implementation notes:
- Secrets remain encrypted in
/home/fizzlepoof/.openclaw/workspace/.secrets/donetick_secrets.json.enc. bin/generate_dashboard.pydecrypts secrets at runtime using the local encryption key and logs in with the Doris service account.- It reads
/api/v1/choresand/api/v1/usersonly. - It writes sanitized task data to
data/todos.jsonfor the dashboard. - It does not expose tokens, passwords, or raw secrets in generated HTML/JSON.
Verify:
cd /opt/doris-dashboard
bin/generate_dashboard.py
python3 - <<'PY'
import json
from pathlib import Path
for item in json.loads(Path('data/todos.json').read_text()):
print(item.get('time'), item.get('title'), item.get('assignee'))
PY
Donetick compact board + topic feedback
2026-05-14: The dashboard's Donetick section was reworked to match the tighter PD Dakboard pattern more closely.
Current behavior:
- Donetick renders compact task cards with due cue, task title, label chips, and a short subtitle.
- Tasks are sorted by urgency first (overdue/today/upcoming/no due date), then due time.
- The dashboard injects a pinned Paperless follow-up card into the Donetick area so that cleanup work stays visible.
- News cards now show
👍 / 👎topic buttons. - Topic feedback is persisted through the local dashboard server into
../doris-digest/data/feedback.jsonwithorigin: "dashboard". Reset hidden topicsclears both browser state and dashboard-origin feedback entries.- Paperless review cards now have
Acknowledge/Dismissactions persisted todata/paperless_review_state.json. - Major dashboard sections are collapsible and remember collapsed state in the browser.
Important note:
- The interactive actions require the dashboard to be served by
bin/dashboard_server.py, not plainpython -m http.server.
Runtime path sanity
The live systemd unit and crontab must point only at:
/opt/doris-dashboard
Do not run the dashboard from an agent workspace. Agent workspaces are for editing and staging; NOMAD host-run services belong under /opt/<service>.
Cron fix — 2026-05-13
The dashboard cron now uses bin/cron_generate_dashboard.sh, which checks America/Chicago daytime internally. This avoids relying on CRON_TZ, which NOMAD's cron did not honor consistently.
Paperless review queue contract
The dashboard displays sanitized Paperless intake triage items written by n8n at data/paperless_review.json. Example contract: data/paperless_review.example.json.
Expected shape is a JSON array. Each item may include:
id,title,original_filename,added,archive_urlcurrent.correspondent,current.document_type,current.tagstriage.summary,triage.suggested_title,triage.document_type,triage.suggested_tags,triage.due_date,triage.needs_review,triage.urgency,triage.reason,triage.confidencesafety.forced_review,safety.eligible_for_safe_apply,safety.apply_safe_enabledqueued_at
Do not write tokens, raw OCR text, API responses, or credentials into this file. It is display-only derived data for local review.