Initial commit: HOA Financial Intelligence Platform MVP

Multi-tenant financial management platform for homeowner associations featuring:
- NestJS backend with 16 modules (auth, accounts, transactions, budgets, units,
  invoices, payments, vendors, reserves, investments, capital projects, reports)
- React + Mantine frontend with dashboard, CRUD pages, and financial reports
- Schema-per-tenant PostgreSQL isolation with JWT-based tenant resolution
- Docker Compose infrastructure (nginx, backend, frontend, postgres, redis)
- Comprehensive seed data for Sunrise Valley HOA demo
- 39 API endpoints with Swagger documentation
- Double-entry bookkeeping with journal entries
- Budget vs actual reporting and Sankey cash flow visualization

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-17 19:58:04 -05:00
commit 243770cea5
118 changed files with 8569 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
import { NavLink, ScrollArea } from '@mantine/core';
import { useNavigate, useLocation } from 'react-router-dom';
import {
IconDashboard,
IconListDetails,
IconReceipt,
IconHome,
IconFileInvoice,
IconCash,
IconReportAnalytics,
IconChartSankey,
IconShieldCheck,
IconPigMoney,
IconBuildingBank,
IconCalendarEvent,
IconUsers,
IconFileText,
IconSettings,
} from '@tabler/icons-react';
const navItems = [
{ label: 'Dashboard', icon: IconDashboard, path: '/dashboard' },
{ label: 'Chart of Accounts', icon: IconListDetails, path: '/accounts' },
{ label: 'Transactions', icon: IconReceipt, path: '/transactions' },
{ label: 'Units / Homeowners', icon: IconHome, path: '/units' },
{ label: 'Invoices', icon: IconFileInvoice, path: '/invoices' },
{ label: 'Payments', icon: IconCash, path: '/payments' },
{ label: 'Budgets', icon: IconReportAnalytics, path: '/budgets/2026' },
{
label: 'Reports',
icon: IconChartSankey,
children: [
{ label: 'Balance Sheet', path: '/reports/balance-sheet' },
{ label: 'Income Statement', path: '/reports/income-statement' },
{ label: 'Cash Flow', path: '/reports/cash-flow' },
{ label: 'Budget vs Actual', path: '/reports/budget-vs-actual' },
{ label: 'Aging Report', path: '/reports/aging' },
{ label: 'Sankey Diagram', path: '/reports/sankey' },
],
},
{ label: 'Reserves', icon: IconShieldCheck, path: '/reserves' },
{ label: 'Investments', icon: IconPigMoney, path: '/investments' },
{ label: 'Capital Projects', icon: IconBuildingBank, path: '/capital-projects' },
{ label: 'Vendors', icon: IconUsers, path: '/vendors' },
{ label: 'Year-End', icon: IconFileText, path: '/year-end' },
{ label: 'Settings', icon: IconSettings, path: '/settings' },
];
export function Sidebar() {
const navigate = useNavigate();
const location = useLocation();
return (
<ScrollArea p="sm">
{navItems.map((item) =>
item.children ? (
<NavLink
key={item.label}
label={item.label}
leftSection={<item.icon size={18} />}
defaultOpened={item.children.some((c) =>
location.pathname.startsWith(c.path),
)}
>
{item.children.map((child) => (
<NavLink
key={child.path}
label={child.label}
active={location.pathname === child.path}
onClick={() => navigate(child.path)}
/>
))}
</NavLink>
) : (
<NavLink
key={item.path}
label={item.label}
leftSection={<item.icon size={18} />}
active={location.pathname === item.path}
onClick={() => navigate(item.path!)}
/>
),
)}
</ScrollArea>
);
}