# Flowchart — `gifts`

> Produced by the Reversa **Archaeologist** (phase: excavation) · doc_level: `complete`
> Generated on 2026-09-17

**Confidence scale:** 🟢 CONFIRMED · 🟡 INFERRED · 🔴 GAP

## `GiftController::form` — validation & save lifecycle 🟢

```mermaid
flowchart TD
    A["submit new/edit gift<br/>(settings/gifts via ModelForm)"] --> B["validate:<br/>name required<br/>image max:1024 mimes<br/>points/limit nullable numeric min:0"]
    B --> C{"editing existing?"}
    C -->|yes| D["quantity rule =<br/>nullable|numeric|min:{used}<br/>(can't drop stock below redeemed)"]
    C -->|no| E["quantity rule = nullable|numeric"]
    D --> F["saving hook"]
    E --> F
    F --> G["points/limit/quantity ?: 0<br/>used = id ? used : 0"]
    G --> H["persist row"]
    H --> I{"image uploaded?"}
    I -->|yes| J["Image::make(storage/app/public/{image})<br/>-&gt;fit(300,300)-&gt;save()"]
    I -->|no| K["done"]
    J --> K
```

## `GiftController::scan` — redeemable-gift lookup 🟢

```mermaid
flowchart TD
    A["GET settings/gifts/scan?q=&active="] --> B["Gift where name LIKE %q%"]
    B --> C{"has('active')?"}
    C -->|yes| D["where active = request(active)"]
    C -->|no| E["(no active filter)"]
    D --> F["take(10)-&gt;get()"]
    E --> F
    F --> G["json {data: [...]}"]
```

**Notes:**
- Redemption itself is enforced elsewhere: `Customer::checkGiftAvailable` (gift exists, `quantity_available !== 0`, per-customer count `< limit` unless `limit=0`, `points <= customer.points`) and the transactional `CustomerController::redeemRewardPoints` — see `flowcharts/customers.md`. 🟢
- `quantity_available = quantity - used` is computed, not stored; the out-of-stock test uses strict `=== 0`. 🟡
