a4942d7684
Wave 1: schema push (service_id nullable + custom_label). Wave 2 (parallel): catalog CRUD page + quote builder tab. Wave 3: E2E human verification checkpoint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
216 lines
9.8 KiB
Markdown
216 lines
9.8 KiB
Markdown
---
|
||
phase: "03"
|
||
plan: "04"
|
||
type: execute
|
||
wave: 3
|
||
depends_on:
|
||
- "03-02"
|
||
- "03-03"
|
||
files_modified: []
|
||
autonomous: false
|
||
requirements:
|
||
- CAT-01
|
||
- CAT-02
|
||
- ADMIN-03
|
||
|
||
must_haves:
|
||
truths:
|
||
- "Admin navigates to /admin/catalog — table shows all services with correct columns and status badges"
|
||
- "Admin adds a service, edits it inline, and disattiva/riattiva it — all changes persist on page refresh"
|
||
- "Admin opens a client's Preventivo tab — adds a catalog item and a freeform item — both appear in the table with correct subtotals and calculated total"
|
||
- "Admin saves an accepted_total — the client dashboard shows that exact amount, not the calculated sum"
|
||
- "A curl request to the client API returns NO quote_items field and NO service_id references"
|
||
artifacts:
|
||
- path: "src/app/admin/catalog/page.tsx"
|
||
provides: "Verified: catalog page loads and renders table"
|
||
- path: "src/components/admin/tabs/QuoteTab.tsx"
|
||
provides: "Verified: three sections render correctly, catalog and freeform items work"
|
||
- path: "src/lib/client-view.ts"
|
||
provides: "Verified: zero quote_items references"
|
||
key_links:
|
||
- from: "clients.accepted_total (DB)"
|
||
to: "client dashboard display"
|
||
via: "client-view.ts query → /c/[token] page"
|
||
pattern: "accepted_total"
|
||
---
|
||
|
||
<objective>
|
||
End-to-end verification of Phase 3. The admin runs the full workflow — create catalog service, add to quote, set accepted_total — and confirms the client dashboard shows the correct total. Also verifies the security constraint: `quote_items` are never returned by the client API.
|
||
|
||
Purpose: Confirms Phase 3 is shippable. Catches any integration issue between catalog, quote builder, and client dashboard before the phase is marked complete.
|
||
Output: Human verification sign-off + SUMMARY.md.
|
||
</objective>
|
||
|
||
<execution_context>
|
||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||
</execution_context>
|
||
|
||
<context>
|
||
@/Users/simonecavalli/IAMCAVALLI/.planning/ROADMAP.md
|
||
@/Users/simonecavalli/IAMCAVALLI/.planning/phases/03-service-catalog-quote-builder/03-02-SUMMARY.md
|
||
@/Users/simonecavalli/IAMCAVALLI/.planning/phases/03-service-catalog-quote-builder/03-03-SUMMARY.md
|
||
</context>
|
||
|
||
<tasks>
|
||
|
||
<task type="auto">
|
||
<name>Task 1: Automated security and integration checks</name>
|
||
<read_first>
|
||
- /Users/simonecavalli/IAMCAVALLI/src/lib/client-view.ts (must contain zero quote_items references)
|
||
- /Users/simonecavalli/IAMCAVALLI/src/app/api (check all client-facing API route files for quote_items leaks)
|
||
</read_first>
|
||
<files></files>
|
||
<action>
|
||
Run the following automated checks in sequence. Report results for each.
|
||
|
||
**Check 1 — TypeScript compiles clean:**
|
||
```bash
|
||
cd /Users/simonecavalli/IAMCAVALLI && npx tsc --noEmit
|
||
```
|
||
Expected: zero output (no errors).
|
||
|
||
**Check 2 — Build succeeds:**
|
||
```bash
|
||
cd /Users/simonecavalli/IAMCAVALLI && npm run build
|
||
```
|
||
Expected: "Compiled successfully" with routes listed. No error lines.
|
||
|
||
**Check 3 — Security: quote_items not in client-facing code:**
|
||
```bash
|
||
cd /Users/simonecavalli/IAMCAVALLI && grep -rn 'quote_items' src/lib/client-view.ts src/app/api/ src/app/c/ 2>/dev/null || echo "CLEAN"
|
||
```
|
||
Expected: "CLEAN" or no output. If any match appears, that file must be fixed before the checkpoint.
|
||
|
||
**Check 4 — Service catalog page references getAllServices:**
|
||
```bash
|
||
cd /Users/simonecavalli/IAMCAVALLI && grep -c 'getAllServices' src/app/admin/catalog/page.tsx
|
||
```
|
||
Expected: 1
|
||
|
||
**Check 5 — NavBar contains Catalogo link:**
|
||
```bash
|
||
cd /Users/simonecavalli/IAMCAVALLI && grep -c '/admin/catalog' src/components/admin/NavBar.tsx
|
||
```
|
||
Expected: 1
|
||
|
||
**Check 6 — Client detail page has Preventivo tab:**
|
||
```bash
|
||
cd /Users/simonecavalli/IAMCAVALLI && grep -c 'Preventivo' src/app/admin/clients/\[id\]/page.tsx
|
||
```
|
||
Expected: 2
|
||
|
||
**Check 7 — quote-actions has requireAdmin in all three actions:**
|
||
```bash
|
||
cd /Users/simonecavalli/IAMCAVALLI && grep -c 'requireAdmin' src/app/admin/clients/\[id\]/quote-actions.ts
|
||
```
|
||
Expected: 3 (one per action)
|
||
|
||
**Check 8 — accepted_total security check (client view does NOT expose quote detail):**
|
||
```bash
|
||
cd /Users/simonecavalli/IAMCAVALLI && grep 'accepted_total\|quote_items\|service_id' src/lib/client-view.ts
|
||
```
|
||
Expected: `accepted_total` appears (it's the field clients see), `quote_items` does NOT appear, `service_id` does NOT appear.
|
||
|
||
If all 8 checks pass, proceed to the human verification checkpoint.
|
||
If any check fails, fix the issue before proceeding.
|
||
</action>
|
||
<verify>
|
||
<automated>cd /Users/simonecavalli/IAMCAVALLI && npx tsc --noEmit && npm run build 2>&1 | tail -5</automated>
|
||
Expected: build output ends with route list — no "Failed to compile" line.
|
||
<automated>cd /Users/simonecavalli/IAMCAVALLI && grep -rn 'quote_items' src/lib/client-view.ts src/app/c/ 2>/dev/null | wc -l | tr -d ' '</automated>
|
||
Expected: 0
|
||
</verify>
|
||
<done>
|
||
All 8 automated checks pass. TypeScript clean, build succeeds, quote_items absent from client-facing code.
|
||
</done>
|
||
</task>
|
||
|
||
<task type="checkpoint:human-verify" gate="blocking">
|
||
<name>Task 2: Human end-to-end verification of Phase 3</name>
|
||
<what-built>
|
||
Service Catalog CRUD at /admin/catalog, Quote Builder tab in client detail, accepted_total round-trip to client dashboard.
|
||
</what-built>
|
||
<how-to-verify>
|
||
Start the dev server: `npm run dev` (port 3000).
|
||
|
||
**Test A — Catalog page:**
|
||
1. Open http://localhost:3000/admin/catalog
|
||
2. Confirm the page loads with "Catalogo Servizi" heading and "Aggiungi servizio" button
|
||
3. Click "Aggiungi servizio" — fill in Nome: "Test Servizio", Prezzo: "500" — click Aggiungi
|
||
4. Confirm "Test Servizio" appears in the table with "Attivo" badge and €500,00 price
|
||
5. Click "Modifica" on the row — change price to "750" — click Salva
|
||
6. Confirm price updates to €750,00 without page reload
|
||
7. Click "Disattiva" — confirm badge changes to "Disattivato" and row becomes dimmed (50% opacity)
|
||
8. Click "Riattiva" — confirm badge returns to "Attivo"
|
||
|
||
**Test B — NavBar:**
|
||
1. Confirm "Catalogo" link appears in the admin NavBar between "Statistiche" and "Esci"
|
||
2. Click it — confirm it navigates to /admin/catalog
|
||
|
||
**Test C — Quote Builder tab:**
|
||
1. Open any existing client at http://localhost:3000/admin/clients/[id]
|
||
2. Confirm "Preventivo" tab appears as 5th tab (after Commenti)
|
||
3. Click the Preventivo tab
|
||
4. Select "Test Servizio" from the dropdown (if inactive, reactivate first) — set qty 1 — click Aggiungi
|
||
5. Confirm item appears in the table with correct unit price and subtotal
|
||
6. Click "Oppure aggiungi voce libera →" — enter Nome: "Extra consulenza", Prezzo: "200", Qty: 2 — click Aggiungi voce libera
|
||
7. Confirm second item appears with "Extra consulenza" label, subtotal €400,00
|
||
8. Confirm "Totale calcolato" shows the sum (e.g., €1.150,00 if service was €750)
|
||
9. Click "Rimuovi" on one item — confirm it disappears
|
||
|
||
**Test D — Accepted total round-trip (critical):**
|
||
1. In the Preventivo tab, set "Totale accettato dal cliente" to 1200 — click Salva
|
||
2. Open the client dashboard at http://localhost:3000/c/[client-token] in a new tab
|
||
3. Confirm the dashboard shows "€1.200,00" (or equivalent) as the accepted total
|
||
4. Back in admin, open the Pagamenti tab — confirm "Totale preventivo" input shows 1200
|
||
|
||
**Test E — Security check (quote_items never exposed):**
|
||
1. In the browser DevTools (Network tab), open the client dashboard /c/[token]
|
||
2. Find any API calls made by that page — inspect their response bodies
|
||
3. Confirm NO response contains "quote_items", "service_id" (from quote context), or individual line item prices
|
||
4. Alternative: run `curl http://localhost:3000/api/client/[client-id-or-token]` if a client API route exists — confirm response has only `accepted_total`, not quote item details
|
||
</how-to-verify>
|
||
<resume-signal>
|
||
Type "approved" if all 5 tests pass. Or describe any failures (e.g., "Test C step 5 fails — items not appearing") so they can be fixed.
|
||
</resume-signal>
|
||
</task>
|
||
|
||
</tasks>
|
||
|
||
<threat_model>
|
||
## Trust Boundaries
|
||
|
||
| Boundary | Description |
|
||
|----------|-------------|
|
||
| Client browser → /c/[token] route | Client sees only what the route explicitly returns — verified here that quote_items are absent |
|
||
|
||
## STRIDE Threat Register
|
||
|
||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||
|-----------|----------|-----------|-------------|-----------------|
|
||
| T-03-04-01 | Information Disclosure | Client dashboard API response | mitigate | Check 3 + Test E verify that no quote_items appear in any client-facing response; if found, fix before approving |
|
||
| T-03-04-02 | Tampering | Phase 3 shipped without DB push | mitigate | 03-01 is a hard dependency of this wave; if drizzle-kit push was skipped, custom_label column absent causes runtime crash caught in Test C |
|
||
</threat_model>
|
||
|
||
<verification>
|
||
Phase 3 complete when:
|
||
1. All 8 automated checks in Task 1 pass
|
||
2. Human verifies Tests A–E in Task 2
|
||
3. Client dashboard shows correct `accepted_total` after update (Test D)
|
||
4. Zero `quote_items` in any client-facing response (Test E)
|
||
</verification>
|
||
|
||
<success_criteria>
|
||
- Service catalog is fully operational: add, edit, disable, re-enable services
|
||
- Quote builder adds catalog items (with snapshotted price) and freeform items (service_id = null)
|
||
- accepted_total write in admin is reflected in client dashboard
|
||
- Phase 3 roadmap success criteria 1–3 are all TRUE:
|
||
1. Admin can add/edit/disable catalog services
|
||
2. Admin can compose a quote from catalog; system calculates total
|
||
3. After saving accepted_total, client dashboard shows correct total; quote_items never exposed
|
||
</success_criteria>
|
||
|
||
<output>
|
||
After completion, create `.planning/phases/03-service-catalog-quote-builder/03-04-SUMMARY.md`
|
||
</output> |