Files
Neon-Desk/lib/types.ts

791 lines
19 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 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' | '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 = {
regime: 'us-gaap' | 'ifrs-full' | 'unknown';
fiscalPack: string | null;
parserVersion: string;
unmappedRowCount: number;
materialUnmappedRowCount: number;
};
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 CompanyAnalysis = {
company: {
ticker: string;
companyName: string;
sector: string | null;
category: string | null;
tags: string[];
cik: string | null;
};
quote: number;
position: Holding | null;
priceHistory: Array<{ date: string; close: number }>;
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;
};