94233b7c66
Three coupled pieces of work, all landing the same PoC:
1. Backend gap-review endpoint (Task #7)
- internal/api/handlers/iace_handler_gap_review.go:
POST /projects/:id/llm-gap-review
feeds Limits-Form + current hazards + current mitigations to
the configured LLM (Qwen / Claude / OpenAI via ProviderRegistry),
parses a JSON suggestion list, filter+stamps confidence, falls
back to a static checklist when LLM is unavailable.
- Adopt step is NOT in this endpoint by design — the user clicks
Adopt in the frontend which calls the existing CreateHazard /
CreateMitigation handlers so provenance flows through the normal
audit trail.
2. Frontend modal + button (Task #8)
- app/sdk/iace/[projectId]/hazards/_components/LLMGapReviewModal.tsx:
reusable modal that POSTs the gap-review endpoint, renders
suggestions with Adopt/Reject UX, shows confidence + norm refs,
source-stamp llm_gap_review vs fallback_static.
- hazards/page.tsx: indigo "KI-Gap-Review" button next to the
existing "Eigene Gefaehrdung" button + modal mount.
3. Tech-File sources appendix (Task #29 — Stufe 4)
- internal/iace/document_export_sources.go: new pdfSourcesAppendix
method appended to ExportPDF. Groups cited norms by license rule
(R1 OSHA/EU-Recht / R3 BreakPilot patterns / R3 DIN-EN-ISO
identifier-only) and emits the legally required statement that
pauschal Impressum-Hinweise nicht ausreichen.
- extractCitedNorms() scans hazard/mitigation text for EN/ISO/IEC/
DIN identifiers in a narrow grammar so prose isn't turned into
spurious citations.
Bonus refactor:
- internal/app/routes.go reached the 500-LOC hard cap when the new
llm-gap-review route was added. Extracted registerIACERoutes into
routes_iace.go (136 LOC). Same wiring, no behaviour change.
Three of the four Attribution-Renderer stages (1, 2, 4) now produce
real output. Stufe 3 ships as <SourceBadge> + <LicenseModuleBanner>
already (commits dfac940 + b9e3eea earlier in this branch).
The PoC is intentionally conservative: every LLM-Suggestion stays
unverbindlich until a human clicks Adopt, and Adopt goes through the
existing normal CreateHazard/CreateMitigation flow (not yet wired in
this commit — separate iteration). The endpoint, modal and provenance
chain are in place for the next iteration to wire Adopt → write path.
137 lines
7.7 KiB
Go
137 lines
7.7 KiB
Go
package app
|
|
|
|
// IACE route registration extracted from routes.go (2026-05-21) because
|
|
// routes.go hit the 500-LOC hard cap when the LLM gap-review endpoint
|
|
// (Task #7) was added. Splitting keeps every routes file under the cap
|
|
// without changing behaviour — `registerRoutes` in routes.go still
|
|
// invokes `registerIACERoutes` exactly once at the same point in the
|
|
// startup sequence.
|
|
|
|
import (
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/api/handlers"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func registerIACERoutes(v1 *gin.RouterGroup, h *handlers.IACEHandler) {
|
|
iaceRoutes := v1.Group("/iace")
|
|
{
|
|
// Library catalogues (read-only reference data).
|
|
iaceRoutes.GET("/hazard-library", h.ListHazardLibrary)
|
|
iaceRoutes.GET("/controls-library", h.ListControlsLibrary)
|
|
iaceRoutes.GET("/norms-library", h.ListNormsLibrary)
|
|
iaceRoutes.GET("/lifecycle-phases", h.ListLifecyclePhases)
|
|
iaceRoutes.GET("/roles", h.ListRoles)
|
|
iaceRoutes.GET("/evidence-types", h.ListEvidenceTypes)
|
|
iaceRoutes.GET("/protective-measures-library", h.ListProtectiveMeasures)
|
|
iaceRoutes.GET("/failure-modes", h.ListFailureModes)
|
|
iaceRoutes.GET("/operational-states", h.ListOperationalStates)
|
|
iaceRoutes.GET("/component-library", h.ListComponentLibrary)
|
|
iaceRoutes.GET("/energy-sources", h.ListEnergySources)
|
|
iaceRoutes.GET("/tags", h.ListTags)
|
|
iaceRoutes.GET("/hazard-patterns", h.ListHazardPatterns)
|
|
|
|
// Project CRUD.
|
|
iaceRoutes.POST("/projects", h.CreateProject)
|
|
iaceRoutes.GET("/projects", h.ListProjects)
|
|
iaceRoutes.GET("/projects/:id", h.GetProject)
|
|
iaceRoutes.PUT("/projects/:id", h.UpdateProject)
|
|
iaceRoutes.DELETE("/projects/:id", h.ArchiveProject)
|
|
iaceRoutes.POST("/projects/:id/init-from-profile", h.InitFromProfile)
|
|
iaceRoutes.POST("/projects/:id/variants", h.CreateVariant)
|
|
iaceRoutes.GET("/projects/:id/variants", h.ListVariants)
|
|
iaceRoutes.GET("/projects/:id/variant-gap", h.GetVariantGap)
|
|
iaceRoutes.POST("/projects/:id/completeness-check", h.CheckCompleteness)
|
|
|
|
// Components.
|
|
iaceRoutes.POST("/projects/:id/components", h.CreateComponent)
|
|
iaceRoutes.GET("/projects/:id/components", h.ListComponents)
|
|
iaceRoutes.PUT("/projects/:id/components/:cid", h.UpdateComponent)
|
|
iaceRoutes.DELETE("/projects/:id/components/:cid", h.DeleteComponent)
|
|
|
|
// Classification + hazards.
|
|
iaceRoutes.POST("/projects/:id/classify", h.Classify)
|
|
iaceRoutes.GET("/projects/:id/classifications", h.GetClassifications)
|
|
iaceRoutes.POST("/projects/:id/classify/:regulation", h.ClassifySingle)
|
|
iaceRoutes.POST("/projects/:id/hazards", h.CreateHazard)
|
|
iaceRoutes.GET("/projects/:id/hazards", h.ListHazards)
|
|
iaceRoutes.PUT("/projects/:id/hazards/:hid", h.UpdateHazard)
|
|
iaceRoutes.POST("/projects/:id/hazards/suggest", h.SuggestHazards)
|
|
iaceRoutes.POST("/projects/:id/match-patterns", h.MatchPatterns)
|
|
iaceRoutes.POST("/projects/:id/parse-narrative", h.ParseNarrative)
|
|
iaceRoutes.POST("/projects/:id/delta-analysis", h.DeltaAnalysis)
|
|
iaceRoutes.POST("/projects/:id/llm-gap-review", h.LLMGapReview)
|
|
iaceRoutes.GET("/projects/:id/fmea/export", h.ExportFMEA)
|
|
iaceRoutes.POST("/projects/:id/components/:cid/suggest-fms", h.SuggestFailureModes)
|
|
iaceRoutes.POST("/projects/:id/apply-patterns", h.ApplyPatternResults)
|
|
iaceRoutes.POST("/projects/:id/hazards/:hid/suggest-measures", h.SuggestMeasuresForHazard)
|
|
iaceRoutes.POST("/projects/:id/mitigations/:mid/suggest-evidence", h.SuggestEvidenceForMitigation)
|
|
iaceRoutes.POST("/projects/:id/hazards/:hid/assess", h.AssessRisk)
|
|
iaceRoutes.GET("/projects/:id/risk-summary", h.GetRiskSummary)
|
|
iaceRoutes.GET("/projects/:id/suggested-norms", h.SuggestProjectNorms)
|
|
iaceRoutes.POST("/projects/:id/hazards/:hid/reassess", h.ReassessRisk)
|
|
|
|
// Mitigations + evidence + verification.
|
|
iaceRoutes.GET("/projects/:id/mitigations", h.ListProjectMitigations)
|
|
iaceRoutes.POST("/projects/:id/hazards/:hid/mitigations", h.CreateMitigation)
|
|
iaceRoutes.DELETE("/projects/:id/mitigations/:mid", h.DeleteMitigation)
|
|
iaceRoutes.PUT("/mitigations/:mid", h.UpdateMitigation)
|
|
iaceRoutes.POST("/mitigations/:mid/verify", h.VerifyMitigation)
|
|
iaceRoutes.POST("/projects/:id/validate-mitigation-hierarchy", h.ValidateMitigationHierarchy)
|
|
iaceRoutes.POST("/projects/:id/evidence", h.UploadEvidence)
|
|
iaceRoutes.GET("/projects/:id/evidence", h.ListEvidence)
|
|
iaceRoutes.POST("/projects/:id/verification-plan", h.CreateVerificationPlan)
|
|
iaceRoutes.PUT("/verification-plan/:vid", h.UpdateVerificationPlan)
|
|
iaceRoutes.POST("/verification-plan/:vid/complete", h.CompleteVerification)
|
|
iaceRoutes.GET("/projects/:id/verifications", h.ListVerificationPlans)
|
|
iaceRoutes.POST("/projects/:id/verifications", h.CreateVerificationAlias)
|
|
iaceRoutes.DELETE("/projects/:id/verifications/:vid", h.DeleteVerificationPlan)
|
|
iaceRoutes.POST("/projects/:id/verifications/:vid/complete", h.CompleteVerificationAlias)
|
|
|
|
// Tech file + monitoring + audit.
|
|
iaceRoutes.POST("/projects/:id/tech-file/generate", h.GenerateTechFile)
|
|
iaceRoutes.GET("/projects/:id/tech-file", h.ListTechFileSections)
|
|
iaceRoutes.PUT("/projects/:id/tech-file/:section", h.UpdateTechFileSection)
|
|
iaceRoutes.POST("/projects/:id/tech-file/:section/approve", h.ApproveTechFileSection)
|
|
iaceRoutes.POST("/projects/:id/tech-file/:section/generate", h.GenerateSingleSection)
|
|
iaceRoutes.GET("/projects/:id/tech-file/export", h.ExportTechFile)
|
|
iaceRoutes.POST("/projects/:id/monitoring", h.CreateMonitoringEvent)
|
|
iaceRoutes.GET("/projects/:id/monitoring", h.ListMonitoringEvents)
|
|
iaceRoutes.PUT("/projects/:id/monitoring/:eid", h.UpdateMonitoringEvent)
|
|
iaceRoutes.GET("/projects/:id/audit-trail", h.GetAuditTrail)
|
|
|
|
// Library + corpus + benchmark.
|
|
iaceRoutes.POST("/library-search", h.SearchLibrary)
|
|
iaceRoutes.GET("/ce-corpus-documents", h.ListCECorpusDocuments)
|
|
iaceRoutes.POST("/projects/:id/initialize", h.InitializeProject)
|
|
iaceRoutes.GET("/projects/:id/hazard-blocks", h.GetHazardBlocks)
|
|
iaceRoutes.POST("/projects/:id/benchmark/import-gt", h.ImportGroundTruth)
|
|
iaceRoutes.GET("/projects/:id/benchmark", h.RunBenchmark)
|
|
iaceRoutes.GET("/projects/:id/benchmark/summary", h.GetBenchmarkSummary)
|
|
|
|
// Regulatory enrichment.
|
|
iaceRoutes.GET("/projects/:id/hazards/:hid/regulatory-hints", h.EnrichHazardWithRegulations)
|
|
iaceRoutes.GET("/projects/:id/mitigations/:mid/regulatory-hints", h.EnrichMitigationWithRegulations)
|
|
iaceRoutes.GET("/projects/:id/regulatory-hints", h.EnrichProjectHazardsBatch)
|
|
iaceRoutes.POST("/projects/:id/tech-file/:section/enrich", h.EnrichTechFileSection)
|
|
|
|
// Production lines.
|
|
iaceRoutes.POST("/production-lines", h.CreateProductionLine)
|
|
iaceRoutes.GET("/production-lines", h.ListProductionLines)
|
|
iaceRoutes.GET("/production-lines/:lid/dashboard", h.GetProductionLineDashboard)
|
|
iaceRoutes.POST("/production-lines/:lid/stations", h.AddStationToLine)
|
|
iaceRoutes.DELETE("/production-lines/:lid/stations/:sid", h.RemoveStationFromLine)
|
|
|
|
// CE x Compliance crossover + clarifications + customer standards.
|
|
iaceRoutes.GET("/projects/:id/compliance-triggers", h.GetComplianceTriggers)
|
|
iaceRoutes.GET("/compliance-faq", h.GetComplianceFAQ)
|
|
iaceRoutes.GET("/projects/:id/clarifications", h.ListClarifications)
|
|
iaceRoutes.GET("/projects/:id/clarifications.csv", h.ExportClarificationsCSV)
|
|
iaceRoutes.GET("/projects/:id/clarifications.html", h.ExportClarificationsHTML)
|
|
iaceRoutes.GET("/projects/:id/clarifications/:cid/detail", h.ListClarificationDetail)
|
|
iaceRoutes.POST("/projects/:id/clarifications/:cid/answer", h.AnswerClarification)
|
|
iaceRoutes.POST("/projects/:id/clarifications/:cid/comment", h.PostClarificationComment)
|
|
iaceRoutes.GET("/projects/:id/customer-standards", h.ListCustomerStandardSuggestions)
|
|
iaceRoutes.POST("/projects/:id/customer-standards/import", h.ImportCustomerStandardSuggestion)
|
|
}
|
|
}
|