Files
Benjamin Sutter d15a13e485 feat: remove Administration workspace — keep only Verwaltung + Suche
- Delete all ops page components (ReviewQueue, AIMonitoring, Governance,
  SourceMonitoring, ActivityTimeline, SignalPipeline)
- Remove OPERATIONS workspace from AppShell config, nav order, path detection
- Remove all /ops/* routes from App.tsx
- Remove WorkspaceType.OPERATIONS from allowedWorkspaces in authService,
  sessionStore, permissions
- Keep MarketIntelligence page (already moved to /supply/market-intelligence)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:32:41 +02:00

96 lines
4.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { MockupMatchProvider } from '../provider/MockupMatchProvider'
import { MockupPropertyProvider } from '../provider/MockupPropertyProvider'
import { MockupNeedProvider } from '../provider/MockupNeedProvider'
import type { MatchFilters } from '../provider/IMatchProvider'
import type { Match } from '../domain/match'
import type { Need } from '../domain/need'
import type { Property } from '../domain/property'
import type { StrongMatchItem } from '../domain/dashboard'
import type { ScoreBreakdown } from '../domain/match'
import type { ListResponse, ItemResponse } from './types'
import { buildFullMatch, computeRankedMatches } from '../features/matching/rankingEngine'
const provider = MockupMatchProvider
export const matchService = {
async getAll(filters?: MatchFilters): Promise<ListResponse<Match>> {
const data = await provider.getAll(filters)
return { data, meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
},
async getById(id: string): Promise<ItemResponse<Match | null>> {
const data = await provider.getById(id)
return { data }
},
async getByNeed(needId: string): Promise<ListResponse<Match>> {
const data = await provider.getByNeed(needId)
return { data, meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
},
async getByProperty(propertyId: string): Promise<ListResponse<Match>> {
const data = await provider.getByProperty(propertyId)
return { data, meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
},
async approve(id: string, reviewedBy: string): Promise<ItemResponse<Match>> {
const data = await provider.approve(id, reviewedBy)
return { data }
},
async getMatchesForProperty(propertyId: string): Promise<ListResponse<Match>> {
const data = await provider.getByProperty(propertyId)
return { data, meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
},
async getMatchDetail(id: string): Promise<ItemResponse<Match | null>> {
const data = await provider.getById(id)
return { data }
},
async getScoreBreakdown(matchId: string): Promise<ItemResponse<ScoreBreakdown | null>> {
const match = await provider.getById(matchId)
return { data: match?.scoreBreakdown ?? null }
},
// ── Engine-based methods ──────────────────────────────────────────────────
computeMatch(need: Need, property: Property): Match {
return buildFullMatch(need, property)
},
async computeMatchesForNeed(needId: string): Promise<ListResponse<Match>> {
const [need, properties] = await Promise.all([
MockupNeedProvider.getById(needId),
MockupPropertyProvider.getAll(),
])
if (!need) return { data: [], meta: { total: 0, page: 1, pageSize: 0, hasMore: false } }
const data = computeRankedMatches(need, properties)
return { data, meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
},
async getStrongMatches(minScore = 80): Promise<StrongMatchItem[]> {
const [matches, properties] = await Promise.all([
provider.getAll(),
MockupPropertyProvider.getAll(),
])
return matches
.filter(m => m.matchScore >= minScore)
.slice(0, 5)
.map(m => {
const prop = properties.find(p => p.id === m.propertyId)
const topFactor = m.positiveFactors?.[0]
const firstAction = m.nextBestActions?.[0]
return {
matchId: m.id,
propertyId: m.propertyId,
propertyTitle: prop?.title ?? 'Unbekanntes Objekt',
propertyAddress: prop?.address
? `${prop.address.street} ${prop.address.houseNumber}, ${prop.address.city}`
: '',
needSummary: m.needId,
matchScore: m.matchScore,
topReason: topFactor?.explanation ?? topFactor?.criterion ?? '',
missingDataCount: m.missingData?.length ?? 0,
nextBestAction: firstAction?.label ?? '',
} satisfies StrongMatchItem
})
},
}