{% extends "base.html" %} {% block title %}{{ seo.title if seo is defined and seo else 'Pipeline Monitor — Live Dashboard | news48' }}{% endblock %} {% block body_class %}page-monitor{% endblock %} {% block content %} ← back to live feed {% set articles = stats.articles %} {% set sentiment = stats.sentiment %} {% set feeds = stats.feeds %} {% set fetches = stats.fetches %} {% set retention = stats.retention %} {% set health = stats.health %} {% set plans = stats.plans %} {% set failures_total = articles.download_failures + articles.parse_failures %} {% set sentiment_total = sentiment.positive + sentiment.neutral + sentiment.negative %} {% set parsed_rate = ((articles.parsed / articles.total * 100) if articles.total else 0) %} {% set unparsed_rate = ((articles.unparsed / articles.total * 100) if articles.total else 0) %} {% set no_content_rate = ((articles.no_content / articles.total * 100) if articles.total else 0) %} {% set positive_width = ((sentiment.positive / sentiment_total * 100) if sentiment_total else 0) %} {% set neutral_width = ((sentiment.neutral / sentiment_total * 100) if sentiment_total else 0) %} {% set negative_width = ((sentiment.negative / sentiment_total * 100) if sentiment_total else 0) %} {% set top_feed_max = feeds.top_feeds[0].article_count if feeds.top_feeds else 1 %}
live dashboard

news48 monitor

Pipeline health & throughput, live.

Real-time numbers from every feed crawl, parse run, and retention sweep — no caching, no staging.

live monitor
articles tracked {{ articles.total }}
feeds watched {{ feeds.total }}
parse coverage {{ '%.1f' % parsed_rate }}%
retention {{ retention.retention_rate }}
snapshot server-rendered

Coverage, backlog & friction.

{{ failures_total }} total failures

How many articles made it through the pipeline.

parsed{{ articles.parsed }}
{{ '%.1f' % parsed_rate }}% of tracked articles
awaiting parse{{ articles.unparsed }}
{{ '%.1f' % unparsed_rate }}% still in queue
no content{{ articles.no_content }}
{{ '%.1f' % no_content_rate }}% source friction
failures {{ failures_total }} {{ articles.download_failures }} download · {{ articles.parse_failures }} parse oldest unparsed {{ articles.oldest_unparsed_at or '—' }}

Stable and accountable.

connected integrity ok

Connection status and database size.

database footprint {{ stats.db_size_mb }} MB

Agent execution state

What the agent layer is working on — pending, running, done, or broken.

pending
{{ plans.pending }}
executing
{{ plans.executing }}
completed
{{ plans.completed }}
failed
{{ plans.failed }}

Story mix sentiment at a glance.

Positive, neutral, and negative breakdown across parsed articles.

{% if sentiment_total > 0 %}
positive {{ sentiment.positive }}
neutral {{ sentiment.neutral }}
negative {{ sentiment.negative }}
positive confidence balanced / neutral coverage negative pressure
{% else %}
No sentiment data yet. Shows up once enough articles are parsed.
{% endif %}

Collection runs

The last few crawl runs and how much each one picked up.

total runs {{ fetches.total }} avg articles/run {{ fetches.avg_articles_per_fetch or '0' }} last fetch {{ fetches.last_fetch_at or '—' }}
{% for run in fetches.recent[:5] %}
{{ run.status or 'unknown' }} #{{ run.id }} {{ run.completed_at or run.started_at or '—' }} {{ run.feeds_fetched }} feeds · {{ run.articles_found }} articles
{% else %}

No recent fetch runs available.

{% endfor %}

Source diversity

Which feeds are pulling their weight and which have gone stale.

{% for feed in feeds.top_feeds[:6] %}
{{ feed.title or feed.url }} {{ feed.url }}
{{ feed.article_count }}
{% else %}

No feed stats available.

{% endfor %}
{% endblock %}