Dashboard Refactor: Flow-based Metrics + Unified Data Model #4

Merged
aetos merged 11 commits from cached-reports into main 2026-05-18 05:37:52 +00:00
Owner

Dashboard Refactor: Flow-based Metrics + Unified Data Model

Summary

This MR transforms the dashboard into a flow-driven, backend-powered analytics system with a significantly cleaner architecture and improved UX.

Overview

This MR introduces a major refactor of the dashboard and report data model, transitioning from separate expense/income handling to a unified flow-based (outflows / inflows) system backed by a single metric structure.

It simplifies data handling, improves UI consistency, and enables better extensibility for future analytics.


Key Changes

1. Data Model Simplification

  • Replaced:

    • expenses / incomes
  • With:

    • metric
ReportPeriod {
  start: string;
  end: string;
  metric: {
    sum: number;
    count: number;
    transactions: Transaction[];
  }
}
  • Eliminates duplication across logic paths
  • Flow is now controlled at query level instead of data shape

2. Flow-based System (Core Change)

  • Introduced:

    type DashboardFlow = "outflows" | "inflows";
    
  • Replaced all references of:

    • expenseoutflows
    • incomeinflows
  • Flow is now:

    • Controlled at Dashboard level
    • Propagated to API query (useReport)

3. API Changes

useReport

  • Removed legacy params:

    • group_by, rolling, include_transactions, etc.
  • New structure:

useReport({
  periods: ["daily", "weekly", "monthly", "all"],
  flow,
  payee,
  tags
})
  • Backend now handles:

    • Flow filtering
    • Aggregation

4. Period System Update

  • Removed:

    • yearly, fyly, full
  • Added:

    • daily
    • all
type PeriodType = "daily" | "weekly" | "monthly" | "all";
  • Updated helpers:

    • periodIdToKey
    • buildPeriodId
    • buildLabel

5. React Query UX Improvement

  • Added:
placeholderData: keepPreviousData
  • Prevents UI flicker on filter/flow changes
  • Enables smooth transitions

6. Dashboard State Refactor

Before

mode: "expense" | "income"

After

flow: "outflows" | "inflows"
  • Introduced onFlowChange callback
  • Lifted flow state to parent (Dashboard.tsx)
  • Flow change triggers API refetch

7. UI Improvements

Flow Toggle

  • Replaced mode toggle with:

    • Outflows / Inflows switch

Loading State Handling

  • Added isFetching across components

  • UI behavior during fetch:

    • Reduced opacity
    • Disabled interactions

Drill-down UX

  • Added:

    • "Clear Drill-down" button

8. New Components

TopPayees

  • New analytics card

  • Shows top payees based on:

    • Selected period
    • Drill-down filters
  • Supports:

    • Click-to-filter (drill-down)

9. Adapter Layer Simplification

Removed mode branching everywhere

Examples:

  • getAmount(period) now uses:

    period.metric.sum
    
  • LatestItems, TopTags, HistoryChart:

    • No longer split logic by expense/income
    • Work on unified transaction stream

10. GroupKey Generalization

Before

{
  payee?: string[];
  tags?: string[];
}

After

{
  [dimension: string]: string[];
}
  • Enables future dimensions without refactor

Behavioral Changes

  • Flow selection now controls backend query
  • All components consume filtered data only
  • No client-side filtering for expense/income

Benefits

  • Single source of truth (metric)
  • Cleaner adapters (no branching explosion)
  • Easier feature additions (new dimensions, filters)
  • Better UX (no flicker, smoother transitions)
  • Backend-driven correctness

Migration Notes

  • Replace all mode usages with flow

  • Update adapters to use metric

  • Remove assumptions about:

    • expenses
    • incomes
  • Ensure API supports:

    • flow
    • new period types

Future Scope

  • Add more dimensions (account, category hierarchy)
  • Multi-flow comparison (inflows vs outflows together)
  • Snapshot-based caching (already partially supported)

Testing Notes

Verify:

  • Flow toggle updates API calls

  • No UI flicker on filter change

  • Drill-down works across:

    • tags
    • payees
  • Daily / Weekly / Monthly / All tabs behave correctly

  • Loading state disables interaction properly


# Dashboard Refactor: Flow-based Metrics + Unified Data Model ## Summary This MR transforms the dashboard into a **flow-driven, backend-powered analytics system** with a significantly cleaner architecture and improved UX. ## Overview This MR introduces a **major refactor of the dashboard and report data model**, transitioning from separate `expense/income` handling to a unified **flow-based (`outflows` / `inflows`) system** backed by a single `metric` structure. It simplifies data handling, improves UI consistency, and enables better extensibility for future analytics. --- ## Key Changes ### 1. Data Model Simplification * Replaced: * `expenses` / `incomes` * With: * `metric` ```ts ReportPeriod { start: string; end: string; metric: { sum: number; count: number; transactions: Transaction[]; } } ``` * Eliminates duplication across logic paths * Flow is now controlled at query level instead of data shape --- ### 2. Flow-based System (Core Change) * Introduced: ```ts type DashboardFlow = "outflows" | "inflows"; ``` * Replaced all references of: * `expense` → `outflows` * `income` → `inflows` * Flow is now: * Controlled at **Dashboard level** * Propagated to **API query (`useReport`)** --- ### 3. API Changes #### `useReport` * Removed legacy params: * `group_by`, `rolling`, `include_transactions`, etc. * New structure: ```ts useReport({ periods: ["daily", "weekly", "monthly", "all"], flow, payee, tags }) ``` * Backend now handles: * Flow filtering * Aggregation --- ### 4. Period System Update * Removed: * yearly, fyly, full * Added: * `daily` * `all` ```ts type PeriodType = "daily" | "weekly" | "monthly" | "all"; ``` * Updated helpers: * `periodIdToKey` * `buildPeriodId` * `buildLabel` --- ### 5. React Query UX Improvement * Added: ```ts placeholderData: keepPreviousData ``` * Prevents UI flicker on filter/flow changes * Enables smooth transitions --- ### 6. Dashboard State Refactor #### Before ```ts mode: "expense" | "income" ``` #### After ```ts flow: "outflows" | "inflows" ``` * Introduced `onFlowChange` callback * Lifted flow state to parent (`Dashboard.tsx`) * Flow change triggers API refetch --- ### 7. UI Improvements #### Flow Toggle * Replaced mode toggle with: * Outflows / Inflows switch #### Loading State Handling * Added `isFetching` across components * UI behavior during fetch: * Reduced opacity * Disabled interactions #### Drill-down UX * Added: * "Clear Drill-down" button --- ### 8. New Components #### TopPayees * New analytics card * Shows top payees based on: * Selected period * Drill-down filters * Supports: * Click-to-filter (drill-down) --- ### 9. Adapter Layer Simplification #### Removed mode branching everywhere Examples: * `getAmount(period)` now uses: ```ts period.metric.sum ``` * `LatestItems`, `TopTags`, `HistoryChart`: * No longer split logic by expense/income * Work on unified transaction stream --- ### 10. GroupKey Generalization #### Before ```ts { payee?: string[]; tags?: string[]; } ``` #### After ```ts { [dimension: string]: string[]; } ``` * Enables future dimensions without refactor --- ## Behavioral Changes * Flow selection now **controls backend query** * All components consume **filtered data only** * No client-side filtering for expense/income --- ## Benefits * Single source of truth (`metric`) * Cleaner adapters (no branching explosion) * Easier feature additions (new dimensions, filters) * Better UX (no flicker, smoother transitions) * Backend-driven correctness --- ## Migration Notes * Replace all `mode` usages with `flow` * Update adapters to use `metric` * Remove assumptions about: * `expenses` * `incomes` * Ensure API supports: * `flow` * new period types --- ## Future Scope * Add more dimensions (account, category hierarchy) * Multi-flow comparison (inflows vs outflows together) * Snapshot-based caching (already partially supported) --- ## Testing Notes Verify: * Flow toggle updates API calls * No UI flicker on filter change * Drill-down works across: * tags * payees * Daily / Weekly / Monthly / All tabs behave correctly * Loading state disables interaction properly ---
aetos added 11 commits 2026-05-18 05:37:41 +00:00
aetos merged commit 8bea3d06f6 into main 2026-05-18 05:37:52 +00:00
aetos deleted branch cached-reports 2026-05-18 05:37:52 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: apps/khata-ui#4
No description provided.