# RateRight: Revised $50→7% Fee + $10 Insurance Model

## Overview

RateRight = **matching service with payment guarantee**, not a payment processor.

**Revenue:**
- Hiring fee: **7% of job value** (min $25, max $100) — contractor pays RateRight
- Insurance: **$10/week** subscription — worker pays RateRight
- Insurance has: $500 claim cap, 2-week waiting period, 10% worker deductible, $1000 max insured job

**We don't process job payments.** Contractor pays worker directly (cash, bank transfer, PayID). We track confirmation only.

---

## Codebase

VPS: `/home/ccuser/rateright-main-site/` (Flask, PostgreSQL, Stripe, Fly.io)

---

## Week 1: Replace Escrow with 7% Fee (min $25, max $100)

### 1.1 Modify `Payment.calculate_amounts()`
**File**: `app/models/contract.py` (~line 331-398)

Current logic:
```python
platform_fee_rate = 0.07
platform_fee = base_amount * platform_fee_rate
# Then: escrow full job value + fee via Stripe
```

New logic:
```python
platform_fee = base_amount * 0.07
platform_fee = max(platform_fee, 25.00)   # minimum $25
platform_fee = min(platform_fee, 100.00)  # maximum $100
# Stripe charges ONLY the fee, not the job value
```

Remove:
- GST calculation on job amount (worker handles own tax)
- Stripe fee deduction from worker payout
- `net_to_worker` calculation
- `gross_amount` = just the platform fee now, not job value + fee
- Referral discount (3%) — remove or keep as a business decision

### 1.2 Simplify Payment Route
**File**: `app/blueprints/legal/routes.py` (~lines 133-380)

Change `POST /legal/payments`:
- Stripe PaymentIntent for **fee amount only** ($25-$100)
- Remove `capture_method='manual'` (no escrow, charge immediately)
- Remove GST/withholding tax handling
- Remove invoice auto-generation
- Flow: calculate fee → charge contractor → mark paid → done

### 1.3 Remove Escrow Release Flow
**File**: `app/blueprints/legal/routes.py` (~lines 432-548)

Disable/remove:
- `POST /contract/<id>/approve-completion` — no escrow to release
- `POST /contract/<id>/mark-complete` — no payment to release
- `stripe_service.capture_payment()` — no manual capture
- `stripe_service.transfer_to_worker()` — we don't pay workers for jobs

### 1.4 Simplify Stripe Webhooks
**File**: `app/blueprints/legal/stripe_webhooks.py`

Keep `payment_intent.succeeded` but simplify:
- Mark the hiring fee as paid
- Remove escrow status tracking
- Remove transfer-related webhook handling

### 1.5 Update Contract Model
**File**: `app/models/contract.py`

Add fields:
- `hiring_fee_amount` (Decimal) — the calculated fee
- `hiring_fee_paid` (Boolean, default False)
- `hiring_fee_payment_id` (FK to Payment)

Remove reliance on:
- `payment_status` escrow states (held_escrow, released, transferred)
- `payment_terms`, `payment_schedule` — we don't manage job payments

### 1.6 Update Templates
**Files**: `app/templates/` (multiple)

- Replace all "7% platform fee" text with "7% fee (min $25, max $100)"
- Remove payment breakdown displays (GST, Stripe fee, net-to-worker)
- Remove escrow/payment-release UI
- Show simple fee amount on contract review
- Key templates:
  - `contracts/review.html` (~line 1321)
  - `legal/faq.html` (~line 115)
  - `legal/payment_terms.html` (~line 58)
  - Landing pages: `index.html`, `countdown.html`

### 1.7 Database Migration
```sql
ALTER TABLE contracts ADD COLUMN hiring_fee_amount NUMERIC(10,2);
ALTER TABLE contracts ADD COLUMN hiring_fee_paid BOOLEAN DEFAULT FALSE;
```

---

## Week 2: Payment Confirmation Tracking

### 2.1 New Payment Confirmation Model
**New file**: `app/models/payment_tracking.py`

```
PaymentConfirmation:
  - id
  - contract_id (FK Contract)
  - contractor_id, worker_id (FK User)
  - expected_amount (Decimal) — agreed job rate
  - payment_method (String: "bank_transfer", "cash", "payid", "other")
  - expected_date (Date)
  - contractor_marked_paid (Boolean, default False)
  - contractor_marked_paid_at (DateTime)
  - worker_confirmed_received (Boolean, default False)
  - worker_confirmed_received_at (DateTime)
  - evidence_url (String) — uploaded proof (screenshot, etc.)
  - status (String: "pending", "confirmed", "disputed")
```

### 2.2 Payment Tracking Routes
**New file**: `app/blueprints/payments/__init__.py` + `routes.py`

Endpoints:
- `POST /payments/mark-paid/<contract_id>` — contractor says "I paid"
- `POST /payments/confirm-received/<contract_id>` — worker says "I got paid"
- `POST /payments/dispute/<contract_id>` — worker says "I didn't get paid"
- `POST /payments/upload-evidence/<contract_id>` — upload proof
- `GET /payments/status/<contract_id>` — view payment status

### 2.3 Payment Tracking UI
**New templates**: `app/templates/payments/`
- `status.html` — shows confirmation state for both parties
- Buttons: "Mark as Paid" (contractor), "Confirm Received" (worker)
- Evidence upload form
- Dispute button with reason field

### 2.4 Notifications
**File**: `app/services/notification_service.py` (extend)

- Notify worker when contractor marks "paid"
- Notify contractor when worker confirms "received"
- Alert admin when dispute filed
- Reminder if no confirmation after 48 hours

### 2.5 Database Migration
```sql
CREATE TABLE payment_confirmations (
  id SERIAL PRIMARY KEY,
  contract_id INTEGER REFERENCES contracts(id),
  contractor_id INTEGER REFERENCES users(id),
  worker_id INTEGER REFERENCES users(id),
  expected_amount NUMERIC(10,2),
  payment_method VARCHAR(50),
  expected_date DATE,
  contractor_marked_paid BOOLEAN DEFAULT FALSE,
  contractor_marked_paid_at TIMESTAMP,
  worker_confirmed_received BOOLEAN DEFAULT FALSE,
  worker_confirmed_received_at TIMESTAMP,
  evidence_url VARCHAR(500),
  status VARCHAR(20) DEFAULT 'pending',
  created_at TIMESTAMP DEFAULT NOW()
);
```

---

## Week 3: $10/Week Insurance Subscriptions

### 3.1 Insurance Models
**New file**: `app/models/insurance.py`

```
InsuranceSubscription:
  - id, worker_id (FK User)
  - stripe_subscription_id, stripe_customer_id
  - status (active/cancelled/past_due)
  - start_date, waiting_period_end (start + 14 days)
  - weekly_amount (default 10.00)
  - total_premiums_paid (Decimal)

InsuranceClaim:
  - id, worker_id, contract_id
  - subscription_id (FK InsuranceSubscription)
  - claim_amount (Decimal, max $500)
  - worker_deductible (10% of claim)
  - payout_amount (90% of claim)
  - description (Text)
  - evidence_urls (JSON array)
  - status (filed/reviewing/approved/denied/paid)
  - filed_date, resolved_date
  - admin_notes (Text)
  - demand_letter_sent (Boolean)
  - demand_letter_date (DateTime)
```

### 3.2 Stripe Subscription Integration
**File**: `app/services/stripe_service.py` (extend)

Add:
- `create_insurance_subscription(worker_id)` — $10/week recurring
- `cancel_insurance_subscription(subscription_id)`
- Webhook handlers: `invoice.paid`, `invoice.payment_failed`, `customer.subscription.deleted`
- Create Stripe Product + Price for $10/week insurance (one-time setup)

### 3.3 Insurance Routes
**New file**: `app/blueprints/insurance/__init__.py` + `routes.py`

Endpoints:
- `GET /insurance` — dashboard (coverage status, claim history)
- `POST /insurance/subscribe` — start subscription
- `POST /insurance/cancel` — cancel subscription
- `POST /insurance/claim` — file claim (contract_id, amount, description, evidence)
- `GET /insurance/claims` — view claims

Validation on claim filing:
- Subscription must be active
- Waiting period (14 days) must have passed
- Claim amount <= $500
- Job value <= $1,000
- Must have payment dispute on record (from Week 2 tracking)
- Must upload evidence

### 3.4 Insurance UI
**New templates**: `app/templates/insurance/`
- `dashboard.html` — subscription status, coverage summary
- `subscribe.html` — Stripe payment form
- `claim_form.html` — file a claim with evidence upload
- `claims.html` — claim history and status

### 3.5 Database Migration
```sql
CREATE TABLE insurance_subscriptions (...);
CREATE TABLE insurance_claims (...);
CREATE INDEX idx_insurance_sub_worker ON insurance_subscriptions(worker_id);
CREATE INDEX idx_insurance_sub_status ON insurance_subscriptions(status);
CREATE INDEX idx_insurance_claim_status ON insurance_claims(status);
```

---

## Week 4: Claims Management + Cleanup

### 4.1 Admin Claims Dashboard
**File**: `app/blueprints/admin/` (extend existing)

- List pending claims with evidence
- Approve/deny with notes
- Trigger payout (Stripe transfer to worker)
- Send demand letter to contractor (automated email)
- Blacklist contractor if non-payment confirmed

### 4.2 Automated Demand Letters
**File**: `app/services/email_service.py` (extend)

Email templates:
1. **Day 0**: "Payment dispute filed — please resolve within 7 days"
2. **Day 7**: "Final warning — legal action will commence"
3. **Day 14**: "Debt referred to collection" (only if claim > $1000)

For claims under $1000: blacklist contractor, absorb loss from insurance fund.

### 4.3 Simplify Ratings
**File**: `app/models/safety.py` (Review model) or `app/models/rating.py`

Current: 1-5 stars across categories (quality, communication, safety)
New: Thumbs up/down + optional comment
- `positive` (Boolean) — thumbs up or down
- `comment` (Text, optional)

### 4.4 Remove Dead Code
- Escrow routes and logic
- GST calculation helpers (`app/utils/compliance.py` — job GST only, keep for our own fee GST)
- Invoice generation for job payments
- Super tracking
- Complex payment status flow

### 4.5 Update Legal Pages
- FAQ: Explain new fee model + insurance
- Payment terms: Simplified (no escrow)
- New page: Insurance terms and conditions

---

## Critical Files Summary

| Priority | File | Change |
|----------|------|--------|
| W1 | `app/models/contract.py` | Modify `calculate_amounts()`: 7% with min $25/max $100, remove escrow |
| W1 | `app/blueprints/legal/routes.py` | Fee-only Stripe charge, remove escrow release |
| W1 | `app/blueprints/legal/stripe_webhooks.py` | Simplify to fee payment only |
| W1 | `app/services/stripe_service.py` | Remove escrow methods, add subscription methods later |
| W1 | `app/main_routes.py` | Update accept_application flow |
| W1 | `app/blueprints/marketplace/routes.py` | Update hiring flow |
| W1 | Multiple templates | Replace fee displays |
| W2 | **NEW** `app/models/payment_tracking.py` | Payment confirmation model |
| W2 | **NEW** `app/blueprints/payments/` | Confirmation routes + templates |
| W3 | **NEW** `app/models/insurance.py` | Subscription + claims models |
| W3 | **NEW** `app/blueprints/insurance/` | Insurance routes + templates |
| W3 | `app/services/stripe_service.py` | Add subscription methods |
| W4 | `app/blueprints/admin/` | Claims management dashboard |
| W4 | `app/services/email_service.py` | Demand letter templates |
| W4 | `app/models/rating.py` or `safety.py` | Simplify to thumbs up/down |

---

## Verification

### Week 1:
- Post job → hire worker → verify Stripe charges fee only (not job value)
- Verify fee: $200 job = $25, $1000 job = $70, $2000 job = $100
- Verify no escrow, no GST calc, no invoice generation

### Week 2:
- Contractor marks "paid" → worker gets notification
- Worker confirms "received" → status = confirmed
- Worker disputes → admin alerted, evidence upload works

### Week 3:
- Worker subscribes to insurance → Stripe subscription created
- File claim after 14 days → validates caps and deductible
- Cancel and resubscribe → works correctly

### Week 4:
- Admin approves claim → payout sent, demand letter sent
- Contractor blacklisted after non-payment
- Ratings: thumbs up/down works, old star system disabled

---

## Migration Strategy

- **Existing contracts**: Grandfather with old 7% model
- **New contracts**: Get 7% (min $25, max $100) fee model
- **Database**: Additive migrations (new tables + columns), no destructive changes
- **Deploy**: Via Fly.io, test on staging first if available
