feat(domain): F004 – expand domain model layer

- need.ts: add SizeRange, MustHaveCriterion, WeightedPreference types; extend Need with desiredLocation, sizeRange, mustHaveCriteria, weightedPreferences, status
- futureSignal.ts: add SignalEvidence type; extend FutureSignal with title, evidence, matchabilityScore, reviewStatus
- aiOutput.ts: new AIOutput entity with type, inputHash, outputJson, provider/model/promptVersion/schemaVersion, reviewStatus
- activityEvent.ts: new ActivityEvent entity with actorId, action, entityType, entityId, timestamp, metadata
- unifiedResult.ts: discriminated union (VerifiedPortfolioResult | ExternalMarketResult | FutureAvailabilityResult)
- index.ts: export all three new files
- Properties.tsx: add LIGHT_INDUSTRIAL + UNKNOWN cases to exhaustive switches

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-15 10:58:27 +02:00
parent 3b45b0c121
commit 0b874865ba
10 changed files with 399 additions and 40 deletions
+101 -6
View File
@@ -1,13 +1,17 @@
// ── Asset Types ───────────────────────────────────────────────────────────────
export const AssetType = {
OFFICE: 'OFFICE',
RETAIL: 'RETAIL',
GASTRO: 'GASTRO',
GASTRO: 'GASTRO', // legacy kept for mock-data compatibility
LIGHT_INDUSTRIAL: 'LIGHT_INDUSTRIAL',
LOGISTICS: 'LOGISTICS',
PRODUCTION: 'PRODUCTION',
MIXED: 'MIXED',
UNKNOWN: 'UNKNOWN',
} as const
export type AssetType = typeof AssetType[keyof typeof AssetType]
// ── Result Types ──────────────────────────────────────────────────────────────
export const ResultType = {
VERIFIED_PORTFOLIO: 'VERIFIED_PORTFOLIO',
EXTERNAL_MARKET: 'EXTERNAL_MARKET',
@@ -15,6 +19,7 @@ export const ResultType = {
} as const
export type ResultType = typeof ResultType[keyof typeof ResultType]
// ── Match Strength ─────────────────────────────────────────────────────────────
export const MatchStrength = {
STRONG: 'STRONG',
MODERATE: 'MODERATE',
@@ -22,6 +27,17 @@ export const MatchStrength = {
} as const
export type MatchStrength = typeof MatchStrength[keyof typeof MatchStrength]
// ── Match Status ──────────────────────────────────────────────────────────────
export const MatchStatus = {
PENDING_REVIEW: 'PENDING_REVIEW',
APPROVED: 'APPROVED',
REJECTED: 'REJECTED',
SHORTLISTED: 'SHORTLISTED',
ARCHIVED: 'ARCHIVED',
} as const
export type MatchStatus = typeof MatchStatus[keyof typeof MatchStatus]
// ── Risk Level ────────────────────────────────────────────────────────────────
export const RiskLevel = {
LOW: 'LOW',
MEDIUM: 'MEDIUM',
@@ -30,6 +46,26 @@ export const RiskLevel = {
} as const
export type RiskLevel = typeof RiskLevel[keyof typeof RiskLevel]
// ── Confidence Level (qualitative) ───────────────────────────────────────────
export const ConfidenceLevel = {
VERY_HIGH: 'VERY_HIGH', // >= 0.90
HIGH: 'HIGH', // >= 0.75
MEDIUM: 'MEDIUM', // >= 0.55
LOW: 'LOW', // >= 0.35
VERY_LOW: 'VERY_LOW', // < 0.35
} as const
export type ConfidenceLevel = typeof ConfidenceLevel[keyof typeof ConfidenceLevel]
// ── Data Quality Level (qualitative) ─────────────────────────────────────────
export const DataQualityLevel = {
HIGH: 'HIGH', // >= 0.80
MEDIUM: 'MEDIUM', // >= 0.60
LOW: 'LOW', // < 0.60
INCOMPLETE: 'INCOMPLETE', // missing critical fields
} as const
export type DataQualityLevel = typeof DataQualityLevel[keyof typeof DataQualityLevel]
// ── Availability Status ───────────────────────────────────────────────────────
export const AvailabilityStatus = {
AVAILABLE_NOW: 'AVAILABLE_NOW',
AVAILABLE_SOON: 'AVAILABLE_SOON',
@@ -39,13 +75,70 @@ export const AvailabilityStatus = {
} as const
export type AvailabilityStatus = typeof AvailabilityStatus[keyof typeof AvailabilityStatus]
export const DataFreshness = {
FRESH: 'FRESH',
STALE: 'STALE',
OUTDATED: 'OUTDATED',
// ── Availability Type (structural distinction) ────────────────────────────────
export const AvailabilityType = {
CONFIRMED: 'CONFIRMED', // verified, date known
INDICATIVE: 'INDICATIVE', // external listing, unconfirmed
PROBABILISTIC: 'PROBABILISTIC', // AI signal, no confirmed date
} as const
export type DataFreshness = typeof DataFreshness[keyof typeof DataFreshness]
export type AvailabilityType = typeof AvailabilityType[keyof typeof AvailabilityType]
// ── Source Type ───────────────────────────────────────────────────────────────
export const SourceType = {
ERP_IMPORT: 'ERP_IMPORT',
MANUAL_ENTRY: 'MANUAL_ENTRY',
IMMOSCOUT_SCRAPE: 'IMMOSCOUT_SCRAPE',
HOMEGATE_SCRAPE: 'HOMEGATE_SCRAPE',
NEWHOME_SCRAPE: 'NEWHOME_SCRAPE',
MATCHOFFICE_SCRAPE: 'MATCHOFFICE_SCRAPE',
MAISON_WORK_SCRAPE: 'MAISON_WORK_SCRAPE',
AI_SIGNAL: 'AI_SIGNAL',
PARTNER_FEED: 'PARTNER_FEED',
UNKNOWN: 'UNKNOWN',
} as const
export type SourceType = typeof SourceType[keyof typeof SourceType]
// ── Freshness Status ──────────────────────────────────────────────────────────
export const FreshnessStatus = {
FRESH: 'FRESH', // updated within 48h
STALE: 'STALE', // 214 days old
OUTDATED: 'OUTDATED', // > 14 days old
} as const
export type FreshnessStatus = typeof FreshnessStatus[keyof typeof FreshnessStatus]
/** @deprecated Use FreshnessStatus — kept for mock-data backward compatibility */
export const DataFreshness = FreshnessStatus
export type DataFreshness = FreshnessStatus
// ── Review Status ─────────────────────────────────────────────────────────────
export const ReviewStatus = {
UNREVIEWED: 'UNREVIEWED',
IN_REVIEW: 'IN_REVIEW',
APPROVED: 'APPROVED',
REJECTED: 'REJECTED',
FLAGGED: 'FLAGGED',
} as const
export type ReviewStatus = typeof ReviewStatus[keyof typeof ReviewStatus]
// ── Sensitivity Level ─────────────────────────────────────────────────────────
export const SensitivityLevel = {
PUBLIC: 'PUBLIC',
INTERNAL: 'INTERNAL',
CONFIDENTIAL: 'CONFIDENTIAL',
RESTRICTED: 'RESTRICTED',
} as const
export type SensitivityLevel = typeof SensitivityLevel[keyof typeof SensitivityLevel]
// ── Shortlist Status ──────────────────────────────────────────────────────────
export const ShortlistStatus = {
ACTIVE: 'ACTIVE',
SHARED: 'SHARED',
ARCHIVED: 'ARCHIVED',
CONVERTED: 'CONVERTED',
} as const
export type ShortlistStatus = typeof ShortlistStatus[keyof typeof ShortlistStatus]
// ── User Role ─────────────────────────────────────────────────────────────────
export const UserRole = {
SUPER_ADMIN: 'SUPER_ADMIN',
ORGANIZATION_ADMIN: 'ORGANIZATION_ADMIN',
@@ -56,6 +149,7 @@ export const UserRole = {
} as const
export type UserRole = typeof UserRole[keyof typeof UserRole]
// ── Signal Type ───────────────────────────────────────────────────────────────
export const SignalType = {
EXPANSION: 'EXPANSION',
POSSIBLE_MOVE_OUT: 'POSSIBLE_MOVE_OUT',
@@ -66,6 +160,7 @@ export const SignalType = {
} as const
export type SignalType = typeof SignalType[keyof typeof SignalType]
// ── Workspace ─────────────────────────────────────────────────────────────────
export const WorkspaceType = {
SUPPLY: 'SUPPLY',
DEMAND: 'DEMAND',