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>
scripts/db-backup.sh provides three commands:
- backup: creates a timestamped, gzipped pg_dump (custom format) in ./backups/
- restore: drops, recreates, and loads a backup with confirmation prompt
- list: shows available backups with sizes and dates
Supports --keep N flag for automatic pruning of backups older than N days,
making it cron-friendly for daily automated backups. Also adds backups/
and *.dump.gz to .gitignore.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers fresh server setup, environment configuration, database backup
(full and per-tenant), restore into staged environment, migration
execution, and verification steps.
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>
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>
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>
The global WriteAccessGuard was checking req.user.role, but req.user is
set by JwtAuthGuard (a per-controller guard) which runs AFTER global guards.
TenantMiddleware sets req.userRole from the JWT before guards execute,
so we now check that property first.
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>
- Wrap account interest query in subquery to avoid SUM(SUM(...)) nesting
- Replace nonexistent interest_earned column with current_value - principal
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>
TypeORM needs explicit type: 'varchar' for nullable string columns
to avoid reflecting the union type as Object.
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>
The AI was making incorrect liquidity warnings because it only saw
current cash positions and annual budget totals — it had no visibility
into the month-by-month cash flow forecast that includes:
- Special assessment collections (reserve fund income from homeowners)
- Monthly budget income/expense breakdown (not just annual totals)
- Investment maturity schedule (when CDs return cash)
- Capital project expense timing
Now the AI receives:
1. Full assessment schedule (regular + special, with frequency)
2. 12-month forward forecast with projected operating/reserve cash,
investment balances, and per-month income/expense drivers
3. Updated system prompt instructing the AI to use the forecast for
liquidity analysis rather than just current balances
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The AI recommendation endpoint calls a large language model (397B params)
which can take 60-120 seconds to respond. Nginx's default 60s proxy_read_timeout
was killing the connection before the response arrived. Added a dedicated
location block with 180s timeout for the recommendations endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add toggle-able debug logging (AI_DEBUG env var) that logs prompts,
request metadata, raw responses, parsed output, and full error chains
- Replace Node.js native fetch() with https module for Docker Alpine
compatibility (fixes "fetch failed" error with large payloads)
- Reduce max_tokens from 16384 to 4096 (qwen3.5 doesn't need thinking
token budget)
- Strip <think> blocks from model responses
- Add AI_DEBUG to docker-compose.yml and .env.example
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
kimi-k2.5 is a thinking model that times out on complex prompts (>3min).
qwen3.5-397b-a17b responds in ~2s with clean JSON output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Increase max_tokens from 4096 to 16384 to accommodate reasoning tokens
- Increase timeout from 90s to 180s for thinking model latency
- Add logging for response diagnostics (content length, reasoning, finish reason)
- Better error message when model exhausts tokens on reasoning
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>
- CSV import/export for Units, Projects, and Vendors with match-on-name/number upsert
- Cash Flow report toggle for Cash Only vs Cash + Investments
- Per-account and bulk opening balance setting with as-of date
- Interest rate field on normal accounts with estimated monthly/annual interest display
- Mobile sidebar auto-close on navigation
- Shared CSV parsing/export utility extracted to frontend/src/utils/csv.ts
DB migration needed for existing tenants:
ALTER TABLE accounts ADD COLUMN IF NOT EXISTS interest_rate DECIMAL(6,4);
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove min={0} from NumberInput to allow negative actuals (refunds/corrections)
- Fix post() in journal-entries service: use id param directly instead of
RETURNING result which returns [rows, count] in TypeORM QueryRunner
- Handle negative amounts in saveActuals(): negative expense credits the
expense account, negative income debits the income account
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add spreadsheet-style Monthly Actuals page for entering monthly actuals
against budget with auto-generated journal entries and reconciliation flag.
Add file attachment support (PDF, images, spreadsheets) on journal entries
for receipts and invoices. Enhance Budget vs Actual report with month
filter dropdown. Add reconciled badge to Transactions page. Replace bcrypt
with bcryptjs to fix Docker cross-platform native binding issues.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move Settings from sidebar Admin section to User Profile dropdown menu
- Add User Preferences page (placeholder for future: dark mode, timezone,
notifications, feature visibility)
- Add Manage Members page for tenant admins to invite/manage board members:
- List all org members with roles, status, join date, last login
- Add new members (creates user account + org membership)
- Change member roles (president, treasurer, secretary, board member,
property manager, viewer)
- Remove members (soft-deactivate)
- Role-gated: only president, admin, treasurer can manage members
- Backend: new org member management endpoints on OrganizationsController
- GET /organizations/members
- POST /organizations/members
- PUT /organizations/members/:id/role
- DELETE /organizations/members/:id
- Bump version to 0.2.0 MVP_P2 (package.json + Settings page)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Hide income, expense, and equity accounts from Accounts view — they are
internal bookkeeping managed via budget import and system operations
- Restrict Add Account form to asset and liability types plus investments
- Update summary cards to show Cash on Hand, Investments, Liabilities, Net Position
- Reports (Income Statement, Balance Sheet, Budget vs Actual, etc.) are unchanged
and continue to use all account types from their own API endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Compute annual_total on data load via hydrateBudgetLine() (was only computed on edit)
- Ensure monthly values are cast to numbers from PostgreSQL response
- Fix summary cards to use pre-computed annual_total instead of re-summing months
- Make Income/Expense section headers sticky so labels stay visible on horizontal scroll
- Split account number and name into separate columns for better readability
- Add section total in annual column for each income/expense group
- Add subtle border between frozen columns and scrollable month data
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change account_number from INTEGER to VARCHAR(50) to support segmented codes
like 30-3001-0000 used by real HOA accounting systems. Budget CSV import now:
- Auto-creates income/expense accounts from CSV when they don't exist
- Infers account_type and fund_type from account number prefix conventions
- Parses currency-formatted values ($48,065.21, $(13,000.00), $-, etc.)
- Reports created accounts back to the user
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Show investment subtable under All accounts tab (was only under Operating/Reserve)
- Add "Withdraw from primary account" switch (on by default) when creating
investments; creates a journal entry to credit the primary asset account
and debit the equity offset, keeping the books balanced
- Prevent all account modals from closing on outside click to avoid data loss
- Replace login page text title with the SVG logo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
System accounts (Operating Fund Balance, Reserve Fund Balance) are auto-created
as double-entry offsets when users set initial balances. They don't represent
real bank accounts and were confusing to see alongside actual accounts. Now
filtered from account lists, tab counts, and summary card totals. They remain
active under the covers for journal entries and are still visible on the
Balance Sheet report where equity belongs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The forecast was counting money twice: operating used asset accounts while
reserve used equity accounts, but both sides of the opening balance journal
entry represent the same funds. Changed all cash balance queries (current,
opening, and historical) to use asset accounts (debit - credit) for both
operating and reserve. Also fixed a LEFT JOIN bug where date filters on
journal_entries didn't prevent journal_entry_lines from being summed,
causing opening balances to include all entries regardless of date.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New feature: Cash Flow page under Financials showing stacked area chart of
operating/reserve cash and investment balances over time. Backend forecast
endpoint integrates assessment income schedules, budget expenses, capital
project costs, and investment maturities to project 24+ months forward.
Historical months show actual journal entry balances; future months are
projected. Includes Operating/Reserve/All fund filter, 12-month sliding
window navigation, forecast reference line, and monthly detail table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Removed standalone Investments tab — investment accounts now show only
under their respective Operating/Reserve tabs with full detail columns
- Investment sub-tables now include: Principal, Current Value, Rate,
Interest Earned, Maturity Value, Maturity Date, Days Remaining, plus
summary cards (Total Principal, Total Current Value, Avg Rate)
- Added investment edit capability via modal (name, institution, type,
fund, principal, current value, rate, purchase/maturity dates, notes)
- Fixed primary account star icon — now shows for all non-system accounts
(was previously restricted to asset type only), allowing users to set
default Operating and Reserve accounts regardless of account type
- Fixed Adjust Balance icon to also show for all non-system accounts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Investment accounts now appear under their respective Operating/Reserve
tabs in the Accounts page, with a compact sub-table showing name, type,
institution, principal/value, rate, interest earned, and maturity info
- Investment values (current_value) are included in dashboard Total Cash KPI
- Reserve investment values are added to Reserve Fund Balance KPI and
project funded percentage calculations
- Year-end report reserve status now includes reserve investment values
- Tab counts updated to include investment accounts per fund type
- Summary cards show separate "asset (investments)" total for visibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Dashboard reserve fund KPI now uses reserve equity accounts (fund balance
position) instead of asset accounts, correctly showing the total reserve
fund balance regardless of how users categorize their reserve accounts
- Projects findAll() and findForPlanning() dynamically compute funded_percentage
and current_fund_balance from reserve equity account balances via CTE,
distributing the total reserve balance proportionally across projects
- Year-end summary reserve status now queries unified projects table instead
of deprecated reserve_components table
- Remove standalone Monthly Assessment field from Units form — assessment
amount is now inherited from the selected assessment group
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: multiple issues with balance computation across the system.
Accounts list:
- findAll() was doing SELECT * FROM accounts, returning the stale
denormalized `balance` column (always 0). Now computes balances from
journal entries using proper double-entry logic (debit-credit for
assets/expenses, credit-debit for liabilities/equity/income).
Dashboard KPIs:
- Total Cash filtered by name LIKE '%Cash%' which missed accounts not
named "Cash". Now queries ALL asset accounts regardless of name.
- Reserve Fund queried the legacy reserve_components.current_fund_balance
column. Now computes from journal entries on reserve asset accounts.
Opening balance journal entries:
- On blank tenants, equity offset accounts (3000/3100) don't exist, so
the balancing journal entry line was silently skipped, leaving entries
unbalanced. Now auto-creates Operating Fund Balance (3000) and Reserve
Fund Balance (3100) equity accounts when needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix account creation initial balance bug: the INSERT RETURNING result
was not being unwrapped correctly from TypeORM's array response, causing
account.id to be undefined and journal entry lines to have $0 amounts.
Now uses findOne() after insert for reliable ID retrieval.
- Add missing balancing equity entry line (debit/credit to account 3000/3100)
so opening balance journal entries are proper double-entry
- Fix account update to use findOne() instead of RETURNING * for consistent
response format
- Add investment account creation to Accounts page: account type dropdown now
shows a separator followed by investment types (CD, Money Market, Treasury,
Savings, Brokerage). Selecting an investment type expands the modal to show
investment-specific fields (institution, principal, interest rate, purchase
date, maturity date, account last 4, notes) and posts to /investment-accounts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Unify reserve_components + capital_projects into single projects model with
full CRUD backend and new Projects page frontend
- Rewrite Capital Planning to read from unified projects/planning endpoint;
add empty state directing users to Projects page when no planning items exist
- Add default designation to assessment groups with auto-set on first creation;
units now require an assessment group (pre-populated with default)
- Add primary account designation (one per fund type) and balance adjustment
via journal entries against equity offset accounts (3000/3100)
- Add computed investment fields (interest earned, maturity value, days remaining)
with PostgreSQL date arithmetic fix for DATE - DATE integer result
- Restructure sidebar: investments in Accounts tab, Year-End under Reports,
Planning section with Projects and Capital Planning
- Fix new tenant creation seeding unwanted default chart of accounts —
new tenants now start with a blank slate
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Admin panel: create tenants with org + first user, manage org status
(active/suspended/archived), contract number and plan level fields
- Units: delete with invoice check, assessment group dropdown binding
- Assessment groups: frequency field (monthly/quarterly/annual) with
income calculations normalized to monthly equivalents
- Sidebar: grouped nav sections (Financials, Assessments, Transactions,
Planning, Reports, Admin), renamed Chart of Accounts to Accounts
- Header: replaced text with SVG logo
- Capital projects: Kanban as default view, table-only PDF export,
Future category (beyond 5-year plan)
- Auth: block login for suspended/archived organizations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add hierarchical roles: SuperUser Admin (is_superadmin flag), Tenant Admin,
Tenant User with separate /admin route and admin panel
- Add Assessment Groups module for property type-based assessment rates
(SFHs, Condos, Estate Lots with different regular/special rates)
- Enhance Chart of Accounts: initial balance on create (with journal entry),
archive/restore accounts, edit all fields including account number & fund type
- Add Budget CSV import with downloadable template and account mapping
- Add Capital Projects Kanban board with drag-and-drop between year columns,
table/kanban view toggle, and PDF export via browser print
- Update seed data with assessment groups, second test user, superadmin flag
- Create repeatable reseed.sh script for clean database population
- Fix AgingReportPage Mantine v7 Table prop compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename app from "HOA Financial Platform" to "HOA LedgerIQ" across all
frontend pages, backend API docs, package.json files, and seed data
- Add Cash Flow Statement report (GET /reports/cash-flow) with operating
and reserve fund activity breakdown, beginning/ending cash balances
- Add Aging Report (GET /reports/aging) with per-unit aging buckets
(current, 1-30, 31-60, 61-90, 90+ days), expandable invoice details
- Add Year-End Package (GET /reports/year-end) with income statement
summary, collection stats, 1099-NEC vendor report, reserve fund status
- Add Settings page showing org info, user profile, and system details
- Replace all PlaceholderPage references with real implementations
- Bump auth store version to 3 for localStorage migration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>