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:
2026-06-11 06:01:59 +02:00
parent 6239eed6e6
commit 3b1f49d059
8 changed files with 2085 additions and 84 deletions
+210
View File
@@ -0,0 +1,210 @@
# Pitfalls Checklist: Business Operations Suite v2.0
Quick reference for preventing the 9 major pitfalls during Phase 79 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