docs(v2.0): finalize roadmap + requirements — phases 7-11 approved for planning
- Upgrade PROJECT.md: v2.0 Business Operations Suite (unified catalog, offers with phases, public quotes, CRM pipeline, auto-provisioning) - Create REQUIREMENTS.md sections: CAT-U, OFFER-B, QUOTE, CRM, WIN requirements for phases 7-11 - Extend ROADMAP.md: 5-phase structure (7-11), 14-19 days total, risk/flag registry - Archive v1.0 milestone (phases 1-6, complete) - Switch STATE.md to v2.0, status=planning - Create research documents: STACK.md, FEATURES_v2.0.md, ARCHITECTURE.md, PITFALLS.md, SUMMARY.md Ready for: /gsd-plan-phase 7 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
# Milestones
|
||||||
|
|
||||||
|
## v1.0 Client Portal & Offer System (Shipped: 2026-06-10)
|
||||||
|
|
||||||
|
**Phases completed:** 6 phases, 24 plans, 29 tasks
|
||||||
|
|
||||||
|
**Key accomplishments:**
|
||||||
|
|
||||||
|
- Next.js 16.2.6 App Router con TypeScript strict, Tailwind v4, Drizzle ORM + postgres-js per Coolify Postgres, e 10 componenti shadcn/ui installati e pronti.
|
||||||
|
- Schema Drizzle ORM completo con 10 tabelle, migration SQL generata e schema live sul database Postgres 16 (Hetzner/Coolify). TypeScript strict compila senza errori.
|
||||||
|
- Edge proxy con validazione token, ClientView type system che esclude quote_items, e Server Component che fetcha tutti i dati cliente senza esporre segreti admin. Build Next.js 16 senza errori TypeScript.
|
||||||
|
- Tutti i componenti UI della dashboard cliente renderizzati come Server Components con design light & clean in Tailwind v4: header con logo iamcavalli + brand name cliente, progress bar globale, timeline laterale delle fasi con barre per fase e task list, sezione pagamenti con badge stato (zero importi singoli), link documenti esterni e log note read-only.
|
||||||
|
- Task 1: scripts/seed.ts
|
||||||
|
- 1. [Rule 1 - Bug] Next.js 16 proxy export name is 'proxy', not 'middleware'
|
||||||
|
- Admin home shows all clients with Acconto/Saldo payment badges; new client form inserts client row + two payment stubs via Zod-validated Server Action with nanoid token auto-generation
|
||||||
|
- Full-featured admin client workspace with Radix Tabs covering phases/tasks, payments, documents, and comments — all mutations via inline Server Actions with server-side validation.
|
||||||
|
- Client-facing approval and comment API routes with token validation, ownership verification, approved_at immutability enforcement, and inline ApproveButton/CommentForm/CommentList wired into the Phase 1 dashboard via PhaseTimeline.
|
||||||
|
- Added `custom_label text` column and made `service_id` nullable in `quote_items` via Drizzle schema edit + Neon DDL push — unblocking Wave 2 free-form quote items
|
||||||
|
- Vertical slice completo `/admin/catalog`: NavBar link + pagina catalogo + tabella con edit inline + form aggiunta servizio + soft-delete toggle, con Server Actions protetti da Zod e requireAdmin()
|
||||||
|
- Admin quote builder tab with catalog dropdown, freeform toggle, items table with calculated total, and accepted_total editor — all backed by Zod-validated Server Actions with requireAdmin guard.
|
||||||
|
- Verifica umana completa: catalogo servizi → preventivo → accepted_total → dashboard cliente, con conferma security constraint quote_items mai esposti
|
||||||
|
- NavBar
|
||||||
|
- `/admin/projects/[id]`
|
||||||
|
- `/api/internal/validate-slug/route.ts`
|
||||||
|
- Five Offer System tables added to schema.ts and production DB via direct SQL migration, with Phase 4 projects table bootstrapped from existing client data.
|
||||||
|
- Full admin CRUD for macro-offers, micro-offers, and offer services at /admin/offers with a client-side checkbox list for service-to-micro assignments and NavBar updated with Forecast and Offerte links.
|
||||||
|
- OffersTab client component for assigning micro-offers to projects with inline accepted_total editing, plus active-offers summary section on the client detail page showing public_name per project.
|
||||||
|
- Client dashboard now shows active offers per project (public_name + cumulative service price + accepted_total), and /admin/forecast displays a 12-month server-side revenue projection spread from project_offers.accepted_total across duration_months.
|
||||||
|
- AdminSidebar.tsx
|
||||||
|
- dashboard-queries.ts
|
||||||
|
|
||||||
|
---
|
||||||
+57
-41
@@ -2,45 +2,56 @@
|
|||||||
|
|
||||||
## What This Is
|
## What This Is
|
||||||
|
|
||||||
Strumento personale in due parti per gestire i clienti di consulenza: una dashboard web (Vercel) dove ogni cliente accede con un link segreto per vedere il suo progetto, e un flusso Claude per aggiungere clienti step-by-step e generare piani + preventivi. Fatto per un professionista del personal branding con clienti attivi da gestire subito.
|
Suite operativa per un consulente di personal branding, live su hub.iamcavalli.net (Coolify/Hetzner): un'area admin (`/admin/*`) per gestire clienti, progetti, offerte e pagamenti, e una dashboard cliente via link segreto (`/client/[token]`) dove ogni cliente vede lo stato del suo progetto. Con la v2.0 si espande in suite completa: catalogo servizi unificato, builder offerte con fasi, preventivi pubblici multistep e CRM con pipeline lead.
|
||||||
|
|
||||||
## Core Value
|
## Core Value
|
||||||
|
|
||||||
Il cliente apre il link e vede esattamente a che punto è il suo progetto, cosa deve ancora succedere e cosa ha già approvato — senza dover scrivere email per chiedere aggiornamenti.
|
Il cliente apre il link e vede esattamente a che punto è il suo progetto, cosa deve ancora succedere e cosa ha già approvato — senza dover scrivere email per chiedere aggiornamenti.
|
||||||
|
|
||||||
|
## Current Milestone: v2.0 Business Operations Suite
|
||||||
|
|
||||||
|
**Goal:** Trasformare ClientHub da portale clienti a suite operativa completa: catalogo servizi unificato + builder offerte con fasi, generazione preventivi pubblici, e CRM con pipeline lead che al "Vinto" crea automaticamente cliente e progetto nell'hub.
|
||||||
|
|
||||||
|
**Target features:**
|
||||||
|
- **Catalogo & Offerte** — tabella `services` unificata (sostituisce `service_catalog` + `offer_services`); builder offerte con fasi e drag&drop dei servizi tra fasi; tag tipo offerta (Entry, Signature, Retainer, custom); tier indipendenti (es. Signature A/B/C)
|
||||||
|
- **Preventivi** — pagina pubblica multistep HTML/CSS generata da cliente + offerte + prezzi scelti di volta in volta; obiettivo delivery entro 2 ore dalla call
|
||||||
|
- **CRM** — pipeline lead (→ Vinto/Perso, preventivo prerequisito); reminder follow-up in dashboard; al "Vinto" auto-crea cliente + progetto con fasi copiate dall'offerta scelta (modificabili, visibili nella pagina pubblica cliente), importo accettato, 1-4 pagamenti configurabili caso per caso
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
### Validated
|
### Validated
|
||||||
|
|
||||||
(None yet — ship to validate)
|
Shipped in v1.0 (Phases 1–6, in produzione su hub.iamcavalli.net):
|
||||||
|
|
||||||
|
- ✓ Ogni cliente ha un URL segreto univoco, nessun login (token rotatable + slug opzionale) — Phase 1/4
|
||||||
|
- ✓ Dashboard cliente: brand, brief, fasi/task con stato, progress, multi-progetto — Phase 1/4
|
||||||
|
- ✓ Il cliente approva deliverable (approved_at immutabile) e lascia commenti — Phase 2
|
||||||
|
- ✓ Il cliente vede solo il totale accettato, mai i prezzi dei singoli servizi — Phase 2/3
|
||||||
|
- ✓ Stato pagamenti acconto/saldo visibile al cliente — Phase 1
|
||||||
|
- ✓ Link a documenti esterni + storico note/decisioni — Phase 1/2
|
||||||
|
- ✓ Area admin completa: clienti, progetti, fasi, task, pagamenti, documenti — Phase 2/4
|
||||||
|
- ✓ Catalogo servizi + quote builder admin (quote_items mai esposti al cliente) — Phase 3
|
||||||
|
- ✓ Sistema offerte: macro/micro/servizi, assegnazione a progetti, forecast 12 mesi — Phase 5
|
||||||
|
- ✓ Offerte attive visibili nella dashboard cliente (solo public_name) — Phase 5
|
||||||
|
- ✓ UX admin: sidebar + dashboard operativa con KPI e activity feed — Phase 6
|
||||||
|
|
||||||
### Active
|
### Active
|
||||||
|
|
||||||
**Dashboard cliente (priorità v1):**
|
**Catalogo & Offerte (priorità 1):**
|
||||||
- [ ] Ogni cliente ha un URL segreto univoco (nessun login richiesto)
|
- [ ] Catalogo servizi unificato (nome + prezzo unitario) usato da offerte e preventivi
|
||||||
- [ ] La dashboard mostra nome cliente, nome brand, brief del progetto e stato attuale
|
- [ ] Offerta = nome + tag tipo (Entry/Signature/Retainer/custom) + fasi ordinate
|
||||||
- [ ] Il piano è strutturato per fasi con milestone e task all'interno di ogni fase
|
- [ ] Ogni fase di un'offerta contiene servizi assegnati, spostabili via drag&drop tra fasi
|
||||||
- [ ] I task hanno stato visibile (da fare / in corso / fatto)
|
- [ ] Migrazione dati: consolidare `service_catalog` + `offer_services` senza perdita
|
||||||
- [ ] Il cliente può approvare i deliverable dalla sua area
|
|
||||||
- [ ] Il cliente può lasciare commenti su task e deliverable
|
|
||||||
- [ ] Il cliente vede solo il totale del preventivo accettato (non i prezzi dei singoli servizi)
|
|
||||||
- [ ] Il cliente vede lo stato dei pagamenti: acconto 50% (da saldare / inviata / saldato) e saldo 50% (da saldare / inviata / saldato)
|
|
||||||
- [ ] Link a documenti e file (Google Drive, PDF, deliverable)
|
|
||||||
- [ ] Storico note e decisioni prese nel tempo
|
|
||||||
|
|
||||||
**Area amministratore (tu):**
|
**Preventivi (priorità 2):**
|
||||||
- [ ] Vista di tutti i clienti con stato sintetico
|
- [ ] Generazione preventivo: cliente + 1-3 offerte + prezzi impostati di volta in volta
|
||||||
- [ ] Gestione completa di ogni cliente: fasi, task, documenti, pagamenti
|
- [ ] Pagina pubblica multistep (HTML/CSS) consultabile dal lead via link
|
||||||
- [ ] Preventivo completo con dettaglio servizi (non visibile al cliente)
|
- [ ] Delivery del preventivo entro 2 ore dalla call (flusso assistito)
|
||||||
|
|
||||||
**Catalogo servizi:**
|
**CRM (priorità 3):**
|
||||||
- [ ] File/database dei servizi con prezzi e cosa è incluso
|
- [ ] Pipeline lead con stati fino a Vinto/Perso (preventivo inviato come prerequisito del Vinto)
|
||||||
- [ ] Usato come base per la generazione assistita dei preventivi
|
- [ ] Reminder follow-up in dashboard: ultima interazione, chi contattare oggi
|
||||||
|
- [ ] Al "Vinto": auto-creazione cliente + progetto con fasi copiate dall'offerta scelta, importo accettato, 1-4 pagamenti scelti caso per caso
|
||||||
**Flusso Claude (v2):**
|
|
||||||
- [ ] Onboarding guidato step-by-step via chat per aggiungere un nuovo cliente
|
|
||||||
- [ ] Generazione del piano a fasi basato sul brief
|
|
||||||
- [ ] Generazione preventivo assistita (Claude suggerisce, tu approvi prima di finalizzare)
|
|
||||||
|
|
||||||
### Out of Scope
|
### Out of Scope
|
||||||
|
|
||||||
@@ -48,32 +59,37 @@ Il cliente apre il link e vede esattamente a che punto è il suo progetto, cosa
|
|||||||
- App mobile nativa — solo web responsive
|
- App mobile nativa — solo web responsive
|
||||||
- Multi-utente con team — solo tu come admin per ora
|
- Multi-utente con team — solo tu come admin per ora
|
||||||
- Prezzi singoli visibili al cliente — vede solo il totale accettato
|
- Prezzi singoli visibili al cliente — vede solo il totale accettato
|
||||||
|
- Email OTP per accesso cliente — design pronto ma deferito a batch successivo su richiesta utente
|
||||||
|
- File hosting — documenti solo come URL esterni (v1 constraint, ancora valido)
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
- Il professionista lavora nel personal branding e content creation (cfr. SparklingOrbit)
|
- Produzione: hub.iamcavalli.net su Coolify (Hetzner), Postgres self-hosted, deploy via webhook Gitea
|
||||||
- Ha clienti attivi ora — la dashboard è la priorità immediata prima del flusso Claude
|
- Stack: Next.js 16 App Router, Drizzle ORM, Auth.js v4 (admin), token middleware (clienti), Tailwind v4, shadcn/ui
|
||||||
- I clienti accedono via link segreto fisso (no account, no password) per semplicità massima
|
- Tutto sotto la stessa app: `/admin/*` (sessione Auth.js) + `/client/[token]/*` (token) + future pagine pubbliche preventivo
|
||||||
- Il preventivo ha sempre struttura acconto 50% + saldo 50%
|
- La sidebar admin (Phase 6) è l'hub di navigazione per le nuove sezioni (CRM, Preventivi, Offerte)
|
||||||
- Il catalogo servizi va costruito da zero durante il progetto
|
- `project_offers` (Phase 5) già copre l'attribuzione di offerte a progetti esistenti — da rifinire, non ricostruire
|
||||||
- Piattaforma di deploy: Vercel
|
- Il flusso commerciale reale: call con lead → preventivo 3 tier (es. Signature A/B/C) in giornata → accettazione → onboarding automatico nell'hub
|
||||||
|
|
||||||
## Constraints
|
## Constraints
|
||||||
|
|
||||||
- **Urgenza**: Clienti attivi da gestire subito — la dashboard cliente deve arrivare per prima
|
- **Data Safety (LOCKED)**: migration solo additive su `clients`, `projects`, `payments`, `phases` — la migrazione del catalogo servizi va pianificata per consolidare senza drop/truncate
|
||||||
- **Semplicità accesso cliente**: Link segreto senza login — nessuna friction per il cliente
|
- **Architettura (LOCKED)**: `clients.token` separato e rotatable; `quote_items` mai esposti via client API; `deliverables.approved_at` immutabile; no file hosting
|
||||||
- **Privacy preventivo**: Il cliente vede solo il totale, mai il dettaglio dei servizi
|
- **Stesso DB**: tutte le nuove aree (CRM, preventivi, offerte) leggono/scrivono lo stesso Postgres — nessun servizio separato
|
||||||
- **Deploy**: Vercel su sottodominio `welcomeclient.iamcavalli.net`
|
- **Numerazione fasi**: v2.0 parte da Phase 7 (v1.0 ha chiuso alla 6)
|
||||||
- **Dominio**: sottodominio di iamcavalli.net — richiede configurazione DNS su dominio esistente
|
|
||||||
|
|
||||||
## Key Decisions
|
## Key Decisions
|
||||||
|
|
||||||
| Decision | Rationale | Outcome |
|
| Decision | Rationale | Outcome |
|
||||||
|----------|-----------|---------|
|
|----------|-----------|---------|
|
||||||
| Link segreto senza login per i clienti | Massima semplicità — nessun account da creare, zero friction | — Pending |
|
| Link segreto senza login per i clienti | Massima semplicità — nessun account da creare, zero friction | ✓ Good |
|
||||||
| Dashboard prima del flusso Claude | Clienti attivi ora, la visibilità al cliente è il valore immediato | — Pending |
|
| Dashboard prima del flusso Claude | Clienti attivi ora, la visibilità al cliente è il valore immediato | ✓ Good |
|
||||||
| Preventivo: cliente vede solo il totale | Il dettaglio dei prezzi è informazione commerciale riservata | — Pending |
|
| Preventivo: cliente vede solo il totale | Il dettaglio dei prezzi è informazione commerciale riservata | ✓ Good |
|
||||||
| Catalogo servizi da costruire da zero | Nessun listino esistente — parte del progetto stesso | — Pending |
|
| Suite unica sotto /admin/* invece di 3 app separate | Stesso DB, stesso deploy, auth unica — overhead di 3 app ingiustificato per singolo admin | — Pending |
|
||||||
|
| Catalogo servizi unificato (una tabella `services`) | Due cataloghi paralleli (service_catalog + offer_services) duplicano manutenzione prezzi | — Pending |
|
||||||
|
| Tier offerte indipendenti (A/B/C separati, stesso tag) | Più semplice di un meccanismo di ereditarietà; ogni tier configurato a sé | — Pending |
|
||||||
|
| Prezzi pacchetti per-preventivo, non da catalogo | Permette di alzare i prezzi nel tempo senza toccare il catalogo | — Pending |
|
||||||
|
| Al "Vinto" le fasi dell'offerta sono COPIATE nel progetto | Il progetto resta modificabile senza toccare il template offerta | — Pending |
|
||||||
|
|
||||||
## Evolution
|
## Evolution
|
||||||
|
|
||||||
@@ -93,4 +109,4 @@ This document evolves at phase transitions and milestone boundaries.
|
|||||||
4. Update Context with current state
|
4. Update Context with current state
|
||||||
|
|
||||||
---
|
---
|
||||||
*Last updated: 2026-05-15 — Phase 2 complete (admin area + client interactions)*
|
*Last updated: 2026-06-10 — Milestone v2.0 started (Business Operations Suite)*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Requirements — ClientHub
|
# Requirements — ClientHub v2.0 Business Operations Suite
|
||||||
|
|
||||||
## Dashboard Cliente (v1)
|
## Dashboard Cliente (v1)
|
||||||
|
|
||||||
@@ -51,20 +51,69 @@
|
|||||||
| OFFER-05 | La dashboard cliente mostra le offerte attive con nome pubblico, prezzo cumulativo dei servizi inclusi e prezzo finale accettato in evidenza; se ha più offerte le vede tutte | Pending |
|
| OFFER-05 | La dashboard cliente mostra le offerte attive con nome pubblico, prezzo cumulativo dei servizi inclusi e prezzo finale accettato in evidenza; se ha più offerte le vede tutte | Pending |
|
||||||
| OFFER-06 | Admin ha una vista revenue forecast dei 12 mesi successivi basata su offerte attive, durata e accepted_total; breakdown mensile con totale fatturato per mese | Pending |
|
| OFFER-06 | Admin ha una vista revenue forecast dei 12 mesi successivi basata su offerte attive, durata e accepted_total; breakdown mensile con totale fatturato per mese | Pending |
|
||||||
|
|
||||||
## Flusso Claude (v2 — deferred to Phase 6)
|
## Catalogo Unificato & Offer Builder (Phase 7–8)
|
||||||
|
|
||||||
|
| ID | Requirement | Status |
|
||||||
|
|----|-------------|--------|
|
||||||
|
| CAT-U-01 | Un'unica tabella `services` unifica `service_catalog` + `offer_services`; migrazione zero data loss con audit trail (`migrated_from`) | Phase 7 |
|
||||||
|
| CAT-U-02 | Admin `/admin/catalog` list/add/edit/soft-delete per i servizi singoli (nome, prezzo_unitario, attivo) | Phase 7 |
|
||||||
|
| OFFER-B-01 | Offer = nome + tag tipo (Entry/Signature/Retainer/custom) + fasi ordinate; fasi indipendenti l'una dall'altra (es. Signature A/B/C non ereditate) | Phase 8 |
|
||||||
|
| OFFER-B-02 | `/admin/offers/[id]/edit` two-column builder: left colonna servizi (ricerca), right colonna fasi con drag&drop tra fasi e dentro fase (reorder) | Phase 8 |
|
||||||
|
| OFFER-B-03 | Drag&drop salva per singolo drop con optimistic update client-side + validazione server; versioning previene race condition da multi-tab edit | Phase 8 |
|
||||||
|
|
||||||
|
## Quote Builder & Public Proposal Pages (Phase 9)
|
||||||
|
|
||||||
|
| ID | Requirement | Status |
|
||||||
|
|----|-------------|--------|
|
||||||
|
| QUOTE-01 | `/admin/quotes/new`: select cliente + 1-3 offerte + override prezzo per ciascuna offerta + genera link pubblico `/quote/[token]` | Phase 9 |
|
||||||
|
| QUOTE-02 | Public `/quote/[token]` pagina multistep (Zod validazione): Step 1 (overview) → Step 2 (tier A/B/C selection + prezzi + fasi) → Step 3 (summary + accept/decline) | Phase 9 |
|
||||||
|
| QUOTE-03 | Accept CTA → POST `/api/public/quote/accept?token=X` con cattura email (opzionale) + note opzionali; registra timestamp accepted_at immutabile | Phase 9 |
|
||||||
|
| QUOTE-04 | Quote token: nanoid 21 char (~122 bits), unico, validato in proxy come `/client/[token]` (nessun login sessione); rate limit 3 views/min per IP | Phase 9 |
|
||||||
|
| QUOTE-05 | Mai esporre `quote_items` (prezzi per servizio) via public API; client API vede solo `accepted_total` (server-side ClientView type enforces) | Phase 9 |
|
||||||
|
|
||||||
|
## CRM Pipeline & Activity Logging (Phase 10)
|
||||||
|
|
||||||
|
| ID | Requirement | Status |
|
||||||
|
|----|-------------|--------|
|
||||||
|
| CRM-01 | Lead CRUD: `/admin/leads` list table (name, email, company, status, last_contact_date, next_action) con create/edit/delete | Phase 10 |
|
||||||
|
| CRM-02 | Lead detail page `/admin/leads/[id]`: full profilo, activity log (reverse chronological), quote(s) sent, actions menu (log activity, send quote, mark won) | Phase 10 |
|
||||||
|
| CRM-03 | Pipeline stages: Contacted → Qualified → Proposal Sent → Negotiating → Won / Lost; transizioni via dropdown (manual di default) | Phase 10 |
|
||||||
|
| CRM-04 | Activity logging: tipi (call, email, meeting, note); ogni attività: type, date, durata (opz), notes; auto-aggiorna lead.last_contact_date | Phase 10 |
|
||||||
|
| CRM-05 | "Log activity" modal: <10 sec UX (type dropdown, date picker, notes textarea, save) — bassa tolleranza per data entry lunghi | Phase 10 |
|
||||||
|
| CRM-06 | Follow-up reminders widget in dashboard: "Follow up today" (leads dove last_contact_date < oggi - 7 giorni); click → jump lead detail | Phase 10 |
|
||||||
|
| CRM-07 | "Send Quote" button in lead detail: select existing quote o crea nuovo; update lead.last_quote_sent + status → "Proposal Sent" | Phase 10 |
|
||||||
|
|
||||||
|
## Auto-Onboarding on Win (Phase 11)
|
||||||
|
|
||||||
|
| ID | Requirement | Status |
|
||||||
|
|----|-------------|--------|
|
||||||
|
| WIN-01 | "Mark as Won" button in lead detail (o auto-triggered da public quote accept); idempotency: call 2 volte = idempotent, stesso client token | Phase 11 |
|
||||||
|
| WIN-02 | winLead(leadId, quoteId): crea client (name da lead, token = nanoid), crea project (name = company/offer name), copia offer fasi → project fasi | Phase 11 |
|
||||||
|
| WIN-03 | 1-4 pagamenti: user sceglie split template (50/50, 3-part, 4-part, custom); registra importo accepted_total da quote | Phase 11 |
|
||||||
|
| WIN-04 | Generate client dashboard link (`/client/[token]`), invia via email al lead (copy-paste OK, email automation deferred Phase 12+) | Phase 11 |
|
||||||
|
| WIN-05 | Quote accept da public link `/quote/[token]` auto-aggiorna lead.status → "Proposal Sent" + trigga win (auto-onboarding) | Phase 11 |
|
||||||
|
| WIN-06 | Copy offer phases → project phases: tutte le fasi copiate con status = "upcoming", le fasi modificabili dopo (template immutabile, instance editable) | Phase 11 |
|
||||||
|
|
||||||
|
## Flusso Claude (v3 — deferred to Phase 13+)
|
||||||
|
|
||||||
| ID | Requirement | Status |
|
| ID | Requirement | Status |
|
||||||
|----|-------------|--------|
|
|----|-------------|--------|
|
||||||
| CLAUDE-01 | Onboarding guidato step-by-step via chat per aggiungere un nuovo cliente | Deferred |
|
| CLAUDE-01 | Onboarding guidato step-by-step via chat per aggiungere un nuovo cliente | Deferred |
|
||||||
| CLAUDE-02 | Generazione del piano a fasi basato sul brief | Deferred |
|
| CLAUDE-02 | Generazione del piano a fasi basato dal brief | Deferred |
|
||||||
| CLAUDE-03 | Generazione preventivo assistita (Claude suggerisce, tu approvi prima di finalizzare) | Deferred |
|
| CLAUDE-03 | Generazione preventivo assistita (Claude suggerisce struttura offerta, tu approvi) | Deferred |
|
||||||
|
|
||||||
## Out of Scope
|
## Out of Scope (v2.0)
|
||||||
|
|
||||||
- Fatturazione e invio fatture (solo stato pagamenti)
|
- Fatturazione e invio fatture (solo stato pagamenti)
|
||||||
- App mobile nativa (solo web responsive)
|
- App mobile nativa (solo web responsive)
|
||||||
- Multi-utente con team (solo admin singolo)
|
- Multi-utente con team (solo admin singolo)
|
||||||
- Prezzi singoli visibili al cliente (solo totale accettato)
|
- Prezzi singoli visibili al cliente (solo totale accettato)
|
||||||
|
- Email automation (manual copy-paste OK per MVP)
|
||||||
|
- Lead scoring / predictive analytics
|
||||||
|
- Team collaboration
|
||||||
|
- Lead de-duplication (manual link on Win)
|
||||||
|
- Proposal expiry logic (open indefinitely)
|
||||||
|
- BullMQ persistent reminders (in-app computed, persistent deferred Phase 12+)
|
||||||
|
|
||||||
## Traceability
|
## Traceability
|
||||||
|
|
||||||
@@ -96,6 +145,29 @@
|
|||||||
| OFFER-04 | Phase 5 | Pending |
|
| OFFER-04 | Phase 5 | Pending |
|
||||||
| OFFER-05 | Phase 5 | Pending |
|
| OFFER-05 | Phase 5 | Pending |
|
||||||
| OFFER-06 | Phase 5 | Pending |
|
| OFFER-06 | Phase 5 | Pending |
|
||||||
| CLAUDE-01 | Phase 6 (v2) | Deferred |
|
| CAT-U-01 | Phase 7 | Phase 7 |
|
||||||
| CLAUDE-02 | Phase 6 (v2) | Deferred |
|
| CAT-U-02 | Phase 7 | Phase 7 |
|
||||||
| CLAUDE-03 | Phase 6 (v2) | Deferred |
|
| OFFER-B-01 | Phase 8 | Phase 8 |
|
||||||
|
| OFFER-B-02 | Phase 8 | Phase 8 |
|
||||||
|
| OFFER-B-03 | Phase 8 | Phase 8 |
|
||||||
|
| QUOTE-01 | Phase 9 | Phase 9 |
|
||||||
|
| QUOTE-02 | Phase 9 | Phase 9 |
|
||||||
|
| QUOTE-03 | Phase 9 | Phase 9 |
|
||||||
|
| QUOTE-04 | Phase 9 | Phase 9 |
|
||||||
|
| QUOTE-05 | Phase 9 | Phase 9 |
|
||||||
|
| CRM-01 | Phase 10 | Phase 10 |
|
||||||
|
| CRM-02 | Phase 10 | Phase 10 |
|
||||||
|
| CRM-03 | Phase 10 | Phase 10 |
|
||||||
|
| CRM-04 | Phase 10 | Phase 10 |
|
||||||
|
| CRM-05 | Phase 10 | Phase 10 |
|
||||||
|
| CRM-06 | Phase 10 | Phase 10 |
|
||||||
|
| CRM-07 | Phase 10 | Phase 10 |
|
||||||
|
| WIN-01 | Phase 11 | Phase 11 |
|
||||||
|
| WIN-02 | Phase 11 | Phase 11 |
|
||||||
|
| WIN-03 | Phase 11 | Phase 11 |
|
||||||
|
| WIN-04 | Phase 11 | Phase 11 |
|
||||||
|
| WIN-05 | Phase 11 | Phase 11 |
|
||||||
|
| WIN-06 | Phase 11 | Phase 11 |
|
||||||
|
| CLAUDE-01 | Phase 13 (v3) | Deferred |
|
||||||
|
| CLAUDE-02 | Phase 13 (v3) | Deferred |
|
||||||
|
| CLAUDE-03 | Phase 13 (v3) | Deferred |
|
||||||
+117
-21
@@ -1,8 +1,10 @@
|
|||||||
# Roadmap: ClientHub
|
# Roadmap: ClientHub v2.0 Business Operations Suite
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
ClientHub si costruisce dall'esterno verso l'interno: prima la dashboard che un cliente reale può aprire su mobile, poi l'area admin per creare e gestire i dati, poi il catalogo servizi e il preventivo interno. Il flusso Claude AI è v2 e dipende da CRUD stabile e catalogo completo. Ogni fase consegna una capacità end-to-end verificabile.
|
**v1.0 (Phases 1–5, Complete)**: ClientHub si costruisce dall'esterno verso l'interno: prima la dashboard cliente, poi l'area admin CRUD, poi catalogo servizi, progetti multi-progetto e sistema offerte.
|
||||||
|
|
||||||
|
**v2.0 (Phases 7–11, Planning)**: Trasformazione da portale clienti a suite operativa completa. Catalogo servizi unificato → template offerte con fasi → generazione preventivi pubblici in 2 ore → CRM pipeline lead → auto-onboarding Won leads con copiat fasi e pagamenti. Obiettivo: delivery completa di proposta, accettazione, e provisioning in workflow continuo.
|
||||||
|
|
||||||
## Phases
|
## Phases
|
||||||
|
|
||||||
@@ -12,12 +14,20 @@ ClientHub si costruisce dall'esterno verso l'interno: prima la dashboard che un
|
|||||||
|
|
||||||
Decimal phases appear between their surrounding integers in numeric order.
|
Decimal phases appear between their surrounding integers in numeric order.
|
||||||
|
|
||||||
|
**v1.0 (Completed):**
|
||||||
- [x] **Phase 1: Foundation & Client Dashboard** - DB schema, token API, dashboard read-only per il cliente con link segreto condivisibile
|
- [x] **Phase 1: Foundation & Client Dashboard** - DB schema, token API, dashboard read-only per il cliente con link segreto condivisibile
|
||||||
- [ ] **Phase 2: Admin Area & Interactive Features** - Auth admin, CRUD completo clienti/fasi/task/deliverable/pagamenti, approvazioni e commenti
|
- [x] **Phase 2: Admin Area & Interactive Features** - Auth admin, CRUD completo clienti/fasi/task/deliverable/pagamenti, approvazioni e commenti
|
||||||
- [ ] **Phase 3: Service Catalog & Quote Builder** - Catalogo servizi riutilizzabile e costruttore preventivi (admin-only, cliente vede solo il totale)
|
- [x] **Phase 3: Service Catalog & Quote Builder** - Catalogo servizi riutilizzabile e costruttore preventivi (admin-only, cliente vede solo il totale)
|
||||||
- [ ] **Phase 4: Progetti — Multi-Project per Cliente** - Modello dati multi-progetto per cliente; dashboard con tabs; /admin/projects; slug link; analytics €/h
|
- [x] **Phase 4: Progetti — Multi-Project per Cliente** - Modello dati multi-progetto per cliente; dashboard con tabs; /admin/projects; slug link; analytics €/h
|
||||||
- [x] **Phase 5: Offer System** - Catalogo macro/micro offerte con servizi assegnabili, assegnazione offerte a progetti, dashboard cliente con offerte attive e revenue forecast 12 mesi per l'admin
|
- [x] **Phase 5: Offer System** - Catalogo macro/micro offerte con servizi assegnabili, assegnazione offerte a progetti, dashboard cliente con offerte attive e revenue forecast 12 mesi per l'admin
|
||||||
- [ ] **Phase 6: Claude AI Onboarding (v2)** - Flusso guidato step-by-step per onboarding cliente e generazione assistita del piano/preventivo
|
- [x] **Phase 6: UX Overhaul** - Admin sidebar + dashboard operativa con KPI e activity feed
|
||||||
|
|
||||||
|
**v2.0 (Planning):**
|
||||||
|
- [ ] **Phase 7: Unified Service Catalog** - Migrazione `service_catalog` + `offer_services` → unica tabella `services`; zero data loss, audit trail per rollback
|
||||||
|
- [ ] **Phase 8: Offer Phases & Quote Templates** - Tabelle `offer_phases`, `quotes`, `offer_phase_services`; struttura hierarchica offer (macro → micro → phase → services)
|
||||||
|
- [ ] **Phase 9: Quote Builder & Public Routes** - Builder preventivi (select offer + override prezzi); `/quote/[token]` pagina pubblica multistep; accettazione
|
||||||
|
- [ ] **Phase 10: CRM Pipeline** - Lead CRUD, attività, follow-up reminders; pipeline stages (5 step); activity log per lead
|
||||||
|
- [ ] **Phase 11: Auto-Provisioning on Win** - Lead → quote accept → auto-crea client + progetto (copia fasi) + 1-4 pagamenti; launch client dashboard
|
||||||
|
|
||||||
## Phase Details
|
## Phase Details
|
||||||
|
|
||||||
@@ -138,23 +148,94 @@ Decimal phases appear between their surrounding integers in numeric order.
|
|||||||
**UI hint**: yes
|
**UI hint**: yes
|
||||||
**Status**: Planning complete
|
**Status**: Planning complete
|
||||||
|
|
||||||
### Phase 7: Claude AI Onboarding (v2)
|
### Phase 7: Unified Service Catalog
|
||||||
**Goal**: L'admin può usare un flusso chat guidato per onboardare un nuovo cliente e generare un piano a fasi e un preventivo assistito da Claude
|
**Goal**: Consolidare `service_catalog` + `offer_services` in un'unica tabella `services`; fondazione per offer builder e quote generator
|
||||||
**Mode:** mvp
|
**Mode:** migration
|
||||||
**Depends on**: Phase 6
|
**Depends on**: Phase 5 (offer_services exists)
|
||||||
**Requirements**: CLAUDE-01, CLAUDE-02, CLAUDE-03
|
**Requirements**: CAT-U-01, CAT-U-02
|
||||||
**Success Criteria** (what must be TRUE):
|
**Success Criteria** (what must be TRUE):
|
||||||
1. L'admin avvia il flusso Claude inserendo il brief del cliente; Claude guida step-by-step la raccolta delle informazioni necessarie
|
1. Una sola tabella `services` con nome, prezzo_unitario, attivo, created_at
|
||||||
2. Al termine del flusso, Claude propone un piano strutturato per fasi che l'admin può accettare o modificare prima di salvarlo
|
2. Migrazione zero data loss: campi audit (`migrated_from`, `migrated_id`) abilitano rollback sicuro
|
||||||
3. Claude suggerisce un preventivo basato sul catalogo servizi; l'admin approva o modifica le voci prima della finalizzazione
|
3. `/admin/catalog` list/add/edit/soft-delete funzionante con nuova tabella
|
||||||
**Plans**: TBD
|
4. Query vecchie servizi falliscono esplicitamente (no silent fallback)
|
||||||
**UI hint**: yes
|
**Plans**: 1 (schema migration + admin page)
|
||||||
**Status**: Pending planning (v2 — may defer indefinitely)
|
**Durata**: 3–4 giorni
|
||||||
|
**Status**: Pending planning
|
||||||
|
**Risk**: SQL deduplication logic; validate on staging before prod
|
||||||
|
|
||||||
|
### Phase 8: Offer Phases & Quote Templates
|
||||||
|
**Goal**: Struttura hierarchica offer (macro → micro → phase → services) con drag&drop builder
|
||||||
|
**Mode:** schema + ui
|
||||||
|
**Depends on**: Phase 7
|
||||||
|
**Requirements**: OFFER-B-01, OFFER-B-02, OFFER-B-03
|
||||||
|
**Success Criteria** (what must be TRUE):
|
||||||
|
1. Nuove tabelle: `offer_phases`, `quotes`, `offer_phase_services`
|
||||||
|
2. `/admin/offers/[id]/edit` builder two-column: left servizi (ricerca), right fasi con drag&drop
|
||||||
|
3. Drag&drop tra fasi e dentro fase (reorder); salva per singolo drop con optimistic update
|
||||||
|
4. Versioning previene race condition da multi-tab edit (409 Conflict su version mismatch)
|
||||||
|
**Plans**: 2 (schema + builder UI)
|
||||||
|
**Durata**: 2–3 giorni
|
||||||
|
**Status**: Pending planning
|
||||||
|
|
||||||
|
### Phase 9: Quote Builder & Public Routes
|
||||||
|
**Goal**: Generazione preventivi 2-click (select offer → override prezzi → link pubblico); pagina multistep pubblico per lead
|
||||||
|
**Mode:** UI + routes
|
||||||
|
**Depends on**: Phase 8
|
||||||
|
**Requirements**: QUOTE-01, QUOTE-02, QUOTE-03, QUOTE-04, QUOTE-05
|
||||||
|
**Success Criteria** (what must be TRUE):
|
||||||
|
1. `/admin/quotes/new`: select cliente + 1-3 offerte + override prezzi → genera `/quote/[token]` link pubblico
|
||||||
|
2. Pagina pubblica `/quote/[token]` multistep (Step 1 overview → Step 2 tier selection → Step 3 summary + accept)
|
||||||
|
3. Accept CTA → `/api/public/quote/accept?token=X` con cattura email + note
|
||||||
|
4. Token: nanoid 21 char, unico, rate limit 3 views/min per IP
|
||||||
|
5. Mai esporre `quote_items` (prezzi per servizio) via public API
|
||||||
|
**Plans**: 3 (quote builder + public routes + security)
|
||||||
|
**Durata**: 4–5 giorni
|
||||||
|
**Status**: Pending planning
|
||||||
|
**Risk**: RHF + React 19 compatibility (dev test prima del merge); PDF generation approach TBD
|
||||||
|
|
||||||
|
### Phase 10: CRM Pipeline & Activity Logging
|
||||||
|
**Goal**: Lead CRUD, activity log, follow-up reminders, quote assignment; pipeline stages
|
||||||
|
**Mode:** UI + CRUD
|
||||||
|
**Depends on**: Phase 5 (project_offers) + Phase 9 (quotes)
|
||||||
|
**Requirements**: CRM-01 through CRM-07
|
||||||
|
**Success Criteria** (what must be TRUE):
|
||||||
|
1. `/admin/leads` list (name, email, company, status, last_contact_date, next_action)
|
||||||
|
2. `/admin/leads/[id]` detail: profilo, activity log reverse-chronological, quote(s) sent, action menu
|
||||||
|
3. Activity types: call, email, meeting, note; auto-aggiorna lead.last_contact_date
|
||||||
|
4. Pipeline stages: Contacted → Qualified → Proposal Sent → Negotiating → Won / Lost
|
||||||
|
5. Follow-up widget in dashboard: "Follow up today" (leads dove last_contact_date < oggi - 7 giorni)
|
||||||
|
6. "Log activity" modal: <10 sec UX (type dropdown, date picker, notes, save)
|
||||||
|
7. "Send Quote" button: select/create quote → update lead.status → "Proposal Sent"
|
||||||
|
**Plans**: 3 (lead CRUD + activity logging + follow-up widget)
|
||||||
|
**Durata**: 3–4 giorni
|
||||||
|
**Status**: Pending planning
|
||||||
|
|
||||||
|
### Phase 11: Auto-Provisioning on Win
|
||||||
|
**Goal**: Lead → quote accept → auto-crea client + progetto (copia fasi) + 1-4 pagamenti; lancia dashboard cliente
|
||||||
|
**Mode:** automation + integration
|
||||||
|
**Depends on**: Phase 9 (quotes) + Phase 10 (CRM)
|
||||||
|
**Requirements**: WIN-01 through WIN-06
|
||||||
|
**Success Criteria** (what must be TRUE):
|
||||||
|
1. "Mark as Won" button in lead detail; idempotency: call 2x = stesso client token
|
||||||
|
2. `winLead(leadId, quoteId)`: create client (token=nanoid) + project (name=company) + copy offer phases → project.phases
|
||||||
|
3. 1-4 pagamenti: user sceglie split template (50/50, 3-part, 4-part, custom); registra accepted_total
|
||||||
|
4. Generate client link + email (copy-paste MVP; email automation deferred Phase 12+)
|
||||||
|
5. Quote accept da public `/quote/[token]` auto-trigga win (auto-onboarding)
|
||||||
|
6. Copy offer phases: status="upcoming", phases modificabili dopo (template immutabile, instance editable)
|
||||||
|
**Plans**: 2 (win action + email + BullMQ optional)
|
||||||
|
**Durata**: 2–3 giorni
|
||||||
|
**Status**: Pending planning
|
||||||
|
**Risk**: Idempotency key implementation; Redis + BullMQ ops (persistent reminders optional MVP)
|
||||||
|
|
||||||
|
### Phase 12+: Deferred Features (Future Milestones)
|
||||||
|
|
||||||
|
- **Phase 12: Email Automation & Polish** — Send quote link via email, email reminders, lead de-duplication UI
|
||||||
|
- **Phase 13: Claude AI Onboarding (v3)** — Chat-guided client onboarding, assisted quote generation, plan suggestion
|
||||||
|
|
||||||
## Progress
|
## Progress
|
||||||
|
|
||||||
**Execution Order:**
|
**v1.0 Execution (Complete):**
|
||||||
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5
|
Phases 1 → 2 → 3 → 4 → 5 executed in order. Phase 6 (UX Overhaul) executed May 31.
|
||||||
|
|
||||||
| Phase | Plans | Status | Completed |
|
| Phase | Plans | Status | Completed |
|
||||||
|-------|-------|--------|-----------|
|
|-------|-------|--------|-----------|
|
||||||
@@ -163,5 +244,20 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5
|
|||||||
| 3. Service Catalog & Quote Builder | 4/4 | ✅ Done | 2026-05-19 |
|
| 3. Service Catalog & Quote Builder | 4/4 | ✅ Done | 2026-05-19 |
|
||||||
| 4. Progetti — Multi-Project per Cliente | 5/5 | ✅ Done | 2026-05-23 |
|
| 4. Progetti — Multi-Project per Cliente | 5/5 | ✅ Done | 2026-05-23 |
|
||||||
| 5. Offer System | 4/4 | ✅ Done | 2026-05-30 |
|
| 5. Offer System | 4/4 | ✅ Done | 2026-05-30 |
|
||||||
| 6. UX Overhaul — Sidebar + Dashboard | 0/2 | Pending | - |
|
| 6. UX Overhaul — Sidebar + Dashboard | 2/2 | ✅ Done | 2026-05-31 |
|
||||||
| 7. Claude AI Onboarding (v2) | 0/TBD | Pending | - |
|
|
||||||
|
**v2.0 Execution (Planning):**
|
||||||
|
Phases 7 → 8 → 9 → 10 → 11 planned for sequential execution. Research complete (2026-06-11), requirements/roadmap finalized. Ready for phase-by-phase planning + execution.
|
||||||
|
|
||||||
|
| Phase | Plans | Status | Estimated Duration | Blocking? |
|
||||||
|
|-------|-------|--------|-------------------|-----------|
|
||||||
|
| 7. Unified Service Catalog | 1 | Pending planning | 3–4 giorni | Foundation |
|
||||||
|
| 8. Offer Phases & Quote Templates | 2 | Pending planning | 2–3 giorni | Foundation |
|
||||||
|
| 9. Quote Builder & Public Routes | 3 | Pending planning | 4–5 giorni | RHF compat test |
|
||||||
|
| 10. CRM Pipeline & Activity Logging | 3 | Pending planning | 3–4 giorni | No |
|
||||||
|
| 11. Auto-Provisioning on Win | 2 | Pending planning | 2–3 giorni | BullMQ ops (optional) |
|
||||||
|
| **Total v2.0 MVP** | **11** | Pending | **14–19 giorni** | — |
|
||||||
|
|
||||||
|
**v2.0 Deferred (Phase 12+):**
|
||||||
|
- Phase 12: Email Automation & Polish
|
||||||
|
- Phase 13: Claude AI Onboarding (v3)
|
||||||
|
|||||||
+18
-14
@@ -1,17 +1,16 @@
|
|||||||
---
|
---
|
||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.0
|
milestone: v2.0
|
||||||
milestone_name: milestone
|
milestone_name: Business Operations Suite
|
||||||
status: completed
|
status: planning
|
||||||
stopped_at: Phase 5 fully executed — Offer System live on hub.iamcavalli.net
|
last_updated: "2026-06-10T20:03:26.545Z"
|
||||||
last_updated: "2026-05-30"
|
last_activity: 2026-06-10
|
||||||
last_activity: 2026-05-30 -- Phase 5 confirmed complete (05-01 through 05-04)
|
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 0
|
||||||
completed_phases: 5
|
completed_phases: 0
|
||||||
total_plans: 21
|
total_plans: 0
|
||||||
completed_plans: 21
|
completed_plans: 0
|
||||||
percent: 100
|
percent: 0
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -24,9 +23,10 @@ See: .planning/PROJECT.md (updated 2026-05-09)
|
|||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 5 — COMPLETE
|
Phase: Not started (defining requirements)
|
||||||
Plan: All plans done (05-01 through 05-04)
|
Plan: —
|
||||||
Status: Production ready — deploy pending
|
Status: Defining requirements
|
||||||
|
Last activity: 2026-06-10 — Milestone v2.0 started
|
||||||
|
|
||||||
## What Was Built (Phase 5)
|
## What Was Built (Phase 5)
|
||||||
|
|
||||||
@@ -76,3 +76,7 @@ Status: Production ready — deploy pending
|
|||||||
|
|
||||||
Last session: 2026-05-27
|
Last session: 2026-05-27
|
||||||
All Phase 4 plans complete. Next: Authelia infra or new feature scope.
|
All Phase 4 plans complete. Next: Authelia infra or new feature scope.
|
||||||
|
|
||||||
|
## Operator Next Steps
|
||||||
|
|
||||||
|
- Start the next milestone with /gsd-new-milestone
|
||||||
|
|||||||
@@ -0,0 +1,210 @@
|
|||||||
|
# Pitfalls Checklist: Business Operations Suite v2.0
|
||||||
|
|
||||||
|
Quick reference for preventing the 9 major pitfalls during Phase 7–9 implementation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Critical Pitfalls (Before Code)
|
||||||
|
|
||||||
|
### 1. Catalog Consolidation Breaks Quotes
|
||||||
|
- [ ] Migration strategy documented (Expand-Contract, not drop)
|
||||||
|
- [ ] Mapping layer between old/new tables designed
|
||||||
|
- [ ] Backfill script tested on production backup
|
||||||
|
- [ ] Referential integrity test query written
|
||||||
|
- [ ] Dual-write period defined (2-3 weeks)
|
||||||
|
- [ ] Rollback plan documented (drop new table, revert code)
|
||||||
|
|
||||||
|
### 2. Offer Template Mutation
|
||||||
|
- [ ] Offer/project hierarchy mapping documented (1 page)
|
||||||
|
- [ ] Copy function uses `db.transaction()` (all-or-nothing)
|
||||||
|
- [ ] Uses `structuredClone()` for deep copy, not `{...spread}`
|
||||||
|
- [ ] Idempotency key added to CRM leads table
|
||||||
|
- [ ] Integration test: copy offer, verify structure consistent across instances
|
||||||
|
- [ ] Test: edit project phase, verify offer template unchanged
|
||||||
|
|
||||||
|
### 3. Public Quote Token Leakage
|
||||||
|
- [ ] Token length ≥ 32 chars (nanoid(32) or nanoid(64))
|
||||||
|
- [ ] Expiration field added (default 7 days)
|
||||||
|
- [ ] Email validation on public page (token + email required)
|
||||||
|
- [ ] Rate limiting implemented (max 3 views/token/minute)
|
||||||
|
- [ ] Code audit: quote_items NOT in public API response
|
||||||
|
- [ ] Test: brute-force 1000 guesses, verify rate limit activates
|
||||||
|
- [ ] Test: enumerate tokens with different emails, verify 401
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Moderate Pitfalls (During Implementation)
|
||||||
|
|
||||||
|
### 4. Drag-and-Drop Race Condition
|
||||||
|
- [ ] `version` field added to offer_phases
|
||||||
|
- [ ] Update mutation checks version (returns 409 if mismatch)
|
||||||
|
- [ ] Server recomputes all sort_orders atomically
|
||||||
|
- [ ] Frontend handles 409 Conflict (refresh UI)
|
||||||
|
- [ ] Test: concurrent drag in 2 tabs, verify final state correct
|
||||||
|
|
||||||
|
### 5. CRM "Win" Double-Click
|
||||||
|
- [ ] Idempotency key added to crm_leads (unique)
|
||||||
|
- [ ] "Win" mutation checks if key already processed
|
||||||
|
- [ ] All sub-steps in single `db.transaction()`
|
||||||
|
- [ ] Button disabled until success
|
||||||
|
- [ ] Idempotency key stored in localStorage
|
||||||
|
- [ ] Test: double-click "Win", verify only 1 client created
|
||||||
|
|
||||||
|
### 6. Offer Copy Missing Tasks/Deliverables
|
||||||
|
- [ ] Mapping documented: offer_micro → project_phase → project_task → deliverable
|
||||||
|
- [ ] Copy function recursive (phases → tasks → deliverables)
|
||||||
|
- [ ] Validation test: assert counts match expected
|
||||||
|
- [ ] Integration test exists (copy, verify structure)
|
||||||
|
- [ ] Query test: no orphaned deliverables (task_id IS NULL)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Minor Pitfalls (Polish)
|
||||||
|
|
||||||
|
### 7. Offer State Not Synced Between Tabs
|
||||||
|
- [ ] `version` field on offer_micros
|
||||||
|
- [ ] Update returns 409 on version mismatch
|
||||||
|
- [ ] UI shows "Offer changed, reload?" dialog
|
||||||
|
|
||||||
|
### 8. CRM Schema Backward Incompatibility
|
||||||
|
- [ ] New columns added as NULLABLE
|
||||||
|
- [ ] Code handles NULL defensively (e.g., `lead.budget ?? 0`)
|
||||||
|
- [ ] Backfill script written (sets defaults for existing rows)
|
||||||
|
- [ ] NOT NULL constraint added only after backfill + validation
|
||||||
|
- [ ] Test: production data copied to test db, code runs without errors
|
||||||
|
|
||||||
|
### 9. CRM Scope Creep
|
||||||
|
- [ ] Must-have features defined for v2.0 (lead pipeline, quote, auto-onboard)
|
||||||
|
- [ ] Should-have features listed for v2.1+ (email, calls, source)
|
||||||
|
- [ ] Won't-have features documented (team, multi-user, integrations)
|
||||||
|
- [ ] Scope document signed off by product
|
||||||
|
- [ ] Success metric defined: "Can go from lead to won project in <30 min"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 7 Checklist (Catalog & Offers)
|
||||||
|
|
||||||
|
**Before code:**
|
||||||
|
- [ ] Catalog consolidation migration plan reviewed
|
||||||
|
- [ ] Offer/project hierarchy documented
|
||||||
|
- [ ] Drag-drop version/locking strategy designed
|
||||||
|
|
||||||
|
**During implementation:**
|
||||||
|
- [ ] Migration backfill tested on production backup
|
||||||
|
- [ ] Drag-drop version field added
|
||||||
|
- [ ] Offer phase copy function atomic (transaction)
|
||||||
|
- [ ] Idempotency key on CRM leads
|
||||||
|
- [ ] Integration tests for copy consistency
|
||||||
|
|
||||||
|
**Before go-live:**
|
||||||
|
- [ ] Dry-run migration on production DB
|
||||||
|
- [ ] Verify referential integrity (no orphaned quote_items)
|
||||||
|
- [ ] Concurrent drag-drop test passes
|
||||||
|
- [ ] Offer copy count validation passes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 8 Checklist (Public Quote Pages)
|
||||||
|
|
||||||
|
**Before code:**
|
||||||
|
- [ ] Token security requirements finalized
|
||||||
|
- [ ] API response schema designed (no quote_items)
|
||||||
|
- [ ] Rate limiting strategy defined
|
||||||
|
|
||||||
|
**During implementation:**
|
||||||
|
- [ ] Token generation (nanoid(32))
|
||||||
|
- [ ] Expiration + email validation
|
||||||
|
- [ ] Rate limiting middleware
|
||||||
|
- [ ] Code audit for quote_items exposure
|
||||||
|
- [ ] Brute-force test (>1000 guesses/sec)
|
||||||
|
|
||||||
|
**Before go-live:**
|
||||||
|
- [ ] Brute-force test activates rate limit
|
||||||
|
- [ ] Enumeration test returns 401 for wrong email
|
||||||
|
- [ ] Expiration test returns 401 after expiration
|
||||||
|
- [ ] Code review: quote_items not in response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 9 Checklist (CRM Won Automation)
|
||||||
|
|
||||||
|
**Before code:**
|
||||||
|
- [ ] Scope document (Must/Should/Could/Won't) reviewed
|
||||||
|
- [ ] Idempotency strategy designed
|
||||||
|
- [ ] Payment plan algorithm defined
|
||||||
|
- [ ] Offer snapshot structure (JSONB) designed
|
||||||
|
|
||||||
|
**During implementation:**
|
||||||
|
- [ ] Idempotency key on crm_leads
|
||||||
|
- [ ] "Win" mutation atomic (client + project + phases + payments)
|
||||||
|
- [ ] Offer snapshot stored on win
|
||||||
|
- [ ] Button disabled until success
|
||||||
|
- [ ] Payment consistency tests
|
||||||
|
|
||||||
|
**Before go-live:**
|
||||||
|
- [ ] Double-click test: only 1 client created
|
||||||
|
- [ ] Network timeout test: retry returns same project
|
||||||
|
- [ ] Partial failure test: rollback on error
|
||||||
|
- [ ] Payment consistency test: correct number created
|
||||||
|
- [ ] Idempotency test: 10x "Win" with same key = 1 client
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Questions Before Each Phase
|
||||||
|
|
||||||
|
**Phase 7:**
|
||||||
|
- ✓ Is catalog consolidation migration safe (Expand-Contract, dual-write)?
|
||||||
|
- ✓ Does offer/project hierarchy mapping make sense (1 micro = 1 phase)?
|
||||||
|
- ✓ Is copy function atomic (all-or-nothing)?
|
||||||
|
- ✓ Do we have integration tests for offer phase structure consistency?
|
||||||
|
|
||||||
|
**Phase 8:**
|
||||||
|
- ✓ Is token length ≥ 32 chars and properly random?
|
||||||
|
- ✓ Do we validate both token AND email on public page?
|
||||||
|
- ✓ Is rate limiting active (max 3 views/token/min)?
|
||||||
|
- ✓ Can we prove quote_items never appears in public response?
|
||||||
|
|
||||||
|
**Phase 9:**
|
||||||
|
- ✓ Is "Win" action atomic (transaction)?
|
||||||
|
- ✓ Does idempotency key prevent duplicates on retry?
|
||||||
|
- ✓ Is button disabled until success?
|
||||||
|
- ✓ Have we defined Must/Should/Won't scope with user?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Validation Matrix
|
||||||
|
|
||||||
|
| Pitfall | Test Case | Expected Outcome | Status |
|
||||||
|
|---------|-----------|------------------|--------|
|
||||||
|
| 1. Catalog consolidation | Backfill migration on prod backup | Zero orphaned quote_items | [ ] |
|
||||||
|
| 2. Offer template mutation | Edit project phase, check offer unchanged | Offer template immutable | [ ] |
|
||||||
|
| 3. Token leakage | Brute-force 1000 guesses/sec | Rate limit activates (429) | [ ] |
|
||||||
|
| 3. Token leakage | Enumerate with wrong email | Returns 401 Unauthorized | [ ] |
|
||||||
|
| 4. Drag-drop race | Concurrent drag in 2 tabs | Final sort_order is coherent | [ ] |
|
||||||
|
| 5. Double-click clients | Click "Win" twice | Only 1 client created | [ ] |
|
||||||
|
| 5. Double-click clients | Network timeout + retry | Same project returned | [ ] |
|
||||||
|
| 6. Missing deliverables | Copy offer to project | All tasks and deliverables copied | [ ] |
|
||||||
|
| 8. Schema backward compat | Copy production data to test DB | No crashes, NULL handled | [ ] |
|
||||||
|
| 9. Payment consistency | "Win" with partial failure | Rollback, no orphaned payments | [ ] |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Red Flags During Development
|
||||||
|
|
||||||
|
🚨 **Stop and review if:**
|
||||||
|
- Offer/project hierarchy mapping is unclear (should be 1 page, explicit)
|
||||||
|
- Drag-drop sort_order updates without version check
|
||||||
|
- "Win" mutation has any non-transactional steps (client created outside txn)
|
||||||
|
- Copy function uses shallow spread (`{...obj}`) instead of `structuredClone()`
|
||||||
|
- Token length < 32 chars
|
||||||
|
- Public API response includes quote_items or per_service_price
|
||||||
|
- CRM leads table has no idempotency_key column
|
||||||
|
- Schema changes add NOT NULL without backfill test
|
||||||
|
- "Win" button not disabled until response received
|
||||||
|
- No rate limiting on public quote page
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Owner:** Development team
|
||||||
|
**Review:** Before each phase kickoff
|
||||||
|
**Update:** As testing results come in
|
||||||
@@ -0,0 +1,302 @@
|
|||||||
|
# Pitfalls Research Summary: Business Operations Suite (v2.0)
|
||||||
|
|
||||||
|
**Project:** ClientHub v2.0 — Adding Business Operations Suite to Production
|
||||||
|
**Research Date:** 2026-06-10
|
||||||
|
**Confidence:** HIGH (domain-specific research backed by schema review + security analysis)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Adding a complex Business Operations Suite (catalog consolidation + offer builder + public quotes + CRM automation) to a production app with real client data creates integration risks not present when building from scratch. This research documents the most dangerous pitfalls (rewrites/data loss) and operational friction points, with concrete prevention strategies for each.
|
||||||
|
|
||||||
|
**Key insight:** Most pitfalls cluster in four areas of high integration complexity:
|
||||||
|
1. **Schema consolidation** — breaking existing quote_items referential integrity
|
||||||
|
2. **Template-to-instance copy semantics** — offer phases mutating templates
|
||||||
|
3. **Optimistic UI + concurrent edits** — sort order conflicts
|
||||||
|
4. **Multi-step workflow atomicity** — CRM automation creating duplicates or partial state
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Critical Pitfalls (Require Design Changes Before Code)
|
||||||
|
|
||||||
|
### Pitfall 1: Catalog Consolidation Breaks Quotes (Data Loss Risk)
|
||||||
|
|
||||||
|
**Severity:** CRITICAL — Can orphan quote_items, break billing calculations
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Two parallel service tables (`service_catalog` for costs, `offer_services` for marketing pricing) need consolidation. Naive merge breaks `quote_items` referential integrity or loses price history.
|
||||||
|
|
||||||
|
**Prevention Strategy:**
|
||||||
|
- **Expand-Contract migration:** Add new unified `services` table alongside old ones, backfill in phases, only drop old tables after validation
|
||||||
|
- **Immutable snapshot:** Store `quote_snapshot: JSONB` in project_offers (freeze prices at time of win)
|
||||||
|
- **Referential integrity test:** Query for orphaned quote_items before/after migration
|
||||||
|
- **Backward compatibility:** Old quotes read from old tables, new quotes use new table, transition over 2-3 weeks
|
||||||
|
|
||||||
|
**Phase:** 7 (Catalog & Offers) — Plan migration design BEFORE any code changes
|
||||||
|
|
||||||
|
**Validation checklist:**
|
||||||
|
- [ ] Migration mapping layer documented (catalog ↔ services ↔ offer_services)
|
||||||
|
- [ ] Backfill strategy written (small batches, checksum validation)
|
||||||
|
- [ ] Dual-write period defined (how long to run old+new in parallel)
|
||||||
|
- [ ] Referential integrity test query exists
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pitfall 2: Offer Template Mutation on Copy (Data Corruption Risk)
|
||||||
|
|
||||||
|
**Severity:** CRITICAL — Templates silently mutate when project phases edited
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Copying offer phases to project via shallow copy = shared references. Admin edits project phase, template phase mutates too. Next deal uses corrupted template. Also: partial copies on retry create duplicate phases.
|
||||||
|
|
||||||
|
**Prevention Strategy:**
|
||||||
|
- **Deep copy with atomic transaction:** Use `db.transaction()` for entire copy operation (all-or-nothing); copy at database level, not in JS
|
||||||
|
- **Immutable template flag:** `offer_micros.is_template = true`, prevent UPDATE on templates
|
||||||
|
- **Idempotency key:** "Win" request includes idempotency key; retry returns same project (no duplicates)
|
||||||
|
- **Explicit hierarchy mapping:** Document what offer_micro → project_phase, what offer_service → project_task/deliverable
|
||||||
|
|
||||||
|
**Phase:** 7 (Offers) for design, 9 (CRM) for "Win" automation
|
||||||
|
|
||||||
|
**Validation checklist:**
|
||||||
|
- [ ] Hierarchy mapping documented (offer ↔ project structures)
|
||||||
|
- [ ] Atomic copy function implemented (single transaction, all-or-nothing)
|
||||||
|
- [ ] Idempotency key added to CRM leads
|
||||||
|
- [ ] Integration tests verify copy structure consistency across multiple instances
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pitfall 3: Public Quote Token Leakage (Security Risk)
|
||||||
|
|
||||||
|
**Severity:** CRITICAL — Token enumeration exposes all pricing
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Public quote page with nanoid 21-char token can be brute-forced or enumerated. Attacker builds pricing database, breaches commercial confidentiality.
|
||||||
|
|
||||||
|
**Prevention Strategy:**
|
||||||
|
- **Longer token:** nanoid(32) instead of 21 (~190 bits vs ~122 bits entropy)
|
||||||
|
- **Access control:** Require both token + email (validate recipient match)
|
||||||
|
- **Expiration:** token_expires_at (default 7 days)
|
||||||
|
- **Rate limiting:** Max 3 views/token/minute (blocks enumeration)
|
||||||
|
- **Never expose quote_items:** Public API response excludes line items, shows TOTAL PRICE ONLY
|
||||||
|
- **Activation state:** Token valid only AFTER admin sends it (not auto-generated on create)
|
||||||
|
|
||||||
|
**Phase:** 8 (Public Quote Pages) — Implement security controls IN PARALLEL with feature
|
||||||
|
|
||||||
|
**Validation checklist:**
|
||||||
|
- [ ] Token length ≥ 32 chars, rate limiting ≥ 3/min
|
||||||
|
- [ ] Email validation on public page (token + email both required)
|
||||||
|
- [ ] Expiration enforced (test expired token returns 401)
|
||||||
|
- [ ] Code audit: quote_items never in public API response
|
||||||
|
- [ ] Brute-force test: verify rate limit activates
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Moderate Pitfalls (Major Refactoring / Data Inconsistency)
|
||||||
|
|
||||||
|
### Pitfall 4: Drag-and-Drop Sort Order Race Condition
|
||||||
|
|
||||||
|
**Severity:** MODERATE — Phases display in wrong order, user frustration
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Concurrent drag-and-drop edits in multiple tabs cause sort_order conflicts. Last write wins, earlier update is lost. No version conflict detection.
|
||||||
|
|
||||||
|
**Prevention Strategy:**
|
||||||
|
- **Optimistic locking:** Add `version` field to offer_phases, update only if version matches (return 409 Conflict if mismatch)
|
||||||
|
- **Server-side recomputation:** Don't trust client's sort_order, recompute all orders atomically based on actual position
|
||||||
|
- **Optimistic UI with reconciliation:** Update frontend instantly, reconcile with server result (409 = refresh)
|
||||||
|
|
||||||
|
**Phase:** 7 (Offer Builder — Drag & Drop)
|
||||||
|
|
||||||
|
**Validation checklist:**
|
||||||
|
- [ ] `version` field added to offer_phases
|
||||||
|
- [ ] Update mutation includes version check
|
||||||
|
- [ ] Server recomputes all sort_orders atomically
|
||||||
|
- [ ] Concurrent edit test exists (open 2 tabs, drag in both)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pitfall 5: CRM "Win" Double-Click Creates Duplicate Clients
|
||||||
|
|
||||||
|
**Severity:** MODERATE — Duplicate clients, broken billing, audit confusion
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Multi-step "Win" automation (create client → project → phases → payments) has no idempotency. Double-click creates two clients, two projects. Network timeouts are invisible to user.
|
||||||
|
|
||||||
|
**Prevention Strategy:**
|
||||||
|
- **Idempotency key:** Every lead has unique idempotency_key; "Win" request checks if key already processed (if yes, return existing client_id)
|
||||||
|
- **Atomic transaction:** All steps (client, project, phases, payments) in single transaction — all succeed or all rollback
|
||||||
|
- **UI feedback:** Button disabled until success (prevents accidental double-click)
|
||||||
|
- **Browser persistence:** Store idempotency_key in localStorage, preserve across refresh
|
||||||
|
|
||||||
|
**Phase:** 9 (CRM Won Automation)
|
||||||
|
|
||||||
|
**Validation checklist:**
|
||||||
|
- [ ] CRM leads table has idempotency_key column (unique)
|
||||||
|
- [ ] "Win" mutation checks for existing key before creating
|
||||||
|
- [ ] All substeps in single db.transaction()
|
||||||
|
- [ ] Button disabled until response received
|
||||||
|
- [ ] Idempotency key stored in localStorage
|
||||||
|
- [ ] Test: double-click "Win", verify only 1 client created
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pitfall 6: Offer Phase Copy Misses Tasks/Deliverables
|
||||||
|
|
||||||
|
**Severity:** MODERATE — Client dashboard shows incomplete phases (no tasks to approve)
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
Copy offer → project phases but forget to copy tasks or deliverables. Client sees phase with no work items.
|
||||||
|
|
||||||
|
**Prevention Strategy:**
|
||||||
|
- **Explicit mapping:** Document offer_micro → project_phase, offer_service → project_task/deliverable mapping
|
||||||
|
- **Full-tree copy function:** Copy phases, then tasks for each phase, then deliverables for each task (all in one transaction)
|
||||||
|
- **Validation test:** Assert phase_count, task_count, deliverable_count match expected values after copy
|
||||||
|
|
||||||
|
**Phase:** 7 (Offers structure design), 9 (Copy implementation)
|
||||||
|
|
||||||
|
**Validation checklist:**
|
||||||
|
- [ ] Mapping documented (offer vs project hierarchies)
|
||||||
|
- [ ] Copy function handles entire tree (phases → tasks → deliverables)
|
||||||
|
- [ ] Integration test: copy offer, verify counts match expected
|
||||||
|
- [ ] Query test: check no deliverables are orphaned (task_id IS NULL)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Minor Pitfalls (Operational Friction)
|
||||||
|
|
||||||
|
### Pitfall 7: Offer State Not Synced Between Tabs
|
||||||
|
|
||||||
|
**Problem:** Admin edits offer in tab 1, tab 2 doesn't know, last save wins (first admin's work lost)
|
||||||
|
|
||||||
|
**Prevention:** Add `version` field, return 409 on version mismatch, show "Offer changed, reload?"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pitfall 8: CRM Schema Backward Incompatibility
|
||||||
|
|
||||||
|
**Problem:** Add new fields (budget, source) as NULL, code assumes populated, crashes
|
||||||
|
|
||||||
|
**Prevention:** Expand-Contract pattern — add as NULL, handle NULL defensively in code, backfill, then add NOT NULL constraint
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pitfall 9: CRM Scope Creep (Feature Bloat)
|
||||||
|
|
||||||
|
**Problem:** "Just add email templates" → 30 hours. "Add calls" → 40 hours. CRM never ships.
|
||||||
|
|
||||||
|
**Prevention:** Explicit Must/Should/Could/Won't scope document. Must-haves only for v2.0: lead pipeline, quote attachment, auto-onboarding. Defer rest.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Design Decisions for Phase 7–9
|
||||||
|
|
||||||
|
| Decision | Why | Validation |
|
||||||
|
|----------|-----|-----------|
|
||||||
|
| Expand-Contract migration for catalog | Zero-downtime, safe rollback, no data loss | Dry-run on prod backup before go-live |
|
||||||
|
| Deep copy + atomic transaction for offer phases | Prevents template mutation, partial copies | Integration test, structure consistency query |
|
||||||
|
| Idempotency key on "Win" action | Safe retry, prevents duplicate clients | Double-click test, query for duplicates |
|
||||||
|
| Public quote token security layers (length, expiration, email, rate limit) | Blocks enumeration, limits leakage | Brute-force test, code audit for quote_items |
|
||||||
|
| Offer snapshot (immutable JSONB) | Preserves what was promised vs. what's executing | Store at win time, display in client dashboard |
|
||||||
|
| Version field on offer_phases + optimistic locking | Detects concurrent edit conflicts | Concurrent drag test, 409 Conflict handling |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Roadmap Implications
|
||||||
|
|
||||||
|
**Phase 7 (Catalog & Offers):**
|
||||||
|
- Design catalog consolidation migration before any code
|
||||||
|
- Implement drag-drop with version fields from start
|
||||||
|
- Document offer/project hierarchy mapping explicitly
|
||||||
|
- Write copy function atomically (no partial copies)
|
||||||
|
|
||||||
|
**Phase 8 (Public Quote Pages):**
|
||||||
|
- Implement token security controls in parallel (not after)
|
||||||
|
- Rate limiting + email validation + expiration
|
||||||
|
- Code audit: quote_items never in response
|
||||||
|
- Test brute-force + enumeration
|
||||||
|
|
||||||
|
**Phase 9 (CRM — Won Automation):**
|
||||||
|
- Add idempotency_key to leads table
|
||||||
|
- Implement atomic "Win" transaction
|
||||||
|
- Store offer snapshot at win time
|
||||||
|
- Define Must/Should/Won't scope before design
|
||||||
|
- Integration tests for payment consistency
|
||||||
|
|
||||||
|
**Phase 10+ (Future):**
|
||||||
|
- Defer: email templates, call logging, team features, integrations
|
||||||
|
- Solo consultant doesn't need multi-user or GoHighLevel-scale features
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Strategy for Confidence
|
||||||
|
|
||||||
|
### Phase 7 (Catalog & Offers)
|
||||||
|
1. Dry-run consolidation migration on production database backup
|
||||||
|
2. Verify all quote_items still resolve to services (no orphans)
|
||||||
|
3. Regenerate quotes from old projects, compare prices to originals
|
||||||
|
4. Concurrent drag-drop test: open offer in 2 tabs, drag in both, verify final state
|
||||||
|
5. Copy offer phases to test project, verify phase/task/deliverable counts
|
||||||
|
|
||||||
|
### Phase 8 (Public Quote Pages)
|
||||||
|
1. Brute-force token space: 1000 guesses/sec, verify rate limit activates
|
||||||
|
2. Enumerate tokens: generate 100 quotes, try to access one meant for different email, verify 401
|
||||||
|
3. Expiration test: set token_expires_at to past, verify access fails
|
||||||
|
4. Code audit: search response JSON for price, quote_items, per_service_price (should be zero matches)
|
||||||
|
5. Authorized access test: correct email + token, verify success
|
||||||
|
|
||||||
|
### Phase 9 (CRM — Won Automation)
|
||||||
|
1. Double-click "Win" button, verify only 1 client created
|
||||||
|
2. Network failure during "Win": simulate timeout after client creation, retry, verify same project returned
|
||||||
|
3. Partial failure: mock project creation failure, verify client not created (rollback)
|
||||||
|
4. Payment consistency: verify 2–4 payments created based on payment plan
|
||||||
|
5. Idempotency: call "Win" 10x with same idempotency_key, verify only 1 project, 1 set of payments
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Confidence Assessment
|
||||||
|
|
||||||
|
| Area | Level | Reason |
|
||||||
|
|------|-------|--------|
|
||||||
|
| Catalog consolidation risks | HIGH | Schema review shows existing quote_items dependencies; migration pattern verified via Drizzle docs |
|
||||||
|
| Offer copy semantics | HIGH | JavaScript shallow copy / deep copy distinction well-understood; transaction guarantees verified |
|
||||||
|
| Token security | HIGH | Brute-force math straightforward; nanoid 32 vs 21 entropy difference verified |
|
||||||
|
| CRM idempotency | HIGH | Idempotency pattern researched across multiple sources; double-click problem well-documented |
|
||||||
|
| Scope creep prevention | MEDIUM | CRM feature bloat is common, but solo consultant constraint makes Must/Should/Won't achievable |
|
||||||
|
| Concurrent edit handling | MEDIUM | Optimistic locking pattern standard, but requires careful implementation in Next.js + Drizzle |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps for Phase Planning
|
||||||
|
|
||||||
|
1. **Before Phase 7 design starts:**
|
||||||
|
- Finalize catalog consolidation migration plan (Expand-Contract timeline)
|
||||||
|
- Document offer/project hierarchy mapping (1 page, code-level documentation)
|
||||||
|
- Design offer copy function signature and transaction strategy
|
||||||
|
|
||||||
|
2. **Before Phase 7 code starts:**
|
||||||
|
- Implement drag-drop versioning (version field + optimistic locking)
|
||||||
|
- Write integration tests for offer phase copy
|
||||||
|
|
||||||
|
3. **Before Phase 8 design starts:**
|
||||||
|
- Token security requirements: length (32), expiration (7d), email validation, rate limit (3/min)
|
||||||
|
- API response schema: exclude quote_items, include total_price only
|
||||||
|
|
||||||
|
4. **Before Phase 9 design starts:**
|
||||||
|
- Finalize Must/Should/Won't scope (document with user/consultant)
|
||||||
|
- Design "Win" workflow: idempotency key + atomic transaction
|
||||||
|
- Define payment plan algorithm (2–4 payments based on offer tier)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References for Implementation
|
||||||
|
|
||||||
|
- **Drizzle migrations:** https://dev.to/whoffagents/zero-downtime-postgres-migrations-with-drizzle-orm-22ga
|
||||||
|
- **Idempotency pattern:** https://codefarm0.medium.com/the-double-click-problem-how-idempotency-saved-our-checkout-system-a704be65d207
|
||||||
|
- **Optimistic updates:** https://www.nirtamir.com/articles/optimistic-updates-state-vs-render/
|
||||||
|
- **Schema evolution:** https://www.dataexpert.io/blog/backward-compatibility-schema-evolution-guide
|
||||||
|
- **Token security:** https://workos.com/blog/oauth-common-attacks-and-how-to-prevent-them/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Document location:** `/Users/simonecavalli/Vault/IAMCAVALLI/.planning/research/PITFALLS_V2.md` (detailed pitfall reference)
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user