- 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>
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>
- 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>
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>
- 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>
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>
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>
- 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>
- 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>
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>
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>
- 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>
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>
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>
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>
- 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>
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>
- 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>
- 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>
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>
- Frontend container nginx listens on 3001 instead of 80 to avoid
conflicts with the host-level reverse proxy
- Removed certbot service, volumes, and SSL config from
docker-compose.prod.yml — SSL/certbot is managed at the host level
- Updated nginx/production.conf: HTTP-only (host handles TLS),
upstream frontend points to port 3001
- Updated nginx/ssl.conf frontend upstream to 3001 for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
The package was imported by AppTour.tsx but missing from package.json,
causing a build failure on fresh installs / production deploys.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Projects with target years beyond the 5-year planning window now
appear in the Future column of the Kanban board (previously they
were invisible). Cards for these projects show their specific target
year as a badge. The Future column uses a 2-column grid layout when
it has more than 3 projects to maximize screen utilization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
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>
- Add global WriteAccessGuard that blocks POST/PUT/PATCH/DELETE for viewer role
- Add @AllowViewer() decorator for endpoints viewers need (switch-org, intro-seen, AI recommendations)
- Add useIsReadOnly hook to auth store for frontend role checks
- Hide write UI (add/edit/delete/import buttons, inline editors) in all 13 data pages for viewers
- Disable inline NumberInputs on Budgets and Monthly Actuals pages for viewers
- Skip onboarding wizard for viewer role users
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Dashboard: Remove tenant name/role subtitle
- Cash Flow: Replace Operating/Reserve net cards with inflow vs outflow
breakdown showing In/Out amounts and signed net; replace Ending Cash
card with AI Financial Health status from saved recommendation
- Accounts: Auto-set first asset account per fund_type as primary on creation
- Investments: Add 5th summary card for projected annual interest earnings
- Sankey: Add Actuals/Budget/Forecast data source toggle and
All Funds/Operating/Reserve fund filter SegmentedControls with
backend support for budget-based and forecast (actuals+budget) queries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Feature 1 - How-To Intro Tour (react-joyride):
- 8-step guided walkthrough highlighting Dashboard, Accounts, Assessments,
Transactions, Budgets, Reports, and AI Investment Planning
- Runs automatically on first login, tracked via has_seen_intro flag on user
- Centralized step config in config/tourSteps.ts for easy text editing
- data-tour attributes on Sidebar nav items and Dashboard for targeting
Feature 2 - Tenant Onboarding Wizard:
- 3-step modal wizard: create operating account, assessment group + units,
import budget CSV
- Runs after tour completes, tracked via onboardingComplete in org settings JSONB
- Reuses existing API endpoints (POST /accounts, /assessment-groups, /units,
/budgets/:year/import)
Backend changes:
- Add has_seen_intro column to shared.users + migration
- Add PATCH /auth/intro-seen endpoint to mark tour complete
- Add PATCH /organizations/settings endpoint for org settings updates
- Include hasSeenIntro in login response, settings in switch-org response
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Accounts page: include investment accounts in Est. Monthly Interest calc,
add Fund column to investment table, split summary cards into Operating/Reserve
- Fix Cash Flow: ending balance now respects includeInvestments toggle
- Fix Budget Manager: separate operating/reserve income in summary cards
- Fix Projects: default sort by planned_date instead of name
- Add Vendors: last_negotiated date field with migration, CSV import/export
- New Quarterly Financial Report: budget vs actuals, over-budget flagging, YTD
- Enhance Dashboard: separate Operating/Reserve fund cards, expanded Quick Stats
with monthly interest, YTD interest earned, planned capital spend
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rate fetcher now scrapes CD, Money Market, and High Yield Savings rates
from Bankrate.com with pauses between fetches to avoid rate limiting
- Historical rate data is preserved (no longer deleted on each fetch)
- Database migration adds rate_type column and tenant ai_recommendations table
- Backend returns market rates grouped by type with latest-batch-only queries
- AI prompt now includes all three rate types for comprehensive analysis
- AI recommendations are saved per-tenant for retrieval on page load
- Frontend: "Market CD Rates" replaced with "Today's Market Rates" tabbed view
- Rates section is collapsible (expanded by default) to save screen space
- Saved recommendations load automatically with "Last Updated" timestamp
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enhancement 1 - Block suspended/archived org access:
- Add org status check in switchOrganization() (auth.service.ts)
- Filter suspended/archived orgs from login response (generateTokenResponse)
- Add org status guard with 60s cache in TenantMiddleware
- Frontend: filter orgs in SelectOrgPage, add 403 handler in api.ts
Enhancement 2 - Change tenant plan level:
- Add updatePlanLevel() to organizations.service.ts
- Add PUT /admin/organizations/:id/plan endpoint
- Frontend: clickable plan dropdown in Organizations table + confirmation modal
- Plan level Select in tenant detail drawer
Enhancement 3 - User impersonation:
- Add impersonateUser() to auth.service.ts with impersonatedBy JWT claim
- Add POST /admin/impersonate/:userId endpoint
- Frontend: Impersonate button in Users tab (disabled for admins)
- Impersonation state management in authStore (start/stop/persist)
- Orange impersonation banner in AppLayout header with stop button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Database: Add login_history, ai_recommendation_log tables; is_platform_owner
column on users; subscription fields on organizations (payment_date,
confirmation_number, renewal_date)
- Backend: New AdminAnalyticsService with platform metrics, tenant detail, and
health score calculations (0-100 based on activity, budget, transactions,
members, AI usage)
- Backend: Login/org-switch now records to login_history; AI recommendations
logged to ai_recommendation_log; platform owner protected from superadmin toggle
- Frontend: 4-tab admin panel (Dashboard, Organizations, Users, Tenant Health)
with tenant detail drawer, subscription management, health scoring visualization
- Platform owner account (admin@hoaledgeriq.com) auto-redirects to admin panel
- Seed data includes platform owner account and sample login history
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add shared.cd_rates table for cross-tenant market data (CD rates from Bankrate)
- Create standalone Puppeteer scraper script (scripts/fetch-cd-rates.ts) for cron-based rate fetching
- Add investment-planning backend module with 3 endpoints: snapshot, cd-rates, recommendations
- AI service gathers tenant financial data (accounts, investments, budgets, projects, cash flow) and calls OpenAI-compatible API (NVIDIA endpoint) for structured investment recommendations
- Create InvestmentPlanningPage with summary cards, current investments table, market CD rates table, and AI recommendation accordion
- Add Investment Planning to sidebar under Planning menu
- Configure AI_API_URL, AI_API_KEY, AI_MODEL environment variables
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix monthly actuals showing same data for all months (SQL JOIN excluded
month filter from SUM — added je.id IS NOT NULL guard)
- Fix units displaying $0 assessment by reading from assessment group
instead of stale unit field; add special assessment column
- Replace proportional project funding with priority-based sequential
allocation — near-term items get fully funded first; add is_funding_locked
flag so users can manually lock a project's fund balance
- Remove post-creation opening balance UI (keep only initial balance on
account creation); remove redundant Fund filter dropdown from Accounts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>