# Gifts Scan — Implementation Tasks

> Produced by the Reversa **Writer** (phase: generation) · doc_level: `complete`
> Generated on 2026-09-21

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

## Prerequisites

- [ ] `Gift` model with `SoftDeletes`, `$fillable`, appended `quantity_available`, and image accessor. 🟢 (`Gift.php`)
- [ ] `gifts` table populated (the `gifts-crud` unit). 🟢 (`create_gifts_table` migration)
- [ ] Admin route group `['web','admin']` + `settings` prefix, with `settings/gifts/scan` declared **before** `resource settings/gifts`. 🟢 (`routes/web.php:86-91`)

## Tasks

> Each task references the legacy file the behaviour was extracted from.

- [ ] T-01, Register `GET settings/gifts/scan` → `GiftController@scan` before the `resource settings/gifts` line so it is not shadowed by the resource `show` route.
  - Legacy origin: `routes/web.php:90-91`
  - Done when: `settings/gifts/scan` resolves to `scan` (not `show`) for an authenticated admin; anonymous → `302` to `auth/login`.
  - Confidence: 🟢

- [ ] T-02, Implement the name search: `$q = request('q')`; `Gift::where('name','like',"%$q%")`.
  - Legacy origin: `GiftController.php:117-118`
  - Done when: results contain only gifts whose name contains `q` (soft-deleted excluded by default scope).
  - Confidence: 🟢

- [ ] T-03, Implement the optional `active` filter: when `request()->has('active')`, chain `->where('active', request('active'))`.
  - Legacy origin: `GiftController.php:119-121`
  - Done when: `?active=1` returns active only; omitting `active` returns both statuses.
  - Confidence: 🟢

- [ ] T-04, Cap and materialise: `->take(10)->get()`.
  - Legacy origin: `GiftController.php:122`
  - Done when: at most 10 rows are returned.
  - Confidence: 🟢

- [ ] T-05, Return the envelope: `response()->json(['data' => $result])` (200, `data` array, empty `[]` when no match).
  - Legacy origin: `GiftController.php:123-125`
  - Done when: the response is `{data:[…]}` with full gift records (incl. `quantity_available`, image URL).
  - Confidence: 🟢

- [ ] T-06, (Decision, not yet in legacy) Define the empty/missing-`q` contract — return `[]` vs the current first-10 behaviour.
  - Legacy origin: `GiftController.php:118`
  - Done when: the empty-query behaviour is decided and enforced.
  - Confidence: 🔴

- [x] T-07, Document that the caller must pass `active=1` and handle `quantity_available` client-side.
  - Legacy origin: `GiftController.php:118-121`; `gifts` flowchart:41
  - Done when: the picker never offers unredeemable gifts, or the contract is explicit.
  - Confidence: 🟢 — ✅ Verified 2026-09-23 (`questions.md#question-7`): the only consumer already calls with `?active=1` and greys out/disables (`pointer-events: none`) any `quantity_available <= 0` option (`customer-statis.blade.php:328,338`). No endpoint change needed.

- [ ] T-08, (Improvement, not in legacy) Add observability on the lookup path.
  - Legacy origin: `GiftController.php:115-126` (absence)
  - Done when: the endpoint emits a structured log/metric.
  - Confidence: 🔴

## Test Tasks

- [ ] TT-01, Name search: `?q=x` returns ≤10 gifts whose name contains "x" as `{data:[…]}` (see `requirements.md`, Acceptance Criteria).
- [ ] TT-02, Active filter: `?q=x&active=1` returns active only; without `active`, both statuses appear.
- [ ] TT-03, Cap: more than 10 matches still return at most 10.
- [ ] TT-04, Soft delete: a deleted gift never appears.
- [ ] TT-05, Payload: each element carries `quantity_available` and an image URL.
- [ ] TT-06, Auth: anonymous request → `302` to `auth/login`.

## Suggested Order

1. T-01 → T-05 (route + query + filter + cap + envelope).
2. T-06 → T-08 (empty-query contract, redeemable filtering, observability).

## Pending Gaps (🔴)

- **Empty-query contract (T-06):** decide `[]` vs first-10.
- **No observability (T-08):** the lookup emits no signal.
