← back to Omega Watches 2
src/types/index.ts
298 lines
// ============================================================================
// OMEGA WATCHES 2.0 — ENTERPRISE TYPE DEFINITIONS
// Dual-Ledger: MSRP Snapshots + Secondary Market Events
// ============================================================================
// --- Watch Reference (Master Entity) ---
export interface WatchReference {
id: string;
brand: string;
collection: string;
model_name: string;
reference_number: string;
calibre: string | null;
case_material: string | null;
case_diameter_mm: number | null;
dial_color: string | null;
year_introduced: number | null;
year_discontinued: number | null;
is_limited_edition: boolean;
limited_edition_count: number | null;
notes: string | null;
created_at: string;
updated_at: string;
}
// --- MSRP Snapshot (Ledger 1: Primary Market) ---
export interface MSRPSnapshot {
msrp_id: string;
reference_id: string;
region_code: string;
currency: string;
msrp_amount: number;
captured_date: string;
source_url: string;
page_hash: string | null;
parser_version: string;
created_at: string;
}
export interface MSRPChangeEvent {
id: string;
reference_id: string;
region_code: string;
change_date: string;
old_price: number;
new_price: number;
currency: string;
pct_change: number;
}
// --- Market Event (Ledger 2: Secondary Market) ---
export type EventType =
| "auction_realized"
| "marketplace_sold"
| "dealer_sold"
| "dealer_ask"
| "forum_listing"
| "price_guide";
export type SellerType =
| "auction_house"
| "dealer"
| "private"
| "marketplace"
| "unknown";
export type FeeSemantics =
| "hammer_only"
| "price_realised"
| "total_to_buyer"
| "unknown";
export type ConditionGrade =
| "new_unworn"
| "excellent"
| "very_good"
| "good"
| "fair"
| "poor"
| "parts_only"
| "unknown";
export interface MarketEvent {
event_id: string;
source_name: string;
source_listing_id: string;
event_type: EventType;
reference_id: string | null;
reference_number_raw: string | null;
serial_number: string | null;
year_text: string | null;
case_material: string | null;
movement: string | null;
condition_raw: string | null;
condition_normalized: ConditionGrade;
provenance_raw: string | null;
sale_date: string | null;
location_text: string | null;
seller_type: SellerType;
// Price fields (dual-ledger fee semantics)
price_amount: number | null;
currency: string;
hammer_price: number | null;
buyers_premium: number | null;
total_to_buyer: number | null;
fee_semantics: FeeSemantics;
// FX normalization
price_usd: number | null;
fx_rate: number | null;
fx_source: string | null;
// Inflation adjustment
price_usd_real: number | null;
cpi_base_year: number | null;
// Metadata
images_json: string[] | null;
source_url: string;
scraped_at: string;
page_hash: string | null;
parser_version: string;
// Quality
quality_score: number | null;
is_quarantined: boolean;
quarantine_reason: string | null;
created_at: string;
}
// --- Data Source ---
export type SourceAccessMethod = "api" | "scrape" | "manual" | "export";
export interface DataSource {
id: string;
name: string;
display_name: string;
source_type: string;
access_method: SourceAccessMethod;
base_url: string | null;
robots_txt_compliant: boolean;
tos_reviewed: boolean;
tos_allows_collection: boolean | null;
reliability_score: number;
coverage_years_from: number | null;
coverage_years_to: number | null;
notes: string | null;
is_active: boolean;
created_at: string;
updated_at: string;
}
// --- Collector Run ---
export type JobStatus =
| "pending"
| "running"
| "completed"
| "failed"
| "cancelled";
export interface CollectorRun {
run_id: string;
source_id: string;
job_type: string;
status: JobStatus;
started_at: string | null;
completed_at: string | null;
records_fetched: number;
records_parsed: number;
records_inserted: number;
records_updated: number;
records_quarantined: number;
records_deduplicated: number;
error_message: string | null;
parser_version: string;
metadata: Record<string, any> | null;
created_at: string;
}
// --- Parser Version ---
export interface ParserVersion {
id: string;
source_id: string;
version: string;
selectors_json: Record<string, any>;
dom_hash: string | null;
is_current: boolean;
tested_at: string | null;
test_pass_rate: number | null;
notes: string | null;
created_at: string;
}
// --- Quarantine Record ---
export interface QuarantineRecord {
id: string;
event_id: string | null;
msrp_id: string | null;
reason: string;
severity: "low" | "medium" | "high" | "critical";
details: Record<string, any> | null;
resolved: boolean;
resolved_by: string | null;
resolved_at: string | null;
resolution_notes: string | null;
created_at: string;
}
// --- Condition Mapping ---
export interface ConditionMapping {
id: string;
source_name: string;
source_category: string;
normalized_grade: ConditionGrade;
score_0_100: number;
version: number;
created_at: string;
}
// --- FX Rate ---
export interface FXRate {
id: string;
currency_from: string;
currency_to: string;
rate: number;
rate_date: string;
source: string;
created_at: string;
}
// --- Audit Log ---
export interface AuditLogEntry {
id: string;
table_name: string;
record_id: string;
operation: "INSERT" | "UPDATE" | "DELETE";
old_values: Record<string, any> | null;
new_values: Record<string, any> | null;
changed_by: string;
ip_address: string | null;
changed_at: string;
}
// --- API Response Wrappers ---
export interface ApiResponse<T> {
success: boolean;
data: T;
meta?: {
total?: number;
page?: number;
per_page?: number;
timestamp: string;
};
}
export interface ApiError {
success: false;
error: {
code: string;
message: string;
details?: any;
};
}
// --- Dashboard / Control Plane ---
export interface SystemHealth {
database: { ok: boolean; latency: number };
collectors: {
active: number;
failed_24h: number;
last_run: string | null;
};
msrp: {
snapshots_today: number;
sources_reporting: number;
last_capture: string | null;
};
market_events: {
total: number;
quarantined: number;
last_ingested: string | null;
};
uptime: number;
version: string;
}
export interface TimeSeriesPoint {
date: string;
value: number;
source?: string;
event_type?: EventType;
condition?: ConditionGrade;
fee_semantics?: FeeSemantics;
}
export interface PriceDistribution {
bucket_low: number;
bucket_high: number;
count: number;
avg_condition_score: number;
}