fix(04): revision 1 — depends_on format + D-12 client list coverage

- 04-02/03/04: change depends_on from filename format to plan ID format
  ('04-01-PLAN.md' → '04-01') to match orchestrator expectations and
  Phase 3 precedent
- 04-02: add Task 3 implementing D-12 — /admin/clients list shows brand
  names below client name and LTV as sum of project accepted_totals;
  update getAllClientsWithPayments query and ClientRow component;
  add src/app/admin/page.tsx, src/lib/admin-queries.ts,
  src/components/admin/ClientRow.tsx to files_modified

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 11:10:25 +02:00
parent d210cf6202
commit 49ef45da83
3 changed files with 106 additions and 4 deletions
@@ -4,7 +4,7 @@ plan: "02"
type: execute type: execute
wave: 2 wave: 2
depends_on: depends_on:
- 04-01-PLAN.md - "04-01"
files_modified: files_modified:
- src/components/admin/NavBar.tsx - src/components/admin/NavBar.tsx
- src/components/admin/ProjectRow.tsx - src/components/admin/ProjectRow.tsx
@@ -12,6 +12,9 @@ files_modified:
- src/app/admin/projects/new/page.tsx - src/app/admin/projects/new/page.tsx
- src/app/admin/projects/project-actions.ts - src/app/admin/projects/project-actions.ts
- src/app/admin/clients/[id]/page.tsx - src/app/admin/clients/[id]/page.tsx
- src/app/admin/page.tsx
- src/lib/admin-queries.ts
- src/components/admin/ClientRow.tsx
autonomous: true autonomous: true
requirements: requirements:
- PROJ-01 - PROJ-01
@@ -25,6 +28,7 @@ must_haves:
- "La pagina /admin/clients/[id] mostra cards dei progetti del cliente con bottone '+ Nuovo Progetto'" - "La pagina /admin/clients/[id] mostra cards dei progetti del cliente con bottone '+ Nuovo Progetto'"
- "Cliccando una card progetto si naviga a /admin/projects/[id]" - "Cliccando una card progetto si naviga a /admin/projects/[id]"
- "createProject e archiveProject sono server actions funzionanti" - "createProject e archiveProject sono server actions funzionanti"
- "La lista /admin/clients mostra brand names dei progetti sotto il nome cliente e il Life Time Value (LTV = somma accepted_total di tutti i progetti del cliente) — D-12"
artifacts: artifacts:
- path: "src/components/admin/NavBar.tsx" - path: "src/components/admin/NavBar.tsx"
provides: "NavBar con link Progetti e Impostazioni" provides: "NavBar con link Progetti e Impostazioni"
@@ -44,6 +48,9 @@ must_haves:
- path: "src/app/admin/clients/[id]/page.tsx" - path: "src/app/admin/clients/[id]/page.tsx"
provides: "Pagina cliente modificata per mostrare project cards" provides: "Pagina cliente modificata per mostrare project cards"
contains: "getClientWithProjects" contains: "getClientWithProjects"
- path: "src/app/admin/page.tsx"
provides: "Lista clienti con brand names secondari e LTV colonna — D-12"
contains: "getAllClientsWithPayments"
key_links: key_links:
- from: "src/app/admin/projects/page.tsx" - from: "src/app/admin/projects/page.tsx"
to: "src/lib/admin-queries.ts" to: "src/lib/admin-queries.ts"
@@ -550,6 +557,101 @@ export default async function NewProjectPage({
<done>/admin/projects funzionale con lista e form creazione; /admin/clients/[id] mostra project cards</done> <done>/admin/projects funzionale con lista e form creazione; /admin/clients/[id] mostra project cards</done>
</task> </task>
<task type="auto">
<name>Task 3: /admin/clients list — brand names secondari e LTV per cliente (D-12)</name>
<files>
src/app/admin/page.tsx
src/lib/admin-queries.ts
src/components/admin/ClientRow.tsx
</files>
<read_first>
- src/app/admin/page.tsx — leggere INTERAMENTE: struttura della lista clienti, ClientRow usage, tabella HTML
- src/components/admin/ClientRow.tsx — leggere come viene mostrato il nome cliente e l'LTV attuale (accepted_total)
- src/lib/admin-queries.ts — leggere getAllClientsWithPayments per capire il tipo corrente ClientWithPayments e la Promise.all interna
</read_first>
<action>
**A. Aggiornare getAllClientsWithPayments in src/lib/admin-queries.ts (D-12)**
La funzione deve restituire anche i brand names dei progetti e il LTV calcolato come somma degli accepted_total di tutti i progetti del cliente.
Estendere il tipo ClientWithPayments (o aggiungere nuovi campi inline) con:
- `projectBrands: string[]` — nomi dei progetti non-archiviati del cliente, ordinati per created_at
- `ltv: string` — somma degli accepted_total di TUTTI i progetti del cliente (inclusi archiviati)
Modificare getAllClientsWithPayments per aggiungere una query projects alla Promise.all esistente:
```typescript
// Aggiungere alla Promise.all dentro getAllClientsWithPayments:
db.select({
client_id: projects.client_id,
name: projects.name,
accepted_total: projects.accepted_total,
archived: projects.archived,
})
.from(projects)
.where(inArray(projects.client_id, clientIds)),
```
Nel map finale, aggiungere il calcolo:
```typescript
const clientProjects = allProjects.filter((p) => p.client_id === client.id);
const projectBrands = clientProjects
.filter((p) => !p.archived)
.map((p) => p.name);
const ltv = clientProjects
.reduce((sum, p) => sum + parseFloat(p.accepted_total ?? "0"), 0)
.toFixed(2);
return {
...existingClientObject,
projectBrands,
ltv,
};
```
Assicurarsi che `projects` sia importato da `@/db/schema` negli import esistenti (da 04-01 è già presente).
**B. Aggiornare src/components/admin/ClientRow.tsx — brand names + LTV colonna (D-12)**
Leggere ClientRow.tsx interamente. Aggiungere:
1. Sotto il nome cliente in bold, aggiungere la riga brand secondaria:
```tsx
{client.projectBrands && client.projectBrands.length > 0 && (
<p className="text-xs text-[#71717a] mt-0.5">
{client.projectBrands.join(" | ")}
</p>
)}
```
2. Per la colonna LTV: sostituire `client.accepted_total` con `client.ltv` (che è ora la somma dei progetti). Se la colonna LTV non esiste ancora, aggiungere una colonna con `€{parseFloat(client.ltv).toLocaleString("it-IT", { minimumFractionDigits: 2 })}`.
3. Aggiornare il tipo prop di ClientRow per includere i nuovi campi:
```typescript
// Aggiungere ai campi di ClientWithPayments usati da ClientRow:
projectBrands: string[];
ltv: string;
```
Se ClientRow usa `ClientWithPayments` importato da admin-queries, il tipo sarà aggiornato automaticamente dalla modifica in A. Verificare che TypeScript non si lamenti.
</action>
<verify>
<automated>npm run build 2>&1 | tail -20</automated>
</verify>
<acceptance_criteria>
- src/lib/admin-queries.ts contains `projectBrands` (grep: `grep "projectBrands" src/lib/admin-queries.ts`)
- src/components/admin/ClientRow.tsx contains `projectBrands.join` (grep)
- src/components/admin/ClientRow.tsx contains `client.ltv` (grep)
- `npm run build` completa senza errori TypeScript
- Visitando /admin ogni riga cliente mostra i brand names sotto il nome (es. "Brand Blu | Brand Verde") e la colonna LTV mostra la somma degli accepted_total di tutti i progetti
</acceptance_criteria>
<done>Lista /admin/clients mostra brand names secondari sotto nome cliente e LTV calcolato come somma dei progetti — D-12 implementato</done>
</task>
</tasks> </tasks>
<threat_model> <threat_model>
@@ -4,7 +4,7 @@ plan: "03"
type: execute type: execute
wave: 2 wave: 2
depends_on: depends_on:
- 04-01-PLAN.md - "04-01"
files_modified: files_modified:
- src/app/admin/projects/[id]/page.tsx - src/app/admin/projects/[id]/page.tsx
- src/app/admin/timer-actions.ts - src/app/admin/timer-actions.ts
@@ -4,8 +4,8 @@ plan: "04"
type: execute type: execute
wave: 3 wave: 3
depends_on: depends_on:
- 04-02-PLAN.md - "04-02"
- 04-03-PLAN.md - "04-03"
files_modified: files_modified:
- src/app/api/internal/validate-slug/route.ts - src/app/api/internal/validate-slug/route.ts
- src/proxy.ts - src/proxy.ts