reclaim/app/lib/data/models.dart
flemming-it 1ad523a91a fix(ui): make T1–T4 readable + lift Recl∆Im into the nav rail
Three small frictions a first-time reader hit at the same time,
fixed in one pass:

  1. The TierBadge said 'T1' without context. Default form is
     now 'T1 · amtlich' / 'T2 · Verband' / 'T3 · Erhebung' /
     'T4 · Signal'. Compact form (heatmap chip wrap) keeps the
     bare code. Tooltip spells out the long form + cites the
     Regel der niedrigsten Stufe (Studie §6.7) so the meaning
     of the cap is at hand on hover.

  2. The Legende's tier row was the abstract one of the four —
     it now inlines all four stage names (amtlich / Verband /
     Erhebung / Signal) and explains why a single T4 component
     drags a whole figure to T4. No more 'what is Tier?' on
     screen.

  3. The DemoBanner repeated 'Tier T4' without explaining what
     T4 is. Now: 'qualitatives Signal — bis NKR/Verbands-
     Pipeline + Juristen-Approval laufen'. The cause-and-cure
     is visible at a glance.

  4. The NavigationRail leading column showed only 'F∆I' as
     brand mark. Now shows 'Recl∆Im' prominently (petrol-signal,
     bold) with 'F∆I' as a small muted vendor tag below.
     Product first, vendor second.

EvidenceTierLabel extension grows a new 'headline' getter for
the one-word default ('amtlich'/'Verband'/…), and 'description'
gets longer, source-naming text (NKR / DESTATIS / DIHK / IHK /
ZDH / BDI). Code paths that used the old short-only badge keep
working because 'short' still returns 'T1'.

flutter pub get refreshed against chain_client_sdk 0.18, which
the fai_chain agent confirmed already carries the gRPC-Web
channel — no SDK bump needed for the web-hub-mode wire.

Signed-off-by: flemming-it <sf@flemming.it>
2026-06-18 14:44:14 +02:00

175 lines
4.7 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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,
});
final Norm norm;
/// Yearly bureaucracy cost across the addressee population.
/// €/year, computed via SKM (`P × F × T × h`).
final double skmEurPerYear;
/// 05, 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;
/// 010, 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;
}