feat(planning): make optimization rules composable

Evaluate explicit, ordered optimization configurations through one shared
planner model. Add six editable presets, durable one-time legacy migration,
and consistent completed and cancelled plan provenance.

Include functional regressions and the agreed trace-removal and benchmark
follow-up specs. Performance acceptance remains in #78 under unchanged gates.

Refs: #70, #71, #72, #73, #74, #75, #76, #77, #78
This commit is contained in:
nessar committed 2026-10-10 16:07:34 +02:00
1 parent 209bf05f36
commit 6811142299
45 files changed
+8795 -3075

No files matched your search

+54 -2
View File
@@ -133,6 +133,51 @@
"after": "danach",
"around": "darum herum",
"auto": "automatisch"
},
"optimization": {
"newRule": "Neue Optimierungsregel",
"defaultName": "Verluste vermeiden",
"elementsLabel": "Planungselemente",
"conditionsLabel": "Bedingungen (alle müssen erfüllt sein)",
"measureLabel": "Messgröße",
"aggregationLabel": "Aggregation",
"directionLabel": "Richtung",
"thresholdLabel": "Präferenzschwelle in Arbeitstagen",
"thresholdSummary": "Präferenzschwelle: {count} Arbeitstage",
"summary": "{direction} {aggregation}: {measure} — {elements}{conditions}.",
"invalidConfiguration": "Wählen Sie passende Elemente, Bedingungen, Messgrößen und Aggregationen sowie bei Bedarf eine positive ganzzahlige Tagesschwelle.",
"nameRequired": "Geben Sie einen Regelnamen ein.",
"elements": {
"leave-balances": "Urlaubsguthaben",
"public-holiday-weeks": "Feiertagswochen",
"time-off-periods": "Arbeitsfreie Zeiträume",
"work-sequences": "Arbeitsfolgen",
"leave-placements": "Geplante Urlaubstage"
},
"conditions": {
"at-risk": "Vom Verfall bedroht",
"complete": "Vollständig",
"internal": "Intern",
"non-empty": "Nicht leer",
"supporting": "Unterstützend"
},
"measures": {
"unplaced-quantity": "Nicht eingeplante Menge",
"public-holiday-week-value": "Wert der Feiertagswochen",
"non-working-day-gain": "Gewinn arbeitsfreier Tage",
"work-sequence-length": "Länge der Arbeitsfolgen",
"work-sequence-deficit": "Defizit der Arbeitsfolgen",
"placement-count": "Anzahl der Platzierungen"
},
"aggregations": {
"sum": "Summe",
"count": "Anzahl",
"maximum": "Maximum"
},
"directions": {
"minimize": "Minimieren",
"maximize": "Maximieren"
}
}
},
"planning": {
@@ -276,7 +321,7 @@
"withoutDay": "Ohne diesen Tag",
"withDay": "Mit diesem Tag",
"noChange": "Diese Werte sind gleich. Regeln und die letzten Entscheidungskriterien (Verfall des Guthabens, dann Datum) können die Auswahl weiterhin beeinflussen.",
"priorityHelp": "Die Kriterien stehen in Prioritätsreihenfolge. Der erste Unterschied hat Vorrang vor den folgenden.",
"priorityHelp": "Verpflichtungen werden gemeinsam erfüllt. Aktive Präferenzen werden in Ihrer Regelreihenfolge verglichen. Nur diese Regeln führen zu neuen Urlaubstagen; früherer Verfall und dann frühere Daten entscheiden bei Gleichstand.",
"tryDate": "Anderes Datum testen",
"plannedDate": "Derzeit geplant für:",
"currentPlan": "Aktueller Plan",
@@ -327,6 +372,10 @@
"placement-date": {
"label": "Frühere Daten bevorzugen",
"help": "Letztes Kriterium, wenn alle anderen Kriterien gleich sind."
},
"optimization": {
"label": "{rule}: {summary}",
"help": "Diese Optimierungspräferenz bewertet ihre gespeicherte Konfiguration. Aktive Präferenzen werden in der angezeigten Reihenfolge verglichen; frühere haben Vorrang."
}
},
"stages": {
@@ -342,7 +391,9 @@
"unavailable": "Dieses Urlaubsguthaben kann an diesem Datum nicht verwendet werden.",
"expired": "Dieses Datum liegt nach dem Verfall des Urlaubsguthabens.",
"type-incompatible": "Diese Urlaubsart kann an diesem Datum nicht verwendet werden.",
"rule-invalid": "Dieses Datum würde eine Planungsregel verletzen."
"rule-invalid": "Dieses Datum würde eine Planungsregel verletzen.",
"invalid-optimization-configuration": "Wählen Sie passende Elemente, Bedingungen, Messgrößen und Aggregationen sowie bei Bedarf eine positive ganzzahlige Tagesschwelle.",
"unsupported-optimization-configuration": "Diese Regel kombiniert unvereinbare Planungselemente und Messgrößen."
},
"preferenceHelp": {
"time_window": "Urlaubstage im bevorzugten Zeitraum. Mehr ist besser.",
@@ -373,6 +424,7 @@
"no-working-date": "Kein Arbeitstag liegt sowohl im Planungszeitraum als auch zwischen Verfügbarkeits- und Ablaufdatum.",
"all-dates-occupied": "Alle Arbeitstage, an denen dieses Urlaubskonto nutzbar ist, sind bereits durch geplanten Urlaub oder gebuchte Tage belegt.",
"preserved": "Für später aufbewahrt: Das Urlaubskonto läuft nach dem Planungszeitraum ab und die Berechnung hat gemäß Ihren Prioritäten keine zusätzliche Platzierung ausgewählt.",
"active-priorities": "Die Berechnung hat dieses Urlaubskonto gemäß Ihren aktiven Regeln ungenutzt gelassen. Ändern Sie die Regeln oder ihre Reihenfolge, um einen anderen Plan anzufordern.",
"calculation-incomplete": "Die Berechnung wurde vor Abschluss der Planung unterbrochen. Die Nichtnutzung ist keine endgültige Entscheidung.",
"not-established": "Diese Berechnung hat keinen genauen Grund für die Nichtnutzung ermittelt."
}