GSR Transformer
ETL service that ingests CSV files (ETF holdings, daily NAV, monthly/quarterly performance) from a US Bank SFTP, validates and coerces them, and writes to Postgres via Prisma 7. A Fastify HTTP API exposes per-fund views over the ingested data.
Project Identity
Repository name is bankofus. The application is also referred to as GSR Transformer (the in-product name). Docs in this folder use both names.
Repository
- Path: /Users/levander/coding/scharge/bankofus
- Branch: main
- Package manager: pnpm 10.20.0
- Module type: ESM
- Build: tsup to dist/
- Deploy target: Kubernetes (Helm chart at helm/gsr-transformer/, ingest as CronJob)
Tech Stack
| Layer | Tech |
|---|---|
| Language | TypeScript 5.9 (ESM) |
| Runtime | Node (tsx for dev, tsup-bundled for prod) |
| HTTP server | Fastify 5 (+ swagger / swagger-ui) |
| ORM | Prisma 7 |
| Database | PostgreSQL |
| CSV parser | PapaParse 5 |
| FTP client | basic-ftp, ssh2-sftp-client |
| Logging | pino + pino-pretty |
| Testing | vitest (introduced 2026-05 with the computed performance endpoints — see 2026-05-11 Computed performance endpoints) |
| Deployment | Helm chart, Kubernetes CronJob for ingest |
Data Sources
Configured in src/targets.ts:
| Datasource | Type | File pattern | Notes |
|---|---|---|---|
| etfHoldingsDs | static | *ETF_Holdings.csv | deletePrevious: true |
| monthlyPerformanceDs | static | *MonthlyPerformance.csv | deletePrevious: true |
| quarterlyPerformanceDs | static | *QuarterlyPerformance.csv | deletePrevious: true |
| dailyEtfDs | timeseries | *DailyNAV.csv | append-only; source for computed since-inception return + quarterly premium/discount |
HTTP API
- Most routes are auto-generated by the TrackedTabularDataSource framework: per-datasource row-shaped routes (latest / timeseries / list).
- Plus hand-written computed routes that aggregate over a table — these deliberately sit outside the framework. See 2026-05-11 Computed performance endpoints:
- GET /etf/:ticker/performance/since-inception — NAV- and market-price-based cumulative return since fund inception (2026-04-22), refreshed daily
- GET /etf/:ticker/premium-discount/quarterly — % days at premium / discount per calendar quarter from inception onward
Documentation
- Agent Context - load this before any agent work
- 2026-05-04 Performance CSV ingest fix - DateTime mistype, empty rows, dash placeholder
- 2026-05-11 Computed performance endpoints - design decisions for since-inception return + quarterly premium/discount endpoints
- LOG - chronological session log
- TOPICS - theme index