Each Evaluation grows a componentSummary field — a small list of
plain strings, one per SKM ingredient (P / F / T / h), tagged
with its tier in the form 'P · T1 — DESTATIS Gewerbeanzeigen'.
The fixtures fill it in for all five pilot norms; the field
defaults to an empty list so flow-produced Evaluations remain
backwards-compatible until a future flow step writes one.
NormsListPage re-arranges the row to make use of the wide-screen
real-estate on the right that used to sit empty:
┌─────────────────────────────────────────────────────────────┐
│ GewO § 14 — Anzeigepflicht │ Schaden │ Komponenten │
│ eli/bund/gewo/14 │ 2.8 Mio € │ P · T1 … │
│ [T1 · amtlich] │ Nutzen │ F · T1 … │
│ │ 2.5 / 5 │ T · T1 … │
│ │ Betroffene │ h · T3 … │
│ │ 180 k │ │
└─────────────────────────────────────────────────────────────┘
The TierBadge moved into the title column (right under the eli)
so the eye lands on the tier of the figure right where the
figure's identity is named. The three metric columns stack
vertically (no more horizontal-only row) which leaves the right
third of the row free for the componentSummary lines — the
information a reviewer was always asking for ('which Komponente
is the bottleneck here?') is now visible without opening the
detail page.
Signed-off-by: flemming-it <sf@flemming.it>
182 lines
5.1 KiB
Dart
182 lines
5.1 KiB
Dart
// Domain model for the F∆I Recl∆Im client.
|
||
//
|
||
// These types are the lingua franca between the (eventually
|
||
// gRPC-fed) repository and the UI. Names mirror the Studie's
|
||
// §5.3 data model.
|
||
|
||
/// Evidence tier of the lowest-tier ingredient in a value.
|
||
/// Per Studie §6.7: "Regel der niedrigsten Stufe" — any composed
|
||
/// figure carries the tier of its weakest input.
|
||
enum EvidenceTier {
|
||
/// Official / peer-reviewed: NKR, DESTATIS, ifo, ZEW.
|
||
t1,
|
||
|
||
/// Verbands-Erhebung: DIHK, BDI, ZDH, IHK.
|
||
t2,
|
||
|
||
/// Eigene strukturierte Erhebung (Phase 2/3).
|
||
t3,
|
||
|
||
/// Qualitatives Signal — pain indicator only, never magnitude.
|
||
t4,
|
||
}
|
||
|
||
extension EvidenceTierLabel on EvidenceTier {
|
||
/// Kompakt-Code für enge Layouts.
|
||
String get short => switch (this) {
|
||
EvidenceTier.t1 => 'T1',
|
||
EvidenceTier.t2 => 'T2',
|
||
EvidenceTier.t3 => 'T3',
|
||
EvidenceTier.t4 => 'T4',
|
||
};
|
||
|
||
/// Ein-Wort-Bedeutung, immer neben dem T-Code zu zeigen.
|
||
String get headline => switch (this) {
|
||
EvidenceTier.t1 => 'amtlich',
|
||
EvidenceTier.t2 => 'Verband',
|
||
EvidenceTier.t3 => 'Erhebung',
|
||
EvidenceTier.t4 => 'Signal',
|
||
};
|
||
|
||
/// Lange Form für Listen, Tooltips, Legend-Texte.
|
||
String get description => switch (this) {
|
||
EvidenceTier.t1 =>
|
||
'amtlich oder peer-reviewed (NKR, DESTATIS, ifo, ZEW)',
|
||
EvidenceTier.t2 =>
|
||
'Verbands-Erhebung (DIHK, IHK, ZDH, BDI)',
|
||
EvidenceTier.t3 =>
|
||
'eigene strukturierte Erhebung (Phase 2/3)',
|
||
EvidenceTier.t4 =>
|
||
'qualitatives Signal — nur Hinweis, keine Magnitude',
|
||
};
|
||
}
|
||
|
||
/// A citable source — never an LLM, always a public document or
|
||
/// dataset reference. UI surfaces these next to every figure.
|
||
class Source {
|
||
const Source({
|
||
required this.label,
|
||
required this.url,
|
||
required this.tier,
|
||
this.note,
|
||
});
|
||
|
||
final String label;
|
||
final String url;
|
||
final EvidenceTier tier;
|
||
final String? note;
|
||
}
|
||
|
||
/// One atomic obligation (Pflicht) extracted from a norm.
|
||
/// Tuple shape matches Studie §6.3.
|
||
class Duty {
|
||
const Duty({
|
||
required this.modality,
|
||
required this.addressee,
|
||
required this.action,
|
||
required this.frequency,
|
||
required this.sourceNorm,
|
||
this.authority,
|
||
this.consequence,
|
||
});
|
||
|
||
final String modality; // OBLIGATION | PROHIBITION | …
|
||
final String addressee;
|
||
final String action;
|
||
final String frequency;
|
||
final String sourceNorm;
|
||
final String? authority;
|
||
final String? consequence;
|
||
}
|
||
|
||
/// One Absatz/paragraph of the actual normative text.
|
||
class NormParagraph {
|
||
const NormParagraph({required this.number, required this.text});
|
||
|
||
/// Source numbering as it appears, e.g. "(1)", "(2a)". Empty
|
||
/// when the source has no Absatz numbering.
|
||
final String number;
|
||
final String text;
|
||
}
|
||
|
||
/// One norm version — a versioned legal text identified by its
|
||
/// (synthetic for now) ELI/CELEX.
|
||
class Norm {
|
||
const Norm({
|
||
required this.eli,
|
||
required this.title,
|
||
required this.jurabk,
|
||
required this.paragraph,
|
||
required this.standDate,
|
||
required this.sourceUrl,
|
||
required this.sourceSha256,
|
||
this.paragraphs = const [],
|
||
});
|
||
|
||
final String eli;
|
||
final String title;
|
||
final String jurabk;
|
||
final String paragraph;
|
||
final DateTime standDate;
|
||
final String sourceUrl;
|
||
final String sourceSha256;
|
||
|
||
/// The actual paragraphs of the norm text, normalised by
|
||
/// `text.akoma_normalize` in live mode. In demo mode the
|
||
/// fixture quotes the public source verbatim under §5 UrhG
|
||
/// (amtliche Werke).
|
||
final List<NormParagraph> paragraphs;
|
||
}
|
||
|
||
/// A heatmap point: one norm with its computed scores.
|
||
/// Axes mirror §6 in the study.
|
||
class Evaluation {
|
||
const Evaluation({
|
||
required this.norm,
|
||
required this.skmEurPerYear,
|
||
required this.benefitScore,
|
||
required this.affectedCount,
|
||
required this.frustScore,
|
||
required this.tierLowest,
|
||
required this.duties,
|
||
required this.sources,
|
||
required this.auditEventId,
|
||
this.notes,
|
||
this.componentSummary = const [],
|
||
});
|
||
|
||
final Norm norm;
|
||
|
||
/// Yearly bureaucracy cost across the addressee population.
|
||
/// €/year, computed via SKM (`P × F × T × h`).
|
||
final double skmEurPerYear;
|
||
|
||
/// 0–5, composite of seven dimensions
|
||
/// (safety / market / legal-certainty / EU-harmony / …).
|
||
final double benefitScore;
|
||
|
||
/// Number of addressees (KMU, Bürger, etc.). UI uses this for
|
||
/// heatmap point size.
|
||
final int affectedCount;
|
||
|
||
/// 0–10, composite of readability + Verweistiefe + Akteurs-
|
||
/// pluralität + Norm-Volatilität.
|
||
final double frustScore;
|
||
|
||
/// Lowest tier among all ingredients of any displayed figure.
|
||
final EvidenceTier tierLowest;
|
||
|
||
final List<Duty> duties;
|
||
final List<Source> sources;
|
||
|
||
/// Pointer into the Ch∆In audit log (SQLite event_log row).
|
||
final String auditEventId;
|
||
|
||
final String? notes;
|
||
|
||
/// Compact lines for at-a-glance reading on list views.
|
||
/// One line per SKM-Komponente (P / F / T / h) plus optional
|
||
/// extras — each carries its tier-tag inline. Empty list ⇒
|
||
/// fall back to the notes field for the list view.
|
||
final List<String> componentSummary;
|
||
}
|