157 lines
14 KiB
Markdown
157 lines
14 KiB
Markdown
# Feature Landscape — UI/UX Polish
|
||
|
||
**Domain:** Personal finance dashboard (pastel spreadsheet aesthetic)
|
||
**Researched:** 2026-03-11
|
||
**Milestone scope:** Existing backend is complete. This pass is purely about making what exists look and feel premium.
|
||
|
||
---
|
||
|
||
## What "Premium" Means for This App
|
||
|
||
The stated vision is "opening the app should feel like opening a beautifully designed personal spreadsheet." That is a specific aesthetic contract: data-dense but not cluttered, color-coded but soft, functional but delightful. A premium personal finance tool is not a banking dashboard (dark, heavy, corporate) — it is closer to Notion or Linear: calm, spacious, consistent, with color that communicates meaning rather than decoration.
|
||
|
||
The gap today: The CSS variables are pure neutral (zero chroma in all OKLCH values), the card headers have correct pastel gradient classes but no actual pastel primary/accent colors, the login screen is a plain white card on a plain white background, and the sidebar has no brand identity. Everything works but nothing _looks_ intentional.
|
||
|
||
---
|
||
|
||
## Table Stakes
|
||
|
||
Features users expect. Missing = product feels unfinished.
|
||
|
||
| Feature | Why Expected | Current State | Complexity | Notes |
|
||
|---------|--------------|---------------|------------|-------|
|
||
| **Pastel color system in CSS variables** | The entire visual identity depends on it — currently all chroma: 0 (neutral grey) | Missing — `--primary`, `--accent`, `--chart-*` use zero-chroma values | Low | Single change in `index.css` unlocks color across every shadcn component. The card header gradient classes are already correct; they just have no color to work with. |
|
||
| **Login/Register: branded background** | Auth screen is the first impression. White card on white screen communicates nothing | Just `bg-background` (white) | Low | Add a soft pastel gradient or subtle pattern to the `min-h-screen` wrapper |
|
||
| **Login/Register: app logo or wordmark** | Users expect a visual identity at the entry point | `CardDescription` shows `app.title` as plain text | Low | Even a styled typographic treatment works without designing an icon |
|
||
| **Sidebar: visual brand identity** | Sidebar is always visible — it anchors the whole app's look | Plain white sidebar, `h2` text for title, no color differentiation | Low–Med | Pastel sidebar background, heavier app name treatment |
|
||
| **Active nav item: clear visual indicator** | Users need to know where they are. shadcn `isActive` prop exists but needs styled colors | `isActive` is wired, unstyled | Low | CSS variable for sidebar-primary needs a real color |
|
||
| **Card hover states on inline-editable rows** | The edit trigger is `hover:bg-muted` — with no muted color it's invisible | No visible hover feedback | Low | Requires a non-neutral `--muted` value |
|
||
| **Loading state: spinner/pulse on form submission** | Buttons say "disabled" during async calls but give no visual motion feedback | `disabled` only | Low | Add Tailwind `animate-pulse` or a lucide `Loader2` spinner inside submit buttons |
|
||
| **Page-level loading skeleton for dashboard** | Dashboard has `<Skeleton>` calls but skeleton is unstyled (neutral grey) | Skeleton exists, no pastel color | Low | Style skeletons to match section colors |
|
||
| **Empty state: first-time experience** | The `t('dashboard.noBudgets')` card is just grey text. First-time users need direction | Bare `text-muted-foreground` text | Low–Med | Illustrative empty state with a CTA to create the first budget |
|
||
| **Category empty state on CategoriesPage** | If no categories exist (possible state), nothing renders — `grouped.filter` could produce empty array | Returns silently empty | Low | Add empty state card with create CTA |
|
||
| **Error feedback on form failures** | Auth errors show raw error strings; no visual differentiation from normal text | `text-destructive` paragraph, but destructive color needs styling | Low | Pair with error icon and styled alert block |
|
||
| **Consistent section headers** | Every dashboard card uses a slightly different gradient (sky-to-indigo, blue-to-indigo, pink-to-rose, etc.) — good start but the overall palette looks fragmented | Each card picks ad-hoc gradient colors | Low | Align gradients to a single palette family derived from the pastel color system |
|
||
| **Typography hierarchy** | Dashboard page has no visual hierarchy — all cards look equal weight. The `FinancialOverview` and `AvailableBalance` should feel like the hero items | All cards same shadow/border/weight | Low–Med | Use subtle elevation (shadow-sm vs shadow) or card size differences to establish hierarchy |
|
||
| **Positive/negative amount coloring** | `VariableExpenses` colors negative remaining red via `text-destructive` — good. `FinancialOverview` and `BillsTracker` do not | Inconsistent | Low | Extend the pattern to all currency display: negative = destructive, over-budget = warning amber |
|
||
| **Responsive sidebar: collapsible on smaller screens** | SidebarProvider supports it, but no toggle button is present in the layout | Not surfaced | Low | Add hamburger/collapse trigger to SidebarInset header area |
|
||
|
||
---
|
||
|
||
## Differentiators
|
||
|
||
Features that are not expected but elevate the experience from "usable" to "delightful."
|
||
|
||
| Feature | Value Proposition | Current State | Complexity | Notes |
|
||
|---------|-------------------|---------------|------------|-------|
|
||
| **Donut chart center label shows month + year** | The `AvailableBalance` donut already has an amount in the center. Adding context (month name) makes it more meaningful at a glance | Only the amount | Low | Render `budget.name` or derived month/year below the amount |
|
||
| **Budget health indicator on header** | A small color-coded badge next to the budget selector (green = on track, amber = tight, red = over) derived from `totals.available` vs total income | Not present | Low–Med | Purely computed from existing data, no backend change |
|
||
| **Inline edit: visual affordance (pencil icon on hover)** | Current inline edit is discoverable only by hovering and noticing the background change. A pencil icon makes it explicit | Background hint only | Low | Add a `lucide-react` `Pencil` icon that fades in on row hover |
|
||
| **Save confirmation: row flash on successful inline edit** | After blur/Enter saves a value, nothing acknowledges the save. A brief green background flash (100ms) confirms the action succeeded | No feedback | Low–Med | CSS `transition` + toggled class; requires tracking save success in row state |
|
||
| **Category creation inside budget item add flow** | Users currently must leave the dashboard, go to Categories, create a category, then return. Linking category management directly from a "add item" action would reduce friction | No cross-page flow | High | Requires dialog-within-dialog or slide-over; warrants its own milestone item |
|
||
| **Month navigator: prev/next arrows beside budget selector** | Instead of only a dropdown, allow quick sequential navigation through budgets. Most months are adjacent | Dropdown only | Med | Would need sorting budgets by date and prev/next pointer logic |
|
||
| **Chart tooltips: formatted with currency** | Recharts `<Tooltip />` renders raw numbers. Formatting with the budget's currency makes tooltips professional | Raw number in tooltip | Low | Custom `Tooltip` formatter using the existing `formatCurrency` util |
|
||
| **Progress bars in BillsTracker for actual vs budget** | Seeing 85% of a bill paid vs just raw numbers adds spatial meaning | Tables only | Med | Bar per row using `actual/budgeted` ratio with color based on threshold |
|
||
| **Animated number transitions** | When inline edits are saved and totals recompute, numbers jump. A short count animation (200ms) makes the update feel responsive | Hard jump | Med | Use a lightweight counter animation hook; only applies to summary numbers in FinancialOverview and AvailableBalance |
|
||
| **Savings/Investments: visual progress toward goal** | Savings and investment items have both budgeted and actual amounts. A thin progress arc per item communicates progress toward monthly target | Table rows only | Med | Small inline arc per row using SVG or Recharts |
|
||
|
||
---
|
||
|
||
## Anti-Features
|
||
|
||
Things to explicitly NOT build during this polish pass.
|
||
|
||
| Anti-Feature | Why Avoid | What to Do Instead |
|
||
|--------------|-----------|-------------------|
|
||
| **Dark mode toggle** | CSS variables for dark are already in `index.css` but the pastel system must be defined first. Dark pastel is a distinct design problem. Adding a toggle now couples two unfinished systems. | Get the light mode color system right first; dark mode in a future milestone |
|
||
| **Custom color picker / theme selector** | PROJECT.md calls this out explicitly as out of scope. Complex state with no current value. | The color tokens are centralized — theme variants can be added later cleanly |
|
||
| **Animated page transitions** | Route-level enter/exit animations (Framer Motion) add JS weight and complexity for marginal benefit in a data-first app | Keep transitions limited to within-page state changes (inline edits, loading states) |
|
||
| **Toast notifications for every action** | Inline save feedback (row flash) is more contextual. Global toasts for every data save are noisy in a dashboard that supports rapid sequential edits | Use toast only for errors and destructive actions (delete), not saves |
|
||
| **Drag-to-reorder categories on the dashboard** | `sort_order` exists on categories but reordering on the dashboard itself is a UX scope expansion. The Categories page is the right place for sort management | Accept keyboard-ordered sort for this milestone |
|
||
| **Charts outside of existing sections** | Do not add new chart types (e.g., multi-month trend line, sparklines per category) in this pass. The goal is polishing existing charts, not adding new data views | Polish the existing Pie, Donut, and BarChart; trend analysis is a future milestone |
|
||
| **Onboarding wizard / guided tour** | First-run experience improvements are valuable but a multi-step wizard is high complexity for a single-user self-hosted app | An improved empty state with a clear CTA is sufficient |
|
||
| **Keyboard shortcuts / command palette** | Power-user feature that belongs after the visual foundation is established | Out of scope for this milestone |
|
||
|
||
---
|
||
|
||
## Feature Dependencies
|
||
|
||
```
|
||
Pastel CSS variable system
|
||
→ active nav item colors (sidebar-primary needs chroma)
|
||
→ card hover states (muted needs chroma)
|
||
→ skeleton background color
|
||
→ button loading spinners (match primary color)
|
||
→ progress bars in BillsTracker (use existing chart color tokens)
|
||
→ budget health badge colors
|
||
|
||
Login branded background
|
||
→ requires background to have a color, which needs the pastel system
|
||
|
||
Inline edit save confirmation (row flash)
|
||
→ requires inline edit mechanism (already exists)
|
||
→ requires knowing save succeeded (currently onSave returns a Promise — can use resolution)
|
||
|
||
Chart tooltip currency formatting
|
||
→ requires access to budget.currency (already in component scope)
|
||
→ no other dependencies
|
||
|
||
Month navigator (prev/next)
|
||
→ requires budget list sorted by date
|
||
→ requires selectBudget to be called (already available in useBudgets hook)
|
||
```
|
||
|
||
---
|
||
|
||
## MVP Recommendation for This Polish Milestone
|
||
|
||
These should be done in order because earlier items unlock later items visually.
|
||
|
||
**First (foundation — everything else depends on it):**
|
||
1. Redefine `--primary`, `--accent`, `--muted`, `--sidebar`, `--chart-1` through `--chart-5` in `index.css` with actual pastel OKLCH values. This single change transforms the entire app.
|
||
2. Apply branded login/register background — a soft pastel gradient wrapping the card.
|
||
|
||
**Second (structural polish — visible on every page load):**
|
||
3. Sidebar brand treatment — pastel sidebar background, heavier app name, colored active nav.
|
||
4. Typography hierarchy on dashboard — make FinancialOverview + AvailableBalance visually the hero row.
|
||
5. Consistent card section header palette — unify the gradient choices across all dashboard cards.
|
||
|
||
**Third (interaction quality):**
|
||
6. Loading spinners inside submit buttons (login, save, budget create).
|
||
7. Inline edit affordance — pencil icon on row hover.
|
||
8. Save confirmation flash on inline edit success.
|
||
9. Positive/negative amount coloring applied consistently across all tables.
|
||
|
||
**Fourth (completeness — guards against "unfinished" feeling):**
|
||
10. Empty state for first-time dashboard (no budgets yet).
|
||
11. Empty state for CategoriesPage.
|
||
12. Chart tooltips formatted with currency.
|
||
13. Collapsible sidebar toggle for smaller screens.
|
||
|
||
**Defer:**
|
||
- Progress bars in BillsTracker: useful but higher complexity; tackle if time allows.
|
||
- Animated number transitions: medium complexity, medium payoff.
|
||
- Category creation inline from dashboard: high complexity, belongs in a future milestone.
|
||
- Month navigator: medium complexity; polish-pass bonus if foundation is solid.
|
||
|
||
---
|
||
|
||
## Confidence Assessment
|
||
|
||
| Area | Confidence | Notes |
|
||
|------|------------|-------|
|
||
| Gap analysis (what's missing) | HIGH | Based on direct code review — all findings are grounded in the actual source |
|
||
| Table stakes categorization | HIGH | Standard UI/UX craft, no library-specific claims |
|
||
| Differentiators | MEDIUM | Based on domain experience with personal finance tools; no external sources were available during this research session |
|
||
| Anti-features | HIGH | Grounded in PROJECT.md constraints and direct complexity analysis |
|
||
|
||
**Note on research method:** WebSearch and Context7 were not available in this session. All findings are derived from direct codebase analysis (all frontend source files read) and domain knowledge of finance dashboard UX patterns. The gap analysis is HIGH confidence because it is based on code inspection. The "premium differentiators" section carries MEDIUM confidence because it reflects design judgment rather than verified external benchmarks. Recommend treating differentiators as starting proposals for the roadmap rather than firm requirements.
|
||
|
||
---
|
||
|
||
## Sources
|
||
|
||
- Direct review: all files under `/frontend/src/` (pages, components, hooks, App.tsx, index.css)
|
||
- Project constraints: `.planning/PROJECT.md`
|
||
- Design intent: `CLAUDE.md` architecture notes
|