feat(studio): carousel size lock, store-actionable today stories, HTTPS MCP suggestions in settings (v0.36.0)

Three concrete changes against operator feedback that the
Today carousel was visually jumping when arrowed and
genre-mixing platform-architecture education with store-
actionable highlights.

- Carousel size pinned. The hero's outer Container picks up
  `BoxConstraints(minHeight: 240)` so a slide with one
  paragraph and a slide with three render at the same
  height. Prev/next no longer reflows the rest of the page.

- Today fallback stories trimmed and re-themed. The four
  shipped slides drop to three:
  - "Public sources" (DeepWiki / Semgrep one-click) — kept
  - "Three text modules already in the store" — new,
    points the operator at text.extract / text.summarize /
    text.translate in the grid below
  - "Try the extract → summarize flow" — new, points at
    flows/extract-summarize.yaml
  Architecture-education stories (sandbox model, hash-
  chained audit, air-gap posture) are gone from this surface
  — they belong on the Welcome page that
  `docs/landing-page-design.md` lays out.

- DeepWiki + Semgrep added to the Settings → MCP-Clients
  add-server suggestion-chip catalogue. Until now the chips
  were nine stdio servers that need Node + npx; the two
  HTTPS public sources only existed as one-click cards in
  the Today hero. Operators who dismissed the hero had no
  in-Settings path to find them. The new entries sit at the
  top of the catalogue with an explicit "Public HTTPS — no
  Node, no API key" descriptor and the same icons the Today
  hero already uses.

- `docs/landing-page-design.md` (new). Captures the design
  for a sidebar Welcome page that hosts the three-pillar
  intro, the trust-posture deck, the getting-started
  checklist, and an embedded-doc reader so operator-facing
  documentation stays inside Studio (`flutter_markdown`
  rendering of bundled `assets/docs/*.md`) instead of
  clicking out to a browser. Three-phase implementation
  plan: scaffolding, embedded docs, computed checklist.
  Build is gated on operator alignment; this doc is the
  alignment artefact.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-05-08 23:53:05 +02:00
parent a7e2eb101a
commit 711436b71d
5 changed files with 227 additions and 30 deletions

View file

@ -2802,6 +2802,12 @@ class _ScreenshotPlaceholder extends StatelessWidget {
/// recompiling Studio see docs/today-pipeline.md. When the
/// operator accepts a story, that single story becomes the
/// active item and the carousel collapses to a single slide.
///
/// **Editorial discipline:** every entry here points at a
/// concrete store / federation item the operator can act on,
/// not abstract platform philosophy. Architecture education
/// (sandbox model, hash-chained audit, air-gap posture) lives
/// on the dedicated Welcome page, not in the store carousel.
const List<TodayStoryData> _kFallbackTodayStories = <TodayStoryData>[
TodayStoryData(
badgeEn: 'PUBLIC SOURCES',
@ -2818,45 +2824,31 @@ const List<TodayStoryData> _kFallbackTodayStories = <TodayStoryData>[
cta: TodayCta.openSettings,
),
TodayStoryData(
badgeEn: 'SANDBOX BY DEFAULT',
badgeDe: 'SANDBOX VON ANFANG AN',
titleEn: 'Every module declares what it can touch',
titleDe: 'Jedes Modul deklariert, worauf es zugreifen darf',
badgeEn: 'TEXT MODULES',
badgeDe: 'TEXT-MODULE',
titleEn: 'Three text modules already in the store',
titleDe: 'Drei Text-Module sind schon im Store',
bodyEn:
'F∆I modules ship with an explicit permission list — network endpoints, files, environment variables. The hub enforces it; nothing reaches outside the sandbox without the operator approving it. Click any installed module to see exactly which permissions it asked for.',
'text.extract pulls plain text from PDFs and DOCX. text.summarize turns long material into a short briefing via your configured System AI. text.translate moves text between languages. All three install in one click from the grid below — search for "text" to find them.',
bodyDe:
'F∆I-Module bringen eine explizite Berechtigungsliste mit — Netzwerk-Endpunkte, Dateien, Umgebungsvariablen. Der Hub setzt sie durch; ohne Operator-Freigabe verlässt nichts die Sandbox. Klicke ein installiertes Modul, um seine genauen Berechtigungen zu sehen.',
'text.extract holt Plaintext aus PDFs und DOCX. text.summarize verdichtet lange Texte über die konfigurierte System-AI zu einem Briefing. text.translate übersetzt zwischen Sprachen. Alle drei lassen sich aus dem Grid unten mit einem Klick installieren — suche nach „text".',
ctaLabelEn: '',
ctaLabelDe: '',
icon: Icons.shield_outlined,
icon: Icons.menu_book_outlined,
cta: TodayCta.none,
),
TodayStoryData(
badgeEn: 'TAMPER-EVIDENT AUDIT',
badgeDe: 'MANIPULATIONSSICHERES AUDIT',
titleEn: 'Every event leaves a hash-chained trace',
titleDe: 'Jedes Ereignis hinterlässt eine hash-verkettete Spur',
badgeEn: 'SAMPLE FLOW',
badgeDe: 'BEISPIEL-FLOW',
titleEn: 'Try the extract → summarize flow',
titleDe: 'Probier den Extract → Summarize-Flow',
bodyEn:
'Flow runs, install / uninstall actions, approval decisions — all of them write into a hash-chained audit log. The Doctor page verifies the chain end-to-end on every load; if a single byte gets touched, you see it. Audit-grade by construction, not by policy.',
'The bundled `flows/extract-summarize.yaml` chains text.extract into text.summarize so a PDF in one end produces a short briefing at the other. Open the Flows tab, hit Run, point it at any document — the result lands as plain text plus an audit-log trail of which modules ran with which inputs.',
bodyDe:
'Flow-Läufe, Installationen und Deinstallationen, Freigabe-Entscheidungen — alles wird in ein hash-verkettetes Audit-Log geschrieben. Die Diagnose-Seite verifiziert die Kette bei jedem Laden komplett; ein verändertes Byte ist sofort sichtbar. Audit-tauglich qua Konstruktion, nicht qua Policy.',
'Der mitgelieferte Flow `flows/extract-summarize.yaml` reicht text.extract an text.summarize weiter — vorne kommt ein PDF rein, hinten kommt ein kurzes Briefing raus. Flows-Tab öffnen, Run klicken, beliebiges Dokument auswählen; das Ergebnis ist Klartext plus Audit-Spur welcher Modul-Schritt mit welchen Eingaben gelaufen ist.',
ctaLabelEn: '',
ctaLabelDe: '',
icon: Icons.shield_outlined,
cta: TodayCta.none,
),
TodayStoryData(
badgeEn: 'AIR-GAP READY',
badgeDe: 'AIR-GAP-TAUGLICH',
titleEn: 'One binary, no Docker, no external services',
titleDe: 'Ein Binary, kein Docker, keine externen Dienste',
bodyEn:
'The whole hub fits in a single binary that runs on Linux, macOS and Windows. SQLite for state, no message broker, no background services to babysit. Once a module is installed, the flow it powers runs without further network access — perfect for regulated environments where outbound calls have to be justified.',
bodyDe:
'Der gesamte Hub steckt in einem einzigen Binary für Linux, macOS und Windows. SQLite für den State, kein Message-Broker, keine Hintergrunddienste, die gepflegt werden müssen. Sobald ein Modul installiert ist, läuft der Flow, der es nutzt, ohne weiteren Netzwerkzugriff — ideal für regulierte Umgebungen, in denen jeder ausgehende Call begründet werden muss.',
ctaLabelEn: '',
ctaLabelDe: '',
icon: Icons.rocket_launch,
icon: Icons.account_tree_outlined,
cta: TodayCta.none,
),
];
@ -2917,6 +2909,12 @@ class _StoreTodayHero extends StatelessWidget {
final ctaLabel = isDe ? story.ctaLabelDe : story.ctaLabelEn;
return Container(
width: double.infinity,
// Min-height keeps the carousel slides at a consistent
// size so the surrounding layout doesn't jump when the
// operator clicks the prev/next chevrons. Sized to fit
// the longest story ( 6 body lines + title + CTA + chip
// row) without leaving empty space on shorter slides.
constraints: const BoxConstraints(minHeight: 240),
padding: const EdgeInsets.fromLTRB(
FaiSpace.xl,
FaiSpace.lg,