Files
Neon-Desk/lib/types.ts

955 lines
22 KiB
TypeScript

export type User = {
id: string;
email: string;
name: string | null;
image: string | null;
};
export type CoverageStatus = "backlog" | "active" | "watch" | "archive";
export type CoveragePriority = "low" | "medium" | "high";
export type ResearchJournalEntryType = "note" | "filing_note" | "status_change";
export type NumberScaleUnit = "thousands" | "millions" | "billions";
export type ResearchArtifactKind =
| "filing"
| "ai_report"
| "note"
| "upload"
| "memo_snapshot"
| "status_change";
export type ResearchArtifactSource = "system" | "user";
export type ResearchVisibilityScope = "private" | "organization";
export type ResearchMemoRating = "strong_buy" | "buy" | "hold" | "sell";
export type ResearchMemoConviction = "low" | "medium" | "high";
export type ResearchMemoSection =
| "thesis"
| "variant_view"
| "catalysts"
| "risks"
| "disconfirming_evidence"
| "next_actions";
export type WatchlistItem = {
id: number;
user_id: string;
ticker: string;
company_name: string;
sector: string | null;
category: string | null;
tags: string[];
created_at: string;
status: CoverageStatus;
priority: CoveragePriority;
updated_at: string;
last_reviewed_at: string | null;
latest_filing_date: string | null;
};
export type Holding = {
id: number;
user_id: string;
ticker: string;
company_name: string | null;
shares: string;
avg_cost: string;
current_price: string | null;
market_value: string;
gain_loss: string;
gain_loss_pct: string;
last_price_at: string | null;
created_at: string;
updated_at: string;
};
export type PortfolioSummary = {
positions: number;
total_value: string;
total_gain_loss: string;
total_cost_basis: string;
avg_return_pct: string;
};
export type FilingExtraction = {
summary: string;
keyPoints: string[];
redFlags: string[];
followUpQuestions: string[];
portfolioSignals: string[];
segmentSpecificData: string[];
geographicRevenueBreakdown: string[];
companySpecificData: string[];
secApiCrossChecks: string[];
confidence: number;
};
export type FilingExtractionMeta = {
provider: string;
model: string;
source: "primary_document" | "metadata_fallback";
generatedAt: string;
};
export type Filing = {
id: number;
ticker: string;
filing_type: "10-K" | "10-Q" | "8-K";
filing_date: string;
accession_number: string;
cik: string;
company_name: string;
filing_url: string | null;
submission_url?: string | null;
primary_document?: string | null;
metrics: {
revenue: number | null;
netIncome: number | null;
totalAssets: number | null;
cash: number | null;
debt: number | null;
} | null;
analysis: {
provider?: string;
model?: string;
text?: string;
legacyInsights?: string;
companyMetrics?: string[];
extraction?: FilingExtraction;
extractionMeta?: FilingExtractionMeta;
} | null;
created_at: string;
updated_at: string;
};
export type TaskStatus = "queued" | "running" | "completed" | "failed";
export type TaskType =
| "sync_filings"
| "refresh_prices"
| "analyze_filing"
| "portfolio_insights"
| "index_search";
export type TickerAutomationSource =
| "analysis"
| "financials"
| "search"
| "graphing"
| "research";
export type TaskStage =
| "queued"
| "running"
| "completed"
| "failed"
| "sync.fetch_filings"
| "sync.discover_assets"
| "sync.extract_taxonomy"
| "sync.normalize_taxonomy"
| "sync.derive_metrics"
| "sync.validate_pdf_metrics"
| "sync.persist_taxonomy"
| "sync.fetch_metrics"
| "sync.persist_filings"
| "sync.hydrate_statements"
| "refresh.load_holdings"
| "refresh.fetch_quotes"
| "refresh.persist_prices"
| "analyze.load_filing"
| "analyze.fetch_document"
| "analyze.extract"
| "analyze.generate_report"
| "analyze.persist_report"
| "search.collect_sources"
| "search.fetch_documents"
| "search.chunk"
| "search.embed"
| "search.persist"
| "insights.load_holdings"
| "insights.generate"
| "insights.persist";
export type TaskStageContext = {
progress?: {
current: number;
total: number;
unit: string;
} | null;
counters?: Record<string, number>;
subject?: {
ticker?: string;
accessionNumber?: string;
label?: string;
} | null;
};
export type TaskNotificationStat = {
label: string;
value: string;
};
export type TaskNotificationAction = {
id:
| "open_details"
| "open_filings"
| "open_analysis"
| "open_analysis_report"
| "open_search"
| "open_portfolio";
label: string;
href: string | null;
primary?: boolean;
};
export type TaskNotificationView = {
title: string;
statusLine: string;
detailLine: string | null;
tone: "info" | "success" | "error";
progress: {
current: number;
total: number;
unit: string;
percent: number | null;
} | null;
stats: TaskNotificationStat[];
actions: TaskNotificationAction[];
};
export type TaskNotificationEntry = {
id: string;
kind: "single" | "filing_sync_batch";
status: TaskStatus;
title: string;
statusLine: string;
detailLine: string | null;
progress: TaskNotificationView["progress"];
stats: TaskNotificationStat[];
updatedAt: string;
primaryTaskId: string;
taskIds: string[];
actions: TaskNotificationAction[];
notificationReadAt: string | null;
notificationSilencedAt: string | null;
meta?: {
tickerCount: number;
runningCount: number;
queuedCount: number;
failureCount: number;
};
};
export type Task = {
id: string;
user_id: string;
task_type: TaskType;
status: TaskStatus;
stage: TaskStage;
stage_detail: string | null;
stage_context: TaskStageContext | null;
resource_key: string | null;
notification_read_at: string | null;
notification_silenced_at: string | null;
priority: number;
payload: Record<string, unknown>;
result: Record<string, unknown> | null;
error: string | null;
attempts: number;
max_attempts: number;
workflow_run_id?: string | null;
created_at: string;
updated_at: string;
finished_at: string | null;
notification: TaskNotificationView;
};
export type TaskStageEvent = {
id: number;
task_id: string;
user_id: string;
stage: TaskStage;
stage_detail: string | null;
stage_context: TaskStageContext | null;
status: TaskStatus;
created_at: string;
};
export type TaskTimeline = {
task: Task;
events: TaskStageEvent[];
};
export type PortfolioInsight = {
id: number;
user_id: string;
provider: string;
model: string;
content: string;
created_at: string;
};
export type ResearchJournalEntry = {
id: number;
user_id: string;
ticker: string;
accession_number: string | null;
entry_type: ResearchJournalEntryType;
title: string | null;
body_markdown: string;
metadata: Record<string, unknown> | null;
created_at: string;
updated_at: string;
};
export type SearchSource = "documents" | "filings" | "research";
export type SearchResult = {
chunkId: number;
documentId: number;
source: SearchSource;
sourceKind: "filing_document" | "filing_brief" | "research_note";
sourceRef: string;
title: string | null;
ticker: string | null;
accessionNumber: string | null;
filingDate: string | null;
citationLabel: string;
headingPath: string | null;
chunkText: string;
snippet: string;
score: number;
vectorRank: number | null;
lexicalRank: number | null;
href: string;
};
export type SearchCitation = {
index: number;
label: string;
chunkId: number;
href: string;
};
export type SearchAnswerResponse = {
answer: string;
citations: SearchCitation[];
results: SearchResult[];
};
export type ResearchArtifact = {
id: number;
user_id: string;
organization_id: string | null;
ticker: string;
accession_number: string | null;
kind: ResearchArtifactKind;
source: ResearchArtifactSource;
subtype: string | null;
title: string | null;
summary: string | null;
body_markdown: string | null;
search_text: string | null;
visibility_scope: ResearchVisibilityScope;
tags: string[];
metadata: Record<string, unknown> | null;
file_name: string | null;
mime_type: string | null;
file_size_bytes: number | null;
storage_path: string | null;
created_at: string;
updated_at: string;
linked_to_memo: boolean;
};
export type ResearchMemo = {
id: number;
user_id: string;
organization_id: string | null;
ticker: string;
rating: ResearchMemoRating | null;
conviction: ResearchMemoConviction | null;
time_horizon_months: number | null;
packet_title: string | null;
packet_subtitle: string | null;
thesis_markdown: string;
variant_view_markdown: string;
catalysts_markdown: string;
risks_markdown: string;
disconfirming_evidence_markdown: string;
next_actions_markdown: string;
created_at: string;
updated_at: string;
};
export type ResearchMemoEvidenceLink = {
id: number;
memo_id: number;
artifact_id: number;
section: ResearchMemoSection;
annotation: string | null;
sort_order: number;
created_at: string;
artifact: ResearchArtifact;
};
export type ResearchPacketSection = {
section: ResearchMemoSection;
title: string;
body_markdown: string;
evidence: ResearchMemoEvidenceLink[];
};
export type ResearchPacket = {
ticker: string;
companyName: string | null;
generated_at: string;
memo: ResearchMemo | null;
sections: ResearchPacketSection[];
};
export type ResearchLibraryResponse = {
artifacts: ResearchArtifact[];
availableTags: string[];
};
export type ResearchWorkspace = {
ticker: string;
companyName: string | null;
coverage: WatchlistItem | null;
latestFilingDate: string | null;
memo: ResearchMemo | null;
library: ResearchArtifact[];
packet: ResearchPacket;
availableTags: string[];
};
export type CompanyFinancialPoint = {
filingDate: string;
filingType: Filing["filing_type"];
revenue: number | null;
netIncome: number | null;
totalAssets: number | null;
cash: number | null;
debt: number | null;
};
export type FinancialStatementKind =
| "income"
| "balance"
| "cash_flow"
| "disclosure"
| "equity"
| "comprehensive_income";
type FinancialHistoryWindow = "10y" | "all";
export type FinancialCadence = "annual" | "quarterly" | "ltm";
export type FinancialDisplayMode = "faithful" | "standardized";
export type FinancialSurfaceKind =
| "income_statement"
| "balance_sheet"
| "cash_flow_statement"
| "equity_statement"
| "disclosures"
| "ratios"
| "segments_kpis"
| "adjusted"
| "custom_metrics";
export type FinancialUnit =
| "currency"
| "count"
| "shares"
| "percent"
| "ratio";
export type FinancialCategory = string;
export type FinancialStatementPeriod = {
id: string;
filingId: number;
accessionNumber: string;
filingDate: string;
periodStart: string | null;
periodEnd: string | null;
filingType: Extract<Filing["filing_type"], "10-K" | "10-Q">;
periodLabel: string;
};
export type TaxonomyDimensionMember = {
axis: string;
member: string;
};
export type TaxonomyStatementRow = {
key: string;
label: string;
conceptKey: string;
qname: string;
namespaceUri: string;
localName: string;
isExtension: boolean;
statement: FinancialStatementKind;
roleUri: string | null;
order: number;
depth: number;
parentKey: string | null;
values: Record<string, number | null>;
units: Record<string, string | null>;
hasDimensions: boolean;
sourceFactIds: number[];
};
type FinancialStatementSurfaceKind = FinancialDisplayMode;
export type DerivedFinancialRow = {
key: string;
label: string;
category: FinancialCategory;
templateSection?: FinancialCategory;
order: number;
unit: FinancialUnit;
values: Record<string, number | null>;
sourceConcepts: string[];
sourceRowKeys: string[];
sourceFactIds: number[];
formulaKey: string | null;
hasDimensions: boolean;
resolvedSourceRowKeys: Record<string, string | null>;
};
export type StandardizedFinancialRow = DerivedFinancialRow;
type StandardizedStatementRow = StandardizedFinancialRow;
export type SurfaceFinancialRow = StandardizedFinancialRow & {
statement?: Extract<
FinancialStatementKind,
"income" | "balance" | "cash_flow" | "equity" | "disclosure"
>;
detailCount?: number;
resolutionMethod?:
| "direct"
| "surface_bridge"
| "formula_derived"
| "not_meaningful";
confidence?: "high" | "medium" | "low";
warningCodes?: string[];
};
export type DetailFinancialRow = {
key: string;
parentSurfaceKey: string;
label: string;
conceptKey: string;
qname: string;
namespaceUri: string;
localName: string;
unit: string | null;
values: Record<string, number | null>;
sourceFactIds: number[];
isExtension: boolean;
dimensionsSummary: string[];
residualFlag: boolean;
};
export type SurfaceDetailMap = Record<string, DetailFinancialRow[]>;
export type NormalizationSummary = {
surfaceRowCount: number;
detailRowCount: number;
kpiRowCount: number;
unmappedRowCount: number;
materialUnmappedRowCount: number;
residualPrimaryCount: number;
residualDisclosureCount: number;
unsupportedConceptCount: number;
issuerOverlayMatchCount: number;
warnings: string[];
};
export type NormalizationMetadata = {
parserEngine: string;
regime: "us-gaap" | "ifrs-full" | "unknown";
fiscalPack: string | null;
parserVersion: string;
surfaceRowCount: number;
detailRowCount: number;
kpiRowCount: number;
unmappedRowCount: number;
materialUnmappedRowCount: number;
residualPrimaryCount: number;
residualDisclosureCount: number;
unsupportedConceptCount: number;
issuerOverlayMatchCount: number;
warnings: string[];
};
export type RatioRow = DerivedFinancialRow & {
denominatorKey: string | null;
};
export type StructuredKpiRow = {
key: string;
label: string;
category: FinancialCategory;
unit: FinancialUnit;
order: number;
segment: string | null;
axis: string | null;
member: string | null;
values: Record<string, number | null>;
sourceConcepts: string[];
sourceFactIds: number[];
provenanceType: "taxonomy" | "structured_note";
hasDimensions: boolean;
};
export type TaxonomyFactRow = {
id: number;
snapshotId: number;
filingId: number;
filingDate: string;
statement: FinancialStatementKind | null;
roleUri: string | null;
conceptKey: string;
qname: string;
namespaceUri: string;
localName: string;
value: number;
contextId: string;
unit: string | null;
decimals: string | null;
periodStart: string | null;
periodEnd: string | null;
periodInstant: string | null;
dimensions: TaxonomyDimensionMember[];
isDimensionless: boolean;
sourceFile: string | null;
};
export type MetricValidationCheck = {
metricKey: keyof NonNullable<Filing["metrics"]>;
taxonomyValue: number | null;
llmValue: number | null;
absoluteDiff: number | null;
relativeDiff: number | null;
status: "not_run" | "matched" | "mismatch" | "error";
evidencePages: number[];
pdfUrl: string | null;
provider: string | null;
model: string | null;
error: string | null;
};
export type MetricValidationResult = {
status: "not_run" | "matched" | "mismatch" | "error";
checks: MetricValidationCheck[];
validatedAt: string | null;
};
type FilingFaithfulStatementRow = {
key: string;
label: string;
concept: string | null;
order: number;
depth: number;
isSubtotal: boolean;
values: Record<string, number | null>;
hasDimensions: boolean;
};
export type DimensionBreakdownRow = {
rowKey: string;
concept: string | null;
sourceRowKey: string | null;
sourceLabel: string | null;
periodId: string;
axis: string;
member: string;
value: number | null;
unit: string | null;
provenanceType?: "taxonomy" | "structured_note";
};
export type TrendSeries = {
key: string;
label: string;
category: FinancialCategory;
unit: FinancialUnit;
values: Record<string, number | null>;
};
export type CompanyFinancialStatementsResponse = {
company: {
ticker: string;
companyName: string;
cik: string | null;
};
surfaceKind: FinancialSurfaceKind;
cadence: FinancialCadence;
displayModes: FinancialDisplayMode[];
defaultDisplayMode: FinancialDisplayMode;
periods: FinancialStatementPeriod[];
statementRows: {
faithful: TaxonomyStatementRow[];
standardized: SurfaceFinancialRow[];
} | null;
statementDetails: SurfaceDetailMap | null;
ratioRows: RatioRow[] | null;
kpiRows: StructuredKpiRow[] | null;
trendSeries: TrendSeries[];
categories: Array<{
key: FinancialCategory;
label: string;
count: number;
}>;
availability: {
adjusted: boolean;
customMetrics: boolean;
};
nextCursor: string | null;
facts: {
rows: TaxonomyFactRow[];
nextCursor: string | null;
} | null;
coverage: {
filings: number;
rows: number;
dimensions: number;
facts: number;
};
dataSourceStatus: {
enabled: boolean;
hydratedFilings: number;
partialFilings: number;
failedFilings: number;
pendingFilings: number;
queuedSync: boolean;
};
metrics: {
taxonomy: Filing["metrics"];
validation: MetricValidationResult | null;
};
normalization: NormalizationMetadata;
dimensionBreakdown: Record<string, DimensionBreakdownRow[]> | null;
};
export type CompanyAiReport = {
accessionNumber: string;
filingDate: string;
filingType: Filing["filing_type"];
provider: string;
model: string;
summary: string;
};
export type CompanyAiReportDetail = CompanyAiReport & {
ticker: string;
companyName: string;
filingUrl: string | null;
submissionUrl: string | null;
primaryDocument: string | null;
};
export type CompanyProfile = {
description: string | null;
exchange: string | null;
industry: string | null;
country: string | null;
website: string | null;
fiscalYearEnd: string | null;
employeeCount: number | null;
source: "sec_derived" | "unavailable";
};
export type CompanyValuationSnapshot = {
sharesOutstanding: number | null;
marketCap: number | null;
enterpriseValue: number | null;
trailingPe: number | null;
evToRevenue: number | null;
evToEbitda: number | null;
source: "derived" | "partial" | "unavailable";
};
export type CompanyBullBear = {
source: "ai_synthesized" | "memo_fallback" | "unavailable";
bull: string[];
bear: string[];
updatedAt: string | null;
};
export type RecentDevelopmentKind =
| "8-K"
| "10-K"
| "10-Q"
| "press_release"
| "news";
export type RecentDevelopmentItem = {
id: string;
kind: RecentDevelopmentKind;
title: string;
url: string | null;
source: string;
publishedAt: string;
summary: string | null;
accessionNumber: string | null;
};
export type RecentDevelopmentsWeeklySnapshot = {
summary: string;
highlights: string[];
itemCount: number;
startDate: string;
endDate: string;
updatedAt: string;
source: "ai_synthesized" | "heuristic";
};
export type RecentDevelopments = {
status: "ready" | "partial" | "unavailable";
items: RecentDevelopmentItem[];
weeklySnapshot: RecentDevelopmentsWeeklySnapshot | null;
};
export type PriceData<T> = {
value: T;
stale: boolean;
};
export type CompanyAnalysis = {
company: {
ticker: string;
companyName: string;
sector: string | null;
category: string | null;
tags: string[];
cik: string | null;
};
quote: PriceData<number | null>;
position: Holding | null;
priceHistory: PriceData<Array<{ date: string; close: number }> | null>;
benchmarkHistory: PriceData<Array<{ date: string; close: number }> | null>;
financials: CompanyFinancialPoint[];
filings: Filing[];
aiReports: CompanyAiReport[];
coverage: WatchlistItem | null;
journalPreview: ResearchJournalEntry[];
recentAiReports: CompanyAiReport[];
latestFilingSummary: {
accessionNumber: string;
filingDate: string;
filingType: Filing["filing_type"];
filingUrl: string | null;
submissionUrl: string | null;
summary: string | null;
hasAnalysis: boolean;
} | null;
keyMetrics: {
referenceDate: string | null;
revenue: number | null;
netIncome: number | null;
totalAssets: number | null;
cash: number | null;
debt: number | null;
netMargin: number | null;
};
companyProfile: CompanyProfile;
valuationSnapshot: CompanyValuationSnapshot;
bullBear: CompanyBullBear;
recentDevelopments: RecentDevelopments;
};
export type NavGroup = "overview" | "research" | "portfolio";
export type NavMatchMode = "exact" | "prefix";
export type NavItem = {
id: string;
href: string;
label: string;
group: NavGroup;
matchMode: NavMatchMode;
preserveTicker?: boolean;
mobilePrimary?: boolean;
};
export type ActiveContext = {
pathname: string;
activeTicker: string | null;
};
// Chart Types
export type ChartType = "line" | "combination";
export type TimeRange = "1W" | "1M" | "3M" | "1Y" | "3Y" | "5Y" | "10Y" | "20Y";
// Chart Data Formats
export type PriceDataPoint = {
date: string;
price: number;
};
export type OHLCVDataPoint = {
date: string;
open: number;
high: number;
low: number;
close: number;
volume: number;
};
export type ChartDataPoint = PriceDataPoint | OHLCVDataPoint;
export type DataSeries<T extends ChartDataPoint = ChartDataPoint> = {
id: string;
label: string;
data: T[];
color?: string;
type?: "line" | "area" | "bar";
visible?: boolean;
};
// Chart Configuration
export type ChartZoomState = {
startIndex: number;
endIndex: number;
isZoomed: boolean;
};
export type ChartColorPalette = {
primary: string;
secondary: string;
positive: string;
negative: string;
grid: string;
text: string;
muted: string;
tooltipBg: string;
tooltipBorder: string;
volume: string;
};
export type InteractivePriceChartProps = {
// Data
data: ChartDataPoint[];
dataSeries?: DataSeries[];
// Configuration
defaultChartType?: ChartType;
defaultTimeRange?: TimeRange;
showVolume?: boolean;
showToolbar?: boolean;
height?: number;
// Customization
colors?: Partial<ChartColorPalette>;
formatters?: {
price?: (value: number) => string;
date?: (value: string) => string;
volume?: (value: number) => string;
};
// Event handlers
onChartTypeChange?: (type: ChartType) => void;
onTimeRangeChange?: (range: TimeRange) => void;
onDataPointHover?: (point: ChartDataPoint | null) => void;
onZoomChange?: (state: ChartZoomState) => void;
// State
loading?: boolean;
error?: string | null;
// Accessibility
ariaLabel?: string;
description?: string;
};