# Expense Reports UI (`/expenses/reports`)

**Date:** 2026-05-31  
**Status:** Draft  
**Spec:** 57  
**Tier:** All tiers  
**Depends on:** `expenses-module`, `foundation-auth-rbac`  
**Referenced by:** `expenses-module`

---

## Overview

Full UI spec for the expense reports screen. Spec 17 (`expenses-module`) owns the `expenses` data model, all API report endpoints, and the brief mention of the reports surface. This spec owns the UI implementation.

---

## Page: `/expenses/reports`

Three tabs: **Expense Detail**, **VAT Summary**, **Vendor Analysis**.

### Controls (shared)

```
┌──────────────────────────────────────────────────────────────┐
│  Expense Reports                       [Export ▾]            │
│                                                              │
│  Period:  [This Month ▾]   From: [____]  To: [____]         │
│  Category: [All ▾]  Project: [All ▾]  User: [All ▾]        │
└──────────────────────────────────────────────────────────────┘
```

Period presets: This Month, Last Month, This Quarter, This Year, Custom.  
Category filter: 8 IL tax deductibility categories (from `packages/types/src/expense-categories.ts`).

Permission: `reports:read`.

---

### Tab: Expense Detail

Filterable table of individual expense records.

```
┌──────────────────────────────────────────────────────────────────┐
│  Date       Vendor        Category          Amount  Deduct%  VAT  │
│  ────────────────────────────────────────────────────────────── │
│  2026-05-28  Office Depot  Office supplies   ₪320    100%    ₪54  │
│  2026-05-27  Café Blue     Meals (25%)       ₪180     25%    ₪31  │
│  2026-05-25  Telecom Ltd   Phone/Internet    ₪250     50%    ₪43  │
│  ────────────────────────────────────────────────────────────── │
│  Totals                                     ₪750           ₪128  │
│                            Deductible total: ₪512                │
└──────────────────────────────────────────────────────────────────┘
```

Columns: Date, Vendor, Category (IL name), Amount (ILS), Deductibility %, VAT, Deductible Amount (Amount × Deduct%), User.  
Row click → opens expense detail drawer (inline view of spec 17's expense detail).

Footer shows: Total Amount, Total VAT, Deductible Total (sum of Amount × Deductibility).

Export: `GET /api/expenses/reports/expense/xlsx` — existing endpoint from spec 17.

---

### Tab: VAT Summary (PCN874)

Period selector: monthly or bimonthly (per tenant setting from spec 61). Matches Israeli Maamad (מועד הדיווח).

```
┌──────────────────────────────────────────────────────────────┐
│  VAT Period: [May 2026 ▾]    Type: [חשבונית מס ▾]           │
│                                                              │
│  PCN874 Summary                                              │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  Code  Description              Amount (ILS)  VAT      │  │
│  │  ────  ──────────────────────────────────────────────  │  │
│  │  220   עסקאות חייבות במס         ₪24,500      ₪4,165   │  │
│  │  225   עסקאות בשיעור אפס                               │  │
│  │  320   תשומות חייבות במס         ₪8,200       ₪1,394   │  │
│  │  ────  ──────────────────────────────────────────────  │  │
│  │  VAT to pay (code 220 − code 320):          ₪2,771    │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                              │
│  [Export PCN874 Excel]                                       │
└──────────────────────────────────────────────────────────────┘
```

PCN874 line codes populated from expense categories + invoice data. Consult spec 17 § PCN874 for field mapping.  
Export: `GET /api/expenses/reports/vat/xlsx` — existing endpoint from spec 17.

---

### Tab: Vendor Analysis

Groups expenses by `vendor_id` (the linked `vendors` entity), falling back to the OCR-extracted `vendor_name` when no vendor is linked. Linked rows show the canonical `vendors.name`; unlinked rows show the raw OCR text. Bar chart + table.

```
┌──────────────────────────────────────────────────────────────┐
│  [Bar chart: top 10 vendors by total spend]                  │
│                                                              │
│  Vendor          Count   Total     Avg Deduct%  VAT Total    │
│  ──────────────────────────────────────────────────────────  │
│  Office Depot      12    ₪3,840     100%         ₪652        │
│  Telecom Ltd        6    ₪1,500      50%         ₪255        │
│  Café / Meals      18    ₪2,160      25%         ₪367        │
└──────────────────────────────────────────────────────────────┘
```

API: `GET /api/expenses/reports/vendors` — existing endpoint from spec 17.  
No export for vendor analysis (data too summary for spreadsheet utility).

---

## Chart Accessibility and RTL

### Accessibility (adopt spec 24 pattern)

1. Wrapper: `role="figure"` `aria-labelledby="{chart-id}-title"`
2. `<figcaption id="{chart-id}-title">` text matches the visual chart heading
3. Visually-hidden `<table>` sibling containing the same data in tabular form; "Show data table" toggle button adjacent to chart
4. SVG root: `<title>` (e.g., `"Expenses by category: Q1 2025"`) + `<desc>` (trend statement)
5. Tooltip: `aria-live="polite"` region echoing tooltip content on hover/focus
6. Interactive segments (pie slices, bars): focusable via Tab, activated via Enter/Space

### RTL Chart Configuration

```tsx
function ExpenseChart({ locale }: { locale: string }) {
  const isRtl = locale === 'he-IL'
  return (
    <ResponsiveContainer>
      {/* Pie charts: label positions are coordinate-based; mirror tooltip anchor only */}
      <PieChart>
        <Tooltip position={{ x: isRtl ? 'left' : 'right' }} />
      </PieChart>
    </ResponsiveContainer>
  )
}
// For BarChart instances in this spec:
// <YAxis orientation={isRtl ? 'right' : 'left'} />
```

---

## Architecture Decisions

| Decision | Choice | Reason |
|----------|--------|--------|
| Three tabs | Not a single filtered table | Each tab serves a different audience: accountant (VAT), manager (detail), owner (vendor spend) |
| PCN874 tab owned here | Not in settings | Report is a view action, not configuration; settings owns only the period type toggle |
| On-demand from `expenses` table | No pre-aggregate | Expense volumes per tenant per quarter ≈ hundreds; GROUP BY < 200ms; no materialization needed |
