phase-10.5: screener enhancements

This commit is contained in:
Kazuma
2026-06-11 19:18:19 -04:00
parent f0c794f0c0
commit bf2a85b5c4
51 changed files with 3745 additions and 36 deletions
+43 -1
View File
@@ -11,6 +11,16 @@ import { CallsController, CalendarService } from './domains/calls';
import { AuthController, AuthService, UserStore, verifyJwt } from './domains/auth';
import type { TokenPayload } from './domains/auth';
import { WatchlistController, WatchlistRepository } from './domains/watchlist';
import {
NewsController,
NewsRepository,
NewsPipeline,
UniverseProvider,
NewsScheduler,
EdgarPoller,
PrWirePoller,
} from './domains/news';
import { DigestController, DigestService } from './domains/digest';
// Shared infrastructure
import {
@@ -141,7 +151,14 @@ export async function buildApp({ logger = true, db: injectedDb }: BuildAppOption
// Register controllers
// Public routes (GET) remain open; write routes require JWT + trader role
new ScreenerController(engine, catalystCache, new SignalSnapshotRepository(db)).register(app);
const newsRepo = new NewsRepository(db);
new ScreenerController(
engine,
catalystCache,
new SignalSnapshotRepository(db),
yahoo,
newsRepo,
).register(app);
new FinanceController(engine, new PortfolioRepository(db), advisor, {
authGuard,
traderGuard,
@@ -154,6 +171,31 @@ export async function buildApp({ logger = true, db: injectedDb }: BuildAppOption
new WatchlistController(new WatchlistRepository(db), { authGuard }).register(app);
// ── News domain (FREE-DATA-STACK) — pipeline + read API + polling ────────
new NewsController(newsRepo, yahoo).register(app);
// ── Digest domain (P1.1) — snapshot diff + catalyst join, on demand ──────
new DigestController(new DigestService(new SignalSnapshotRepository(db), newsRepo)).register(app);
// Polling runs inside the server unless NEWS_POLL=off (use bin/poll-news.ts
// from cron instead). Timers are unref'd and cleared on app.close().
if (process.env.NEWS_POLL !== 'off') {
const newsLogger = {
log: (...args: unknown[]) => app.log.info(args.map(String).join(' ')),
warn: (...args: unknown[]) => app.log.warn(args.map(String).join(' ')),
write: () => {},
};
const newsScheduler = new NewsScheduler(
new NewsPipeline(newsRepo),
new UniverseProvider(db),
new EdgarPoller(newsLogger),
new PrWirePoller(newsLogger),
newsLogger,
);
app.addHook('onReady', async () => newsScheduler.start());
app.addHook('onClose', async () => newsScheduler.stop());
}
app.get('/health', async () => ({ status: 'ok' }));
return app;