feat: admin-configurable FINRA download URL

- Add finra_config singleton table (base_url + updated_at)
- Add getFinraBaseUrl() and setFinraBaseUrl() to admin.ts
  Resolution order: DB config > env FINRA_BASE_URL > built-in default
- Add finraConfig query + finraConfigUpdate mutation to admin tRPC router
- Update FinraIngestService.downloadAndIngestFinra to accept optional baseUrl
  param; falls back to getFinraBaseUrl(db) when omitted
- FinraBulkAdapter resolves URL implicitly via the service (no adapter change)
- Add migration #10 for existing DBs
This commit is contained in:
Investor Flow Build
2026-07-25 13:11:50 -04:00
parent 0b9df1e9d3
commit 8a00363dd0
5 changed files with 48 additions and 5 deletions
@@ -1,6 +1,5 @@
import type { DatabaseSync } from 'node:sqlite';
const FINRA_BASE_URL = process.env.FINRA_BASE_URL ?? 'https://www.finra.org/sites/default/files';
import { getFinraBaseUrl } from '../admin/admin.ts';
/** Format a FINRA consolidated-short-interest filename: CAshvol{YYYYMMDD}.txt */
function finraFilename(settlementDate: string): string {
@@ -64,13 +63,14 @@ function parseFinraFile(
}
/** Download and ingest a FINRA consolidated-short-interest file.
* Returns count of symbols stored. */
* baseUrl resolves from DB config > env FINRA_BASE_URL > built-in default when omitted. */
export async function downloadAndIngestFinra(
db: DatabaseSync,
settlementDate: string,
baseUrl?: string,
): Promise<{ symbolsStored: number; sourceFile: string; exchanges: string[] }> {
const url = baseUrl ?? getFinraBaseUrl(db);
const filename = finraFilename(settlementDate);
const url = `${FINRA_BASE_URL}/${filename}`;
const ingestedAt = new Date().toISOString();
console.log(`[finra] downloading ${url}`);