Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions docs/planning/completion-audit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# PrepFlow — Completion Audit (Step 0)

> Generated 2026-06-27 by an autonomous engineering pass. Baseline commit: `816f7e1 chore: initial commit` on `main`.
> This report inventorys the existing code against `DECISIONS.md` §3–6 and the project objective to find what is complete, stubbed, or missing before any feature work begins.

## 1. Controllers / routes — complete vs stubbed

| Controller | Method | Route | State |
|---|---|---|---|
| `AuthController` | `register` | `POST /api/register` | ✅ Complete — validates, `Hash::make`, `Auth::login`, `session()->regenerate(true)`. |
| | `login` | `POST /api/login` | ✅ Complete — `Hash::check`, regenerate. |
| | `logout` | `POST /api/logout` (auth) | ✅ Complete — `invalidate()` + `regenerateToken()`. |
| | `me` | `GET /api/me` (auth) | ✅ Complete. |
| `MenuController` | `index` | `GET /api/menu` | ✅ Complete — raw PDO prepared statement, `?all=1` admin flag. |
| | `store` | `POST /api/admin/menu` | ✅ Complete — PDO prepared INSERT. |
| | `update` | `PATCH /api/admin/menu/{id}` | ✅ Complete — dynamic SET, PDO. |
| | `destroy` | `DELETE /api/admin/menu/{id}` | ✅ Complete — soft-delete via `is_available=0`. |
| | `uploadImage` | `POST /api/admin/menu/image` | ✅ Complete — Cloudinary singleton, data-URL in. |
| `OrderController` | `batches` | `GET /api/batches` (auth) | ✅ Complete. |
| | `index` | `GET /api/orders` (auth) | ✅ Complete — scoped to `user_id`. |
| | `store` | `POST /api/orders` (auth) | ✅ Complete — `DB::transaction` + `lockForUpdate` capacity check. |
| | `show` | `GET /api/orders/{id}` (auth) | ✅ Complete — authz: customer can't read others' orders. |
| | `uploadProof` | `POST /api/orders/{id}/payment-proof` (auth) | ✅ Complete — data-URL decode, local disk store, `pending→payment_uploaded`, audit row. |
| | `adminIndex` | `GET /api/admin/orders` (admin) | ✅ Complete — filter by status/date. |
| | `updateStatus` | `PATCH /api/admin/orders/{id}/status` (admin) | ✅ Complete — audit row `status:{from}->{to}`. |
| `ConfigController` | `paymentMethods` | `GET /api/payment-methods` | ⚠️ Read-only. No admin CRUD for payment methods (DECISIONS §3 implies admin manages `payment_methods`; Settings UI is display-only). |
| | `fulfillmentOptions` | `GET /api/fulfillment-options` | ⚠️ Read-only. No admin CRUD. |
| `PrepController` | `index` | `GET /api/admin/prep` (admin) | ✅ Complete — aggregation SQL, optional date filter. |

**Verdict:** Backend is functionally complete for the locked Phase-1 scope. Gaps are (a) no admin write endpoints for payment methods / fulfillment options (Settings is display-only), and (b) no shipping/courier-link/email/Maps endpoints (Phase 2 scope, not yet in DECISIONS.md).

## 2. Customer screens — exist and what they call

| Route file | Path | API calls | State |
|---|---|---|---|
| `Home.tsx` | `/` | none | ✅ Static marketing hero + "how it works". |
| `Menu.tsx` | `/menu` | `GET /menu` | ✅ Lists available items, add-to-cart, loading skeleton. |
| `Cart.tsx` | `/cart` | none (local store) | ✅ Qty edit, remove, clear, total. |
| `Checkout.tsx` | `/checkout` | `POST /orders`, `POST /orders/{id}/payment-proof`, `GET /payment-methods`, `GET /fulfillment-options` | ⚠️ Functional but **pre-Phase-2**: no shipping fee display, no maps/address autocomplete, no success screen (navigates to `/orders/{id}`), payment-proof camera uses `Camera.getPhoto` directly instead of `capturePhoto()` helper. |
| `Orders.tsx` | `/orders` | `GET /orders` | ✅ List with status badges. |
| `OrderDetail.tsx` | `/orders/:id` | `GET /orders/:id` | ⚠️ Tracker renders `courier_note` as plain text only — no courier-link card / "awaiting booking" placeholder, no shipping fee line, no success-state screen. |
| `Login.tsx` | `/login` | `POST /login` | ✅ Loading state + error toast. |
| `Register.tsx` | `/register` | `POST /register` | ✅ Loading state + error toast. |

## 3. Admin screens — exist and what they call

| Route file | Path | API calls | State |
|---|---|---|---|
| `Dashboard.tsx` | `/admin` | `GET /admin/orders` | ⚠️ Status-count cards + recent list. **No order-pattern charts** (DECISIONS §6.3 "Order pattern dashboard" is a stub). |
| `MenuManager.tsx` | `/admin/menu` | menu CRUD + `POST /admin/menu/image` | ✅ Full CRUD + camera via `capturePhoto()` helper. |
| `Orders.tsx` | `/admin/orders` | `GET /admin/orders?status=` | ✅ Filter chips + list. |
| `OrderDetail.tsx` | `/admin/orders/:id` | `GET /orders/:id`, `PATCH /admin/orders/:id}/status` | ⚠️ Advance/reject works. **No courier-link paste field** (only `rejection_reason` input exists). |
| `Prep.tsx` | `/admin/prep` | `GET /admin/prep?date=` | ✅ Procurement table. |
| `Settings.tsx` | `/admin/settings` | `GET /payment-methods`, `GET /fulfillment-options` | ⚠️ **Display-only** — no CRUD controls; copy says "Editing controls arrive in the next iteration." |

## 4. DECISIONS.md §3–6 feature coverage

### §3 Payment flow (no GCash API)
- ✅ GCash/Bank: QR + account shown, screenshot upload → `payment_uploaded`, admin verify → `confirmed`.
- ✅ COD: skips screenshot; admin accept → `confirmed`.
- ✅ Card tile is disabled "Coming Soon" (`is_active=false`, filtered out in Checkout).
- ⚠️ Admin payment-verification queue: `OrderDetail` shows proof + total side-by-side but there is no dedicated queue view (it's folded into the status-filtered Orders list).

### §4 Fulfillment flow (seller-preferred couriers, no API)
- ✅ `fulfillment_options` configured per context; customer picks mode.
- ✅ Delivery address recorded; `courier_note` field exists.
- ❌ **Seller "paste rider/courier note" UI is missing** — `updateStatus` accepts `courier_note` but the admin OrderDetail form has no input for it. This is the central gap for Phase-2 shipping.

### §5 Order lifecycle
- ✅ Full ENUM present in schema, migration, `shared/index.ts`, `types.ts`.
- ✅ `pending→payment_uploaded→confirmed→preparing→ready/out_for_delivery→completed`; `cancelled` path.
- ✅ Every status transition writes an `AuditLog` row with `action: "status:{from}->{to}"`.

### §6 Core innovations
1. ✅ **Procurement list** — `PrepController` + `v_daily_procurement` view + `/admin/prep`.
2. ✅ **Batch capacity meter + cutoff** — `OrderController::store` inside `DB::transaction` + `lockForUpdate`; `/batches` endpoint; (capacity bar UI in Checkout is not present, only the endpoint).
3. ⚠️ **Order pattern dashboard** — only status-count cards; no SQL-aggregate charts.
4. ❌ **Smart reorder / favorites** — no top-N per customer, no "Order Again" pre-fill. Fully missing.

## 5. Test coverage

| Test file | Covers |
|---|---|
| `MenuCrudTest` | Menu CRUD, authz, validation, soft-delete (8 tests). |
| `MenuImageUploadTest` | Cloudinary upload mocked, authz, error paths (6 tests). |
| `ExampleTest` (Feature + Unit) | Laravel defaults. |

**Missing tests (per Step 8):**
- ❌ `AuthTest` — register, login, logout, session regeneration, role assignment.
- ❌ `OrderTest` — create, capacity enforcement, status transitions, audit-log writes, customer authz.
- ❌ `PaymentProofTest` — upload, status transition to `payment_uploaded`, audit.
- ❌ `ConfigTest` — payment methods + fulfillment options listing.
- ❌ `PrepTest` — procurement list aggregation.

Only Menu has feature tests today, as the objective states.

## 6. Customer payment-proof camera flow — wiring status

- `POST /api/orders/{id}/payment-proof` endpoint: ✅ implemented (`OrderController::uploadProof`).
- `apps/web/src/lib/camera.ts` `capturePhoto()`: ✅ exists, used by **admin** `MenuManager`.
- `Checkout.tsx` payment-proof capture: ⚠️ **wired, but not via the shared helper.** It calls `Camera.getPhoto` directly (lines 35–46) with a `catch` that toasts "Camera cancelled" on *any* error, and a separate hidden `<input type=file>` path. This works but diverges from AGENTS.md §1 (camera.ts is the canonical capture seam) and swallows non-cancel errors as "cancelled". Step 7 will rewire it to `capturePhoto()` + `CaptureCancelledError` for parity with MenuManager and to surface real errors.

## 7. storage:link

- ✅ `api/public/storage` symlink already exists (points to `api/storage/app/public`). Not needed to re-run; `uploadProof` writes to the `public` disk and returns its URL.

## 8. Other observations / quick wins

- `.env.example` has `DB_CONNECTION=sqlite` (correct for the `:memory:` test driver per AGENTS.md §3) and `CLOUDINARY_URL=` placeholder. No `PAYMONGO_*`, `GOOGLE_MAPS_API_KEY`, or `MAIL_*` Phase-2 placeholders yet.
- `bootstrap/app.php` disables CSRF for `api/*` for SPA dev convenience (documented).
- No `pint.json` — Pint runs on Laravel defaults (PSR-12). Step 8 must run `vendor/bin/pint --test` repo-wide and fix the 16 pre-existing failures the objective flags.
- `composer.lock` and `bun.lock` are committed and tracked.
- Order model `fillable`/`casts` has no `shipping_fee` or `courier_link` yet (Phase-2 columns).
- `v_daily_procurement` view exists in `schema.sql` but SQLite (test driver) ignores `CREATE VIEW`; `PrepController` uses inline SQL so tests will work.

## 9. Summary — what to build, in order

1. **DECISIONS.md §8** — unlock Phase-2 scope with reasoning (Step 1).
2. **Shipping tiers** — `shipping_fee` + `courier_link` columns (3-mirror sync), tier table, checkout integration, seller courier-link paste (Step 2). *Centerpiece.*
3. **PayMongo** — opt-in checkout-session redirect, webhook, card tile activation (Step 3).
4. **Maps** — server Distance Matrix proxy, Places autocomplete, dropdown fallback (Step 4).
5. **Transactional email** — `OrderConfirmationMail` mailable, triggers, `Mail::fake()` test (Step 5).
6. **Success screen + tracker** — `/orders/:id/success`, courier-link rendering (Step 6).
7. **Customer camera** — rewire Checkout to `capturePhoto()` (Step 7).
8. **Backend completion + tests** — Auth/Order/PaymentProof/Config/Prep tests, pint cleanup, admin config CRUD (Step 8).
9. **Frontend completion** — charts, reorder, settings CRUD, responsive sweep (Step 9).
10. **Gates + git + report** (Steps 10–12).