96a752ecf7
- Restructured server layer with 5 domains: shared, screener, portfolio, calls, finance - Migrated 58 TypeScript files to domain-driven structure - Updated CLAUDE.md with new architecture documentation - Added .gitignore rules for .md files (except CLAUDE.md) - Removed unused CatalystAnalyst import from app.ts - Fixed lint errors: removed unused imports, fixed regex escape, added console suppressions - Verified no sensitive data in git history - Server code compiles cleanly with TypeScript strict mode
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
import type { FastifyInstance, FastifyRequest } from 'fastify';
|
|
import { ScreenerEngine } from './ScreenerEngine';
|
|
import { CatalystCache } from '../../domains/shared';
|
|
import type { LiveAssetResult } from '../../domains/shared';
|
|
import { screenSchema } from '../../domains/shared/types/schemas';
|
|
|
|
export class ScreenerController {
|
|
constructor(
|
|
private readonly engine: ScreenerEngine,
|
|
private readonly catalystCache: CatalystCache,
|
|
) {}
|
|
|
|
register(app: FastifyInstance): void {
|
|
app.post(
|
|
'/api/screen',
|
|
{ schema: screenSchema, config: { rateLimit: { max: 10, timeWindow: '1 minute' } } },
|
|
this.screen.bind(this),
|
|
);
|
|
app.get(
|
|
'/api/screen/catalysts',
|
|
{ config: { rateLimit: { max: 10, timeWindow: '1 minute' } } },
|
|
this.catalysts.bind(this),
|
|
);
|
|
}
|
|
|
|
private static serializeAssets(arr: LiveAssetResult[]) {
|
|
return arr.map((r) => ({
|
|
...r,
|
|
asset: {
|
|
ticker: r.asset.ticker,
|
|
type: r.asset.type,
|
|
currentPrice: r.asset.currentPrice,
|
|
metrics: r.asset.metrics,
|
|
displayMetrics: r.asset.getDisplayMetrics(),
|
|
},
|
|
}));
|
|
}
|
|
|
|
private async screen(req: FastifyRequest) {
|
|
const tickers = (req.body as { tickers: string[] }).tickers.map((t) => t.toUpperCase());
|
|
const results = await this.engine.screenTickers(tickers);
|
|
return {
|
|
...results,
|
|
STOCK: ScreenerController.serializeAssets(results.STOCK as LiveAssetResult[]),
|
|
ETF: ScreenerController.serializeAssets(results.ETF as LiveAssetResult[]),
|
|
BOND: ScreenerController.serializeAssets(results.BOND as LiveAssetResult[]),
|
|
};
|
|
}
|
|
|
|
private async catalysts() {
|
|
const { tickers, stories } = await this.catalystCache.get();
|
|
return { tickers, stories };
|
|
}
|
|
}
|