feat: BetrVG-Compliance-Modul — Obligations, Konflikt-Score, Frontend
1. BetrVG Obligations (JSON V2): 12 Pflichten basierend auf §87, §90, §94, §95, §99, §111 - BAG-Rechtsprechung referenziert (M365, SAP, Standardsoftware) - Applicability: DE + >=5 Mitarbeiter 2. Betriebsrats-Konflikt-Score (0-100): Gewichtete Formel aus 8 Faktoren - Ueberwachungseignung, HR-Bezug, Individualisierbarkeit, Automation - Escalation-Trigger: Score>=50 ohne BR → E2, Score>=75 → E3 3. Frontend: 3 neue Intake-Felder (Monitoring, HR, BR-Konsultation) - BR-Konflikt-Badge in Use-Case-Liste + Detail-Seite - Farbcodierung: gruen/gelb/orange/rot Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -333,6 +333,10 @@ function AdvisoryBoardPageInner() {
|
||||
purposes: [] as string[],
|
||||
// Automation (single-select tile)
|
||||
automation: '' as string,
|
||||
// BetrVG / works council
|
||||
employee_monitoring: false,
|
||||
hr_decision_support: false,
|
||||
works_council_consulted: false,
|
||||
// Hosting (single-select tile)
|
||||
hosting_provider: '' as string,
|
||||
hosting_region: '' as string,
|
||||
@@ -420,6 +424,9 @@ function AdvisoryBoardPageInner() {
|
||||
retention_purpose: form.retention_purpose,
|
||||
contracts_list: form.contracts,
|
||||
subprocessors: form.subprocessors,
|
||||
employee_monitoring: form.employee_monitoring,
|
||||
hr_decision_support: form.hr_decision_support,
|
||||
works_council_consulted: form.works_council_consulted,
|
||||
store_raw_text: true,
|
||||
}
|
||||
|
||||
@@ -777,6 +784,52 @@ function AdvisoryBoardPageInner() {
|
||||
Informationspflicht, Recht auf menschliche Ueberpruefung und Anfechtungsmoeglichkeit.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* BetrVG Section */}
|
||||
<div className="mt-6 pt-6 border-t border-gray-200">
|
||||
<h3 className="text-sm font-semibold text-gray-900 mb-1">Betriebsrat & Beschaeftigtendaten</h3>
|
||||
<p className="text-xs text-gray-500 mb-4">
|
||||
Relevant fuer deutsche Unternehmen mit Betriebsrat (§87 Abs.1 Nr.6 BetrVG).
|
||||
</p>
|
||||
<div className="space-y-3">
|
||||
<label className="flex items-center gap-3 p-3 rounded-lg border border-gray-200 hover:bg-gray-50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={form.employee_monitoring}
|
||||
onChange={(e) => updateForm({ employee_monitoring: e.target.checked })}
|
||||
className="w-4 h-4 rounded border-gray-300 text-purple-600 focus:ring-purple-500"
|
||||
/>
|
||||
<div>
|
||||
<span className="text-sm font-medium text-gray-900">System kann Verhalten/Leistung ueberwachen</span>
|
||||
<p className="text-xs text-gray-500">Nutzungslogs, Produktivitaetskennzahlen, Kommunikationsanalyse</p>
|
||||
</div>
|
||||
</label>
|
||||
<label className="flex items-center gap-3 p-3 rounded-lg border border-gray-200 hover:bg-gray-50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={form.hr_decision_support}
|
||||
onChange={(e) => updateForm({ hr_decision_support: e.target.checked })}
|
||||
className="w-4 h-4 rounded border-gray-300 text-purple-600 focus:ring-purple-500"
|
||||
/>
|
||||
<div>
|
||||
<span className="text-sm font-medium text-gray-900">System unterstuetzt HR-Entscheidungen</span>
|
||||
<p className="text-xs text-gray-500">Recruiting, Bewertung, Befoerderung, Kuendigung</p>
|
||||
</div>
|
||||
</label>
|
||||
<label className="flex items-center gap-3 p-3 rounded-lg border border-gray-200 hover:bg-gray-50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={form.works_council_consulted}
|
||||
onChange={(e) => updateForm({ works_council_consulted: e.target.checked })}
|
||||
className="w-4 h-4 rounded border-gray-300 text-purple-600 focus:ring-purple-500"
|
||||
/>
|
||||
<div>
|
||||
<span className="text-sm font-medium text-gray-900">Betriebsrat wurde konsultiert</span>
|
||||
<p className="text-xs text-gray-500">Betriebsvereinbarung liegt vor oder ist in Verhandlung</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ interface FullAssessment {
|
||||
dsfa_recommended: boolean
|
||||
art22_risk: boolean
|
||||
training_allowed: string
|
||||
betrvg_conflict_score?: number
|
||||
betrvg_consultation_required?: boolean
|
||||
triggered_rules?: TriggeredRule[]
|
||||
required_controls?: RequiredControl[]
|
||||
recommended_architecture?: PatternRecommendation[]
|
||||
@@ -167,6 +169,8 @@ export default function AssessmentDetailPage() {
|
||||
dsfa_recommended: assessment.dsfa_recommended,
|
||||
art22_risk: assessment.art22_risk,
|
||||
training_allowed: assessment.training_allowed,
|
||||
betrvg_conflict_score: assessment.betrvg_conflict_score,
|
||||
betrvg_consultation_required: assessment.betrvg_consultation_required,
|
||||
// AssessmentResultCard expects rule_code; backend stores code — map here
|
||||
triggered_rules: assessment.triggered_rules?.map(r => ({
|
||||
rule_code: r.code,
|
||||
|
||||
@@ -10,6 +10,8 @@ interface Assessment {
|
||||
feasibility: string
|
||||
risk_level: string
|
||||
risk_score: number
|
||||
betrvg_conflict_score?: number
|
||||
betrvg_consultation_required?: boolean
|
||||
domain: string
|
||||
created_at: string
|
||||
}
|
||||
@@ -194,6 +196,16 @@ export default function UseCasesPage() {
|
||||
<span className={`px-2 py-0.5 text-xs rounded-full ${feasibility.bg} ${feasibility.text}`}>
|
||||
{feasibility.label}
|
||||
</span>
|
||||
{assessment.betrvg_conflict_score != null && assessment.betrvg_conflict_score > 0 && (
|
||||
<span className={`px-2 py-0.5 text-xs rounded-full ${
|
||||
assessment.betrvg_conflict_score >= 75 ? 'bg-red-100 text-red-700' :
|
||||
assessment.betrvg_conflict_score >= 50 ? 'bg-orange-100 text-orange-700' :
|
||||
assessment.betrvg_conflict_score >= 25 ? 'bg-yellow-100 text-yellow-700' :
|
||||
'bg-green-100 text-green-700'
|
||||
}`}>
|
||||
BR {assessment.betrvg_conflict_score}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-4 text-sm text-gray-500">
|
||||
<span>{assessment.domain}</span>
|
||||
|
||||
@@ -10,6 +10,8 @@ interface AssessmentResult {
|
||||
dsfa_recommended: boolean
|
||||
art22_risk: boolean
|
||||
training_allowed: string
|
||||
betrvg_conflict_score?: number
|
||||
betrvg_consultation_required?: boolean
|
||||
summary: string
|
||||
recommendation: string
|
||||
alternative_approach?: string
|
||||
@@ -76,6 +78,21 @@ export function AssessmentResultCard({ result }: AssessmentResultCardProps) {
|
||||
Art. 22 Risiko
|
||||
</span>
|
||||
)}
|
||||
{result.betrvg_conflict_score != null && result.betrvg_conflict_score > 0 && (
|
||||
<span className={`px-3 py-1 rounded-full text-sm font-medium ${
|
||||
result.betrvg_conflict_score >= 75 ? 'bg-red-100 text-red-700' :
|
||||
result.betrvg_conflict_score >= 50 ? 'bg-orange-100 text-orange-700' :
|
||||
result.betrvg_conflict_score >= 25 ? 'bg-yellow-100 text-yellow-700' :
|
||||
'bg-green-100 text-green-700'
|
||||
}`}>
|
||||
BR-Konflikt: {result.betrvg_conflict_score}/100
|
||||
</span>
|
||||
)}
|
||||
{result.betrvg_consultation_required && (
|
||||
<span className="px-3 py-1 rounded-full text-sm bg-purple-100 text-purple-700">
|
||||
BR-Konsultation erforderlich
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-gray-700">{result.summary}</p>
|
||||
<p className="text-sm text-gray-500 mt-2">{result.recommendation}</p>
|
||||
|
||||
Reference in New Issue
Block a user