Update spec: new two-column dashboard layout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
74f924c715
commit
02e512a4a6
@ -156,29 +156,38 @@ GET /api/transactions/categories
|
||||
Returns 200: string[] sorted alphabetically
|
||||
|
||||
GET /api/dashboard/summary
|
||||
Query: year (required), month (required)
|
||||
Returns 200: { totalSpent, totalIncome, currentBalance }
|
||||
— totalSpent: absolute value of sum of negative amounts WHERE booking_date
|
||||
falls within the given year+month
|
||||
— totalIncome: sum of positive amounts within the given year+month
|
||||
— currentBalance: balance from the transaction with the globally latest
|
||||
booking_date (highest id as tiebreaker), ignoring year/month
|
||||
filter; null if no transactions exist at all
|
||||
Query: year (required), month (optional)
|
||||
— if month omitted: totals are for the entire year
|
||||
— if month provided: totals are for that month only
|
||||
Returns 200: { totalSpent, totalIncome }
|
||||
— totalSpent: absolute value of sum of negative amounts for the period
|
||||
— totalIncome: sum of positive amounts for the period
|
||||
|
||||
GET /api/dashboard/spending-by-category
|
||||
Query: year (required), month (required)
|
||||
Query: year (required), month (optional)
|
||||
— if month omitted: totals for the entire year
|
||||
— if month provided: totals for that month only
|
||||
Returns 200: [{ category, total }]
|
||||
— total: absolute value of sum of negative amounts for that category in period
|
||||
— positive amounts within any category are excluded from totals
|
||||
— sorted descending by total
|
||||
|
||||
GET /api/dashboard/balance-trend
|
||||
GET /api/dashboard/monthly-balances
|
||||
Query: year (required)
|
||||
Returns 200: [{ month, closingBalance }]
|
||||
— one entry per month that has transactions (months with no transactions omitted)
|
||||
— closingBalance: balance from the transaction with the latest booking_date
|
||||
in that month (highest id as tiebreaker for same-date rows)
|
||||
— always year-scoped; ignores any month selection
|
||||
— always year-scoped
|
||||
|
||||
GET /api/dashboard/cumulative-spending
|
||||
Query: year (required), month (required)
|
||||
Returns 200: [{ day, cumulativeSpent }]
|
||||
— one entry per day that has outgoing transactions within the given month
|
||||
— cumulativeSpent: running absolute total of negative amounts from day 1
|
||||
through that day (sorted ascending by day)
|
||||
— days with no spending are included with the previous day's cumulative value
|
||||
so the line chart has no gaps
|
||||
```
|
||||
|
||||
---
|
||||
@ -192,24 +201,32 @@ GET /api/dashboard/balance-trend
|
||||
| Login | `/login` | No |
|
||||
| Dashboard | `/` | Yes |
|
||||
| Transactions | `/transactions` | Yes |
|
||||
| Import | `/import` | Yes |
|
||||
|
||||
JWT and `expiresAt` stored in `localStorage`. Vue Router navigation guard checks local expiry and redirects unauthenticated/expired users to `/login`. On 401 API response, auth store clears storage and redirects to `/login`.
|
||||
|
||||
### Dashboard Layout
|
||||
|
||||
Three KPI cards across the top (data from `/api/dashboard/summary`):
|
||||
- **Total Spent** — absolute value of negative amounts for selected month/year
|
||||
- **Total Income** — sum of positive amounts for selected month/year
|
||||
- **Current Balance** — globally most recent balance (not period-filtered); shows `—` if null
|
||||
**App bar** — spans full width at top. Contains app title on the left and an "Upload CSV" button on the right. Clicking Upload CSV opens a file picker dialog; the selected file is uploaded via `POST /api/transactions/import` with an inline result snackbar ("Imported X, skipped Y" or error message). No separate import page.
|
||||
|
||||
Cards show a skeleton loader while fetching and an error state (red border, retry button) on failure.
|
||||
**Two-column body** — equal-width columns side by side below the app bar.
|
||||
|
||||
Two charts below, side by side:
|
||||
- **Spending by Category** (ApexCharts horizontal bar) — category totals for selected month/year
|
||||
- **Balance Trend** (ApexCharts line) — closing balance per month for selected year; chart title includes year (e.g. "Balance trend — 2025") to communicate it is not filtered by month
|
||||
**Left column — Year Summary**
|
||||
- Toolbar: previous-year button, selected year label, next-year button
|
||||
- Summary row: Total Expenses (red) | Total Income (green) — year-only totals (see API note below)
|
||||
- Two sub-columns:
|
||||
- **Doughnut chart** (ApexCharts) — expenses by category for the selected year; legend with category name and amount
|
||||
- **Monthly balances bar chart** (ApexCharts) — closing balance per month for the selected year, from `/api/dashboard/monthly-balances`
|
||||
|
||||
Period picker (month + year dropdowns) in the app bar updates KPI cards and spending chart. Balance trend updates only when the year changes.
|
||||
**Right column — Month Summary**
|
||||
- Toolbar: previous-month button, selected month+year label, next-month button (wraps year when crossing Jan/Dec boundary)
|
||||
- Summary row: Total Expenses (red) | Total Income (green) — from `/api/dashboard/summary` (year+month)
|
||||
- Two sub-columns:
|
||||
- **Doughnut chart** (ApexCharts) — expenses by category for the selected month; legend with category name and amount
|
||||
- **Cumulative spending line chart** (ApexCharts) — running total of expenses day by day through the selected month, from `/api/dashboard/cumulative-spending`
|
||||
|
||||
All widgets show a skeleton loader while fetching and a subtle error indicator on failure.
|
||||
|
||||
The year selection (left toolbar) and month selection (right toolbar) are independent — changing one does not affect the other.
|
||||
|
||||
### Transactions Page
|
||||
|
||||
@ -219,14 +236,12 @@ Vuetify data table:
|
||||
- Search box — server-side (`search` query param, debounced 300 ms)
|
||||
- Server-side pagination (page, pageSize=50)
|
||||
|
||||
### Import Page
|
||||
|
||||
File input (`.csv` only), upload button. On success: "Imported X transactions, skipped Y duplicates." On error: shows the `error` string from the API response.
|
||||
|
||||
### State Management (Pinia)
|
||||
|
||||
- `auth` — token, expiresAt, login/logout actions, 401 handler
|
||||
- `period` — selected year/month, shared across dashboard and transactions
|
||||
- `dashYear` — selected year for the year summary column
|
||||
- `dashMonth` / `dashMonthYear` — selected month+year for the month summary column
|
||||
- `txPeriod` — selected year/month for the transactions page
|
||||
|
||||
---
|
||||
|
||||
@ -248,8 +263,9 @@ account-tracking/
|
||||
│ ├── src/
|
||||
│ │ ├── api/ # NSwag-generated client (do not edit manually)
|
||||
│ │ ├── stores/ # Pinia: auth, period
|
||||
│ │ ├── views/ # Login, Dashboard, Transactions, Import
|
||||
│ │ └── components/ # KpiCard, SpendingChart, BalanceTrendChart
|
||||
│ │ ├── views/ # Login, Dashboard, Transactions
|
||||
│ │ └── components/ # YearSummary, MonthSummary, DonutChart,
|
||||
│ │ # MonthlyBalancesChart, CumulativeSpendingChart
|
||||
│ ├── nswag.json # NSwag config (input: openapi.json, output: src/api/)
|
||||
│ ├── vite.config.ts # includes /api proxy to http://localhost:5000
|
||||
│ └── Dockerfile
|
||||
@ -267,8 +283,10 @@ account-tracking/
|
||||
- **Deduplication via `transaction_id`** — format `transhist-v-YYYY-MM_<sha>`; VARCHAR(512) utf8mb4_bin (case-sensitive) for correctness and future-proofing.
|
||||
- **CSV header detection** — scan for line starting with `číslo účtu`; do not hardcode line number.
|
||||
- **Spending totals exclude positive amounts per category** — refunds within a spending category are excluded from totals.
|
||||
- **`currentBalance` is not period-filtered** — always the globally latest transaction balance; clearly documented in API spec and shown as "not filtered" in UI.
|
||||
- **Balance trend omits months with no transactions** — ApexCharts handles sparse data; no zero-fill.
|
||||
- **Dashboard is two independent columns** — year summary (left) and month summary (right) each have their own period toolbar; they do not share state.
|
||||
- **Upload CSV in app bar** — file picker dialog in-place, no separate import page; result shown as snackbar.
|
||||
- **Month summary line chart is cumulative spending** — running total of expenses day by day through the selected month; gaps filled so line is continuous.
|
||||
- **Monthly balances bar chart** — closing balance per month for the year (sparse, months with no data omitted).
|
||||
- **Search is contains-match (OR)** — `%term%` on counter_party_name OR message; case-insensitive via utf8mb4_unicode_ci.
|
||||
- **Server-side search and pagination** — no client-side filtering of paginated data.
|
||||
- **NSwag via MSBuild** — `openapi.json` generated at `dotnet build`; web Dockerfile copies it; no running API needed.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user