Sales CRM & RFP Spec Stories
How do we think slowly so the answer library compounds and win rate climbs?
Intent Contract
Agent autonomy boundary. Not parsed by engineering — governance instrument for humans and agents.
| Dimension | Statement |
|---|---|
| Objective | Vertical CRM for construction/infrastructure sales that learns from every bid — answer once, auto-fill forever, win rate climbs. |
| Outcomes | 1. Answer library has 10+ approved entries within 14 days of pilot. 2. Second RFP auto-fills 5+ answers from first. 3. Win rate trends >30%. |
| Health Metrics | Auth uptime (no regression). Data integrity (no orphaned records). Page load <2s on all CRM routes. |
| Constraints | Hard: Multi-tenant isolation (org data never leaks). Steering: Vertical-first (construction entities native, not configured). |
| Autonomy | Allowed: UI layout, component choice, query optimization. Escalate: Schema changes, new entity types. Never: Delete user data, modify billing without confirmation. |
| Stop Rules | Complete when: all Build Contract rows at Live + 1 real RFP processed end-to-end. Halt when: auth regresses or library shows 0 queries after 14 days. |
| Counter-metrics | Answer library must not become a data-entry chore — if users stop approving answers after week 2, the workflow has failed. Auto-fill must not degrade answer quality — if SME rejection rate exceeds 30%, the algorithm is matching wrong. |
| Blast Radius | CRM routes (all /crm/*), server actions (contact/deal/venture CRUD), answer library (new matching algorithm), Stripe webhooks (payment flow). Multi-tenant isolation is the critical boundary. |
| Rollback | Feature flags per module. Answer library can be disabled without affecting CRM CRUD. Auto-fill algorithm can be rolled back to manual-only. Stripe integration can be disabled without losing deal data. |
Story Contract
Stories are test contracts. Each row converts to test files. Tests must be RED before implementation starts. Tests going GREEN = value delivered.
Every story follows the P2P arc: Pain (who hurts, measurable cost) → Performance Target (the number that proves it works) → Validated Outcome (the Tight Five dimension this serves).
| # | WHEN (Trigger + Precondition) | THEN (Exact Assertion) | ARTIFACT | Test Type | FORBIDDEN (Must not happen) | OUTCOME (Performance Number) |
|---|---|---|---|---|---|---|
| S1 | User navigates to /crm/contacts with 20+ contacts in DB for current org | List renders with pagination (10 per page). Search input filters by name in <500ms. Click on contact row navigates to detail page showing linked ventures, deals, and activity history. | BLOCKER — test path TBD by engineering | e2e | List dumps all records without pagination. Search returns 0 results for exact name match that exists. Contact detail shows contacts from another org. | Find any contact in <5s vs scrolling spreadsheet rows at ~30s per lookup |
| S2 | User navigates to /crm/pipeline with deals across 3+ stages, each with dollar values | Kanban renders cards per stage. Dollar values sum per column header. Drag card from "Proposal" to "Negotiation" persists on page reload. Deal count badge updates. | BLOCKER — test path TBD by engineering | e2e | Drag updates UI but does not persist — card reverts on reload. Pipeline shows $0 column total when deals have values. Cards from other orgs appear in pipeline. | Pipeline status visible in <10s vs weekly team call + shared spreadsheet reconciliation |
| S3 | Venture A has 5+ approved answers in library AND user creates Venture B with 3+ questions that match Venture A questions by keyword overlap | Auto-fill populates Venture B with matching answers from library. Fill rate % displayed on venture detail. Each auto-filled answer shows source venture link. Unapproved answers excluded from auto-fill. | BLOCKER — test path TBD by engineering | integration | Auto-fill returns 0 matches when identical questions exist in library. Auto-fill silently succeeds with 200 response but creates 0 answer records. Auto-fill pulls from unapproved/rejected answers. | Venture B response time <8 hours at 70% fill rate vs 20-40 hours from scratch per RFP |
| S4 | User logs a call from deal detail page with notes, 2 linked contacts, and a follow-up date 3 days from now | Activity record appears on deal timeline AND both contact timelines within 5s. Follow-up creates a task with due date, assignee, and linked deal. Task visible on /crm/calendar for the due date. | BLOCKER — test path TBD by engineering | integration | Activity logged on deal timeline but missing from contact timeline. Task created without due date or assignee. Activity references contacts from a different org. | Zero follow-ups forgotten — task appears on due date vs current "I think we promised to send that last week" |
| S5 | User creates a venture linked to: 1 deal, 2 contacts with buying roles (Decision Maker, Influencer), and 1 property with GPS coordinates | Venture detail page shows: deal link (clickable), contacts with role badges, property with address and map pin. Deal detail shows venture link. Contact detail shows venture + role. Property detail shows linked venture. | BLOCKER — test path TBD by engineering | e2e | Venture links to deal but deal detail does not show venture. Stakeholder role assigned but not visible on contact profile page. Property created without GPS/address renders blank map. | New hire understands deal context in <2 min vs 30 min verbal explanation from colleague |
| S6 | User opens Go/No-Go scoring form for a venture with RFP deadline in 14 days | All 8 criteria render (Relationship, Capability, Capacity, Competition, Margin, Location, Terms, Timeline). User scores each. Composite computes with weights. Result: 70%+ = Go, 50-70% = Review, <50% = No-Go. Decision persists per venture. | BLOCKER — test path TBD by engineering | integration | Score always computes "Go" regardless of criteria values. Form saves with fewer than 8 criteria scored. Score saved but not visible on venture detail or pipeline card. | Stop pursuing unwinnable bids — save 20-40 hours per no-go decision at $1,150 estimated value |
| S7 | User navigates to /crm/analytics with 3+ ventures containing 10+ total approved answers across all ventures | Library growth chart renders answers over time. Per-venture fill rate % visible. Time saved estimate computed: approved_answers × avg_time_per_manual_answer. Compound rate shows projected fill rate at current growth pace. | BLOCKER — test path TBD by engineering | integration | Analytics page shows 0 approved answers when library has entries. Fill rate always displays 0% despite auto-fills working. Time saved shows $0 when fill rate >0%. | Prove compound ROI: $1,150 per RFP saved × fill rate %. Library value grows with every approved answer. |
Tight Five coverage check:
| P Dimension | Stories covering it | Gap? |
|---|---|---|
| Pain (3-5 tools, 20-40h per RFP) | S1 (contact lookup pain), S2 (pipeline visibility pain), S3 (copy-paste pain) | No |
| Demand (app live, real data) | S5 (relationship linking — construction-specific), S6 (Go/No-Go — industry workflow) | No |
| Edge (vertical + compounding library) | S3 (auto-fill compound), S7 (compound measurement) | No |
| Trend (AI vertical SaaS) | S3 (AI auto-fill), S6 (qualification scoring) | No |
| Conversion (pilot proof) | S7 (ROI measurement), S3 (time saved per RFP) | No |
Build Contract
The deliverable. Engineering builds from this. Commissioning reads this. Every row has an acceptance test.
Job 1: Know Who I'm Dealing With
| # | Function | Artifact | Verification | Value | State |
|---|---|---|---|---|---|
| 1 | Browse, search, filter contacts | Contact list page at /crm/contacts | List loads <1s, search filters in <500ms. 29 contacts render. | Find the right person in seconds | Partial |
| 2 | View profile, linked ventures, linked deals | Contact detail page with relationship graph | Click contact card → detail page with linked entities | See full relationship context before a meeting | Broken |
| 3 | Add new contact with company | Contact create form + redirect | Create saves, redirects to detail with canonical ID | Capture a new relationship immediately | Partial |
| 4 | View company with all contacts and deals | Company detail page | Company shows all contacts + deals + activity | Understand an organisation's full engagement | Built |
| 27 | Log calls, emails, meetings per deal | Activity timeline component | Log from deal, appears on both deal and contact timelines | Build an interaction history | Built |
| 28 | Bulk import contacts from spreadsheet | CSV import page with validation | Upload 50 contacts, all appear with correct fields, duplicates flagged | Onboard existing contacts in minutes | Not verified |
Job 2: See Where Every Deal Stands
| # | Function | Artifact | Verification | Value | State |
|---|---|---|---|---|---|
| 5 | Visual kanban of all deals by stage | Deal pipeline at /crm/deals | Cards/Table/Kanban views. 8 deals render with values + weighted pipeline. | See where every deal stands at a glance | Live |
| 6 | Create new deal with value and stage | Deal create form | Save + appears on pipeline in correct column | Capture a new opportunity immediately | Live |
| 7 | View deal with stakeholders, linked RFP, activity | Deal detail page | All relationships visible, click-through to venture + contacts | Understand everything about opportunity | Live |
| 8 | Add contacts as stakeholders with buying roles | Stakeholder management UI | Assign role, see influence mapping, remove stakeholder | Map the buying committee | Live |
| 9 | Summary cards and pipeline overview | CRM Overview at /crm + Dashboard at /dashboard | Cards show correct counts (29 contacts, 8 deals, 10 activities). L4 verified 2026-03-21. | Know what needs attention today | Live |
| 10 | Track pipeline and won revenue targets | Monthly goals component | Set target, track progress, percentage updates with deal changes | Know if you're on track this month | Live |
| 38 | Predict deal close probability | Sales forecasting algorithm + insights UI | Probability correlates with actual close rate within 20% over 10 deals | Know which deals will close and when | Dormant |
| 35 | Analytics and forecasts | Insights dashboard at /insights | Financial, Sales Forecast, Deal Analytics, Scoreboard, RAG, HITL — all render with 0 data | Make data-driven decisions | Partial |
Job 3: Win More Bids, Waste Less Time
| # | Function | Artifact | Verification | Value | State |
|---|---|---|---|---|---|
| 11 | Visual board of RFP projects by stage | Venture kanban page | Cards show stage, linked deal, deadline. Drag between stages. | Track every bid from discovery to submit | Live |
| 12 | View RFP questions, linked deal, linked contacts | Venture detail page | All Q&A visible, linked deal clickable, contacts with roles shown | Full picture of a bid in one page | Live |
| 13 | Create new RFP venture | Venture create form | Save + appears on kanban, link to deal optional | Start tracking a new bid | Live |
| 16 | Manage Q&A per venture | RFP questions list + CRUD | Add, edit, delete questions. Reorder by drag. | Structure the RFP response | Live |
| 17 | Review AI answer or write manual answer | Answer detail editor | AI draft visible, manual override saves, approval status tracks | Build library one question at a time | Live |
| 18 | AI-powered answer generation across venture | AI Loop endpoint + UI trigger | Generate answers for all unanswered Qs, each references source material | Auto-generate draft answers | Built |
| 19 | Generate presentation deck from answers | Deck generation endpoint + download | PDF/PPTX output with all approved answers formatted | Turn answers into a deliverable | Built |
| 20 | Upload PDF, DOCX, TXT to ventures | Document upload component | File persists, linked to venture, extractable text | Attach RFP documents to right project | Live |
| 21 | Auto-populate RFP answers from library | Auto-fill algorithm + UI indicator | Venture B auto-fills 5+ answers from Venture A library | Cut 70% of RFP response time | Live |
| 22 | Store approved answers for reuse | Answer library page with search | Approved answer queryable by keyword, linked to source venture | Never write the same answer twice | Built |
| 23 | SME approval workflow for answers | Review queue page | Assign reviewer, approve/reject, status visible on answer | Ensure answer quality before auto-fill | Built |
| 24 | Track time saved, fill rate, compound growth | RFP analytics dashboard | Fill rate %, time saved estimate, library growth chart. Route /crm/analytics → 404. May have moved to /insights. | Prove the ROI of the RFP tool | Broken |
| 31 | Qualification checklist for RFP decisions | Go/No-Go scoring form | 8 criteria scored, recommendation displayed, saved per venture | Stop wasting time on unwinnable bids | Gap |
| 34 | Assign reviewers to answer queues | RFP assignment UI | Assign reviewer per question, notification sent, queue filtered | Distribute review work across team | Gap |
| 39 | Track answer library growth rate | Compound rate algorithm + chart | Growth curve visible, projected fill rate at current pace | Prove the RFP tool compounds over time | Dormant |
| 40 | Auto-classify uploaded documents | RFP type detection algorithm | Upload PDF, type auto-detected with >80% accuracy | Skip manual tagging on every upload | Dormant |
Job 4: Never Let a Follow-Up Fall Through
| # | Function | Artifact | Verification | Value | State |
|---|---|---|---|---|---|
| 25 | Create, assign, track tasks | Task management UI at /crm/tasks | Page renders with empty state + "Create Your First Task" CTA. 0 tasks. | Never let a follow-up fall through | Partial |
| 26 | View deadlines and follow-ups by date | Calendar page at /crm/calendar | Route → 404. Not deployed. | See the week ahead | Broken |
| 36 | Team plans and task tracking | Plans page | Create plan, assign tasks, filter by team member | Coordinate team activity | Stub |
Job 5: Link People, Places, and Projects
| # | Function | Artifact | Verification | Value | State |
|---|---|---|---|---|---|
| 14 | Bidirectional link between RFP venture and CRM deal | Venture-deal link UI | Link from either side, both detail pages show the link | One project, one deal, full picture | Live |
| 15 | Assign roles and influence to linked contacts | Stakeholder role assignment | Role dropdown, influence score, visible on deal + venture | Know who decides, influences, blocks | Live |
| 30 | Track physical sites as standalone entities | Property registry page | Create property, link to venture, GPS + address, site photos | Link projects to real-world locations | Partial |
Cross-Cutting
| # | Function | Artifact | Verification | Value | State |
|---|---|---|---|---|---|
| 29 | Search across contacts, deals, ventures | Global search component | Search "Acme" returns contacts, deals, and ventures in <500ms | Find anything from one search box | Partial |
| 32 | Sign-in, sign-up, user management | Auth pages + session management | Login works, redirects to /dashboard. L4 verified 2026-03-21. | Secure access per user | Live |
| 33 | App-wide sidebar and top nav | Navigation component | Sidebar works. Pipeline dropdown expands to Contacts/Deals/Tasks/Activities. Active state correct. "Contacts" from dropdown → CRM Overview, not contacts list (nav mismatch). | Move between modules without friction | Partial |
| 37 | AI agent registry and workflows | Agents page | Registry loads, agent list visible, workflow trigger functional | Automate repetitive sales tasks | Stub |
| 41 | Accept subscription payments via Stripe | Stripe integration + webhook handler | Checkout creates subscription, webhook confirms, seat counted | Get paid for the product | Partial |
Principles
What truths constrain the design?
The Job
| Element | Detail |
|---|---|
| Situation | Construction sales team has 3 weeks to respond to an RFP and half the questions have been answered before. |
| Intention | Find those answers, auto-fill from the library, get SME review, and submit on time. |
| Obstacle | Copy-paste from old Word docs, hope someone saved the right version. 3-5 tools per deal. |
| Hardest Thing | The AI value prop requires seed data that requires active usage that requires working auth. Chicken-and-egg. |
The hidden objection: "I don't want to enter data just so a system can show it back to me." The answer library solves this — answer once, the system learns, and auto-fills next time. The data entry IS the value creation.
Why Now
22% win rate (industry average: 20-30%)
3-5 tools per deal (CRM + spreadsheet + email + file share + notebook)
20-40 hours per RFP response (70% copy-paste from previous bids)
0 approved answers in the library (auto-fill returns nothing)
$1,150 estimated value per RFP saved (from analytics page)
The product is 49% live. The demand generation isn't. Fix auth (done) -> seed library -> prove compound -> recruit pilot.
Design Constraints
| Constraint | Rationale |
|---|---|
| Vertical-first | Generic CRMs force configuration tax. Native entities (Property, Venture, multi-company deals) |
| Answer library is the moat | Auto-fill from library creates compounding value — each bid makes the next faster |
| Multi-tenant from day one | Org isolation required for pilot customers |
| Agent composes, human sends | Hidden objection: "AI outreach feels spammy." Human review before every external action. |
Vertical CRM Thesis
Generic CRMs can be configured for construction. None are designed for it. Configuration tax compounds: every new hire needs custom field setup, every report needs field mapping, every integration needs configuration. Industry-specific entities (Property, Venture, multi-company deals) require custom objects. This CRM has these natively.
| Capability | Salesforce | HubSpot | Pipedrive | This CRM |
|---|---|---|---|---|
| Contact/Company mgmt | Yes | Yes | Yes | Yes |
| Visual pipeline | Yes | Yes | Yes | Yes |
| Property/site registry | No (custom obj) | No | No | Native |
| Multi-company deals | Yes (complex) | Limited | No | Native |
| RFP/tender workflow | No (add-on) | No | No | Native |
| AI answer auto-fill | No | No | No | Native |
| Price per seat/month | $75-300 | $0-150 | $15-100 | Target: $30-80 |
Performance
How do we know it's working?
Priority Score
PRIORITY = Pain x Demand x Edge x Trend x Conversion
| Dimension | Score (1-5) | Evidence |
|---|---|---|
| Pain | 5 | 3-5 tools per deal. 20-40h per RFP. Copy-paste from Word docs. 22% win rate. |
| Demand | 4 | App live with real data. 23 contacts, 3 ventures. No competitor has native RFP workflow. |
| Edge | 3 | Vertical CRM + AI auto-fill + compounding library. No proprietary data yet. |
| Trend | 4 | AI vertical SaaS fastest growing. Construction tech accelerating. |
| Conversion | 3 | $30-80/seat vs Salesforce $75-300. Internal use only. Needs pilot. |
| Composite | 720 | 5 x 4 x 3 x 4 x 3 |
North Star: Win Rate > 30% (currently 22%).
Quality Targets
| Metric | Target | Now |
|---|---|---|
| Win rate | >30% | 22% |
| First answer to library | Within 7 days of pilot | N/A |
| Deal creation (activation) | Within 48h of onboarding | N/A |
| Library size | 10+ approved | 0 |
| Weekly active usage | CRM + RFP modules | Internal only |
Failure Budget
| Failure Type | Budget | Response |
|---|---|---|
| Auth regression | 0% | Immediate fix — blocks all users |
| Data loss | 0% | Immediate fix — trust destroyed |
| Route 404 | <5% | Fix within sprint — broken navigation |
| Auto-fill mismatch | <10% | Review algorithm — wrong answers cost trust |
Kill signal: Contacts but no deals = rolodex. Ventures but no answers = project board.
Platform
What do we control?
Domain Model
CONTACTS <--> COMPANIES
| |
VENTURES <--> DEALS (Bids)
| |
PROPERTIES DOCUMENTS
| Entity | What It Represents | Key Fields |
|---|---|---|
| Contact | A person you do business with | Name, role, company, phone, email, tags, status |
| Company | An organisation (client, subcontractor, supplier) | Name, type, industry, ABN/tax ID, address |
| Property | A physical site or address where work happens | Address, GPS, site type, status, photos |
| Venture | A project or job that ties people, places, and bids | Name, property, client company, stage, value |
| Deal | A bid, tender, or commercial opportunity | Venture link, value, stage, due date, probability |
| Activity | Any interaction (call, email, meeting, site visit) | Type, date, contacts, notes, linked entity |
| Document | Proposals, RFPs, contracts, drawings | File, version, type, linked deal/venture |
Current State (Commissioned 2026-03-20)
| Component | Built | Wired | Working | Notes |
|---|---|---|---|---|
| Auth + sessions | Yes | Yes | Partial | Login works. URL doesn't update after redirect. |
| Contact list | Yes | Yes | Partial | 29 contacts render. No pagination. Cards not clickable. |
| Contact detail | Yes | ? | No | Click from list does nothing. Detail page unreachable. |
| Company pages | Yes | Yes | Partial | Needs verification |
| Deal pipeline | Yes | Yes | Yes | Kanban, Cards, Table views all work. 8 deals, $1.32M. |
| CRM Overview | Yes | Yes | Yes | Summary cards correct. Pipeline mini-chart works. |
| Venture + RFP Q&A | Yes | Yes | Yes | Hub renders. 0 ventures, 0 answers — no seed data. |
| Answer library | Yes | Partial | No | Built but 0 entries. 70% fill rate displayed (misleading). |
| AI auto-fill | Yes | Yes | No | Returns nothing (empty library) |
| Insights | Yes | Yes | Partial | 6 dashboard types render. All show 0 data. |
| Tasks | Yes | Yes | Partial | Page renders with empty state. Create CTA present. |
| Calendar | No | No | No | /crm/calendar → 404 |
| RFP analytics | No | No | No | /crm/analytics → 404 |
| Chat | Yes | ? | ? | Not tested. Sidebar link exists. |
| Stripe payments | Yes | Partial | No | Webhooks not wired |
| 3 algorithms | Yes | No | No | Dormant in agency lib |
Delivery State (Honest count after 2026-03-20 commissioning)
| State | Count | % |
|---|---|---|
| Live | 14 | 34% |
| Partial | 9 | 22% |
| Built | 5 | 12% |
| Broken | 3 | 7% |
| Dormant | 3 | 7% |
| Gap | 2 | 5% |
| Stub | 2 | 5% |
| Not verified | 3 | 7% |
Build Ratio
~75% composition (platform, auth, data layer), ~25% new code (answer library compound, Go/No-Go, assignments).
Protocols
How do we coordinate?
RFP Workflow
TENDER NOTICE -> GO/NO-GO DECISION -> BID PREPARATION -> SUBMISSION -> EVALUATION -> AWARD/LOSS -> HANDOVER
Go/No-Go Checklist
| Criteria | Question | Weight |
|---|---|---|
| Relationship | Do we know the decision-maker? | High |
| Capability | Have we done this type of work before? | High |
| Capacity | Do we have the team available? | High |
| Competition | How many competitors are bidding? | Medium |
| Margin | Can we hit target margin at competitive price? | High |
| Location | Is the site in our operating area? | Medium |
| Terms | Are contract terms acceptable? | Medium |
| Timeline | Can we meet the submission deadline? | High |
Score: 70%+ = Go. 50-70% = Review. Below 50% = No-Go.
Build Order (Revised 2026-03-20 — foundation first)
Previous build order started with dormant algorithms. Wrong. Fix what's broken before adding what's missing.
Dependency chain: Contact detail → Activity logging → Chat → Tasks → Answer library → Auto-fill compound → Analytics
| Sprint | Features | What | Why First | Acceptance |
|---|---|---|---|---|
| F0 | #2, #32, #33 | Fix contact detail click-through. Fix auth URL redirect. Fix sidebar nav routing. | Foundation. Nothing works downstream if you can't open a contact. Agents need contact detail to operate. | Click contact card → detail page with linked deals/ventures. Auth redirect updates URL. Sidebar "Contacts" → /crm/contacts. |
| F1 | #1, Chat | Add pagination to contacts (10/page). Wire chat function. | Scale + engagement. 29 contacts works. 200 won't. Chat is the engagement surface — users need a reason to come back. | Pagination at 10/page. Chat sends/receives messages. |
| F2 | #27, #25 | Activity logging from deal detail. Task creation from deal. | Enables follow-up loop. Can't build interaction history or track follow-ups without these. | Log call from deal → appears on deal + contact timelines. Create task from deal with due date. |
| F3 | #26 | Deploy calendar page | Closes follow-up loop. Tasks without a calendar view are invisible. | /crm/calendar renders tasks on correct dates. |
| F4 | #22, #23, seed | Answer library + review queue + seed 5 ventures with 20 answers | Proves compound. Empty library = dead value prop. Manual seed breaks the chicken-and-egg. | Library has 20+ approved answers. Review queue shows pending. |
| F5 | #21, #18, #24 | Auto-fill from seeded library. AI answer generation. RFP analytics page. | Value multiplier. Only works after F4 seeds the library. Analytics proves ROI. | Venture B auto-fills 5+ from library. /crm/analytics renders fill rate + time saved. |
| Park | #30, #31, #34, #29, #38-41 | Properties, Go/No-Go, assignments, search, algorithms, Stripe | Only after F5 proves compound. These scale what works — don't build them before proving the core loop. | — |
Kill date: 2026-04-07 (extended from 2026-03-24 — original was unrealistic given foundation gaps discovered).