phase-2: extract shared utils
This commit is contained in:
@@ -32,7 +32,7 @@ npm start -- AAPL MSFT VOO # CLI: specific tickers
|
||||
npm run finance # CLI: portfolio advice + SimpleFIN → finance-report.html
|
||||
npm test # run all unit tests (node:test, zero external deps)
|
||||
npm run test:watch # watch mode — uses verbose spec reporter
|
||||
npm run format # format all src/bin/tests with Prettier
|
||||
npm run format # format all server/bin/tests with Prettier
|
||||
npm run format:check # check formatting without writing (used in CI/pre-commit)
|
||||
npm run ui:install # install UI dependencies (ui/ subdirectory)
|
||||
```
|
||||
@@ -56,7 +56,7 @@ scripts/
|
||||
prompts/
|
||||
catalyst-analysis.md ← daily catalyst analysis playbook (LLM prompt + workflow)
|
||||
|
||||
src/
|
||||
server/
|
||||
config/
|
||||
ScoringConfig.js ← CREDIT_RATING_SCALE + ScoringRules (single source of truth)
|
||||
constants.js ← SIGNAL, ASSET_TYPE, SECTOR, SCORE_MODE, REGIME, SIGNAL_ORDER
|
||||
@@ -199,7 +199,7 @@ CORS is configured for `CLIENT_ORIGIN` env var (default `http://localhost:5173`)
|
||||
|
||||
## ScoringConfig Key Values
|
||||
|
||||
`src/config/ScoringConfig.js` — single source of truth for all gates, weights, thresholds.
|
||||
`server/config/ScoringConfig.js` — single source of truth for all gates, weights, thresholds.
|
||||
|
||||
**STOCK base gates (Fundamental mode):**
|
||||
- `maxPERatio: 15` — Graham's actual rule (trailing P/E)
|
||||
@@ -234,7 +234,7 @@ CORS is configured for `CLIENT_ORIGIN` env var (default `http://localhost:5173`)
|
||||
|
||||
## MarketRegime (INFLATED overrides)
|
||||
|
||||
`src/market/MarketRegime.js` derives gate overrides from live benchmarks and current rate regime:
|
||||
`server/market/MarketRegime.js` derives gate overrides from live benchmarks and current rate regime:
|
||||
|
||||
| Gate | Formula (NORMAL rates) | Formula (HIGH rates) |
|
||||
|---|---|---|
|
||||
@@ -365,10 +365,10 @@ Test output: silent on pass, shows only failures + one summary line (`scripts/su
|
||||
- Asset `type` (uppercased) is the routing key across DataMapper, asset classes, `SCORERS` map, and ScoringRules.
|
||||
- Prefer adjusting `ScoringConfig` or `MarketRegime` over hardcoding numbers in scorers.
|
||||
- BenchmarkProvider caches for 1 hour — restart the server to force a fresh fetch.
|
||||
- All entry points live in `bin/`. Do not add logic to entry points — they call into `src/`.
|
||||
- `bin/server.js` starts Fastify; `src/server/` contains all route logic.
|
||||
- **Never** call `process.exit()` inside `src/` — only `bin/` may do that.
|
||||
- Class instances don't survive `JSON.stringify`. Call `getDisplayMetrics()` server-side before returning from API routes (see `src/server/routes/screener.js` `serializeAssets()`).
|
||||
- All entry points live in `bin/`. Do not add logic to entry points — they call into `server/`.
|
||||
- `bin/server.js` starts Fastify; `server/server/` contains all route logic.
|
||||
- **Never** call `process.exit()` inside `server/` — only `bin/` may do that.
|
||||
- Class instances don't survive `JSON.stringify`. Call `getDisplayMetrics()` server-side before returning from API routes (see `server/server/routes/screener.js` `serializeAssets()`).
|
||||
|
||||
---
|
||||
|
||||
@@ -381,7 +381,7 @@ All items completed. Additional features delivered alongside cleanup:
|
||||
|
||||
**Cleanup done:**
|
||||
- Deleted root-level `finance.js`, `import-portfolio.js`, `markdown.md`
|
||||
- Deleted `src/server/routes/analyze.js` (orphaned route file)
|
||||
- Deleted `server/server/routes/analyze.js` (orphaned route file)
|
||||
- Removed dead `analysis` state, `analysisOpen` state, and "🤖 AI Market Analysis" panel from `+page.svelte`
|
||||
- Fixed `.gitignore` — `portfolio.json`, `market-calls.json`, `.env` are now excluded from git
|
||||
|
||||
@@ -398,13 +398,19 @@ All items completed. Additional features delivered alongside cleanup:
|
||||
**Pending (deferred to later):**
|
||||
- LLM Analysis button on portfolio page (analyse holdings against current news)
|
||||
|
||||
### Phase 2 — Extract Shared Utilities
|
||||
- Create `ui/src/lib/utils.ts` with all pure functions currently duplicated across pages: `sigOrd`, `sorted`, `verdictShort`, `vClass`, `fmtPE`, `fmt`, `fmtShort`, `glClass`
|
||||
- Create `src/server/utils/logger.js` with shared `noopLogger` constant (currently copy-pasted in `screener.js` and `app.js`)
|
||||
### Phase 2 — Extract Shared Utilities ✅ COMPLETE
|
||||
|
||||
### Phase 3 — Rename `src/` → `server/`
|
||||
- Rename the directory and update all import paths in `bin/`, internal routes, and `CLAUDE.md`
|
||||
- Makes the API layer unambiguous — `src/` conventionally implies "all project source"
|
||||
**Done:**
|
||||
- Created `ui/src/lib/utils.ts` — typed shared pure functions: `sigOrd`, `sorted`, `verdictShort`, `vClass`, `fmtPE`, `fmt`, `fmtShort`, `glClass`, `advClass`. Exports `Signal` type.
|
||||
- Created `server/server/utils/logger.js` — shared `noopLogger` constant, imported by `screener.js`, `app.js`, `finance.js`, and `calls.js`
|
||||
- Added TypeScript support to `ui/` — `tsconfig.json` extending SvelteKit's generated config, `typescript` and `svelte-check` added as dev dependencies
|
||||
- All three pages (`+page.svelte`, `safe-buys/+page.svelte`, `portfolio/+page.svelte`) now import from `$lib/utils.js` instead of duplicating logic
|
||||
|
||||
### Phase 3 — Rename `src/` → `server/` ✅ COMPLETE
|
||||
|
||||
**Done:**
|
||||
- Renamed `src/` to `server/` — `src/server/` is now `server/server/`
|
||||
- Updated all import paths in `bin/`, `tests/`, and `CLAUDE.md`
|
||||
|
||||
### Phase 4 — SCSS Migration
|
||||
Replace per-component `<style>` blocks with a shared token system in `ui/src/styles/`:
|
||||
@@ -455,10 +461,10 @@ SvelteKit supports TypeScript natively — components just need `<script lang="t
|
||||
|
||||
## Adding a New Asset Type
|
||||
|
||||
1. Create a subclass of `Asset` in `src/screener/assets/` with a flat `metrics` object and `getDisplayMetrics()`.
|
||||
1. Create a subclass of `Asset` in `server/screener/assets/` with a flat `metrics` object and `getDisplayMetrics()`.
|
||||
2. Add a per-type entry (`gates` / `weights` / `thresholds`) to `ScoringRules` in `ScoringConfig.js`.
|
||||
3. Add inflated overrides in `MarketRegime.getInflatedOverrides()`.
|
||||
4. Create a Scorer in `src/screener/scorers/` exposing `score(metrics, rules, marketContext)`.
|
||||
4. Create a Scorer in `server/screener/scorers/` exposing `score(metrics, rules, marketContext)`.
|
||||
5. Add a mapper in `DataMapper.js`.
|
||||
6. Wire into `ScreenerEngine`: add `case` in `_buildAsset`, entry in `SCORERS` map.
|
||||
7. Add the new type to `serializeAssets()` handling in `src/server/routes/screener.js`.
|
||||
7. Add the new type to `serializeAssets()` handling in `server/server/routes/screener.js`.
|
||||
|
||||
Reference in New Issue
Block a user