3b1f49d059
- 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>
7.8 KiB
7.8 KiB
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
versionfield 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
versionfield 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 ofstructuredClone() - 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