From 7dc3d6c3fb59a3ea100a40c767f57fb624235f03 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:06:39 +0000 Subject: [PATCH 1/7] Initial plan From 1669e8f66968c736601dc287528ef1fb2d5a1d56 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:11:29 +0000 Subject: [PATCH 2/7] Add advanced bank statement example with deep financial insights Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com> --- .../json/bank-statement-advanced.idoc.json | 905 ++++++++++++++++++ 1 file changed, 905 insertions(+) create mode 100644 packages/web-deploy/json/bank-statement-advanced.idoc.json diff --git a/packages/web-deploy/json/bank-statement-advanced.idoc.json b/packages/web-deploy/json/bank-statement-advanced.idoc.json new file mode 100644 index 00000000..3f9bac7a --- /dev/null +++ b/packages/web-deploy/json/bank-statement-advanced.idoc.json @@ -0,0 +1,905 @@ +{ + "$schema": "../../../docs/schema/idoc_v1.json", + "title": "Advanced Personal Financial Dashboard", + "style": { + "css": [ + "body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }", + "body { display: grid; grid-template-areas: 'header header header' 'summary metrics insights' 'trends spending budget' 'merchants patterns categories' 'transactions transactions transactions'; grid-template-columns: 1fr 1fr 1fr; gap: 20px; max-width: 1600px; margin: 0 auto; }", + ".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }", + "#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }", + "#summary { grid-area: summary; text-align: center; min-width: 0; overflow: hidden; }", + "#metrics { grid-area: metrics; min-width: 0; overflow: hidden; }", + "#insights { grid-area: insights; min-width: 0; overflow: hidden; }", + "#trends { grid-area: trends; min-width: 0; overflow: hidden; }", + "#spending { grid-area: spending; min-width: 0; overflow: hidden; }", + "#budget { grid-area: budget; min-width: 0; overflow: hidden; }", + "#merchants { grid-area: merchants; min-width: 0; overflow: hidden; }", + "#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }", + "#categories { grid-area: categories; min-width: 0; overflow: hidden; }", + "#transactions { grid-area: transactions; min-width: 0; overflow: hidden; }", + "h1 { margin: 0; padding: 20px 0; font-size: 2em; font-weight: 600; }", + "h2 { margin: 10px 0; font-size: 2em; color: #2d3748; font-weight: 600; }", + "h3 { margin: 0 0 15px 0; font-size: 1.2em; color: #4a5568; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }", + ".tabulator { max-width: 100%; overflow: auto; }", + ".tabulator .tabulator-table { min-width: fit-content; }", + ".metric { text-align: center; margin: 10px 0; padding: 15px; background: #f7fafc; border-radius: 8px; border-left: 4px solid #3182ce; }", + ".metric .value { font-size: 1.5em; font-weight: bold; color: #2d3748; }", + ".metric .label { font-size: 0.9em; color: #718096; text-transform: uppercase; letter-spacing: 0.5px; }", + ".positive { color: #38a169; }", + ".negative { color: #e53e3e; }", + ".warning { color: #d69e2e; }", + ".slider-container { margin: 15px 0; }", + ".slider-label { font-weight: 500; color: #2d3748; margin-bottom: 8px; display: block; }", + "@media (max-width: 1200px) { body { grid-template-columns: 1fr 1fr; grid-template-areas: 'header header' 'summary metrics' 'insights trends' 'spending budget' 'merchants patterns' 'categories categories' 'transactions transactions'; } }", + "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'metrics' 'insights' 'trends' 'spending' 'budget' 'merchants' 'patterns' 'categories' 'transactions'; } }" + ] + }, + "dataLoaders": [ + { + "dataSourceName": "transactions", + "type": "inline", + "format": "csv", + "content": [ + "date,description,category,amount,type,merchant", + "2024-01-02,Salary Deposit,Income,3500.00,income,Employer", + "2024-01-03,Rent Payment,Housing,-1200.00,expense,Property Management Co", + "2024-01-04,Grocery Store,Food,-85.50,expense,Whole Foods", + "2024-01-05,Gas Station,Transportation,-45.00,expense,Shell", + "2024-01-06,Coffee Shop,Food,-12.75,expense,Starbucks", + "2024-01-08,Electric Bill,Utilities,-89.99,expense,ConEd", + "2024-01-10,Movie Tickets,Entertainment,-28.00,expense,AMC Theaters", + "2024-01-12,Pharmacy,Healthcare,-25.99,expense,CVS Pharmacy", + "2024-01-14,Online Shopping,Shopping,-67.89,expense,Amazon", + "2024-01-15,Freelance Project,Income,850.00,income,Client ABC", + "2024-01-16,Restaurant,Food,-42.50,expense,Local Bistro", + "2024-01-18,Internet Bill,Utilities,-59.99,expense,Comcast", + "2024-01-20,Gym Membership,Health,-29.99,expense,Planet Fitness", + "2024-01-22,Grocery Store,Food,-92.34,expense,Whole Foods", + "2024-01-24,Car Insurance,Transportation,-125.00,expense,Geico", + "2024-01-25,Clothing Store,Shopping,-89.99,expense,H&M", + "2024-01-26,Savings Transfer,Savings,-500.00,transfer,Savings Account", + "2024-01-28,Gas Station,Transportation,-38.75,expense,Shell", + "2024-01-30,Phone Bill,Utilities,-45.00,expense,Verizon", + "2024-02-01,Coffee Shop,Food,-8.50,expense,Starbucks", + "2024-02-03,Subscription,Entertainment,-15.99,expense,Netflix", + "2024-02-05,Grocery Store,Food,-78.25,expense,Trader Joes", + "2024-02-07,Restaurant,Food,-65.00,expense,Local Bistro", + "2024-02-10,Gas Station,Transportation,-42.30,expense,Exxon", + "2024-02-12,Online Shopping,Shopping,-125.50,expense,Amazon", + "2024-02-14,Date Night,Entertainment,-95.00,expense,Fine Dining", + "2024-02-16,Freelance Project,Income,750.00,income,Client XYZ", + "2024-02-18,Pharmacy,Healthcare,-18.75,expense,Walgreens", + "2024-02-20,Coffee Shop,Food,-11.25,expense,Local Cafe", + "2024-02-22,Grocery Store,Food,-89.50,expense,Whole Foods", + "2024-02-25,Clothing Store,Shopping,-145.99,expense,Target", + "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell" + ] + }, + { + "dataSourceName": "categoryBudgets", + "type": "inline", + "format": "csv", + "content": [ + "category,budgetAmount,color", + "Housing,1200,#667eea", + "Food,400,#764ba2", + "Transportation,300,#f093fb", + "Utilities,250,#4ecdc4", + "Entertainment,200,#45b7d1", + "Healthcare,150,#96ceb4", + "Shopping,200,#feca57", + "Health,50,#ff9ff3", + "Savings,600,#54a0ff" + ] + } + ], + "variables": [ + { + "variableId": "selectedTimeframe", + "type": "string", + "initialValue": "All Time" + }, + { + "variableId": "totalIncome", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'income'" + }, + { + "type": "aggregate", + "ops": ["sum"], + "fields": ["amount"], + "as": ["total"] + } + ] + } + }, + { + "variableId": "totalExpenses", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "aggregate", + "ops": ["sum"], + "fields": ["amount"], + "as": ["total"] + } + ] + } + }, + { + "variableId": "totalSavings", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'transfer' && datum.category === 'Savings'" + }, + { + "type": "aggregate", + "ops": ["sum"], + "fields": ["amount"], + "as": ["total"] + } + ] + } + }, + { + "variableId": "currentBalance", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "aggregate", + "ops": ["sum"], + "fields": ["amount"], + "as": ["total"] + } + ] + } + }, + { + "variableId": "expensesByCategory", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "aggregate", + "groupby": ["category"], + "ops": ["sum", "count"], + "fields": ["absAmount", "absAmount"], + "as": ["totalAmount", "transactionCount"] + } + ] + } + }, + { + "variableId": "budgetComparison", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["expensesByCategory", "categoryBudgets"], + "dataFrameTransformations": [ + { + "type": "lookup", + "from": "categoryBudgets", + "key": "category", + "fields": ["budgetAmount", "color"], + "as": ["budget", "color"] + }, + { + "type": "formula", + "expr": "datum.totalAmount - datum.budget", + "as": "variance" + }, + { + "type": "formula", + "expr": "datum.totalAmount / datum.budget", + "as": "percentOfBudget" + }, + { + "type": "formula", + "expr": "datum.budget - datum.totalAmount", + "as": "remaining" + } + ] + } + }, + { + "variableId": "topMerchants", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "aggregate", + "groupby": ["merchant"], + "ops": ["sum", "count"], + "fields": ["absAmount", "absAmount"], + "as": ["totalSpent", "visitCount"] + }, + { + "type": "window", + "ops": ["rank"], + "fields": [null], + "as": ["rank"], + "sort": [{"field": "totalSpent", "order": "descending"}] + }, + { + "type": "filter", + "expr": "datum.rank <= 10" + } + ] + } + }, + { + "variableId": "dailySpending", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "formula", + "expr": "datetime(datum.date)", + "as": "dateTime" + }, + { + "type": "formula", + "expr": "day(datum.dateTime)", + "as": "dayOfWeek" + }, + { + "type": "aggregate", + "groupby": ["date"], + "ops": ["sum"], + "fields": ["absAmount"], + "as": ["dailyTotal"] + } + ] + } + }, + { + "variableId": "weeklySpending", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "formula", + "expr": "datetime(datum.date)", + "as": "dateTime" + }, + { + "type": "formula", + "expr": "week(datum.dateTime)", + "as": "weekOfYear" + }, + { + "type": "aggregate", + "groupby": ["weekOfYear"], + "ops": ["sum"], + "fields": ["absAmount"], + "as": ["weeklyTotal"] + } + ] + } + }, + { + "variableId": "spendingByDayOfWeek", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "formula", + "expr": "datetime(datum.date)", + "as": "dateTime" + }, + { + "type": "formula", + "expr": "day(datum.dateTime)", + "as": "dayOfWeek" + }, + { + "type": "formula", + "expr": "datum.dayOfWeek === 0 ? 'Sunday' : datum.dayOfWeek === 1 ? 'Monday' : datum.dayOfWeek === 2 ? 'Tuesday' : datum.dayOfWeek === 3 ? 'Wednesday' : datum.dayOfWeek === 4 ? 'Thursday' : datum.dayOfWeek === 5 ? 'Friday' : 'Saturday'", + "as": "dayName" + }, + { + "type": "aggregate", + "groupby": ["dayOfWeek", "dayName"], + "ops": ["sum", "count"], + "fields": ["absAmount", "absAmount"], + "as": ["totalSpent", "transactionCount"] + } + ] + } + }, + { + "variableId": "formattedIncome", + "type": "string", + "initialValue": "$0.00", + "calculation": { + "vegaExpression": "'$' + format(length(data('totalIncome')) > 0 ? data('totalIncome')[0].total : 0, ',.2f')" + } + }, + { + "variableId": "formattedExpenses", + "type": "string", + "initialValue": "$0.00", + "calculation": { + "vegaExpression": "'$' + format(abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0), ',.2f')" + } + }, + { + "variableId": "formattedBalance", + "type": "string", + "initialValue": "$0.00", + "calculation": { + "vegaExpression": "'$' + format(length(data('currentBalance')) > 0 ? data('currentBalance')[0].total : 0, ',.2f')" + } + }, + { + "variableId": "formattedSavings", + "type": "string", + "initialValue": "$0.00", + "calculation": { + "vegaExpression": "'$' + format(abs(length(data('totalSavings')) > 0 ? data('totalSavings')[0].total : 0), ',.2f')" + } + }, + { + "variableId": "savingsRate", + "type": "string", + "initialValue": "0%", + "calculation": { + "vegaExpression": "format((abs(length(data('totalSavings')) > 0 ? data('totalSavings')[0].total : 0) / (length(data('totalIncome')) > 0 ? data('totalIncome')[0].total : 1)) * 100, '.1f') + '%'" + } + }, + { + "variableId": "avgDailySpending", + "type": "string", + "initialValue": "$0.00", + "calculation": { + "vegaExpression": "'$' + format((abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0) / 30), ',.2f')" + } + } + ], + "groups": [ + { + "groupId": "header", + "elements": [ + "# 💰 Advanced Personal Financial Dashboard", + "**Deep insights into your spending habits and financial patterns**" + ] + }, + { + "groupId": "summary", + "elements": [ + "### 📊 Financial Overview", + "", + "**Total Income:** {{formattedIncome}}", + "**Total Expenses:** {{formattedExpenses}}", + "**Current Balance:** {{formattedBalance}}", + "**Total Savings:** {{formattedSavings}}", + "", + "#### Quick Stats", + { + "type": "tabulator", + "dataSourceName": "expensesByCategory", + "editable": false, + "cssClass": "compact-table", + "tabulatorOptions": { + "layout": "fitColumns", + "headerSort": false, + "initialSort": [ + {"column": "totalAmount", "dir": "desc"} + ], + "columns": [ + { + "title": "Category", + "field": "category", + "sorter": "string" + }, + { + "title": "Total", + "field": "totalAmount", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + }, + { + "title": "Transactions", + "field": "transactionCount", + "sorter": "number" + } + ] + } + } + ] + }, + { + "groupId": "metrics", + "elements": [ + "### 🎯 Key Metrics", + "", + "
", + "
{{savingsRate}}
", + "
Savings Rate
", + "
", + "", + "
", + "
{{avgDailySpending}}
", + "
Avg Daily Spending
", + "
", + "", + "#### Financial Health", + "- **Expense Ratio:** High spending in Food and Housing", + "- **Saving Behavior:** Regular savings transfers detected", + "- **Income Diversity:** Salary + Freelance income" + ] + }, + { + "groupId": "insights", + "elements": [ + "### 🔍 Smart Insights", + "", + "**Top Spending Categories:**", + "1. Housing ({{formattedExpenses}} of expenses)", + "2. Food & Dining (frequent purchases)", + "3. Transportation (regular fuel costs)", + "", + "**Spending Patterns:**", + "- Most active merchant: Starbucks (frequent coffee purchases)", + "- Grocery shopping: Mostly Whole Foods", + "- Regular bills: Utilities paid on time", + "", + "**Recommendations:**", + "- Consider bulk coffee purchases to reduce café visits", + "- Monitor entertainment spending trends", + "- Great job on consistent savings!" + ] + }, + { + "groupId": "trends", + "elements": [ + "### 📈 Spending Trends", + { + "type": "chart", + "chartKey": "dailySpendingTrend" + } + ] + }, + { + "groupId": "spending", + "elements": [ + "### 🥧 Category Breakdown", + { + "type": "chart", + "chartKey": "expensesPieChart" + } + ] + }, + { + "groupId": "budget", + "elements": [ + "### 🎯 Budget vs Actual", + { + "type": "tabulator", + "dataSourceName": "budgetComparison", + "editable": false, + "tabulatorOptions": { + "layout": "fitColumns", + "columns": [ + { + "title": "Category", + "field": "category", + "sorter": "string" + }, + { + "title": "Budget", + "field": "budget", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + }, + { + "title": "Actual", + "field": "totalAmount", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + }, + { + "title": "Variance", + "field": "variance", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + }, + { + "title": "% of Budget", + "field": "percentOfBudget", + "formatter": "progress", + "formatterParams": { + "min": 0, + "max": 2, + "color": ["green", "orange", "red"], + "legend": true + }, + "sorter": "number" + } + ] + } + } + ] + }, + { + "groupId": "merchants", + "elements": [ + "### 🏪 Top Merchants", + { + "type": "tabulator", + "dataSourceName": "topMerchants", + "editable": false, + "tabulatorOptions": { + "layout": "fitColumns", + "columns": [ + { + "title": "Merchant", + "field": "merchant", + "sorter": "string" + }, + { + "title": "Total Spent", + "field": "totalSpent", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + }, + { + "title": "Visits", + "field": "visitCount", + "sorter": "number" + } + ] + } + } + ] + }, + { + "groupId": "patterns", + "elements": [ + "### 📅 Day of Week Patterns", + { + "type": "chart", + "chartKey": "dayOfWeekSpending" + } + ] + }, + { + "groupId": "categories", + "elements": [ + "### 📊 Category Deep Dive", + { + "type": "chart", + "chartKey": "budgetComparisonChart" + } + ] + }, + { + "groupId": "transactions", + "elements": [ + "### 📋 Transaction History", + "**Edit transactions below to update your analysis**", + { + "type": "tabulator", + "variableId": "editableTransactions", + "dataSourceName": "transactions", + "editable": true, + "tabulatorOptions": { + "layout": "fitColumns", + "maxHeight": "400px", + "columns": [ + { + "title": "Date", + "field": "date", + "sorter": "date", + "editor": "date" + }, + { + "title": "Description", + "field": "description", + "editor": "input" + }, + { + "title": "Merchant", + "field": "merchant", + "editor": "input" + }, + { + "title": "Category", + "field": "category", + "editor": "list", + "editorParams": { + "values": ["Income", "Housing", "Food", "Transportation", "Utilities", "Entertainment", "Healthcare", "Shopping", "Health", "Savings"] + } + }, + { + "title": "Amount", + "field": "amount", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "editor": "number", + "editorParams": { + "step": 0.01 + } + }, + { + "title": "Type", + "field": "type", + "editor": "list", + "editorParams": { + "values": ["income", "expense", "transfer"] + } + } + ], + "addRowPos": "top" + } + } + ] + } + ], + "resources": { + "charts": { + "expensesPieChart": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 300, + "data": { + "name": "expensesByCategory" + }, + "mark": { + "type": "arc", + "innerRadius": 50, + "stroke": "white", + "strokeWidth": 2 + }, + "encoding": { + "theta": { + "field": "totalAmount", + "type": "quantitative", + "title": "Amount Spent" + }, + "color": { + "field": "category", + "type": "nominal", + "sort": {"field": "totalAmount", "order": "descending"}, + "scale": { + "range": ["#667eea", "#764ba2", "#f093fb", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57", "#ff9ff3", "#54a0ff"] + }, + "legend": { + "orient": "right", + "title": "Category" + } + }, + "tooltip": [ + {"field": "category", "type": "nominal", "title": "Category"}, + {"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"}, + {"field": "transactionCount", "type": "quantitative", "title": "Transactions"} + ] + } + }, + "dailySpendingTrend": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 200, + "data": { + "name": "dailySpending" + }, + "mark": { + "type": "line", + "point": true, + "strokeWidth": 3 + }, + "encoding": { + "x": { + "field": "date", + "type": "temporal", + "title": "Date" + }, + "y": { + "field": "dailyTotal", + "type": "quantitative", + "title": "Daily Spending ($)" + }, + "color": { + "value": "#667eea" + }, + "tooltip": [ + {"field": "date", "type": "temporal", "title": "Date"}, + {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"} + ] + } + }, + "dayOfWeekSpending": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 200, + "data": { + "name": "spendingByDayOfWeek" + }, + "mark": "bar", + "encoding": { + "x": { + "field": "dayName", + "type": "ordinal", + "title": "Day of Week", + "sort": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] + }, + "y": { + "field": "totalSpent", + "type": "quantitative", + "title": "Total Spent ($)" + }, + "color": { + "field": "totalSpent", + "type": "quantitative", + "scale": { + "range": ["#e8f4f8", "#2e86ab"] + }, + "legend": null + }, + "tooltip": [ + {"field": "dayName", "type": "nominal", "title": "Day"}, + {"field": "totalSpent", "type": "quantitative", "title": "Amount", "format": "$,.2f"}, + {"field": "transactionCount", "type": "quantitative", "title": "Transactions"} + ] + } + }, + "budgetComparisonChart": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 300, + "data": { + "name": "budgetComparison" + }, + "transform": [ + { + "fold": ["budget", "totalAmount"], + "as": ["type", "amount"] + } + ], + "mark": "bar", + "encoding": { + "x": { + "field": "category", + "type": "nominal", + "title": "Category" + }, + "y": { + "field": "amount", + "type": "quantitative", + "title": "Amount ($)" + }, + "color": { + "field": "type", + "type": "nominal", + "scale": { + "domain": ["budget", "totalAmount"], + "range": ["#a8dadc", "#e63946"] + }, + "legend": { + "title": "Type", + "labelExpr": "datum.label === 'budget' ? 'Budget' : 'Actual'" + } + }, + "xOffset": { + "field": "type", + "type": "nominal" + }, + "tooltip": [ + {"field": "category", "type": "nominal", "title": "Category"}, + {"field": "type", "type": "nominal", "title": "Type"}, + {"field": "amount", "type": "quantitative", "title": "Amount", "format": "$,.2f"} + ] + } + } + } + } +} \ No newline at end of file From 66dac868d07a3dc6f50022fd164288e25c8d08fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:17:12 +0000 Subject: [PATCH 3/7] Enhance bank statement with time filtering, spending heatmap, and smart insights Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com> --- .../json/bank-statement-advanced.idoc.json | 157 ++++++++++++++++-- 1 file changed, 143 insertions(+), 14 deletions(-) diff --git a/packages/web-deploy/json/bank-statement-advanced.idoc.json b/packages/web-deploy/json/bank-statement-advanced.idoc.json index 3f9bac7a..f00723b1 100644 --- a/packages/web-deploy/json/bank-statement-advanced.idoc.json +++ b/packages/web-deploy/json/bank-statement-advanced.idoc.json @@ -72,7 +72,19 @@ "2024-02-20,Coffee Shop,Food,-11.25,expense,Local Cafe", "2024-02-22,Grocery Store,Food,-89.50,expense,Whole Foods", "2024-02-25,Clothing Store,Shopping,-145.99,expense,Target", - "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell" + "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell", + "2024-03-02,Coffee Shop,Food,-9.75,expense,Starbucks", + "2024-03-05,Grocery Store,Food,-112.34,expense,Whole Foods", + "2024-03-08,Streaming Service,Entertainment,-12.99,expense,Disney+", + "2024-03-10,Phone Bill,Utilities,-45.00,expense,Verizon", + "2024-03-12,Restaurant,Food,-78.50,expense,Fine Dining", + "2024-03-15,Freelance Project,Income,920.00,income,Client DEF", + "2024-03-18,Gas Station,Transportation,-41.25,expense,Exxon", + "2024-03-20,Online Shopping,Shopping,-89.99,expense,Amazon", + "2024-03-22,Gym Membership,Health,-29.99,expense,Planet Fitness", + "2024-03-25,Electric Bill,Utilities,-95.75,expense,ConEd", + "2024-03-28,Coffee Shop,Food,-13.50,expense,Local Cafe", + "2024-03-30,Savings Transfer,Savings,-600.00,transfer,Savings Account" ] }, { @@ -100,12 +112,32 @@ "initialValue": "All Time" }, { - "variableId": "totalIncome", + "variableId": "filteredTransactions", "type": "object", "isArray": true, "initialValue": [], "calculation": { "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "formula", + "expr": "selectedTimeframe === 'January' ? (year(datum.date) === 2024 && month(datum.date) === 0) : selectedTimeframe === 'February' ? (year(datum.date) === 2024 && month(datum.date) === 1) : selectedTimeframe === 'March' ? (year(datum.date) === 2024 && month(datum.date) === 2) : true", + "as": "timeMatch" + }, + { + "type": "filter", + "expr": "datum.timeMatch" + } + ] + } + }, + { + "variableId": "totalIncome", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["filteredTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -126,7 +158,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["editableTransactions"], + "dataSourceNames": ["filteredTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -147,7 +179,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["editableTransactions"], + "dataSourceNames": ["filteredTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -168,7 +200,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["editableTransactions"], + "dataSourceNames": ["filteredTransactions"], "dataFrameTransformations": [ { "type": "aggregate", @@ -185,7 +217,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["editableTransactions"], + "dataSourceNames": ["filteredTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -245,7 +277,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["editableTransactions"], + "dataSourceNames": ["filteredTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -283,7 +315,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["editableTransactions"], + "dataSourceNames": ["filteredTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -320,7 +352,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["editableTransactions"], + "dataSourceNames": ["filteredTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -357,7 +389,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["editableTransactions"], + "dataSourceNames": ["filteredTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -440,6 +472,30 @@ "calculation": { "vegaExpression": "'$' + format((abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0) / 30), ',.2f')" } + }, + { + "variableId": "highestExpenseCategory", + "type": "string", + "initialValue": "None", + "calculation": { + "vegaExpression": "length(data('expensesByCategory')) > 0 ? data('expensesByCategory')[0].category : 'None'" + } + }, + { + "variableId": "totalTransactions", + "type": "string", + "initialValue": "0", + "calculation": { + "vegaExpression": "'' + length(data('filteredTransactions'))" + } + }, + { + "variableId": "expenseTransactions", + "type": "string", + "initialValue": "0", + "calculation": { + "vegaExpression": "'' + length(data('filteredTransactions').filter(function(d) { return d.type === 'expense'; }))" + } } ], "groups": [ @@ -455,6 +511,13 @@ "elements": [ "### 📊 Financial Overview", "", + { + "type": "dropdown", + "variableId": "selectedTimeframe", + "label": "Time Period:", + "options": ["All Time", "January", "February", "March"] + }, + "", "**Total Income:** {{formattedIncome}}", "**Total Expenses:** {{formattedExpenses}}", "**Current Balance:** {{formattedBalance}}", @@ -524,16 +587,21 @@ "elements": [ "### 🔍 Smart Insights", "", - "**Top Spending Categories:**", - "1. Housing ({{formattedExpenses}} of expenses)", - "2. Food & Dining (frequent purchases)", - "3. Transportation (regular fuel costs)", + "**Spending Summary:**", + "- **Total Transactions:** {{totalTransactions}}", + "- **Expense Transactions:** {{expenseTransactions}}", + "- **Top Category:** {{highestExpenseCategory}}", "", "**Spending Patterns:**", "- Most active merchant: Starbucks (frequent coffee purchases)", "- Grocery shopping: Mostly Whole Foods", "- Regular bills: Utilities paid on time", "", + "**Financial Health Alerts:**", + "- ⚠️ Food spending is above average", + "- ✅ Regular savings pattern detected", + "- 💡 Consider consolidating grocery shopping", + "", "**Recommendations:**", "- Consider bulk coffee purchases to reduce café visits", "- Monitor entertainment spending trends", @@ -547,6 +615,12 @@ { "type": "chart", "chartKey": "dailySpendingTrend" + }, + "", + "#### Daily Spending Heatmap", + { + "type": "chart", + "chartKey": "spendingHeatmap" } ] }, @@ -899,6 +973,61 @@ {"field": "amount", "type": "quantitative", "title": "Amount", "format": "$,.2f"} ] } + }, + "spendingHeatmap": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 250, + "data": { + "name": "dailySpending" + }, + "transform": [ + { + "formula": "datetime(datum.date)", + "as": "dateTime" + }, + { + "formula": "day(datum.dateTime)", + "as": "dayOfWeek" + }, + { + "formula": "date(datum.dateTime)", + "as": "dayOfMonth" + }, + { + "formula": "month(datum.dateTime)", + "as": "monthNumber" + } + ], + "mark": "rect", + "encoding": { + "x": { + "field": "dayOfWeek", + "type": "ordinal", + "title": "Day of Week", + "scale": { + "domain": [1, 2, 3, 4, 5, 6, 0] + } + }, + "y": { + "field": "dayOfMonth", + "type": "ordinal", + "title": "Day of Month" + }, + "color": { + "field": "dailyTotal", + "type": "quantitative", + "title": "Amount Spent", + "scale": { + "scheme": "blues", + "range": ["#f7fbff", "#08519c"] + } + }, + "tooltip": [ + {"field": "date", "type": "temporal", "title": "Date"}, + {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"} + ] + } } } } From ecf2feee041e230ec04c2eafaf81ee806f39d1f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:31:28 +0000 Subject: [PATCH 4/7] Fix bank statement advanced example - remove invalid Vega expressions and time filtering Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com> --- .../json/bank-statement-advanced.idoc.json | 242 ++---------------- 1 file changed, 27 insertions(+), 215 deletions(-) diff --git a/packages/web-deploy/json/bank-statement-advanced.idoc.json b/packages/web-deploy/json/bank-statement-advanced.idoc.json index f00723b1..49645898 100644 --- a/packages/web-deploy/json/bank-statement-advanced.idoc.json +++ b/packages/web-deploy/json/bank-statement-advanced.idoc.json @@ -1,17 +1,17 @@ { "$schema": "../../../docs/schema/idoc_v1.json", - "title": "Advanced Personal Financial Dashboard", + "title": "Enhanced Personal Bank Statement", "style": { "css": [ "body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }", - "body { display: grid; grid-template-areas: 'header header header' 'summary metrics insights' 'trends spending budget' 'merchants patterns categories' 'transactions transactions transactions'; grid-template-columns: 1fr 1fr 1fr; gap: 20px; max-width: 1600px; margin: 0 auto; }", + "body { display: grid; grid-template-areas: 'header header header' 'summary metrics insights' 'chart trends budget' 'merchants patterns categories' 'transactions transactions transactions'; grid-template-columns: 1fr 1fr 1fr; gap: 20px; max-width: 1600px; margin: 0 auto; }", ".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }", "#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }", "#summary { grid-area: summary; text-align: center; min-width: 0; overflow: hidden; }", "#metrics { grid-area: metrics; min-width: 0; overflow: hidden; }", "#insights { grid-area: insights; min-width: 0; overflow: hidden; }", + "#chart { grid-area: chart; min-width: 0; overflow: hidden; }", "#trends { grid-area: trends; min-width: 0; overflow: hidden; }", - "#spending { grid-area: spending; min-width: 0; overflow: hidden; }", "#budget { grid-area: budget; min-width: 0; overflow: hidden; }", "#merchants { grid-area: merchants; min-width: 0; overflow: hidden; }", "#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }", @@ -22,16 +22,14 @@ "h3 { margin: 0 0 15px 0; font-size: 1.2em; color: #4a5568; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }", ".tabulator { max-width: 100%; overflow: auto; }", ".tabulator .tabulator-table { min-width: fit-content; }", + ".compact-table { font-size: 0.85em; }", + ".compact-table .tabulator-header { height: 30px; }", + ".compact-table .tabulator-row { height: 28px; }", ".metric { text-align: center; margin: 10px 0; padding: 15px; background: #f7fafc; border-radius: 8px; border-left: 4px solid #3182ce; }", ".metric .value { font-size: 1.5em; font-weight: bold; color: #2d3748; }", ".metric .label { font-size: 0.9em; color: #718096; text-transform: uppercase; letter-spacing: 0.5px; }", - ".positive { color: #38a169; }", - ".negative { color: #e53e3e; }", - ".warning { color: #d69e2e; }", - ".slider-container { margin: 15px 0; }", - ".slider-label { font-weight: 500; color: #2d3748; margin-bottom: 8px; display: block; }", - "@media (max-width: 1200px) { body { grid-template-columns: 1fr 1fr; grid-template-areas: 'header header' 'summary metrics' 'insights trends' 'spending budget' 'merchants patterns' 'categories categories' 'transactions transactions'; } }", - "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'metrics' 'insights' 'trends' 'spending' 'budget' 'merchants' 'patterns' 'categories' 'transactions'; } }" + "@media (max-width: 1200px) { body { grid-template-columns: 1fr 1fr; grid-template-areas: 'header header' 'summary metrics' 'insights chart' 'trends budget' 'merchants patterns' 'categories categories' 'transactions transactions'; } }", + "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'metrics' 'insights' 'chart' 'trends' 'budget' 'merchants' 'patterns' 'categories' 'transactions'; } }" ] }, "dataLoaders": [ @@ -72,19 +70,7 @@ "2024-02-20,Coffee Shop,Food,-11.25,expense,Local Cafe", "2024-02-22,Grocery Store,Food,-89.50,expense,Whole Foods", "2024-02-25,Clothing Store,Shopping,-145.99,expense,Target", - "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell", - "2024-03-02,Coffee Shop,Food,-9.75,expense,Starbucks", - "2024-03-05,Grocery Store,Food,-112.34,expense,Whole Foods", - "2024-03-08,Streaming Service,Entertainment,-12.99,expense,Disney+", - "2024-03-10,Phone Bill,Utilities,-45.00,expense,Verizon", - "2024-03-12,Restaurant,Food,-78.50,expense,Fine Dining", - "2024-03-15,Freelance Project,Income,920.00,income,Client DEF", - "2024-03-18,Gas Station,Transportation,-41.25,expense,Exxon", - "2024-03-20,Online Shopping,Shopping,-89.99,expense,Amazon", - "2024-03-22,Gym Membership,Health,-29.99,expense,Planet Fitness", - "2024-03-25,Electric Bill,Utilities,-95.75,expense,ConEd", - "2024-03-28,Coffee Shop,Food,-13.50,expense,Local Cafe", - "2024-03-30,Savings Transfer,Savings,-600.00,transfer,Savings Account" + "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell" ] }, { @@ -106,38 +92,13 @@ } ], "variables": [ - { - "variableId": "selectedTimeframe", - "type": "string", - "initialValue": "All Time" - }, - { - "variableId": "filteredTransactions", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["editableTransactions"], - "dataFrameTransformations": [ - { - "type": "formula", - "expr": "selectedTimeframe === 'January' ? (year(datum.date) === 2024 && month(datum.date) === 0) : selectedTimeframe === 'February' ? (year(datum.date) === 2024 && month(datum.date) === 1) : selectedTimeframe === 'March' ? (year(datum.date) === 2024 && month(datum.date) === 2) : true", - "as": "timeMatch" - }, - { - "type": "filter", - "expr": "datum.timeMatch" - } - ] - } - }, { "variableId": "totalIncome", "type": "object", "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["filteredTransactions"], + "dataSourceNames": ["editableTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -158,7 +119,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["filteredTransactions"], + "dataSourceNames": ["editableTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -179,7 +140,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["filteredTransactions"], + "dataSourceNames": ["editableTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -200,7 +161,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["filteredTransactions"], + "dataSourceNames": ["editableTransactions"], "dataFrameTransformations": [ { "type": "aggregate", @@ -217,7 +178,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["filteredTransactions"], + "dataSourceNames": ["editableTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -262,11 +223,6 @@ "type": "formula", "expr": "datum.totalAmount / datum.budget", "as": "percentOfBudget" - }, - { - "type": "formula", - "expr": "datum.budget - datum.totalAmount", - "as": "remaining" } ] } @@ -277,7 +233,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["filteredTransactions"], + "dataSourceNames": ["editableTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -315,7 +271,7 @@ "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["filteredTransactions"], + "dataSourceNames": ["editableTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -326,16 +282,6 @@ "expr": "abs(datum.amount)", "as": "absAmount" }, - { - "type": "formula", - "expr": "datetime(datum.date)", - "as": "dateTime" - }, - { - "type": "formula", - "expr": "day(datum.dateTime)", - "as": "dayOfWeek" - }, { "type": "aggregate", "groupby": ["date"], @@ -346,50 +292,13 @@ ] } }, - { - "variableId": "weeklySpending", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["filteredTransactions"], - "dataFrameTransformations": [ - { - "type": "filter", - "expr": "datum.type === 'expense'" - }, - { - "type": "formula", - "expr": "abs(datum.amount)", - "as": "absAmount" - }, - { - "type": "formula", - "expr": "datetime(datum.date)", - "as": "dateTime" - }, - { - "type": "formula", - "expr": "week(datum.dateTime)", - "as": "weekOfYear" - }, - { - "type": "aggregate", - "groupby": ["weekOfYear"], - "ops": ["sum"], - "fields": ["absAmount"], - "as": ["weeklyTotal"] - } - ] - } - }, { "variableId": "spendingByDayOfWeek", "type": "object", "isArray": true, "initialValue": [], "calculation": { - "dataSourceNames": ["filteredTransactions"], + "dataSourceNames": ["editableTransactions"], "dataFrameTransformations": [ { "type": "filter", @@ -472,37 +381,13 @@ "calculation": { "vegaExpression": "'$' + format((abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0) / 30), ',.2f')" } - }, - { - "variableId": "highestExpenseCategory", - "type": "string", - "initialValue": "None", - "calculation": { - "vegaExpression": "length(data('expensesByCategory')) > 0 ? data('expensesByCategory')[0].category : 'None'" - } - }, - { - "variableId": "totalTransactions", - "type": "string", - "initialValue": "0", - "calculation": { - "vegaExpression": "'' + length(data('filteredTransactions'))" - } - }, - { - "variableId": "expenseTransactions", - "type": "string", - "initialValue": "0", - "calculation": { - "vegaExpression": "'' + length(data('filteredTransactions').filter(function(d) { return d.type === 'expense'; }))" - } } ], "groups": [ { "groupId": "header", "elements": [ - "# 💰 Advanced Personal Financial Dashboard", + "# 💰 Enhanced Personal Bank Statement", "**Deep insights into your spending habits and financial patterns**" ] }, @@ -511,19 +396,12 @@ "elements": [ "### 📊 Financial Overview", "", - { - "type": "dropdown", - "variableId": "selectedTimeframe", - "label": "Time Period:", - "options": ["All Time", "January", "February", "March"] - }, - "", "**Total Income:** {{formattedIncome}}", "**Total Expenses:** {{formattedExpenses}}", "**Current Balance:** {{formattedBalance}}", "**Total Savings:** {{formattedSavings}}", "", - "#### Quick Stats", + "#### Category Summary", { "type": "tabulator", "dataSourceName": "expensesByCategory", @@ -587,18 +465,13 @@ "elements": [ "### 🔍 Smart Insights", "", - "**Spending Summary:**", - "- **Total Transactions:** {{totalTransactions}}", - "- **Expense Transactions:** {{expenseTransactions}}", - "- **Top Category:** {{highestExpenseCategory}}", - "", "**Spending Patterns:**", "- Most active merchant: Starbucks (frequent coffee purchases)", "- Grocery shopping: Mostly Whole Foods", "- Regular bills: Utilities paid on time", "", "**Financial Health Alerts:**", - "- ⚠️ Food spending is above average", + "- ⚠️ Food spending may be above budget", "- ✅ Regular savings pattern detected", "- 💡 Consider consolidating grocery shopping", "", @@ -609,28 +482,22 @@ ] }, { - "groupId": "trends", + "groupId": "chart", "elements": [ - "### 📈 Spending Trends", + "### 🥧 Expense Distribution", { "type": "chart", - "chartKey": "dailySpendingTrend" - }, - "", - "#### Daily Spending Heatmap", - { - "type": "chart", - "chartKey": "spendingHeatmap" + "chartKey": "expensesPieChart" } ] }, { - "groupId": "spending", + "groupId": "trends", "elements": [ - "### 🥧 Category Breakdown", + "### 📈 Daily Spending Trends", { "type": "chart", - "chartKey": "expensesPieChart" + "chartKey": "dailySpendingTrend" } ] }, @@ -746,7 +613,7 @@ { "groupId": "categories", "elements": [ - "### 📊 Category Deep Dive", + "### 📊 Budget Comparison Chart", { "type": "chart", "chartKey": "budgetComparisonChart" @@ -973,61 +840,6 @@ {"field": "amount", "type": "quantitative", "title": "Amount", "format": "$,.2f"} ] } - }, - "spendingHeatmap": { - "$schema": "https://vega.github.io/schema/vega-lite/v6.json", - "width": "container", - "height": 250, - "data": { - "name": "dailySpending" - }, - "transform": [ - { - "formula": "datetime(datum.date)", - "as": "dateTime" - }, - { - "formula": "day(datum.dateTime)", - "as": "dayOfWeek" - }, - { - "formula": "date(datum.dateTime)", - "as": "dayOfMonth" - }, - { - "formula": "month(datum.dateTime)", - "as": "monthNumber" - } - ], - "mark": "rect", - "encoding": { - "x": { - "field": "dayOfWeek", - "type": "ordinal", - "title": "Day of Week", - "scale": { - "domain": [1, 2, 3, 4, 5, 6, 0] - } - }, - "y": { - "field": "dayOfMonth", - "type": "ordinal", - "title": "Day of Month" - }, - "color": { - "field": "dailyTotal", - "type": "quantitative", - "title": "Amount Spent", - "scale": { - "scheme": "blues", - "range": ["#f7fbff", "#08519c"] - } - }, - "tooltip": [ - {"field": "date", "type": "temporal", "title": "Date"}, - {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"} - ] - } } } } From 36a1c29c05989999bdb5a57fa1052b0ed4d93ce2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:41:58 +0000 Subject: [PATCH 5/7] Add deeper category analysis to bank statement - keep original structure, add drill-down insights Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com> --- .../json/bank-statement-advanced.idoc.json | 846 ------------------ .../web-deploy/json/bank-statement.idoc.json | 250 +++++- 2 files changed, 248 insertions(+), 848 deletions(-) delete mode 100644 packages/web-deploy/json/bank-statement-advanced.idoc.json diff --git a/packages/web-deploy/json/bank-statement-advanced.idoc.json b/packages/web-deploy/json/bank-statement-advanced.idoc.json deleted file mode 100644 index 49645898..00000000 --- a/packages/web-deploy/json/bank-statement-advanced.idoc.json +++ /dev/null @@ -1,846 +0,0 @@ -{ - "$schema": "../../../docs/schema/idoc_v1.json", - "title": "Enhanced Personal Bank Statement", - "style": { - "css": [ - "body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }", - "body { display: grid; grid-template-areas: 'header header header' 'summary metrics insights' 'chart trends budget' 'merchants patterns categories' 'transactions transactions transactions'; grid-template-columns: 1fr 1fr 1fr; gap: 20px; max-width: 1600px; margin: 0 auto; }", - ".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }", - "#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }", - "#summary { grid-area: summary; text-align: center; min-width: 0; overflow: hidden; }", - "#metrics { grid-area: metrics; min-width: 0; overflow: hidden; }", - "#insights { grid-area: insights; min-width: 0; overflow: hidden; }", - "#chart { grid-area: chart; min-width: 0; overflow: hidden; }", - "#trends { grid-area: trends; min-width: 0; overflow: hidden; }", - "#budget { grid-area: budget; min-width: 0; overflow: hidden; }", - "#merchants { grid-area: merchants; min-width: 0; overflow: hidden; }", - "#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }", - "#categories { grid-area: categories; min-width: 0; overflow: hidden; }", - "#transactions { grid-area: transactions; min-width: 0; overflow: hidden; }", - "h1 { margin: 0; padding: 20px 0; font-size: 2em; font-weight: 600; }", - "h2 { margin: 10px 0; font-size: 2em; color: #2d3748; font-weight: 600; }", - "h3 { margin: 0 0 15px 0; font-size: 1.2em; color: #4a5568; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }", - ".tabulator { max-width: 100%; overflow: auto; }", - ".tabulator .tabulator-table { min-width: fit-content; }", - ".compact-table { font-size: 0.85em; }", - ".compact-table .tabulator-header { height: 30px; }", - ".compact-table .tabulator-row { height: 28px; }", - ".metric { text-align: center; margin: 10px 0; padding: 15px; background: #f7fafc; border-radius: 8px; border-left: 4px solid #3182ce; }", - ".metric .value { font-size: 1.5em; font-weight: bold; color: #2d3748; }", - ".metric .label { font-size: 0.9em; color: #718096; text-transform: uppercase; letter-spacing: 0.5px; }", - "@media (max-width: 1200px) { body { grid-template-columns: 1fr 1fr; grid-template-areas: 'header header' 'summary metrics' 'insights chart' 'trends budget' 'merchants patterns' 'categories categories' 'transactions transactions'; } }", - "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'metrics' 'insights' 'chart' 'trends' 'budget' 'merchants' 'patterns' 'categories' 'transactions'; } }" - ] - }, - "dataLoaders": [ - { - "dataSourceName": "transactions", - "type": "inline", - "format": "csv", - "content": [ - "date,description,category,amount,type,merchant", - "2024-01-02,Salary Deposit,Income,3500.00,income,Employer", - "2024-01-03,Rent Payment,Housing,-1200.00,expense,Property Management Co", - "2024-01-04,Grocery Store,Food,-85.50,expense,Whole Foods", - "2024-01-05,Gas Station,Transportation,-45.00,expense,Shell", - "2024-01-06,Coffee Shop,Food,-12.75,expense,Starbucks", - "2024-01-08,Electric Bill,Utilities,-89.99,expense,ConEd", - "2024-01-10,Movie Tickets,Entertainment,-28.00,expense,AMC Theaters", - "2024-01-12,Pharmacy,Healthcare,-25.99,expense,CVS Pharmacy", - "2024-01-14,Online Shopping,Shopping,-67.89,expense,Amazon", - "2024-01-15,Freelance Project,Income,850.00,income,Client ABC", - "2024-01-16,Restaurant,Food,-42.50,expense,Local Bistro", - "2024-01-18,Internet Bill,Utilities,-59.99,expense,Comcast", - "2024-01-20,Gym Membership,Health,-29.99,expense,Planet Fitness", - "2024-01-22,Grocery Store,Food,-92.34,expense,Whole Foods", - "2024-01-24,Car Insurance,Transportation,-125.00,expense,Geico", - "2024-01-25,Clothing Store,Shopping,-89.99,expense,H&M", - "2024-01-26,Savings Transfer,Savings,-500.00,transfer,Savings Account", - "2024-01-28,Gas Station,Transportation,-38.75,expense,Shell", - "2024-01-30,Phone Bill,Utilities,-45.00,expense,Verizon", - "2024-02-01,Coffee Shop,Food,-8.50,expense,Starbucks", - "2024-02-03,Subscription,Entertainment,-15.99,expense,Netflix", - "2024-02-05,Grocery Store,Food,-78.25,expense,Trader Joes", - "2024-02-07,Restaurant,Food,-65.00,expense,Local Bistro", - "2024-02-10,Gas Station,Transportation,-42.30,expense,Exxon", - "2024-02-12,Online Shopping,Shopping,-125.50,expense,Amazon", - "2024-02-14,Date Night,Entertainment,-95.00,expense,Fine Dining", - "2024-02-16,Freelance Project,Income,750.00,income,Client XYZ", - "2024-02-18,Pharmacy,Healthcare,-18.75,expense,Walgreens", - "2024-02-20,Coffee Shop,Food,-11.25,expense,Local Cafe", - "2024-02-22,Grocery Store,Food,-89.50,expense,Whole Foods", - "2024-02-25,Clothing Store,Shopping,-145.99,expense,Target", - "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell" - ] - }, - { - "dataSourceName": "categoryBudgets", - "type": "inline", - "format": "csv", - "content": [ - "category,budgetAmount,color", - "Housing,1200,#667eea", - "Food,400,#764ba2", - "Transportation,300,#f093fb", - "Utilities,250,#4ecdc4", - "Entertainment,200,#45b7d1", - "Healthcare,150,#96ceb4", - "Shopping,200,#feca57", - "Health,50,#ff9ff3", - "Savings,600,#54a0ff" - ] - } - ], - "variables": [ - { - "variableId": "totalIncome", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["editableTransactions"], - "dataFrameTransformations": [ - { - "type": "filter", - "expr": "datum.type === 'income'" - }, - { - "type": "aggregate", - "ops": ["sum"], - "fields": ["amount"], - "as": ["total"] - } - ] - } - }, - { - "variableId": "totalExpenses", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["editableTransactions"], - "dataFrameTransformations": [ - { - "type": "filter", - "expr": "datum.type === 'expense'" - }, - { - "type": "aggregate", - "ops": ["sum"], - "fields": ["amount"], - "as": ["total"] - } - ] - } - }, - { - "variableId": "totalSavings", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["editableTransactions"], - "dataFrameTransformations": [ - { - "type": "filter", - "expr": "datum.type === 'transfer' && datum.category === 'Savings'" - }, - { - "type": "aggregate", - "ops": ["sum"], - "fields": ["amount"], - "as": ["total"] - } - ] - } - }, - { - "variableId": "currentBalance", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["editableTransactions"], - "dataFrameTransformations": [ - { - "type": "aggregate", - "ops": ["sum"], - "fields": ["amount"], - "as": ["total"] - } - ] - } - }, - { - "variableId": "expensesByCategory", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["editableTransactions"], - "dataFrameTransformations": [ - { - "type": "filter", - "expr": "datum.type === 'expense'" - }, - { - "type": "formula", - "expr": "abs(datum.amount)", - "as": "absAmount" - }, - { - "type": "aggregate", - "groupby": ["category"], - "ops": ["sum", "count"], - "fields": ["absAmount", "absAmount"], - "as": ["totalAmount", "transactionCount"] - } - ] - } - }, - { - "variableId": "budgetComparison", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["expensesByCategory", "categoryBudgets"], - "dataFrameTransformations": [ - { - "type": "lookup", - "from": "categoryBudgets", - "key": "category", - "fields": ["budgetAmount", "color"], - "as": ["budget", "color"] - }, - { - "type": "formula", - "expr": "datum.totalAmount - datum.budget", - "as": "variance" - }, - { - "type": "formula", - "expr": "datum.totalAmount / datum.budget", - "as": "percentOfBudget" - } - ] - } - }, - { - "variableId": "topMerchants", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["editableTransactions"], - "dataFrameTransformations": [ - { - "type": "filter", - "expr": "datum.type === 'expense'" - }, - { - "type": "formula", - "expr": "abs(datum.amount)", - "as": "absAmount" - }, - { - "type": "aggregate", - "groupby": ["merchant"], - "ops": ["sum", "count"], - "fields": ["absAmount", "absAmount"], - "as": ["totalSpent", "visitCount"] - }, - { - "type": "window", - "ops": ["rank"], - "fields": [null], - "as": ["rank"], - "sort": [{"field": "totalSpent", "order": "descending"}] - }, - { - "type": "filter", - "expr": "datum.rank <= 10" - } - ] - } - }, - { - "variableId": "dailySpending", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["editableTransactions"], - "dataFrameTransformations": [ - { - "type": "filter", - "expr": "datum.type === 'expense'" - }, - { - "type": "formula", - "expr": "abs(datum.amount)", - "as": "absAmount" - }, - { - "type": "aggregate", - "groupby": ["date"], - "ops": ["sum"], - "fields": ["absAmount"], - "as": ["dailyTotal"] - } - ] - } - }, - { - "variableId": "spendingByDayOfWeek", - "type": "object", - "isArray": true, - "initialValue": [], - "calculation": { - "dataSourceNames": ["editableTransactions"], - "dataFrameTransformations": [ - { - "type": "filter", - "expr": "datum.type === 'expense'" - }, - { - "type": "formula", - "expr": "abs(datum.amount)", - "as": "absAmount" - }, - { - "type": "formula", - "expr": "datetime(datum.date)", - "as": "dateTime" - }, - { - "type": "formula", - "expr": "day(datum.dateTime)", - "as": "dayOfWeek" - }, - { - "type": "formula", - "expr": "datum.dayOfWeek === 0 ? 'Sunday' : datum.dayOfWeek === 1 ? 'Monday' : datum.dayOfWeek === 2 ? 'Tuesday' : datum.dayOfWeek === 3 ? 'Wednesday' : datum.dayOfWeek === 4 ? 'Thursday' : datum.dayOfWeek === 5 ? 'Friday' : 'Saturday'", - "as": "dayName" - }, - { - "type": "aggregate", - "groupby": ["dayOfWeek", "dayName"], - "ops": ["sum", "count"], - "fields": ["absAmount", "absAmount"], - "as": ["totalSpent", "transactionCount"] - } - ] - } - }, - { - "variableId": "formattedIncome", - "type": "string", - "initialValue": "$0.00", - "calculation": { - "vegaExpression": "'$' + format(length(data('totalIncome')) > 0 ? data('totalIncome')[0].total : 0, ',.2f')" - } - }, - { - "variableId": "formattedExpenses", - "type": "string", - "initialValue": "$0.00", - "calculation": { - "vegaExpression": "'$' + format(abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0), ',.2f')" - } - }, - { - "variableId": "formattedBalance", - "type": "string", - "initialValue": "$0.00", - "calculation": { - "vegaExpression": "'$' + format(length(data('currentBalance')) > 0 ? data('currentBalance')[0].total : 0, ',.2f')" - } - }, - { - "variableId": "formattedSavings", - "type": "string", - "initialValue": "$0.00", - "calculation": { - "vegaExpression": "'$' + format(abs(length(data('totalSavings')) > 0 ? data('totalSavings')[0].total : 0), ',.2f')" - } - }, - { - "variableId": "savingsRate", - "type": "string", - "initialValue": "0%", - "calculation": { - "vegaExpression": "format((abs(length(data('totalSavings')) > 0 ? data('totalSavings')[0].total : 0) / (length(data('totalIncome')) > 0 ? data('totalIncome')[0].total : 1)) * 100, '.1f') + '%'" - } - }, - { - "variableId": "avgDailySpending", - "type": "string", - "initialValue": "$0.00", - "calculation": { - "vegaExpression": "'$' + format((abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0) / 30), ',.2f')" - } - } - ], - "groups": [ - { - "groupId": "header", - "elements": [ - "# 💰 Enhanced Personal Bank Statement", - "**Deep insights into your spending habits and financial patterns**" - ] - }, - { - "groupId": "summary", - "elements": [ - "### 📊 Financial Overview", - "", - "**Total Income:** {{formattedIncome}}", - "**Total Expenses:** {{formattedExpenses}}", - "**Current Balance:** {{formattedBalance}}", - "**Total Savings:** {{formattedSavings}}", - "", - "#### Category Summary", - { - "type": "tabulator", - "dataSourceName": "expensesByCategory", - "editable": false, - "cssClass": "compact-table", - "tabulatorOptions": { - "layout": "fitColumns", - "headerSort": false, - "initialSort": [ - {"column": "totalAmount", "dir": "desc"} - ], - "columns": [ - { - "title": "Category", - "field": "category", - "sorter": "string" - }, - { - "title": "Total", - "field": "totalAmount", - "formatter": "money", - "formatterParams": { - "symbol": "$", - "precision": 2 - }, - "sorter": "number" - }, - { - "title": "Transactions", - "field": "transactionCount", - "sorter": "number" - } - ] - } - } - ] - }, - { - "groupId": "metrics", - "elements": [ - "### 🎯 Key Metrics", - "", - "
", - "
{{savingsRate}}
", - "
Savings Rate
", - "
", - "", - "
", - "
{{avgDailySpending}}
", - "
Avg Daily Spending
", - "
", - "", - "#### Financial Health", - "- **Expense Ratio:** High spending in Food and Housing", - "- **Saving Behavior:** Regular savings transfers detected", - "- **Income Diversity:** Salary + Freelance income" - ] - }, - { - "groupId": "insights", - "elements": [ - "### 🔍 Smart Insights", - "", - "**Spending Patterns:**", - "- Most active merchant: Starbucks (frequent coffee purchases)", - "- Grocery shopping: Mostly Whole Foods", - "- Regular bills: Utilities paid on time", - "", - "**Financial Health Alerts:**", - "- ⚠️ Food spending may be above budget", - "- ✅ Regular savings pattern detected", - "- 💡 Consider consolidating grocery shopping", - "", - "**Recommendations:**", - "- Consider bulk coffee purchases to reduce café visits", - "- Monitor entertainment spending trends", - "- Great job on consistent savings!" - ] - }, - { - "groupId": "chart", - "elements": [ - "### 🥧 Expense Distribution", - { - "type": "chart", - "chartKey": "expensesPieChart" - } - ] - }, - { - "groupId": "trends", - "elements": [ - "### 📈 Daily Spending Trends", - { - "type": "chart", - "chartKey": "dailySpendingTrend" - } - ] - }, - { - "groupId": "budget", - "elements": [ - "### 🎯 Budget vs Actual", - { - "type": "tabulator", - "dataSourceName": "budgetComparison", - "editable": false, - "tabulatorOptions": { - "layout": "fitColumns", - "columns": [ - { - "title": "Category", - "field": "category", - "sorter": "string" - }, - { - "title": "Budget", - "field": "budget", - "formatter": "money", - "formatterParams": { - "symbol": "$", - "precision": 2 - }, - "sorter": "number" - }, - { - "title": "Actual", - "field": "totalAmount", - "formatter": "money", - "formatterParams": { - "symbol": "$", - "precision": 2 - }, - "sorter": "number" - }, - { - "title": "Variance", - "field": "variance", - "formatter": "money", - "formatterParams": { - "symbol": "$", - "precision": 2 - }, - "sorter": "number" - }, - { - "title": "% of Budget", - "field": "percentOfBudget", - "formatter": "progress", - "formatterParams": { - "min": 0, - "max": 2, - "color": ["green", "orange", "red"], - "legend": true - }, - "sorter": "number" - } - ] - } - } - ] - }, - { - "groupId": "merchants", - "elements": [ - "### 🏪 Top Merchants", - { - "type": "tabulator", - "dataSourceName": "topMerchants", - "editable": false, - "tabulatorOptions": { - "layout": "fitColumns", - "columns": [ - { - "title": "Merchant", - "field": "merchant", - "sorter": "string" - }, - { - "title": "Total Spent", - "field": "totalSpent", - "formatter": "money", - "formatterParams": { - "symbol": "$", - "precision": 2 - }, - "sorter": "number" - }, - { - "title": "Visits", - "field": "visitCount", - "sorter": "number" - } - ] - } - } - ] - }, - { - "groupId": "patterns", - "elements": [ - "### 📅 Day of Week Patterns", - { - "type": "chart", - "chartKey": "dayOfWeekSpending" - } - ] - }, - { - "groupId": "categories", - "elements": [ - "### 📊 Budget Comparison Chart", - { - "type": "chart", - "chartKey": "budgetComparisonChart" - } - ] - }, - { - "groupId": "transactions", - "elements": [ - "### 📋 Transaction History", - "**Edit transactions below to update your analysis**", - { - "type": "tabulator", - "variableId": "editableTransactions", - "dataSourceName": "transactions", - "editable": true, - "tabulatorOptions": { - "layout": "fitColumns", - "maxHeight": "400px", - "columns": [ - { - "title": "Date", - "field": "date", - "sorter": "date", - "editor": "date" - }, - { - "title": "Description", - "field": "description", - "editor": "input" - }, - { - "title": "Merchant", - "field": "merchant", - "editor": "input" - }, - { - "title": "Category", - "field": "category", - "editor": "list", - "editorParams": { - "values": ["Income", "Housing", "Food", "Transportation", "Utilities", "Entertainment", "Healthcare", "Shopping", "Health", "Savings"] - } - }, - { - "title": "Amount", - "field": "amount", - "formatter": "money", - "formatterParams": { - "symbol": "$", - "precision": 2 - }, - "editor": "number", - "editorParams": { - "step": 0.01 - } - }, - { - "title": "Type", - "field": "type", - "editor": "list", - "editorParams": { - "values": ["income", "expense", "transfer"] - } - } - ], - "addRowPos": "top" - } - } - ] - } - ], - "resources": { - "charts": { - "expensesPieChart": { - "$schema": "https://vega.github.io/schema/vega-lite/v6.json", - "width": "container", - "height": 300, - "data": { - "name": "expensesByCategory" - }, - "mark": { - "type": "arc", - "innerRadius": 50, - "stroke": "white", - "strokeWidth": 2 - }, - "encoding": { - "theta": { - "field": "totalAmount", - "type": "quantitative", - "title": "Amount Spent" - }, - "color": { - "field": "category", - "type": "nominal", - "sort": {"field": "totalAmount", "order": "descending"}, - "scale": { - "range": ["#667eea", "#764ba2", "#f093fb", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57", "#ff9ff3", "#54a0ff"] - }, - "legend": { - "orient": "right", - "title": "Category" - } - }, - "tooltip": [ - {"field": "category", "type": "nominal", "title": "Category"}, - {"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"}, - {"field": "transactionCount", "type": "quantitative", "title": "Transactions"} - ] - } - }, - "dailySpendingTrend": { - "$schema": "https://vega.github.io/schema/vega-lite/v6.json", - "width": "container", - "height": 200, - "data": { - "name": "dailySpending" - }, - "mark": { - "type": "line", - "point": true, - "strokeWidth": 3 - }, - "encoding": { - "x": { - "field": "date", - "type": "temporal", - "title": "Date" - }, - "y": { - "field": "dailyTotal", - "type": "quantitative", - "title": "Daily Spending ($)" - }, - "color": { - "value": "#667eea" - }, - "tooltip": [ - {"field": "date", "type": "temporal", "title": "Date"}, - {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"} - ] - } - }, - "dayOfWeekSpending": { - "$schema": "https://vega.github.io/schema/vega-lite/v6.json", - "width": "container", - "height": 200, - "data": { - "name": "spendingByDayOfWeek" - }, - "mark": "bar", - "encoding": { - "x": { - "field": "dayName", - "type": "ordinal", - "title": "Day of Week", - "sort": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] - }, - "y": { - "field": "totalSpent", - "type": "quantitative", - "title": "Total Spent ($)" - }, - "color": { - "field": "totalSpent", - "type": "quantitative", - "scale": { - "range": ["#e8f4f8", "#2e86ab"] - }, - "legend": null - }, - "tooltip": [ - {"field": "dayName", "type": "nominal", "title": "Day"}, - {"field": "totalSpent", "type": "quantitative", "title": "Amount", "format": "$,.2f"}, - {"field": "transactionCount", "type": "quantitative", "title": "Transactions"} - ] - } - }, - "budgetComparisonChart": { - "$schema": "https://vega.github.io/schema/vega-lite/v6.json", - "width": "container", - "height": 300, - "data": { - "name": "budgetComparison" - }, - "transform": [ - { - "fold": ["budget", "totalAmount"], - "as": ["type", "amount"] - } - ], - "mark": "bar", - "encoding": { - "x": { - "field": "category", - "type": "nominal", - "title": "Category" - }, - "y": { - "field": "amount", - "type": "quantitative", - "title": "Amount ($)" - }, - "color": { - "field": "type", - "type": "nominal", - "scale": { - "domain": ["budget", "totalAmount"], - "range": ["#a8dadc", "#e63946"] - }, - "legend": { - "title": "Type", - "labelExpr": "datum.label === 'budget' ? 'Budget' : 'Actual'" - } - }, - "xOffset": { - "field": "type", - "type": "nominal" - }, - "tooltip": [ - {"field": "category", "type": "nominal", "title": "Category"}, - {"field": "type", "type": "nominal", "title": "Type"}, - {"field": "amount", "type": "quantitative", "title": "Amount", "format": "$,.2f"} - ] - } - } - } - } -} \ No newline at end of file diff --git a/packages/web-deploy/json/bank-statement.idoc.json b/packages/web-deploy/json/bank-statement.idoc.json index 3f8d2312..f0c6430c 100644 --- a/packages/web-deploy/json/bank-statement.idoc.json +++ b/packages/web-deploy/json/bank-statement.idoc.json @@ -4,12 +4,15 @@ "style": { "css": [ "body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }", - "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }", + "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions' 'drilldown drilldown' 'trends patterns'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }", ".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }", "#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }", "#summary { grid-area: summary; text-align: center; min-width: 0; }", "#chart { grid-area: chart; min-width: 0; }", "#transactions { grid-area: transactions; min-width: 0; }", + "#drilldown { grid-area: drilldown; min-width: 0; overflow: hidden; }", + "#trends { grid-area: trends; min-width: 0; overflow: hidden; }", + "#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }", "h1 { margin: 0; padding: 20px 0; font-size: 2em; font-weight: 600; }", "h2 { margin: 10px 0; font-size: 2em; color: #2d3748; font-weight: 600; }", "h3 { margin: 0 0 15px 0; font-size: 1.2em; color: #4a5568; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }", @@ -18,7 +21,7 @@ ".compact-table { font-size: 0.85em; }", ".compact-table .tabulator-header { height: 30px; }", ".compact-table .tabulator-row { height: 28px; }", - "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions'; } }" + "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions' 'drilldown' 'trends' 'patterns'; } }" ] }, "dataLoaders": [ @@ -160,6 +163,102 @@ "calculation": { "vegaExpression": "'$' + format(length(data('currentBalance')) > 0 ? data('currentBalance')[0].total : 0, ',.2f')" } + }, + { + "variableId": "transactionsByCategory", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "aggregate", + "groupby": ["category"], + "ops": ["sum", "count", "mean", "max"], + "fields": ["absAmount", "absAmount", "absAmount", "absAmount"], + "as": ["totalAmount", "transactionCount", "avgAmount", "maxAmount"] + } + ] + } + }, + { + "variableId": "dailySpending", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "aggregate", + "groupby": ["date"], + "ops": ["sum"], + "fields": ["absAmount"], + "as": ["dailyTotal"] + } + ] + } + }, + { + "variableId": "spendingByDayOfWeek", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "formula", + "expr": "datetime(datum.date)", + "as": "dateTime" + }, + { + "type": "formula", + "expr": "day(datum.dateTime)", + "as": "dayOfWeek" + }, + { + "type": "formula", + "expr": "datum.dayOfWeek === 0 ? 'Sunday' : datum.dayOfWeek === 1 ? 'Monday' : datum.dayOfWeek === 2 ? 'Tuesday' : datum.dayOfWeek === 3 ? 'Wednesday' : datum.dayOfWeek === 4 ? 'Thursday' : datum.dayOfWeek === 5 ? 'Friday' : 'Saturday'", + "as": "dayName" + }, + { + "type": "aggregate", + "groupby": ["dayOfWeek", "dayName"], + "ops": ["sum", "count"], + "fields": ["absAmount", "absAmount"], + "as": ["totalSpent", "transactionCount"] + } + ] + } } ], "groups": [ @@ -281,6 +380,86 @@ } } ] + }, + { + "groupId": "drilldown", + "elements": [ + "### 🔍 Category Deep Dive", + "**Detailed breakdown of spending patterns by category**", + { + "type": "tabulator", + "dataSourceName": "transactionsByCategory", + "editable": false, + "tabulatorOptions": { + "layout": "fitColumns", + "initialSort": [ + {"column": "totalAmount", "dir": "desc"} + ], + "columns": [ + { + "title": "Category", + "field": "category", + "sorter": "string" + }, + { + "title": "Total Spent", + "field": "totalAmount", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + }, + { + "title": "Transactions", + "field": "transactionCount", + "sorter": "number" + }, + { + "title": "Avg per Transaction", + "field": "avgAmount", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + }, + { + "title": "Largest Transaction", + "field": "maxAmount", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + } + ] + } + } + ] + }, + { + "groupId": "trends", + "elements": [ + "### 📈 Spending Trends", + { + "type": "chart", + "chartKey": "dailySpendingTrend" + } + ] + }, + { + "groupId": "patterns", + "elements": [ + "### 📅 Spending Patterns", + { + "type": "chart", + "chartKey": "dayOfWeekSpending" + } + ] } ], "resources": { @@ -327,6 +506,73 @@ {"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"} ] } + }, + "dailySpendingTrend": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 250, + "data": { + "name": "dailySpending" + }, + "mark": { + "type": "line", + "point": true, + "strokeWidth": 3 + }, + "encoding": { + "x": { + "field": "date", + "type": "temporal", + "title": "Date" + }, + "y": { + "field": "dailyTotal", + "type": "quantitative", + "title": "Daily Spending ($)" + }, + "color": { + "value": "#667eea" + }, + "tooltip": [ + {"field": "date", "type": "temporal", "title": "Date"}, + {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"} + ] + } + }, + "dayOfWeekSpending": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 250, + "data": { + "name": "spendingByDayOfWeek" + }, + "mark": "bar", + "encoding": { + "x": { + "field": "dayName", + "type": "ordinal", + "title": "Day of Week", + "sort": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] + }, + "y": { + "field": "totalSpent", + "type": "quantitative", + "title": "Total Spent ($)" + }, + "color": { + "field": "totalSpent", + "type": "quantitative", + "scale": { + "range": ["#e8f4f8", "#2e86ab"] + }, + "legend": null + }, + "tooltip": [ + {"field": "dayName", "type": "nominal", "title": "Day"}, + {"field": "totalSpent", "type": "quantitative", "title": "Amount", "format": "$,.2f"}, + {"field": "transactionCount", "type": "quantitative", "title": "Transactions"} + ] + } } } } From d087848dfbe0c2e36da47110adcef6d987ba569c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 18:12:19 +0000 Subject: [PATCH 6/7] Add horizontal bar chart with trellising by category showing spending per description Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com> --- .../web-deploy/json/bank-statement.idoc.json | 124 +++++++++++++++++- 1 file changed, 121 insertions(+), 3 deletions(-) diff --git a/packages/web-deploy/json/bank-statement.idoc.json b/packages/web-deploy/json/bank-statement.idoc.json index f0c6430c..b0205399 100644 --- a/packages/web-deploy/json/bank-statement.idoc.json +++ b/packages/web-deploy/json/bank-statement.idoc.json @@ -4,13 +4,14 @@ "style": { "css": [ "body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }", - "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions' 'drilldown drilldown' 'trends patterns'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }", + "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions' 'drilldown drilldown' 'breakdown breakdown' 'trends patterns'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }", ".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }", "#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }", "#summary { grid-area: summary; text-align: center; min-width: 0; }", "#chart { grid-area: chart; min-width: 0; }", "#transactions { grid-area: transactions; min-width: 0; }", "#drilldown { grid-area: drilldown; min-width: 0; overflow: hidden; }", + "#breakdown { grid-area: breakdown; min-width: 0; overflow: hidden; }", "#trends { grid-area: trends; min-width: 0; overflow: hidden; }", "#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }", "h1 { margin: 0; padding: 20px 0; font-size: 2em; font-weight: 600; }", @@ -21,7 +22,7 @@ ".compact-table { font-size: 0.85em; }", ".compact-table .tabulator-header { height: 30px; }", ".compact-table .tabulator-row { height: 28px; }", - "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions' 'drilldown' 'trends' 'patterns'; } }" + "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions' 'drilldown' 'breakdown' 'trends' 'patterns'; } }" ] }, "dataLoaders": [ @@ -49,7 +50,35 @@ "2024-01-25,Clothing Store,Shopping,-89.99,expense", "2024-01-26,Savings Transfer,Savings,-500.00,transfer", "2024-01-28,Gas Station,Transportation,-38.75,expense", - "2024-01-30,Phone Bill,Utilities,-45.00,expense" + "2024-01-30,Phone Bill,Utilities,-45.00,expense", + "2024-02-01,Supermarket,Food,-95.20,expense", + "2024-02-02,Coffee Shop,Food,-8.50,expense", + "2024-02-03,Fast Food,Food,-15.75,expense", + "2024-02-04,Grocery Store,Food,-78.90,expense", + "2024-02-05,Dining Out,Food,-65.00,expense", + "2024-02-06,Water Bill,Utilities,-35.50,expense", + "2024-02-07,Gas Bill,Utilities,-125.75,expense", + "2024-02-08,Cable TV,Utilities,-89.99,expense", + "2024-02-09,Bus Pass,Transportation,-55.00,expense", + "2024-02-10,Uber Ride,Transportation,-18.50,expense", + "2024-02-11,Parking Fee,Transportation,-12.00,expense", + "2024-02-12,Train Ticket,Transportation,-25.75,expense", + "2024-02-13,Online Store,Shopping,-145.00,expense", + "2024-02-14,Department Store,Shopping,-89.50,expense", + "2024-02-15,Bookstore,Shopping,-35.99,expense", + "2024-02-16,Electronics Store,Shopping,-299.99,expense", + "2024-02-17,Streaming Service,Entertainment,-15.99,expense", + "2024-02-18,Concert Tickets,Entertainment,-85.00,expense", + "2024-02-19,Game Purchase,Entertainment,-49.99,expense", + "2024-02-20,Movie Theater,Entertainment,-32.50,expense", + "2024-02-21,Doctor Visit,Healthcare,-150.00,expense", + "2024-02-22,Prescription,Healthcare,-45.50,expense", + "2024-02-23,Dental Cleaning,Healthcare,-125.00,expense", + "2024-02-24,Vitamins,Healthcare,-35.99,expense", + "2024-02-25,Mortgage Payment,Housing,-1200.00,expense", + "2024-02-26,Home Insurance,Housing,-85.00,expense", + "2024-02-27,Property Tax,Housing,-450.00,expense", + "2024-02-28,Home Repairs,Housing,-125.50,expense" ] } ], @@ -259,6 +288,33 @@ } ] } + }, + { + "variableId": "expensesByDescription", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "aggregate", + "groupby": ["category", "description"], + "ops": ["sum"], + "fields": ["absAmount"], + "as": ["totalAmount"] + } + ] + } } ], "groups": [ @@ -441,6 +497,17 @@ } ] }, + { + "groupId": "breakdown", + "elements": [ + "### 📊 Spending Breakdown by Description", + "**Amount spent per description within each category**", + { + "type": "chart", + "chartKey": "expensesByDescriptionChart" + } + ] + }, { "groupId": "trends", "elements": [ @@ -573,6 +640,57 @@ {"field": "transactionCount", "type": "quantitative", "title": "Transactions"} ] } + }, + "expensesByDescriptionChart": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 400, + "data": { + "name": "expensesByDescription" + }, + "mark": "bar", + "encoding": { + "row": { + "field": "category", + "type": "nominal", + "title": "Category", + "header": { + "labelAngle": 0, + "labelAlign": "left", + "labelFontSize": 12, + "labelFontWeight": "bold" + } + }, + "y": { + "field": "description", + "type": "nominal", + "title": "Description", + "sort": {"field": "totalAmount", "order": "descending"} + }, + "x": { + "field": "totalAmount", + "type": "quantitative", + "title": "Amount Spent ($)" + }, + "color": { + "field": "category", + "type": "nominal", + "scale": { + "range": ["#667eea", "#764ba2", "#f093fb", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57", "#ff9ff3", "#54a0ff"] + }, + "legend": null + }, + "tooltip": [ + {"field": "category", "type": "nominal", "title": "Category"}, + {"field": "description", "type": "nominal", "title": "Description"}, + {"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"} + ] + }, + "resolve": { + "scale": { + "y": "independent" + } + } } } } From bbfed5d32df52dffb67150cb8c3f93287339be87 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 22:20:20 +0000 Subject: [PATCH 7/7] Fix trellis chart clipping by removing fixed height and adding spacing Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com> --- packages/web-deploy/json/bank-statement.idoc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-deploy/json/bank-statement.idoc.json b/packages/web-deploy/json/bank-statement.idoc.json index b0205399..4bfa6f09 100644 --- a/packages/web-deploy/json/bank-statement.idoc.json +++ b/packages/web-deploy/json/bank-statement.idoc.json @@ -644,11 +644,11 @@ "expensesByDescriptionChart": { "$schema": "https://vega.github.io/schema/vega-lite/v6.json", "width": "container", - "height": 400, "data": { "name": "expensesByDescription" }, "mark": "bar", + "spacing": 20, "encoding": { "row": { "field": "category",