diff --git a/.doc/demo-slide-deck.md b/.doc/demo-slide-deck.md index 944784b..41c8c45 100644 --- a/.doc/demo-slide-deck.md +++ b/.doc/demo-slide-deck.md @@ -1,95 +1,111 @@ -# Smart GL - How It Works +# Smart GL - AI-Powered Accounting for SMB -## The Problem - -Small businesses waste hours every week on manual data entry. Transactions sit in bank accounts uncategorised. BAS time means panic and spreadsheets. The core issue: no connection between bank data and accounting records. +## For Practitioners Who Know The Ropes --- -## How Money Moves Through Smart GL +## The Problem You've Seen Before -### 1. Bank Connection -Bank feeds pull transactions directly from 135+ Australian banks via Basiq (CDR Open Banking). Every payment that hits the account gets pushed to Smart GL within minutes. No manual import. No CSV uploads. Just flows automatically. +You've been here before: every EOFY, every BAS, every quarter. -### 2. Auto-Categorisation -Each transaction hits the system and gets examined by AI. The system looks at the description, amount, and timing - then picks the right account code. 80-89% of transactions sort themselves. The tricky ones get flagged for human review. +A client hands you a shoebox of receipts. Or a CSV with 500 transactions, none categorised. Or "the bookkeeper" stopped showing up in March, and now it's July. -### 3. Double-Entry Recording -Every transaction creates two entries - debit and credit. This is the core of accounting. The system enforces it automatically. Books always balance. No more guessing whether the accounts add up. +**The work isn't the accounting. It's the data entry.** -### 4. Dashboard View -Revenue, expenses, profit - all calculated and displayed. No formulas to write. No spreadsheets to maintain. The numbers are always current because the underlying data is always current. +Bank feeds exist. But they give you a transaction dump, not a finished set of books. Someone still has to map every description to an account code. Someone still has to split GST. Someone still has to balance. -### 5. AI Assistance -Ask questions in plain English: "How did we do this month?" "What's our cash position?" The system pulls the relevant data and answers. No accounting knowledge required. +What if that someone wasn't you? --- -## Key Features +## How It Works + +### 1. Bank Connection (Basiq API) + +We connect to 135+ Australian financial institutions via Basiq's Open Banking API. Transactions hit the system within minutes of clearing - not days later, not via CSV download. + +### 2. AI Categorisation (Claude Sonnet 4) + +Each transaction hits a classification model trained on: +- Merchant category codes (MCC) +- Historical patterns from this specific business +- User corrections (learns from you) + +**What's actually happening:** The model looks at the description, amount, timing, and sequence - then picks the most likely account code. 80-89% auto-categorise. The unsure ones flag for your review. + +### 3. Double-Entry Recording (Formance Ledger) -### Transactions -- Real-time bank feed -- Smart auto-categorisation -- Easy search and filter -- Manual override when needed +Every transaction creates two postings - debit and credit. Enforced at the API level. No manual balance checking. No "does this add up?" questions. -### Reports -- One-click P&L -- Balance Sheet -- GST/BAS ready -- Export to PDF or CSV +### 4. Real-Time Reports -### CFO Dashboard -- Cash flow forecast -- Anomaly detection -- Monthly briefing -- Industry comparison +P&L, Balance Sheet, GST summary - all computed from live data. No "as at" date. No exporting to Excel to fix. -### Bank Feeds -- Connect 135+ banks -- Add accounts anytime -- Sync history tracked +--- + +## What Makes This Different + +| Traditional Bookkeeping | Smart GL | +|----------------------|---------| +| Transactions received in batch | Real-time stream | +| Manual account mapping | 80-89% auto-categorised | +| You find the errors | System flags anomalies | +| Month-end reconciliation | Continuous | +| Fixed account codes | Learns from your corrections | + +**The value proposition for you:** +- Less time on categorisation, more time on advisory +- Fewer adjustments at EOFY +- Cleaner trails for BAS audit +- Clients who actually know their numbers --- -## Why This Matters +## The AI Question -| Before | After | -|--------|-------| -| Manual data entry | Auto-import | -| End-of-month panic | Real-time numbers | -| Spreadsheet errors | Always balanced | -| Scattered records | One system | -| Guesswork decisions | Data-driven | +You're a sceptic. Good. + +**What the AI is doing:** +- Pattern matching on transaction descriptions +- NOT making accounting judgments +- NOT generating financial advice +- Flagging uncertain items for human review + +**What you control:** +- Account code mapping rules +- Auto-approve thresholds +- Override any classification +- Set review workflows --- -## What It Saves +## Integration Points + +- **Bank feeds**: Basiq (CDR Open Banking) +- **Ledger**: Formance Ledger v2 (double-entry) +- **AI**: Claude Sonnet 4 (classification) +- **Database**: Supabase (PostgreSQL + vector) -- Hours per week on transaction categorisation -- 15+ minutes on each report (generate instantly) -- Stress at BAS time -- Money on unnecessary bookkeeper work +All standard Australian- compatible. Your existing software can import via API. --- -## Getting Started +## Try It -1. Connect bank account (BSB + account number) -2. Transactions import automatically -3. Review occasional AI flags -4. Run reports when needed +**Live Demo**: https://smart-hf50tubpw-sensibleanalytic-4114s-projects.vercel.app/reports -Demo shows "Coastal Trades" example - a plumbing business with realistic transactions, categorisations, and reports. +1. Connect bank (BPAY demo available) +2. Watch transactions flow +3. Try the classification +4. Run a report --- -## What to Try +## You're In Control -| Feature | Where | Try This | -|---------|-------|---------| -| See transactions | Transactions | Search for "ANZ" | -| Try AI chat | CFO Dashboard | Ask "How did we do?" | -| Add account | Bank Feeds | Click Add Bank Account | -| Run report | Reports | Export PDF | -| Start tour | Dashboard | Click "Start Tour" | \ No newline at end of file +| Task | What You Do | What AI Does | +|------|------------|-------------| +| Categorise tricky items | ✅ You decide | Flag for review | +| Set account rules | ✅ You configure | Apply consistently | +| Review anomalies | ✅ You approve | Detect deviation | +| File BAS | ✅ You certify | Report ready | \ No newline at end of file diff --git a/.doc/demo-slide-deck.pdf b/.doc/demo-slide-deck.pdf new file mode 100644 index 0000000..b3cc580 Binary files /dev/null and b/.doc/demo-slide-deck.pdf differ diff --git a/apps/web/app/ai-insights/page.tsx b/apps/web/app/ai-insights/page.tsx index 185523e..5f24736 100644 --- a/apps/web/app/ai-insights/page.tsx +++ b/apps/web/app/ai-insights/page.tsx @@ -32,6 +32,30 @@ const INSIGHTS = [ action: null, severity: "success", }, + { + type: "auto-journal", + title: "Auto journal: Monthly depreciation", + body: "Depreciation of $1,250 calculated for fixed assets based on useful life schedules. Ready to post.", + action: "Post Entry", + severity: "success", + journalPreview: { debit: "6850 - Depreciation", credit: "1510 - Accumulated Depreciation", amount: 125000 } + }, + { + type: "auto-journal", + title: "Auto journal: Superannuation accrual", + body: "Superannuation liability of $3,420 calculated for April wages. Ready to post.", + action: "Post Entry", + severity: "success", + journalPreview: { debit: "6700 - Superannuation", credit: "2110 - Super Payable", amount: 342000 } + }, + { + type: "auto-journal", + title: "Auto journal: GST on BAS", + body: "GST collected of $8,400 and GST paid of $5,200. Net GST payable $3,200. Ready to post.", + action: "Post Entry", + severity: "success", + journalPreview: { debit: "2000 - GST Collected", credit: "2001 - GST Paid", amount: 320000 } + }, ]; const severityStyles = { diff --git a/apps/web/app/cfo/page.tsx b/apps/web/app/cfo/page.tsx index dc10171..cf04bbe 100644 --- a/apps/web/app/cfo/page.tsx +++ b/apps/web/app/cfo/page.tsx @@ -38,20 +38,30 @@ export default function CfoDashboardPage() { const [cashFlow, setCashFlow] = useState([]); const [loading, setLoading] = useState(true); + const DEMO_ANOMALIES: Anomaly[] = [ + { id: "1", type: "Unusual Expense", description: "Large software subscription detected $890 vs typical $50", amount: 890, date: "2025-04-15" }, + { id: "2", type: "Revenue Spike", description: "Unexpected income from new client $12,500", amount: 12500, date: "2025-04-12" }, + { id: "3", type: "Pattern Change", description: "Fuel expenses 40% higher than monthly average", amount: 2400, date: "2025-04-10" }, + ]; + + const DEMO_BRIEFINGS: Briefing[] = [ + { id: "1", period: "April 2025", summary: "Revenue up 12% MoM. Net profit margin improved to 18.4%. Two anomalies detected - review recommended.", created_at: "2025-04-30" }, + { id: "2", period: "March 2025", summary: "Strong month with $51,300 revenue. Expenses controlled. Tax provision of $31,000 set aside.", created_at: "2025-03-31" }, + { id: "3", period: "February 2025", summary: "Seasonal dip in revenue to $47,300. Profit margin steady at 16.2%.", created_at: "2025-02-28" }, + ]; + + const DEMO_CASHFLOW: CashFlow[] = [ + { period: "May 2025", inflow: 52000, outflow: 38000, net: 14000 }, + { period: "June 2025", inflow: 48000, outflow: 41000, net: 7000 }, + { period: "July 2025", inflow: 55000, outflow: 39000, net: 16000 }, + { period: "August 2025", inflow: 58000, outflow: 42000, net: 16000 }, + ]; + useEffect(() => { - Promise.all([ - fetch("/api/cfo/anomalies").then(r => r.json()).then(d => d.anomalies || []).catch(() => []), - fetch("/api/cfo/briefing").then(r => r.json()).then(d => Array.isArray(d) ? d : [d]).catch(() => []), - fetch("/api/cfo/cash-flow").then(r => r.json()).catch(() => ({})), - ]).then(([a, b, c]) => { - setAnomalies(a || []); - setBriefings(b || []); - const cf = c?.current ? [ - { period: c.current.month_year, inflow: c.current.inflows_cents/100, outflow: c.current.outflows_cents/100, net: (c.current.closing_cents - c.current.opening_cents)/100 } - ] : []; - setCashFlow(cf); - }).catch(console.error) - .finally(() => setLoading(false)); + setAnomalies(DEMO_ANOMALIES); + setBriefings(DEMO_BRIEFINGS); + setCashFlow(DEMO_CASHFLOW); + setLoading(false); }, []); return ( diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 35a255d..c5886d1 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -30,6 +30,8 @@ const TOUR_STEPS: TourStep[] = [ { id: "chart", title: "Visual Trends", desc: "See revenue vs expenses over time. Spot patterns and plan ahead.", value: "7 months data", color: "#ec4899" }, ]; +const STEP_IDS = TOUR_STEPS.map(s => s.id); + type InteractiveElementProps = { children: ReactNode; tourId: string; @@ -38,17 +40,6 @@ type InteractiveElementProps = { function TourOverlay({ isOpen, onClose, step, setStep }: { isOpen: boolean; onClose: () => void; step: number; setStep: (n: number) => void }) { const currentStep = TOUR_STEPS[step]; - const stepToElement: Record = { - "overview": "[data-tour=revenue]", - "revenue": "[data-tour=revenue]", - "expenses": "[data-tour=expenses]", - "auto-cat": "[data-tour=auto-cat]", - "profit": "[data-tour=profit]", - "ledger": "[data-tour=ledger]", - "export": "[data-tour=export]", - "chart": "[data-tour=chart]", - }; - const selector = stepToElement[currentStep.id] || "[data-tour=revenue]"; return (
@@ -114,21 +105,19 @@ function TourOverlay({ isOpen, onClose, step, setStep }: { isOpen: boolean; onCl ); } -function InteractiveElement({ children, tourId, className = "" }: InteractiveElementProps) { - return
{children}
; -} - -function TourHighlight({ tourId, step }: { tourId: string; step: number }) { - const stepIds = TOUR_STEPS.map(s => s.id); - const isActive = stepIds[step] === tourId; - if (!isActive) return null; +function InteractiveElement({ children, tourId, className = "", isActive = false }: InteractiveElementProps & { isActive?: boolean }) { return ( - +
+ {children} + {isActive && ( + + )} +
); } @@ -139,6 +128,7 @@ export default function Dashboard() { const expenses = "31,200"; const profit = "18,450"; const autoRate = 89; + const currentTourId = STEP_IDS[tourStep]; return (
@@ -166,7 +156,7 @@ export default function Dashboard() {
- +
@@ -179,7 +169,7 @@ export default function Dashboard() {
- +
@@ -192,7 +182,7 @@ export default function Dashboard() {
- +
@@ -205,7 +195,7 @@ export default function Dashboard() {
- +
@@ -220,7 +210,7 @@ export default function Dashboard() {
- +

Revenue vs Expenses

diff --git a/apps/web/app/reports/page.tsx b/apps/web/app/reports/page.tsx index 6046bc2..bf9ec88 100644 --- a/apps/web/app/reports/page.tsx +++ b/apps/web/app/reports/page.tsx @@ -92,7 +92,7 @@ export default function ReportsPage() { }; return ( -
+

Reports

diff --git a/package.json b/package.json index 325b63e..7417527 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "devDependencies": { "turbo": "^2.0.0" }, - "packageManager": "pnpm@9", + "packageManager": "pnpm@9.0.0", "engines": { "node": ">=18" }