Chapters: 

I want to 1 ) add a check is valid to the .pdf for Catalogue 2) display mini-ops dashboard -maybe as a separate tab. 

Mini Ops Dashboard

Host: localhost.localdomain
OS: Linux 6.17.4-200.fc42.x86_64
Python: 3.13.9
CPU Usage: 2.6%
Memory Usage: 31.6%
Disk Usage: 25.8%
Load (1 min): 0.52685546875
Processes: 498
Net Sent: 494.1 MB / Recv: 1249.0 MB
Boot Time: 2025-11-02 10:31
Uptime: 12 days, 23:50:11
 

Let's move forward cleanly from where we left TransferDepot.
You’re asking for two concrete features:

  1. Add a “PDF validity check” for the Catalogue board PDF.
  2. Add a Mini Ops Dashboard, ideally as a separate tab within the TransferDepot interface.

Yes — I have access to everything we built so far:

  • the /files storage under transferdepot-001
  • the /run/status heartbeat system
  • the existing Flask structure with routes, templates, and the admin API
  • and the “Service Snapshot” block you just posted.

Below is exactly how we proceed without breaking anything.


1. PDF Validity Check for On-Call Board

Goal

When the cron-produced PDF arrives (or on-demand), run a validity test so we never serve corrupt PDFs again.

Approach

Use PyPDF2 or pypdf (lighter) — both work offline — to attempt to parse the first page.
If it throws an exception → invalid.

New utility: utils/pdfcheck.py

# utils/pdfcheck.py
from pypdf import PdfReader

def is_valid_pdf(path: str) -> bool:
    try:
        reader = PdfReader(path)
        _ = reader.pages[0]   # force load first page
        return True
    except Exception:
        return False

Modify your On-Call lookup route

Your current placeholder says:

On-call board: file not found

Replace it with something like:

from utils.pdfcheck import is_valid_pdf

ONCALL_PATH = "/home/tux/sh1re/transferdepot-001/files/catalogue_board.pdf"

@app.route("/admin/oncall")
def admin_oncall_page():
    status = "missing"
    if os.path.exists(ONCALL_PATH):
        if is_valid_pdf(ONCALL_PATH):
            status = "valid"
        else:
            status = "invalid"

    return render_template("admin_oncall.html", status=status)

This gives Lisa a definitive result when she checks the admin page.


2. Mini Ops Dashboard — as a separate tab

We already built the data collector (get_system_stats() or equivalent).
We can now surface it in a nicer view.

New Route

@app.route("/admin/miniops")
def mini_ops_dashboard():
    stats = get_system_stats()  # you already have this
    return render_template("miniops.html", stats=stats)

New Template Tab (miniops.html)

Very simple grid layout (no JS, no CDN needed):

<!DOCTYPE html>
<html>
<head>
    <title>Mini Ops Dashboard</title>
    <style>
        body { font-family: Arial, sans-serif; padding: 20px; }
        .grid {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 20px;
        }
        .card {
            padding: 16px;
            border-radius: 12px;
            background: #f7f7f7;
            box-shadow: 0 1px 3px rgba(0,0,0,0.2);
        }
        h2 { margin-bottom: 10px; }
        .label { font-weight: bold; }
    </style>
</head>
<body>
    <h1>Mini Ops Dashboard</h1>

    <div class="grid">
        <div class="card"><span class="label">Host:</span><br>{{ stats.hostname }}</div>
        <div class="card"><span class="label">OS:</span><br>{{ stats.os }}</div>
        <div class="card"><span class="label">Python:</span><br>{{ stats.python }}</div>
        <div class="card"><span class="label">CPU Usage:</span><br>{{ stats.cpu }}%</div>
        <div class="card"><span class="label">Memory Usage:</span><br>{{ stats.memory }}%</div>
        <div class="card"><span class="label">Disk Usage:</span><br>{{ stats.disk }}%</div>
        <div class="card"><span class="label">Load (1 min):</span><br>{{ stats.load1 }}</div>
        <div class="card"><span class="label">Processes:</span><br>{{ stats.procs }}</div>
        <div class="card"><span class="label">Net Sent / Recv:</span><br>{{ stats.net_sent }} / {{ stats.net_recv }}</div>
        <div class="card"><span class="label">Boot Time:</span><br>{{ stats.boot }}</div>
        <div class="card"><span class="label">Uptime:</span><br>{{ stats.uptime }}</div>
    </div>

</body>
</html>

Navigation

In your base template, add:

<li><a href="/admin/miniops">Mini Ops Dashboard</a></li>

🎯 What you get after these two additions

Admin → “Service Snapshot” now includes:

  • On-call PDF status
  • Link to Mini Ops Dashboard

Mini Ops Dashboard provides:

  • Hostname
  • OS + Python
  • CPU, memory, disk
  • Load
  • Processes
  • Network IO
  • Boot time + uptime
  • Looks modern but zero JS — compatible with your air-gapped environment

PDF check:

  • No more guessing whether a broken cron-generated PDF is good