2026-May-Fixes #19

Merged
JoeBot merged 5 commits from 2026-May-Fixes into main 2026-05-22 10:09:28 -04:00
Owner

This bulk package fixed several issues as well as introduced dynamic versioning

This bulk package fixed several issues as well as introduced dynamic versioning
JoeBot added 5 commits 2026-05-22 10:09:20 -04:00
- Monthly actuals grid now filters actual_amount to entry_type='monthly_actual'
  only, so other posted JEs in the same month don't bleed into the actuals UI
- Remove manual accounts.balance reversal from void() — the reversal JE's post()
  call already handles balance updates, preventing double-decrement per void
- Date void reversal entries to the original entry's date (not today) so
  historical monthly cash-flow periods stay accurate when actuals are re-edited
- Cash flow forecast now derives opening investment balances from investments
  purchased before the forecast start date rather than using current-snapshot
  totals, fixing historical months showing wrong investment balances

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Monthly Actuals — Option A:
- Replace operating cash account offset with per-fund equity account clearing
- Equity accounts 3000/3100 now absorb the net P&L from actuals entries
- Cash account is never touched by monthly actuals, eliminating the balance
  discrepancy that required manual cash adjustments
- Per-fund routing: operating income/expense clears to 3000, reserve to 3100
- Falls back gracefully if only one equity account exists

Scenario Activation (Issue 4):
- updateScenario now accepts userId and triggers materialisation when
  status transitions to 'active'
- Each pending scenario investment is created as a real investment_accounts
  record dated to its purchase_date (future dates are supported)
- Journal entries are posted at the purchase_date using the fund's primary
  cash account and equity offset (matching manual account creation)
- Rollover detection: if an existing active investment matures within 7 days
  of the new investment's purchase_date and shares the same fund_type, the
  system creates a maturity JE (proceeds → cash) and a reinvestment JE
  (cash → new CD) rather than a fresh cash deduction, then retires the
  source investment
- Per-investment failures are logged but do not abort the rest of the batch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three root causes addressed:

1. nginx routing gap — bare GET /api (no trailing slash) fell through
   `location /api/` to the Vite dev proxy, which forwarded it to the
   backend as an unmatched path. Added `location = /api` exact-match
   block before the prefix block to catch it and proxy directly to
   the backend health handler.

2. AppController root handler — added @Get() (maps to GET /api with
   global prefix) so bare /api requests return a clean 200 instead of
   a 404 that registers as a phantom NR transaction.

3. New Relic transaction naming — NestJS's setGlobalPrefix('api')
   causes NR's Express instrumentation to bucket ALL requests into the
   generic "Expressjs/GET/api$" segment, making per-endpoint APM data
   completely useless. The new NewRelicTransactionInterceptor calls
   newrelic.setTransactionName() with "METHOD /route/pattern" for
   every request (after routing, so req.route is populated with the
   matched template). Gracefully no-ops in dev where NR is not loaded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Issue 2 fix made the opening investment balance point-in-time
(only CDs purchased before startYear-01-01), with a comment promising
that later purchases would be re-added "when their purchase month is
processed in the forecast loop" — but that loop code never existed.
The loop only ever subtracted maturing CDs, never added purchased ones.

Result: every CD bought during the charted window vanished from the
chart. For Pine Creek (all 5 CDs purchased in 2026) the operating
investment line showed $0 instead of $65,000 and reserve showed
$10,000 instead of $60,032.

Fix: build a purchaseIndex (mirroring maturityIndex) of investments
purchased on/after startYear-01-01, keyed by purchase year-month, and
credit each CD's value to the running investment balance in its
purchase month — applied before the historical/forecast branch so it
works for both actual and projected months.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the hardcoded version string in SettingsPage.tsx with a single
source of truth: a /VERSION file at the repo root. To cut a new release,
edit only that one file.

Frontend:
- vite.config.ts reads /VERSION at dev-server startup and injects it as
  the __APP_VERSION__ global via Vite's define mechanism (compile-time,
  zero runtime cost). Falls back to VITE_APP_VERSION env var for prod
  Docker builds that pass it as a build arg.
- vite-env.d.ts adds the TypeScript declaration for __APP_VERSION__.
- SettingsPage.tsx Badge now renders {__APP_VERSION__} instead of the
  literal string.

Backend:
- app.controller.ts reads /VERSION once at module load and includes
  "version" in both GET /api and GET /api/health responses.
- NewRelicTransactionInterceptor tags every NR transaction with
  newrelic.addCustomAttribute('appVersion', version) so releases can be
  compared in NRQL: SELECT average(duration) FROM Transaction WHERE
  appVersion = '2026.5.22'

Docker:
- docker-compose.yml mounts ./VERSION:/app/VERSION:ro in both backend
  and frontend dev containers.
- Production Dockerfiles include COPY VERSION ./ with a comment
  instructing CI to copy the root VERSION into each build context before
  docker build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
JoeBot merged commit 709d64553c into main 2026-05-22 10:09:28 -04:00
JoeBot deleted branch 2026-May-Fixes 2026-05-22 10:09:28 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JoeBot/HOA_Financial_Platform#19
No description provided.