feat: add verification method, categories, and dedup UI to control library
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 44s
CI/CD / test-python-backend-compliance (push) Successful in 40s
CI/CD / test-python-document-crawler (push) Successful in 22s
CI/CD / test-python-dsms-gateway (push) Successful in 17s
CI/CD / validate-canonical-controls (push) Successful in 10s
CI/CD / Deploy (push) Successful in 4s

- Migration 047: verification_method + category columns, 17 category lookup table
- Backend: new filters, GET /categories, GET /controls/{id}/similar (embedding-based)
- Frontend: filter dropdowns, badges, dedup UI in ControlDetail with merge workflow
- ControlForm: verification method + category selects
- Provenance: verification methods, categories, master library strategy sections
- Fix UUID cast syntax in generator routes (::uuid -> CAST)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-14 07:55:22 +01:00
parent 8a05fcc2f0
commit b6e6ffaaee
10 changed files with 577 additions and 44 deletions

View File

@@ -27,9 +27,13 @@ export async function GET(request: NextRequest) {
case 'controls': {
const severity = searchParams.get('severity')
const domain = searchParams.get('domain')
const verificationMethod = searchParams.get('verification_method')
const categoryFilter = searchParams.get('category')
const params = new URLSearchParams()
if (severity) params.set('severity', severity)
if (domain) params.set('domain', domain)
if (verificationMethod) params.set('verification_method', verificationMethod)
if (categoryFilter) params.set('category', categoryFilter)
const qs = params.toString()
backendPath = `/api/compliance/v1/canonical/controls${qs ? `?${qs}` : ''}`
break
@@ -76,6 +80,20 @@ export async function GET(request: NextRequest) {
backendPath = '/api/compliance/v1/canonical/generate/processed-stats'
break
case 'categories':
backendPath = '/api/compliance/v1/canonical/categories'
break
case 'similar': {
const simControlId = searchParams.get('id')
if (!simControlId) {
return NextResponse.json({ error: 'Missing control id' }, { status: 400 })
}
const simThreshold = searchParams.get('threshold') || '0.85'
backendPath = `/api/compliance/v1/canonical/controls/${encodeURIComponent(simControlId)}/similar?threshold=${simThreshold}`
break
}
case 'blocked-sources':
backendPath = '/api/compliance/v1/canonical/blocked-sources'
break