SPA_TemperProductionOverview/__init__.py
Erik aa115a0b8d feat: scaffold Temper-Linie live-overview page-module (temper_overview)
Vue 3 + Vite 8 + TS + PrimeVue 4 (Nora/Industrial) + Pinia + vue-i18n SPA, served
by the SPRO gateway as a static page-module under /module/temper_overview and
embedded into Grafana via iframe.

- Ports the LOCKED design #4 "Shop-floor Schematic": one connected line
  Pressen -> (cyan) -> Ofen -> (green) -> Fertig; carts under their origin press;
  oven trays as dwell-progress bars; finished band; range picker scoping only the
  Fertig figures. Flow/order colours match PressV (fleet recognisability).
- Python page-module wrapper: register(app) mounts committed dist/ + a no-auth
  read API (GET /api/overview). Kernel DB seam in _db.py.
- Backend returns SAMPLE data; frontend falls back to bundled sample so `npm run
  dev` renders with zero backend (TODO markers point at the real temper aggregates).
- Rich README bakes in the design, contract, wiring + Grafana embedding for
  standalone development.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 20:41:04 +02:00

52 lines
2.2 KiB
Python

"""temper_overview — the Temper-Linie live-overview page-module for the SPRO gateway.
This repository is a **gateway page-module**, not a standalone server. It is
mounted into the SPRO Universal Gateway as a git submodule at
``<gateway>/modules/temper_overview/`` and discovered automatically by the kernel
module loader (``app.core.modules.load_modules``), which imports this package and
calls ``register(app)`` after the core routers are mounted.
It does two things:
* mounts the built Vue SPA (``dist/``) as static files under ``/module/temper_overview``;
* exposes a small **read-only, no-auth** JSON API under ``/module/temper_overview/api``
for the page to call (same origin → no CORS, no token).
The data is non-sensitive shop-floor data, so — like the kernel's ``/health`` and
``/heartbeat`` — the page API is deliberately unauthenticated. This is a per-page,
purpose-built read surface: never expose the generic ``POST /query/mariadb`` proxy
to the browser.
See ``agent_docs/vue-page-modules.md`` in the gateway repo for the full runbook,
and this repo's ``README.md`` for the design + build/deploy notes.
"""
from __future__ import annotations
from pathlib import Path
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
MODULE_NAME = "temper_overview"
# MUST match vite.config.ts `base` (with a trailing slash on the Vite side).
MODULE_PREFIX = "/module/temper_overview"
def register(app: FastAPI) -> None:
"""Mount the data API and the SPA onto the gateway app.
Called once by the kernel loader during app construction. Order matters: a
``StaticFiles`` mount captures every path under its prefix, so the ``/api``
routes are registered FIRST or the mount would shadow them.
"""
# 1) Data API first (imported lazily so package import stays cheap).
from .api import routes
app.include_router(routes.router)
# 2) Then the SPA. html=True serves dist/index.html at the prefix root.
# dist/ MUST exist (it is committed) — if it is missing this raises and the
# loader logs-and-skips the module (the kernel stays up but the page 404s).
dist = Path(__file__).resolve().parent / "dist"
app.mount(MODULE_PREFIX, StaticFiles(directory=dist, html=True), name=MODULE_NAME)