Commit Graph

116 Commits

Author SHA1 Message Date
9cd641923d feat: enterprise pricing shows "Request Quote" linking to interest form
Enterprise plan no longer displays a fixed price. Instead it shows
"Request Quote" and the CTA opens the interest form on hoaledgeriq.com
in a new tab to capture leads for custom quotes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 07:47:19 -04:00
af68304692 feat: sidebar reorg, compact view preference, and UI polish
- Remove redundant Settings link from sidebar (accessible via user menu)
- Move Transactions section below Board Reference for better grouping
- Promote Investment Scenarios to its own top-level sidebar item
- Add Compact View preference with tighter spacing theme
- Wire compact theme into MantineProvider with dynamic switching
- Enable Compact View toggle in both Preferences and Settings pages
- Install missing @simplewebauthn/browser package (lock file update)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 06:39:41 -04:00
20438b7ef5 docs: add payment, onboarding, and auth reference guide
Covers Stripe billing flow, provisioning pipeline, activation magic links,
onboarding checklist, refresh tokens, MFA, SSO, passkeys, env var reference,
manual intervention checklist, and full API endpoint reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 06:24:59 -04:00
e9738420ea fix: swap Quick Stats and Recent Transactions on dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:21:15 -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
1d1073cba1 style: add white glow outline to logo in dark mode
Use CSS drop-shadow filter on the logo img in dark mode to create a
subtle white outline that helps the transparent-background logo stand
out against the dark header and login page backgrounds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 15:02:04 -04:00
cf061c1505 fix: Budget Manager shows stale data when switching years
The budgetData was stored in a separate useState and updated inside
queryFn. When switching years, React Query served cached data with
isLoading=false but the local state still held the previous year's
data, causing the "no budget" empty state to flash intermittently.

Fix: Use query data directly as source of truth. Local state (editData)
is only used when actively editing. Added a small spinner indicator
when refetching in the background.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 14:59:46 -04:00
5ebfc4f3aa chore: replace SVG logo with transparent-background PNG for dark theme support
- Add new logo.png (2090x512) with transparent background
- Update AppLayout and LoginPage imports from .svg to .png
- Old SVG had opaque background that clashed with dark theme

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 14:52:46 -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
b13fbfe8c7 Merge branch 'claude/ecstatic-elgamal' 2026-03-13 14:52:59 -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
9a082d2950 Merge branch 'claude/ecstatic-elgamal' 2026-03-13 14:41:20 -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
8e2456dcae Merge branch 'claude/ecstatic-elgamal' 2026-03-11 15:51:12 -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
2de0cde94c Merge branch 'claude/ecstatic-elgamal' 2026-03-11 15:47:02 -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
f47fbfcf93 Merge branch 'claude/ecstatic-elgamal' 2026-03-11 15:42:24 -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
208c1dd7bc 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:32:51 -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
a047144922 Added userID and URL to Chatwoot Script 2026-03-10 14:49:50 -04:00
508a86d16c fix: resolve Vite parse5 HTML error in index.html
Fix malformed Chatwoot chat widget script that caused Vite's parse5
HTML parser to throw "eof-in-element-that-can-contain-only-text".
Also fix broken URL (https// -> https://) for the chat widget.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:32:35 -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
6bd080f8c4 Merge branch 'claude/practical-rhodes' 2026-03-10 14:22:14 -04:00
be3a5191c5 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-10 14:22:08 -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
7d4df25d16 Update frontend/index.html 2026-03-09 14:17:04 -04:00
538828b91a Merge pull request 'fix: dark mode styling across 5 pages' (#4) from fix/dark-mode-styling into main 2026-03-09 14:04:50 -04:00
14160854b9 fix: resolve hardcoded light backgrounds breaking dark mode across 5 pages
Replace hardcoded light colors (#e6f9e6, #fde8e8, white, #e9ecef) with
theme-aware alternatives using usePreferencesStore. Affected pages:
- CashFlowForecastPage: forecast row and striped row backgrounds
- MonthlyActualsPage: sticky column backgrounds, borders, section headers
- BudgetsPage: sticky column backgrounds, borders, section headers
- BudgetVsActualPage: income/expense section header backgrounds
- QuarterlyReportPage: income/expense and total row backgrounds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 14:02:46 -04:00
36d486d78c Add Chat Widget for support
added support chat widget to index.html
2026-03-09 13:31:17 -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
4759374883 feat: add dark mode with persistent user preference
Add dark mode support using Mantine's built-in color scheme system,
persisted via a new Zustand preferences store. Includes a quick toggle
in the app header and an enabled switch in User Preferences. Also
removes the "AI Health Scores" title from the dashboard to reclaim
vertical space.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:36:11 -04:00
cb6e34d5ce feat: add password reset utility script
Usage: ./scripts/reset-password.sh <email> <new-password>
Generates bcrypt hash via bcryptjs in the backend container,
updates the database, and verifies the hash matches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:19:22 -05: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
c429dcc033 Merge pull request 'fix: improve AI health score accuracy and consistency' (#1) from ai-improvements into main
Reviewed-on: #1
2026-03-06 14:44:39 -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
3790a3bd9e docs: add scaling guide for production infrastructure
Covers vertical tuning, managed service offloading, horizontal scaling
with replicas, and multi-node strategies. Includes resource budgets for
the current 4-core/24GB VM, monitoring thresholds for New Relic alerts,
PostgreSQL/Redis tuning values, and a scaling decision tree.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:06:22 -05:00