86 Commits

Author SHA1 Message Date
43b10869f0 feat: add flexible capability-based RBAC with per-tenant customization
Introduces a capability layer on top of existing roles that controls
feature visibility and access. Capabilities follow an area.feature.action
taxonomy (~35 capabilities) with sensible defaults per role. Tenant admins
can customize via grant/revoke overrides stored in org settings JSONB.

Key changes:
- Add vice_president role to DB schema
- Backend: capability constants, resolution logic, CapabilityGuard (global),
  @RequireCapability decorator on all 16 tenant controllers
- Frontend: permission hooks (useCanEdit, useHasCapability), CapabilityGate
  component, sidebar filtering by capability, all 17 pages migrated from
  useIsReadOnly to capability-based checks
- New admin UI: /settings/permissions matrix page for per-tenant role
  customization with grant/revoke delta model
- GET /organizations/my-capabilities endpoint for capability refresh
- Validation of permissionOverrides in settings updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 15:28:14 -04:00
JoeBot
bd174fc22b fix: normalize API URL to prevent duplicate /chat/completions path
Users entering the full endpoint URL (e.g. https://openrouter.ai/api/v1/chat/completions)
caused a 404 because the code appended /chat/completions again. Now strips any trailing
/chat/completions before re-appending, and adds a hint in the UI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 08:14:37 -04:00
JoeBot
4797669591 feat: add shadow AI benchmarking for admin model comparison
Add a new admin-only feature that allows the platform owner to benchmark
the production AI model against up to 2 alternate models (any OpenAI-compatible
API) using real tenant data, without impacting users.

Backend:
- Shared AI caller utility (ai-caller.ts) for OpenAI-compatible endpoints
- Shadow AI module with service, controller, and 3 entities
- 6 admin API endpoints for model config CRUD, run trigger, and history
- Auto-creates shadow_ai_models, shadow_runs, shadow_run_results tables
- Exposes health-scores and investment-planning prompt builders for reuse

Frontend:
- New admin page at /admin/shadow-ai with 3 tabs:
  - Model Configuration (production + 2 alternate slots)
  - Run Comparison (tenant select, feature select, side-by-side results)
  - History (filterable run log with detail drill-down)
- Full side-by-side output display with diff highlighting
- Sidebar navigation link for AI Benchmarking

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 07:50:59 -04:00
JoeBot
d430b96b51 feat: add admin ideas management page with private notes
Adds a dedicated super admin page for managing idea submissions across
all tenants. Includes status summary cards, filterable/searchable table,
detail modal with status updates, and private admin notes for internal
tracking (sprint refs, thoughts, follow-ups). Notes are not visible to
tenant users.

- Database: admin_note column on shared.ideas (019 migration)
- Backend: PUT /admin/ideas/:id/note endpoint
- Frontend: AdminIdeasPage with table, filters, detail modal
- Sidebar: "Idea Submissions" nav link in admin sections
- Routing: /admin/ideas route under SuperAdminRoute guard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 17:35:30 -04:00
JoeBot
140cd7acb7 feat: add ideation feature with per-tenant toggle
Adds idea submission capability gated by a per-tenant feature flag.
Super admins can enable/disable ideation for specific tenants via the
admin tenant detail drawer. Users see a lightbulb icon in the header
when enabled, opening a modal to submit ideas (title + description).
Ideas are stored in shared schema for cross-tenant backlog querying.

- Database: shared.ideas table (018-ideas.sql migration)
- Backend: Ideas NestJS module (entity, service, controller)
- Admin API: GET /admin/ideas, PUT /admin/ideas/:id/status,
  PUT /admin/organizations/:id/settings
- Frontend: IdeaModal component, lightbulb ActionIcon in header
- Admin UI: Feature Toggles card with ideation Switch in drawer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 17:20:37 -04:00
2f6297ae68 fix: reserve fund health AI prompt uses planned dates instead of remaining life years
Remaining life years is documentation-only reference info. The board's
planned project date is the authoritative timeline for urgency assessment.
Updates data gathering, prompt construction, and system instructions to
base all urgency on target_year/target_month instead of remaining_life_years.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 14:28:37 -04:00
121b8138e3 fix: investment scenario detail blank screen and auto-renew refresh
Move useMemo hook above early returns to satisfy React Rules of Hooks,
fixing blank screen when navigating to scenario detail. Also re-fetch
scenario after projection updates so auto-renew renewal records appear
automatically without requiring manual navigation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 15:04:44 -04:00
2b331bb3ef feat: investment chart alignment, auto-renew records, fund transfers, capital planning report, and upcoming activities (v2026.3.24)
- Lock InvestmentTimeline and ProjectionChart to shared X axis range
- Auto-create renewal scenario_investments records when auto_renew is true
- Add fund transfer mechanism between asset accounts with journal entries
- Add Capital Planning Report (5-year forecast grouped by category)
- Add Upcoming Investment Activities dashboard card (maturities + planned purchases)
- Bump version to 2026.3.24

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 14:41:17 -04:00
66e2f87a96 feat: UX enhancements, member limits, forecast fix, and menu cleanup (v2026.3.19)
- Onboarding wizard: add Reserve Account step between Operating and Assessments,
  redirect to Budget Planning on completion
- Dashboard: health score pending state shows clickable links to set up missing items
- Projects/Vendors: rich empty-state wizard screens with real-world examples and CTAs
- Investment Planning: auto-refresh AI recommendations when empty or stale (>30 days)
- Hide Invoices and Payments menus (see PARKING-LOT.md for re-enablement)
- Send welcome email via Resend when new members are added to a tenant
- Enforce 5-member limit for Starter/Standard/Professional plans (Enterprise unlimited)
- Cash flow forecast: only mark months as "Actual" when journal entries exist,
  fixing the issue where months without data showed as actuals
- Bump version to 2026.3.19

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 14:47:04 -04:00
db8b520009 fix: billing portal error, onboarding wizard improvements, budget empty state
- Fix "Manage Billing" button error for trial orgs without Stripe customer;
  add fallback to retrieve customer from subscription, show helpful message
  for trial users, and surface real error messages in the UI
- Add "Balance As-Of Date" field to onboarding wizard so opening balance
  journal entries use the correct statement date instead of today
- Add "Total Unit Count" field to onboarding wizard assessment group step
  so cash flow projections work immediately
- Remove broken budget upload step from onboarding wizard (was using legacy
  budgets endpoint); replace with guidance to use Budget Planning page
- Replace bare "No budget plan lines" text with rich onboarding-style card
  featuring download template and upload CSV action buttons

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 09:43:49 -04:00
a996208cb8 feat: add annual billing, free trial, upgrade/downgrade, and ACH invoice support
- Add monthly/annual billing toggle with 25% annual discount on pricing page
- Implement 14-day no-card free trial (server-side Stripe subscription creation)
- Enable upgrade/downgrade via Stripe Customer Portal
- Add admin-initiated ACH/invoice billing for enterprise customers
- Add billing card to Settings page with plan info and Manage Billing button
- Handle past_due status with read-only grace period access
- Add trial ending and trial expired email templates
- Add DB migration for billing_interval and collection_method columns
- Update ONBOARDING-AND-AUTH.md documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 08:04:51 -04:00
170461c359 Merge branch 'claude/reverent-moore' - Resend email integration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 18:33:17 -04:00
aacec1cce3 feat: integrate Resend for transactional email delivery
Replace the stubbed email service with Resend API integration.
Emails are sent with branded HTML templates including activation,
welcome, payment failed, member invite, and password reset flows.

- Install resend@6.9.4 in backend
- Rewrite EmailService with Resend SDK + graceful fallback to
  stub mode when API key is not configured
- Add branded HTML email template with CTA buttons, preheader
  text, and fallback URL for all email types
- Add reply-to support (sales@hoaledgeriq.com in production)
- Track send status (sent/failed) in shared.email_log metadata
- Add RESEND_API_KEY, RESEND_FROM_ADDRESS, RESEND_REPLY_TO env
  vars to both docker-compose.yml and docker-compose.prod.yml
- Add sendPasswordResetEmail() method for future use

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 18:29:20 -04:00
19fb2c037c feat(security): address findings from v2 security assessment
- L2: Add server_tokens off to nginx configs to hide version
- M1: Add X-Frame-Options, X-Content-Type-Options, Referrer-Policy,
  Permissions-Policy headers to all nginx routes
- L3: Add global NoCacheInterceptor (Cache-Control: no-store) on all
  API responses to prevent caching of sensitive financial data
- C1: Disable open registration by default (ALLOW_OPEN_REGISTRATION env)
- H3: Add logout endpoint with correct HTTP 200 status code
- M2: Implement full password reset flow (forgot-password, reset-password,
  change-password) with hashed tokens, 15-min expiry, single-use
- Reduce JWT access token expiry from 24h to 1h
- Add EmailService stub (logs to shared.email_log)
- Add DB migration 016 for password_reset_tokens table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 07:46:11 -04:00
dfcd172ef3 feat: SaaS onboarding, Stripe billing, MFA, SSO, passkeys, refresh tokens
Complete SaaS self-service onboarding sprint:

- Stripe-powered signup flow: pricing page → checkout → provisioning → activation
- Refresh token infrastructure: 1h access tokens + 30-day httpOnly cookie refresh
- TOTP MFA with QR setup, recovery codes, and login challenge flow
- Google + Azure AD SSO (conditional on env vars) with account linking
- WebAuthn passkey registration and passwordless login
- Guided onboarding checklist with server-side progress tracking
- Stubbed email service (console + DB logging, ready for real provider)
- Settings page with tabbed security settings (MFA, passkeys, linked accounts)
- Login page enhanced with MFA verification, SSO buttons, passkey login
- Database migration 015 with all new tables and columns
- Version bump to 2026.03.17

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:12:35 -04:00
17bdebfb52 chore: reorganize sidebar navigation and bump version to 2026.03.16
Remove the Planning section. Move Projects and Capital Planning (as
sub-item) into Board Planning. Move Investment Planning with Investment
Scenarios as sub-item into Board Planning. Move Vendors into new Board
Reference section. Board Planning order: Budget Planning, Projects >
Capital Planning, Assessment Scenarios, Investment Planning > Investment
Scenarios, Compare Scenarios. Sidebar now supports parent items with
their own route plus nested children.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:28:45 -04:00
159c59734e feat: investment scenario UX improvements and interest calculations
- Refresh Recommendations now shows inline processing banner with
  animated progress bar while keeping existing results visible (dimmed).
  Auto-scrolls to AI section and shows titled notification on completion.
- Investment recommendations now auto-calculate purchase and maturity
  dates from a configurable start date (defaults to today) in the
  "Add to Plan" modal, so scenarios build projections immediately.
- Projection engine computes per-investment and total interest earned,
  ROI percentage, and total principal invested. Summary cards on the
  Investment Scenario detail page display these metrics prominently.
- Replaced dropdown action menu with inline Edit/Execute/Remove
  icon buttons matching the assessment scenarios pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:18:40 -04:00
7ba5c414b1 fix: handle multi-component investment recommendations (CD ladders)
When adding a multi-stage investment strategy (e.g. CD ladder) from AI
recommendations to a board planning scenario, all component investments
are now created as separate rows instead of collapsing into a single
investment. The AI prompt now instructs inclusion of a components array,
the backend loops through components to create individual scenario
investments, and the frontend passes and displays component details.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 15:59:56 -04:00
a98a7192bb fix: assessment scenarios UX tweaks and projection improvements
- Reorder sidebar: Assessment Scenarios now directly under Budget Planning
- Simplify special assessment form: remove Total Amount, keep Per Unit only
- Replace Duration field from free-text installments to dropdown (one-time/quarterly/6mo/annual)
- Update Change column display to show total per-unit with duration label
- Fix Reserve Coverage to use planned capital project costs instead of budget expenses
- Include capital_projects table in projection engine alongside projects table
- Replace actions dropdown menu with inline Edit/Remove icon buttons
- Remove Refresh Projection button (projection auto-refreshes on changes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 15:28:33 -04:00
f20f54b128 fix: compound inflation, budget planner CSV import, simplify budget manager
- Fix compound inflation: use Math.pow(1 + rate/100, yearsGap) instead of
  flat rate so multi-year gaps (e.g., 2026→2029) compound annually
- Budget Planner: add CSV import flow + Download Template button; show proper
  empty state when no base budget exists with Create/Import options
- Budget Manager: remove CSV import, Download Template, and Save buttons;
  redirect users to Budget Planner when no budget exists for selected year
- Fix getAvailableYears to return null latestBudgetYear when no budgets exist
  and include current year in year selector for fresh tenants

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 14:39:31 -04:00
f2b0b57535 fix: use correct column name for accounts table in budget planning query
The accounts table uses 'name' not 'account_name'. Alias it correctly
in the getPlan JOIN query.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 10:37:47 -04:00
e6fe2314de feat: add Future Year Budget Planning with inflation-adjusted projections
Adds budget planning capability under Board Planning, allowing HOA boards
to model future year budgets with configurable per-year inflation rates.

Backend:
- New budget_plans + budget_plan_lines tables (migration 014)
- BudgetPlanningService: CRUD, inflation generation (per-month preservation),
  status workflow (planning → approved → ratified), ratify-to-official copy
- 8 new API endpoints on board-planning controller
- Projection engine (both board-planning and reports) now falls back to
  planned budgets via UNION ALL query when no official budget exists
- Extended year range from 3 to dynamic based on projection months

Frontend:
- BudgetPlanningPage with monthly grid table (mirrors BudgetsPage pattern)
- Year selector, inflation rate control, status progression buttons
- Inline editing with save, confirmation modals for status changes
- Manual edit tracking with visual indicator
- Summary cards for income/expense totals

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 10:24:18 -04:00
c8d77aaa48 feat: add Board Planning module with investment/assessment scenario modeling
Implements Phase 11 Forecasting Tools - a "what-if" scenario planning system
for HOA boards to model financial decisions before committing.

Backend:
- 3 new tenant-scoped tables: board_scenarios, scenario_investments, scenario_assessments
- Migration script (013) for existing tenants
- Full CRUD service for scenarios, investments, and assessments
- Projection engine adapted from cash flow forecast with investment/assessment deltas
- Scenario comparison endpoint (up to 4 scenarios)
- Investment execution flow: converts planned → real investment_accounts + journal entry

Frontend:
- New "Board Planning" sidebar section with 3 pages
- Investment Scenarios: list, create, detail with investments table + timeline
- Assessment Scenarios: list, create, detail with changes table
- Scenario Comparison: multi-select overlay chart + summary metrics
- Shared components: ProjectionChart, InvestmentTimeline, ScenarioCard, forms
- AI Recommendation → Investment Plan integration (Story 1A)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 09:52:10 -04:00
280a5996f6 fix: use rate-based estimate for interest YoY projection
The projected interest was extrapolating from sparse YTD journal entries,
producing inaccurate results early in the year. Now uses the same
rate-based est_monthly_interest calculation (from account balances and
investment rates) for remaining months, consistent with the dashboard KPI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:52:54 -04:00
82433955bd feat: dashboard quick stats enhancements and monthly actuals read/edit mode
Dashboard Quick Stats:
- Create Capital Projects section with "Planned Capital Spend 2026"
- Fix Interest Earned YTD to pull from actual journal entries on
  interest income accounts instead of unrealized investment gains
- Add Interest Earned YoY showing projected current year vs last year
  actuals with percentage change badge

Monthly Actuals:
- Default to read-only view when actuals are already reconciled
- Show "Edit Actuals" button instead of "Save Actuals" for reconciled months
- Add confirmation modal warning that editing will void existing journal
  entry before allowing edits
- New months without actuals open directly in edit mode

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:41:14 -04:00
1acd8c3bff fix: check reserve-funded projects instead of unused reserve_components table
The missing-data warning was checking the reserve_components table,
which users never populate. All reserve data lives in the projects
table. Now only warns when no reserve-funded projects exist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:51:12 -04:00
94c7c90b91 fix: use project estimated_cost for reserve funded ratio calculation
The health score funded ratio was only reading from the reserve_components
table (replacement_cost), but users enter their reserve data on the
Projects page using estimated_cost. When reserve_components is empty,
the funded ratio now falls back to reserve-funded projects for:
- Total replacement cost (estimated_cost)
- Component funding status (current_fund_balance)
- Urgent components due within 5 years (remaining_life_years)
- AI prompt component detail lines

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:46:56 -04:00
04771f370c fix: clarify reserve health score when no components are entered
- Add missing-data warning when reserve_components table is empty so
  users see "No reserve components found" on the dashboard
- Change AI prompt to show "N/A" instead of "0.0%" for funded ratio
  when no components exist, preventing misleading "0% funded" reports
- Instruct AI not to report 0% funded when data is simply missing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:42:15 -04:00
61a4f27af4 security: address assessment findings and bump to v2026.3.11
- C1: Disable Swagger UI in production (env gate)
- M1+M2: Add Helmet.js for security headers (CSP, X-Frame-Options,
  X-Content-Type-Options, Referrer-Policy) and remove X-Powered-By
- H2: Add @nestjs/throttler rate limiting (5 req/min on login/register)
- M4: Remove orgSchema from JWT payload and client-side storage;
  tenant middleware now resolves schema from orgId via cached DB lookup
- L1: Fix Chatwoot user identification (read from auth store on ready)
- Remove schemaName from frontend Organization type and UI displays

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:22:58 -04:00
16e1ada261 fix: budget save error and add read-only view mode (v2026.03.10)
Fix budget save 500 error caused by three data mismatches between
frontend and backend: wrapped payload ({lines:[...]}) vs expected
raw array, snake_case vs camelCase field names (account_id vs
accountId), and dec_amt vs dec for December values.

Add read-only budget view as default for existing budgets with an
"Edit Budget" button to enter edit mode, and Cancel to discard
changes - reducing accidental edits.

Bump version to 2026.03.10 across all packages and settings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:28:09 -04:00
b0282b7f8b fix: show P&L debit/credit totals on journal entries list
The previous aggregation used simple SUM(debit)/SUM(credit) which
always produced equal values for balanced entries. This was misleading
for entries with income/expense lines (e.g., monthly actuals).

Now, when an entry has income/expense lines, the totals reflect only
P&L account activity (expenses as debits, income as credits), excluding
the cash offset. For balance-sheet-only entries (opening balances,
adjustments), the full entry totals are shown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:41:26 -04:00
ac72905ecb fix: add total_debit/total_credit aggregations to journal entries list
The findAll query was missing SUM aggregations, so the frontend received
no total_debit/total_credit fields and fell back to displaying $0.00.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:17:08 -04:00
3bf6b8c6c9 fix: update password when adding existing user to new org
When an existing user was added to a new organization via the member
management UI, the password entered in the form was silently ignored.
This caused the user to be unable to log in with the password they
were given, since the hash in the database was from their original
account creation for a different org.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:49:23 -04:00
2b72951e66 chore: bump version to 2026.3.7 (Beta)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:01:57 -05:00
69dad7cc74 fix: resolve 5 invoice/payment issues from user feedback
- Replace misleading 'sent' status with 'pending' (no email capability)
- Show assessment group name instead of raw 'regular_assessment' type
- Add owner last name to invoice table
- Fix payment creation Internal Server Error (PostgreSQL $2 type cast)
- Add edit/delete capability for payment records with invoice recalc

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:01:57 -05:00
efa5aca35f feat: add flexible billing frequency support for invoices
Assessment groups can now define billing frequency (monthly, quarterly,
annual) with configurable due months and due day. Invoice generation
respects each group's schedule - only generating invoices when the
selected month is a billing month for that group. Adds a generation
preview showing which groups will be billed, period tracking on
invoices, and billing period context in the payments UI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:01:57 -05:00
9146118df1 feat: async AI calls, 10-min timeout, and failure messaging
- Make all AI endpoints (health scores + investment recommendations)
  fire-and-forget: POST returns immediately, frontend polls for results
- Extend AI API timeout from 2-5 min to 10 min for both services
- Add "last analysis failed — showing cached data" message to the
  Investment Recommendations panel (matches health score widgets)
- Add status/error_message columns to ai_recommendations table
- Remove nginx AI timeout overrides (no longer needed)
- Users can now navigate away during AI processing without interruption

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:42:53 -05:00
07d15001ae fix: improve AI health score accuracy and consistency
Address 4 issues identified in AI feature audit:

1. Reduce temperature from 0.3 to 0.1 for health score calculations
   to reduce 16-40 point score volatility across runs

2. Add explicit cash runway classification rules to operating prompt
   preventing the model from rating sub-3-month runway as "positive"

3. Pre-compute total special assessment income in both operating and
   reserve prompts, eliminating per-unit vs total confusion ($300
   vs $20,100)

4. Make YTD budget comparison actuals-aware: only compare months with
   posted journal entries, show current month budget separately, and
   add prompt guidance about month-end posting cadence

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:44:12 -05:00
a0b366e94a fix: resolve critical SQL and display bugs across 5 financial reports
- Fix systemic LEFT JOIN date filter bug in Balance Sheet, Income Statement,
  and Cash Flow Statement by using parenthesized INNER JOIN pattern so
  SUM(jel.debit/credit) respects date parameters
- Add Current Year Net Income synthetic equity line to Balance Sheet to
  satisfy the accounting equation (A = L + E) during open fiscal periods
- Add investment_accounts balances to Balance Sheet assets and corresponding
  equity lines for reserve/operating investment holdings
- Fix Cash Flow Statement beginning/ending cash always showing $0 by
  replacing LIKE '%Cash%' filter with account_type = 'asset'
- Fix Year-End Package HTTP 500 by replacing broken invoices.vendor_id
  query with journal-entry-based vendor payment lookup
- Fix Quarterly Report defaulting to previous quarter instead of current
- Fix Quarterly Report date subtitle off-by-one day from UTC parsing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 14:15:01 -05:00
337b6061b2 feat: reliability enhancements for AI services and capital planning
1. Health Scores — separate operating/reserve refresh
   - Added POST /health-scores/calculate/operating and /calculate/reserve
   - Each health card now has its own Refresh button
   - On failure, shows cached (last good) data with "last analysis failed"
     watermark instead of blank "Error calculating score"
   - Backend getLatestScores returns latest complete score + failure flag

2. Investment Planning — increased AI timeout to 5 minutes
   - Backend callAI timeout: 180s → 300s
   - Frontend axios timeout: set explicitly to 300s (was browser default)
   - Host nginx proxy_read_timeout: 180s → 300s
   - Loading message updated to reflect longer wait times

3. Capital Planning — Unscheduled column moved to rightmost position
   - Kanban column order: current year → future → unscheduled (was leftmost)
   - Puts immediate/near-term projects front and center

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 12:02:30 -05:00
05e241c792 fix: allow null planned_date when updating projects
Empty string date values from the frontend were being passed directly
to PostgreSQL, which cannot cast "" to DATE. Normalize empty strings
to null for all date columns in the update method and the dedicated
updatePlannedDate endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:05:29 -05:00
5ee4c71fc1 chore: update package-lock.json with newrelic dependency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:54:12 -05:00
81908e48ea feat: add New Relic APM instrumentation to backend
Add Node.js New Relic agent with an on/off switch via NEW_RELIC_ENABLED
in .env. Uses a preload script (-r newrelic-preload.js) so the agent
loads before all other modules. Configured entirely through environment
variables — no newrelic.js config file needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:31:56 -05:00
7e6c4c16ce Update backend/src/main.ts 2026-03-02 17:56:01 -05:00
8db89373e0 Add production infrastructure: compiled builds, clustering, connection pooling
Root cause of 502 errors under 30 concurrent users: the production server
was running dev-mode infrastructure (Vite dev server, NestJS --watch,
no DB connection pooling, single Node.js process).

Changes:
- backend/Dockerfile: multi-stage prod build (compiled JS, no devDeps)
- frontend/Dockerfile: multi-stage prod build (static assets served by nginx)
- frontend/nginx.conf: SPA routing config for frontend container
- docker-compose.prod.yml: production overlay with tuned Postgres, memory
  limits, health checks, restart policies
- nginx/production.conf: keepalive upstreams, proxy buffering, rate limiting
- backend/src/main.ts: Node.js clustering (1 worker per CPU, up to 4),
  conditional request logging, production CORS
- backend/src/app.module.ts: TypeORM connection pool (max 30, min 5)
- docs/DEPLOYMENT.md: new Production Deployment section

Deploy with: docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:55:30 -05:00
063741adc7 Capital Planning: add Unscheduled bucket for imported projects without target_year
Projects imported via CSV that lack a target_year were invisible in Capital
Planning because findForPlanning() filtered on target_year IS NOT NULL. This
removes that filter and adds an "Unscheduled" Kanban column (orange background,
2-col layout) so users can drag unscheduled projects into year buckets.
Also bumps app version to 2026.3.2 (beta).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:03:39 -05:00
b0b36df4e4 Reserve health: add projected cash flow with special assessments; add Last Updated to cards
Reserve fund analysis now includes 12-month forward projection with
special assessment income (by frequency), monthly budget data,
capital project costs, and investment maturities. AI prompt updated
to evaluate projected reserve liquidity and timing risks.

Both health score dashboard cards now show a subtle "Last updated"
timestamp at the bottom.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:18:34 -05:00
aa7f2dab32 Add 12-month projected cash flow to operating health score analysis
The operating health score now includes forward-looking cash flow
projections using monthly budget data, assessment income schedules,
and operating project costs. AI prompt updated to evaluate projected
liquidity, timing risks, and year-end cash position.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:10:51 -05:00
d2d553eed6 Fix health scores: use correct invoices column name (amount, not amount_due)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:00:23 -05:00
2ca277b6e6 Phase 8: AI-driven operating and reserve fund health scores
Add daily AI health score calculation (0-100) for both operating and
reserve funds. Scores include trajectory tracking, factor analysis,
recommendations, and data readiness checks. Dashboard displays
graphical RingProgress gauges with color-coded scores, trend
indicators, and expandable detail popovers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 09:56:56 -05:00