# Proposal Acceptance → Contract Creation Flow

**Date:** 2026-05-31  
**Status:** Draft  
**Spec:** 78  
**Tier:** All tiers  
**Depends on:** `marketing-catalogs-campaigns`, `contracts-esignature`, `marketing-leads-pipeline`, `foundation-auth-rbac`  
**Referenced by:** `marketing-catalogs-campaigns`, `contracts-esignature`

---

## Overview

UI flow bridging proposal acceptance to contract creation. Spec 51 (public-proposal-view) explicitly states "Acceptance is non-binding acknowledgment only. No automatic charge, contract, or invoice creation. Staff follows up manually." This spec defines what "staff follows up manually" looks like as a concrete UI flow — the in-app trigger point and the contract creation pre-fill.

---

## Context

When a proposal is accepted, the tenant staff receive a notification: "[Recipient] accepted proposal: [Name]". Staff then need to create a contract. Currently, no UI guides this next step — the flow breaks at proposal acceptance.

---

## Trigger Point: Proposal Detail View

On the proposal detail view (`/proposals/:id`, owned by spec 130 `proposal-editor`), accepted proposals gain a "Create Contract" CTA:

```
┌──────────────────────────────────────────────────────────────┐
│  Proposal: Website Redesign — Acme Corp                     │
│  Status: ✓ Accepted — 2026-05-28 by Dana Katz (Acme Corp)   │
│                                                              │
│  [View Proposal]   [Create Contract →]   [Create Invoice →]  │
└──────────────────────────────────────────────────────────────┘
```

Two options:
- **Create Contract** → opens contract creation pre-filled from proposal (see below)
- **Create Invoice** → navigates to `/invoices/new?proposal_id={id}` (proposal → invoice direct path, skipping contract)

If a contract is already linked (`proposals.contract_id`): "View Contract →" replaces the CTA.

---

## Data Model

```sql
ALTER TABLE proposals ADD COLUMN contract_id UUID REFERENCES contracts(id) ON DELETE SET NULL;
```

---

## "Create Contract" Flow

Navigates to `/contracts/new?proposal_id={id}`. The contract creation form (spec 48) is extended:

### Pre-fill from proposal

- **Parties**: customer from `proposals.customer_id` (if linked) or `proposals.lead_id → leads.customer_id`; sender is the tenant
- **Contract title**: "{Proposal name} — Service Agreement" (editable)
- **Content**: proposal's pricing section extracted into a contract pricing clause (editable Tiptap content)
- **Signatories**: pre-filled with the accepted-by recipient's name + email (from `proposals.accepted_by_name` + `proposals.customer_email`)

```
┌──────────────────────────────────────────────────────────────┐
│  New Contract  ·  From proposal: Website Redesign            │
│                                                              │
│  Title:    [Website Redesign — Service Agreement_________]   │
│                                                              │
│  Customer: [Acme Corp ▾]  (pre-filled)                      │
│                                                              │
│  Signatories:                                                │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  1. Dana Katz   dana@acme.com   (recipient, pre-filled)│  │
│  │  + Add signatory                                     │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                              │
│  Content: [Tiptap editor — pre-filled from proposal pricing] │
│                                                              │
│  Linked proposal: Website Redesign [×]                      │
│                                                              │
│  [Save Draft]              [Send for Signing]                │
└──────────────────────────────────────────────────────────────┘
```

On save: `contracts.proposal_id = proposalId` (new column below) and `proposals.contract_id = newContractId` set in same transaction.

---

## Data Model (additional)

```sql
ALTER TABLE contracts ADD COLUMN proposal_id UUID REFERENCES proposals(id) ON DELETE SET NULL;
```

---

## Proposal Detail: Contract Tab

`/proposals/:id` (spec 130 `proposal-editor`) gains a "Contract" tab:

```
┌──────────────────────────────────────────────────────────────┐
│  Proposal: Website Redesign                                  │
│  [Details]  [Timeline]  [Contract]                          │
│                                                              │
│  ── Contract ───────────────────────────────────────────── │
│                                                              │
│  Website Redesign — Service Agreement                       │
│  Status: SENT — awaiting signature from Dana Katz           │
│  [View Contract →]                                           │
│                                                              │
└──────────────────────────────────────────────────────────────┘
```

If no contract: CTA "Create Contract from this proposal".

---

## Notification Enhancement

Spec 51's acceptance notification ("Proposal accepted") gains an action button in the in-app notification:

```
[Recipient] accepted proposal: [Name]
[Create Contract →]  [Create Invoice →]  [View Proposal →]
```

These deep-link buttons let staff act from the notification center without navigating manually.

---

## API Extensions

```
GET  /api/proposals/:id/contract
  → get linked contract (if any)
     returns: { contract: { id, title, status } } | null

POST /api/contracts (existing endpoint — spec 48)
  → extended: accepts proposal_id in body
     On create: sets contracts.proposal_id + proposals.contract_id in same transaction
```

---

## Architecture Decisions

| Decision | Choice | Reason |
|----------|--------|--------|
| Non-automatic (staff-triggered) | Not auto-created on acceptance | Spec 23/51 decision: acceptance is non-binding; not every accepted proposal leads to a contract (some proceed to invoice directly) |
| Pre-fill from proposal | Not blank contract form | Reduces duplicate data entry — proposal already captured the scope, price, and recipient; re-entry would be waste |
| Bilateral links (contract_id on proposals, proposal_id on contracts) | Both directions | Navigation in both directions is common: "what contract came from this proposal?" and "what proposal preceded this contract?" |
| Direct proposal → invoice option | Not forced via contract | Some engagements (small, trusted clients) don't need a formal contract; forcing contract creation blocks the invoice path |
