Files
Neon-Desk/lib/types.ts
francy51 14a7773504 Add consolidated disclosure statement type
Create unified disclosure statement to organize footnote disclosures
separate from primary financial statements. Disclosures are now grouped
by type (tax, debt, securities, derivatives, leases, intangibles, ma,
revenue, cash_flow) in a dedicated statement type for cleaner UI
presentation.
2026-03-16 18:54:23 -04:00

939 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 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";
export 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"
| "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[];
};
export 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;
export type StandardizedStatementRow = StandardizedFinancialRow;
export type SurfaceFinancialRow = StandardizedFinancialRow & {
statement?: Extract<
FinancialStatementKind,
"income" | "balance" | "cash_flow"
>;
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;
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;
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;
};
export 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;
};