merge: phases 1–5 refactor, CI hardening, docs (coolify → main)
Some checks failed
Build + Deploy / build-admin-compliance (push) Failing after 47s
Build + Deploy / build-backend-compliance (push) Successful in 11s
Build + Deploy / build-ai-sdk (push) Successful in 34s
Build + Deploy / build-developer-portal (push) Successful in 56s
Build + Deploy / build-tts (push) Successful in 26s
Build + Deploy / build-document-crawler (push) Successful in 15s
Build + Deploy / build-dsms-gateway (push) Successful in 13s
Build + Deploy / trigger-orca (push) Has been skipped
CI/CD / loc-budget (push) Successful in 22s
CI/CD / guardrail-integrity (push) Has been skipped
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been cancelled
CI/CD / test-go-ai-compliance (push) Has been cancelled
CI/CD / test-python-backend-compliance (push) Has been cancelled
CI/CD / test-python-document-crawler (push) Has been cancelled
CI/CD / test-python-dsms-gateway (push) Successful in 28s
CI/CD / sbom-scan (push) Has been cancelled
CI/CD / validate-canonical-controls (push) Successful in 20s

Phase 1: backend-compliance — partial service-layer extraction
Phase 2: ai-compliance-sdk — full hexagonal split; iace/ucca/training handlers
  and stores split into focused files; cmd/server/main.go → internal/app/
Phase 3: admin-compliance — types.ts, tom-generator loader, and major page
  components split; lib document generators extracted
Phase 4: dsms-gateway, consent-sdk, developer-portal, breakpilot-compliance-sdk
Phase 5 CI hardening:
  - loc-budget job now scans whole repo (blocking, no || true)
  - sbom-scan / grype blocking on high+ CVEs
  - ai-compliance-sdk/.golangci.yml: strict golangci-lint config
  - check-loc.sh: skip test_*.py and *.html; loc-exceptions.txt expanded
  - deleted stray routes.py.backup (2512 LOC)
Docs:
  - root README.md with CI badge, service table, quick start, CI pipeline table
  - CONTRIBUTING.md: setup, pre-commit checklist, guardrail marker reference
  - CLAUDE.md: First-Time Setup & Claude Code Onboarding section
  - all 7 service READMEs updated (stale phase refs, current architecture)
  - AGENTS.go/python/typescript.md enhanced with linting, DI, barrel re-export
  - .gitignore: dist/, .turbo/, pnpm-lock.yaml added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-19 16:11:53 +02:00
1258 changed files with 210195 additions and 145532 deletions

View File

@@ -1,17 +1,10 @@
'use client'
import { useState } from 'react'
interface VerificationItem {
id: string
title: string
[key: string]: unknown
}
import type { VerificationItem } from './verification-types'
export function CompleteModal({
item,
onSubmit,
onClose,
item, onSubmit, onClose,
}: {
item: VerificationItem
onSubmit: (id: string, result: string, passed: boolean) => void
@@ -40,17 +33,13 @@ export function CompleteModal({
<div className="flex gap-3">
<button
onClick={() => setPassed(true)}
className={`flex-1 py-2 rounded-lg border text-sm font-medium transition-colors ${
passed ? 'border-green-400 bg-green-50 text-green-700' : 'border-gray-200 text-gray-500 hover:bg-gray-50'
}`}
className={`flex-1 py-2 rounded-lg border text-sm font-medium transition-colors ${passed ? 'border-green-400 bg-green-50 text-green-700' : 'border-gray-200 text-gray-500 hover:bg-gray-50'}`}
>
Bestanden
</button>
<button
onClick={() => setPassed(false)}
className={`flex-1 py-2 rounded-lg border text-sm font-medium transition-colors ${
!passed ? 'border-red-400 bg-red-50 text-red-700' : 'border-gray-200 text-gray-500 hover:bg-gray-50'
}`}
className={`flex-1 py-2 rounded-lg border text-sm font-medium transition-colors ${!passed ? 'border-red-400 bg-red-50 text-red-700' : 'border-gray-200 text-gray-500 hover:bg-gray-50'}`}
>
Nicht bestanden
</button>
@@ -60,9 +49,7 @@ export function CompleteModal({
<div className="mt-6 flex items-center gap-3">
<button
onClick={() => onSubmit(item.id, result, passed)} disabled={!result}
className={`px-6 py-2 rounded-lg font-medium transition-colors ${
result ? 'bg-purple-600 text-white hover:bg-purple-700' : 'bg-gray-200 text-gray-400 cursor-not-allowed'
}`}
className={`px-6 py-2 rounded-lg font-medium transition-colors ${result ? 'bg-purple-600 text-white hover:bg-purple-700' : 'bg-gray-200 text-gray-400 cursor-not-allowed'}`}
>
Abschliessen
</button>

View File

@@ -1,33 +1,10 @@
'use client'
import { useState } from 'react'
interface SuggestedEvidence {
id: string
name: string
description: string
method: string
tags?: string[]
}
const VERIFICATION_METHOD_LABELS: Record<string, string> = {
design_review: 'Design-Review',
calculation: 'Berechnung',
test_report: 'Pruefbericht',
validation: 'Validierung',
electrical_test: 'Elektrische Pruefung',
software_test: 'Software-Test',
penetration_test: 'Penetrationstest',
acceptance_protocol: 'Abnahmeprotokoll',
user_test: 'Anwendertest',
documentation_release: 'Dokumentenfreigabe',
}
import { VERIFICATION_METHODS, type SuggestedEvidence } from './verification-types'
export function SuggestEvidenceModal({
mitigations,
projectId,
onAddEvidence,
onClose,
mitigations, projectId, onAddEvidence, onClose,
}: {
mitigations: { id: string; title: string }[]
projectId: string
@@ -69,7 +46,8 @@ export function SuggestEvidenceModal({
</p>
<div className="flex flex-wrap gap-2">
{mitigations.map(m => (
<button key={m.id} onClick={() => handleSelectMitigation(m.id)}
<button
key={m.id} onClick={() => handleSelectMitigation(m.id)}
className={`px-3 py-1.5 text-xs rounded-lg border transition-colors ${
selectedMitigation === m.id
? 'border-purple-400 bg-purple-50 text-purple-700 font-medium'
@@ -81,7 +59,6 @@ export function SuggestEvidenceModal({
))}
</div>
</div>
<div className="flex-1 overflow-auto p-6">
{loadingSuggestions ? (
<div className="flex items-center justify-center py-12">
@@ -97,7 +74,7 @@ export function SuggestEvidenceModal({
<span className="text-xs font-mono text-gray-400">{ev.id}</span>
{ev.method && (
<span className="text-xs px-1.5 py-0.5 rounded bg-blue-50 text-blue-600">
{VERIFICATION_METHOD_LABELS[ev.method] || ev.method}
{VERIFICATION_METHODS.find(m => m.value === ev.method)?.label || ev.method}
</span>
)}
</div>

View File

@@ -1,33 +1,10 @@
'use client'
import { useState } from 'react'
export interface VerificationFormData {
title: string
description: string
method: string
linked_hazard_id: string
linked_mitigation_id: string
}
const VERIFICATION_METHODS = [
{ value: 'design_review', label: 'Design-Review' },
{ value: 'calculation', label: 'Berechnung' },
{ value: 'test_report', label: 'Pruefbericht' },
{ value: 'validation', label: 'Validierung' },
{ value: 'electrical_test', label: 'Elektrische Pruefung' },
{ value: 'software_test', label: 'Software-Test' },
{ value: 'penetration_test', label: 'Penetrationstest' },
{ value: 'acceptance_protocol', label: 'Abnahmeprotokoll' },
{ value: 'user_test', label: 'Anwendertest' },
{ value: 'documentation_release', label: 'Dokumentenfreigabe' },
]
import { VERIFICATION_METHODS, type VerificationFormData } from './verification-types'
export function VerificationForm({
onSubmit,
onCancel,
hazards,
mitigations,
onSubmit, onCancel, hazards, mitigations,
}: {
onSubmit: (data: VerificationFormData) => void
onCancel: () => void
@@ -59,9 +36,7 @@ export function VerificationForm({
onChange={(e) => setFormData({ ...formData, method: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent dark:bg-gray-700 dark:border-gray-600 dark:text-white"
>
{VERIFICATION_METHODS.map((m) => (
<option key={m.value} value={m.value}>{m.label}</option>
))}
{VERIFICATION_METHODS.map((m) => <option key={m.value} value={m.value}>{m.label}</option>)}
</select>
</div>
</div>
@@ -70,7 +45,8 @@ export function VerificationForm({
<textarea
value={formData.description}
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
rows={2} placeholder="Beschreiben Sie den Verifikationsschritt..."
rows={2}
placeholder="Beschreiben Sie den Verifikationsschritt..."
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent dark:bg-gray-700 dark:border-gray-600 dark:text-white"
/>
</div>
@@ -102,9 +78,7 @@ export function VerificationForm({
<div className="mt-4 flex items-center gap-3">
<button
onClick={() => onSubmit(formData)} disabled={!formData.title}
className={`px-6 py-2 rounded-lg font-medium transition-colors ${
formData.title ? 'bg-purple-600 text-white hover:bg-purple-700' : 'bg-gray-200 text-gray-400 cursor-not-allowed'
}`}
className={`px-6 py-2 rounded-lg font-medium transition-colors ${formData.title ? 'bg-purple-600 text-white hover:bg-purple-700' : 'bg-gray-200 text-gray-400 cursor-not-allowed'}`}
>
Hinzufuegen
</button>

View File

@@ -1,30 +1,18 @@
import { StatusBadge } from './StatusBadge'
'use client'
interface VerificationItem {
id: string
title: string
description: string
method: string
status: 'pending' | 'in_progress' | 'completed' | 'failed'
result: string | null
linked_hazard_name: string | null
linked_mitigation_name: string | null
completed_at: string | null
completed_by: string | null
created_at: string
}
import { VERIFICATION_METHODS, STATUS_CONFIG, type VerificationItem } from './verification-types'
const VERIFICATION_METHOD_LABELS: Record<string, string> = {
design_review: 'Design-Review', calculation: 'Berechnung', test_report: 'Pruefbericht',
validation: 'Validierung', electrical_test: 'Elektrische Pruefung', software_test: 'Software-Test',
penetration_test: 'Penetrationstest', acceptance_protocol: 'Abnahmeprotokoll',
user_test: 'Anwendertest', documentation_release: 'Dokumentenfreigabe',
function StatusBadge({ status }: { status: string }) {
const config = STATUS_CONFIG[status] || STATUS_CONFIG.pending
return (
<span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${config.color}`}>
{config.label}
</span>
)
}
export function VerificationTable({
items,
onComplete,
onDelete,
items, onComplete, onDelete,
}: {
items: VerificationItem[]
onComplete: (item: VerificationItem) => void
@@ -50,13 +38,11 @@ export function VerificationTable({
<tr key={item.id} className="hover:bg-gray-50 dark:hover:bg-gray-750 transition-colors">
<td className="px-4 py-3">
<div className="text-sm font-medium text-gray-900 dark:text-white">{item.title}</div>
{item.description && (
<div className="text-xs text-gray-500 truncate max-w-[200px]">{item.description}</div>
)}
{item.description && <div className="text-xs text-gray-500 truncate max-w-[200px]">{item.description}</div>}
</td>
<td className="px-4 py-3">
<span className="text-xs px-2 py-0.5 rounded bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300">
{VERIFICATION_METHOD_LABELS[item.method] || item.method}
{VERIFICATION_METHODS.find((m) => m.value === item.method)?.label || item.method}
</span>
</td>
<td className="px-4 py-3 text-sm text-gray-600">{item.linked_hazard_name || '--'}</td>

View File

@@ -0,0 +1,51 @@
export interface VerificationItem {
id: string
title: string
description: string
method: string
status: 'pending' | 'in_progress' | 'completed' | 'failed'
result: string | null
linked_hazard_id: string | null
linked_hazard_name: string | null
linked_mitigation_id: string | null
linked_mitigation_name: string | null
completed_at: string | null
completed_by: string | null
created_at: string
}
export interface VerificationFormData {
title: string
description: string
method: string
linked_hazard_id: string
linked_mitigation_id: string
}
export interface SuggestedEvidence {
id: string
name: string
description: string
method: string
tags?: string[]
}
export const VERIFICATION_METHODS = [
{ value: 'design_review', label: 'Design-Review', description: 'Systematische Pruefung der Konstruktionsunterlagen' },
{ value: 'calculation', label: 'Berechnung', description: 'Rechnerischer Nachweis (FEM, Festigkeit, Thermik)' },
{ value: 'test_report', label: 'Pruefbericht', description: 'Dokumentierter Test mit Messprotokoll' },
{ value: 'validation', label: 'Validierung', description: 'Nachweis der Eignung unter realen Betriebsbedingungen' },
{ value: 'electrical_test', label: 'Elektrische Pruefung', description: 'Isolationsmessung, Schutzleiter, Spannungsfestigkeit' },
{ value: 'software_test', label: 'Software-Test', description: 'Unit-, Integrations- oder Systemtest der Steuerungssoftware' },
{ value: 'penetration_test', label: 'Penetrationstest', description: 'Security-Test der Netzwerk- und Steuerungskomponenten' },
{ value: 'acceptance_protocol', label: 'Abnahmeprotokoll', description: 'Formelle Abnahme mit Checkliste und Unterschrift' },
{ value: 'user_test', label: 'Anwendertest', description: 'Pruefung durch Bediener unter realen Einsatzbedingungen' },
{ value: 'documentation_release', label: 'Dokumentenfreigabe', description: 'Formelle Freigabe der technischen Dokumentation' },
]
export const STATUS_CONFIG: Record<string, { label: string; color: string }> = {
pending: { label: 'Ausstehend', color: 'bg-gray-100 text-gray-700' },
in_progress: { label: 'In Bearbeitung', color: 'bg-blue-100 text-blue-700' },
completed: { label: 'Abgeschlossen', color: 'bg-green-100 text-green-700' },
failed: { label: 'Fehlgeschlagen', color: 'bg-red-100 text-red-700' },
}