# Phase 6: Dashboard API — Completion Log

## Date Completed
2026-03-12

## Files Created
| File | Purpose |
|---|---|
| `app/Services/ShopManager/DashboardService.php` | Shared query logic: period resolution, previous period calc, paid orders base query, sparkline generation, percentage change |
| `app/Http/Controllers/Api/Employee/ShopManager/Dashboard/RevenueController.php` | Revenue total, % change vs previous period, daily chart data |
| `app/Http/Controllers/Api/Employee/ShopManager/Dashboard/CheckoutSnapshotController.php` | 3-tab snapshot: checkout count, basket average, risk (refunds) with sparklines |
| `app/Http/Controllers/Api/Employee/ShopManager/Dashboard/SalesPerformanceController.php` | Sales grouped by day of week, supports revenue/orders/basket metrics |
| `app/Http/Controllers/Api/Employee/ShopManager/Dashboard/BestSellerController.php` | Top-selling products by quantity sold in period |
| `app/Http/Controllers/Api/Employee/ShopManager/Dashboard/RecentActivityController.php` | Unified feed merging sales + stock adjustment events |
| `app/Http/Controllers/Api/Employee/ShopManager/Dashboard/TopCategoriesController.php` | Category breakdown by % of revenue with trend labels |
| `tests/Feature/Controllers/ShopManager/DashboardTest.php` | Comprehensive tests for all 6 dashboard endpoints |

## Files Modified
| File | Change |
|---|---|
| `routes/api.php` | Added 6 dashboard route imports and GET routes under `dashboard/*` prefix |

## Migrations
No new migrations required — all data comes from existing `orders`, `order_items`, `products`, `categories`, and `product_variation_stocks` tables.

## Tests Written
| Test File | Test Count | All Pass? |
|---|---|---|
| `tests/Feature/Controllers/ShopManager/DashboardTest.php` | 19 | Pending run |

### Test Coverage
- Revenue: total, % change, chart entries per day, custom date range, empty state
- Checkout Snapshot: all 3 sections structure, basket average calculation, empty state
- Sales Performance: day-of-week grouping, current day highlight, 7 entries
- Best Sellers: most sold product, empty state
- Recent Activity: sales events, merged sales+stock events, empty state
- Top Categories: correct percentages, empty state
- Period defaults work when no params
- Non-shop-manager gets 403 on all 6 endpoints

## Swagger Docs
- [x] All 6 new controllers have @OA\ annotations (Get, Parameters, Responses)
- [ ] `php artisan l5-swagger:generate` — not yet run

## Quality Checks
- [ ] `./gitCheck.sh` passes — not yet run
- [x] `declare(strict_types=1)` in every PHP file
- [x] No dd(), dump(), var_dump() in code
- [x] All classes are final
- [x] public_id used in API (never id)
- [ ] `composer test` — not yet run

## Commits
Not yet committed.

## Architecture Decisions

### DashboardService
Central service providing:
- **Period resolution**: `today`, `7d`, `14d`, `30d`, `custom` → Carbon date pairs
- **Previous period**: calculates equivalent prior period for % change comparisons
- **Base query**: `paidOrdersQuery(place, from, to)` returns Builder for PAID orders scoped to place and date range
- **Sparkline**: generates daily data points filling gaps with zeros
- **Percentage change**: handles division by zero gracefully

### Revenue
- Sums `order_items.money_price_amount` joined through orders
- Chart: one entry per day with gap-filling
- Currency detected from latest order item, defaults to USD

### Checkout Snapshot
- **Checkout tab**: COUNT of PAID orders
- **Basket tab**: AVG of per-order item totals
- **Risk tab**: COUNT of orders with `refunded_at` set; `failed_payments` hardcoded to 0 (Stripe failures not tracked per architecture decision)

### Sales Performance
- Uses MySQL `DAYOFWEEK()` for grouping (1=SUN through 7=SAT)
- Supports 3 metrics: revenue (sum), orders (count), basket (avg)
- Highlights current day with `is_today` flag

### Best Sellers
- Sums quantity from `order_items.metadata->$.quantity` via `JSON_EXTRACT`
- Badge logic: "TOP RATED" if avg approved review rating >= 4.0

### Recent Activity
- Merges two sources: PAID orders (sale type) and manual stock adjustments (inventory type, where `order_id IS NULL`)
- Sorted by timestamp DESC, limited to N items
- `updates_count` = PAID orders in last 24h

### Top Categories
- Joins OrderItems → Products → Categories for PAID orders
- Calculates % of total revenue per category
- Trend: compares current vs previous period percentage (>2% diff = rising/declining, else stable)
- Highest % category always gets "best" trend

## Endpoints Summary
| Method | Path | Controller |
|---|---|---|
| GET | `/v1/places/{place}/shop/dashboard/revenue` | RevenueController |
| GET | `/v1/places/{place}/shop/dashboard/checkout-snapshot` | CheckoutSnapshotController |
| GET | `/v1/places/{place}/shop/dashboard/sales-performance` | SalesPerformanceController |
| GET | `/v1/places/{place}/shop/dashboard/best-sellers` | BestSellerController |
| GET | `/v1/places/{place}/shop/dashboard/recent-activity` | RecentActivityController |
| GET | `/v1/places/{place}/shop/dashboard/top-categories` | TopCategoriesController |

## Blockers / Open Questions
- `./gitCheck.sh` and `composer test` need to be run to verify lint/PHPStan/test compliance
- `php artisan l5-swagger:generate` needs to be run after verification
- Dashboard caching (Redis with midnight pre-compute) is described in the phase doc but was **not implemented** — these endpoints query live data. Caching can be layered on top later via middleware or service-level cache if performance requires it.
