# Features, Merchants & Rates

# Drop — Merchant, Recipients & Rates

> **Note (2026-02-14):** This document predates the current architecture. Drop now uses a **pass-through PSD2 model** (PISP/AISP) — Drop NEVER holds customer money. Some sections below reference wallet/balance concepts from the earlier BaaS design. The current architecture is defined in [architecture-document.md](../architecture/architecture-document.md) and [Drop CLAUDE.md](/ALAI/products/Drop/CLAUDE.md).

## 1. Recipients

### Data Model

```typescript
interface Contact {
  id: string;
  name: string;
  iban: string;
  avatar: string;  // 2-char initials
}
```

### Current Implementation

**Sample contacts** (hardcoded in `src/app/send/page.tsx`):
| Name | IBAN | Country |
|------|------|---------|
| Sara M. | DE89370400440532013000 | Germany |
| Amir K. | FR7630006000011234567890189 | France |
| Lejla H. | AT611904300234573201 | Austria |

**Mock contacts** (`src/lib/mockData.ts`):
| Name | IBAN | Country |
|------|------|---------|
| John Doe | DE89 3704 0044 0532 0130 00 | Germany |
| Jane Smith | FR76 3000 6000 0112 3456 7890 189 | France |
| Mike Wilson | GB29 NWBK 6016 1331 9268 19 | UK |

### RecipientStep UI (`src/app/send/page.tsx`)

- Search bar (filters by name or IBAN)
- Contact list with avatar, name, truncated IBAN
- "Add new recipient" button (placeholder — not wired)
- Click to select → moves to AmountStep

### Send Money Flow (6 steps)

```
RecipientStep → AmountStep → ConfirmStep → Processing → Success/Error
```

1. **Recipient** — select from contacts or search
2. **Amount** — input + quick buttons (€10, €50, €100, €200) + optional note
3. **Confirm** — review: amount, recipient, IBAN, note, fee (Free)
4. **Processing** — loading animation
5. **Success** — confirmation with amount and name
6. **Error** — message + retry

### API: Send Money

```
POST /api/transactions
Authorization: Bearer <jwt>
Body: { toIban: string, amount: number, reference?: string }
```

Validations:
- Required: `toIban`, `amount`
- `amount > 0`
- Balance sufficient
- Creates `SepaCredit` transaction with direction `Debit`
- Updates account balance atomically

### Future (not yet implemented)
- Add/edit/delete saved recipients
- Favorite/frequent contacts
- Import from phone contacts (mobile app)
- Recipient groups

---

## 2. Merchant Payments

### Current State: Demo Only

Merchant payments exist as:
- `CardTransaction` type in schema
- `simulatePurchase()` method in AppContext (no-op, logs to console)
- Demo buttons on dashboard: "Netflix €9.99", "Groceries €45"

### Transaction Types

| Type | Direction | Use Case |
|------|-----------|----------|
| `SepaCredit` | Debit | Outgoing SEPA transfer |
| `SepaDebit` | Credit | Incoming SEPA transfer |
| `CardTransaction` | Debit | Card purchase at merchant |

### AppContext Method

```typescript
const simulatePurchase = async (amount: number, merchant: string) => {
  // No-op — no API route for card purchases yet
  console.log("[AppContext] simulatePurchase not implemented:", { amount, merchant });
  return { id: 'demo_auth', amount, merchant };
};
```

### Stripe Issuing Mock (`src/lib/services/mock-stripe.ts`)

Card authorization logic:
- Checks card status (active)
- Checks spending limit (`spending_limit` vs `spent_this_month + amount`)
- Returns approved/declined
- Physical card ordering supported

### Transaction Display (`src/components/TransactionItem.tsx`)

Shows for each transaction:
- Icon (emoji for type)
- Description (merchant name or counterparty)
- Date (formatted)
- Amount (green for incoming, gray for outgoing)

### Future (post-MVP)
- Merchant directory/discovery
- Bill pay integration
- Recurring payments to merchants
- Purchase categorization (AI)
- Merchant notifications

---

## 3. Rates, Fees & Limits

### Currency

**MVP:** EUR only (single account)

Formatting (`src/lib/mockData.ts`):
```typescript
formatCurrency(amount, currency = "EUR")
// Uses Intl.NumberFormat("de-DE") → "€1.234,56"
```

### Fees

| Transaction Type | Fee |
|-----------------|-----|
| SEPA transfer | Free |
| Card top-up | Free |
| Card payment | Free (interchange 0.2-0.3% from merchant) |

All transfers show "Free" in the UI confirmation step.

### Transfer Limits (from MVP spec)

| Type | Daily | Monthly |
|------|-------|---------|
| Internal P2P | €5,000 | €20,000 |
| SEPA | €2,000 | €10,000 |

### Top-up Limits

| Parameter | Value |
|-----------|-------|
| Minimum | €5 |
| Maximum | €10,000 |
| Preset options | €20, €50, €100, €200, €500 |

### Card Spending

| Parameter | Value |
|-----------|-------|
| Monthly limit (default) | €5,000 |
| Tracked via | `spent_this_month` column |

### Revenue Model (post-MVP)

| Stream | Rate |
|--------|------|
| Interchange fees | 0.2-0.3% of card transactions |
| FX markup | 0.5-2% on currency conversion |
| Premium subscription | €5-15/month |
| Interest income | On deposits |
| Lending | Personal loans, BNPL, overdrafts |

### Multi-Currency (Future)
- Additional currency accounts (GBP, USD, etc.)
- Real-time FX rates display
- FX conversion with 0.5-2% markup
- Currency selection at transfer time

---

## 4. Database Schema Reference

### transactions
```sql
CREATE TABLE transactions (
  id TEXT PRIMARY KEY,
  account_id TEXT NOT NULL REFERENCES accounts(id),
  type TEXT NOT NULL,        -- SepaCredit | SepaDebit | CardTransaction
  amount REAL NOT NULL,
  currency TEXT DEFAULT 'EUR',
  direction TEXT NOT NULL,   -- Credit | Debit
  status TEXT DEFAULT 'Pending',  -- Pending | Booked | Rejected
  counterparty TEXT,         -- Recipient IBAN or merchant name
  reference TEXT,            -- Payment note
  created_at TEXT DEFAULT (datetime('now'))
);
```

### accounts
```sql
CREATE TABLE accounts (
  id TEXT PRIMARY KEY,
  user_id TEXT NOT NULL REFERENCES users(id),
  iban TEXT UNIQUE NOT NULL,   -- Format: BA393912XXXXXXXX
  bic TEXT DEFAULT 'FONLBA22',
  currency TEXT DEFAULT 'EUR',
  balance REAL DEFAULT 0,
  status TEXT DEFAULT 'Opened',
  created_at TEXT DEFAULT (datetime('now'))
);
```

### cards
```sql
CREATE TABLE cards (
  id TEXT PRIMARY KEY,
  user_id TEXT NOT NULL REFERENCES users(id),
  type TEXT NOT NULL DEFAULT 'virtual',
  brand TEXT DEFAULT 'Visa',
  last4 TEXT NOT NULL,
  exp_month INTEGER NOT NULL,
  exp_year INTEGER NOT NULL,
  status TEXT DEFAULT 'active',
  spending_limit REAL DEFAULT 5000,
  spent_this_month REAL DEFAULT 0,
  cardholder_name TEXT,
  created_at TEXT DEFAULT (datetime('now'))
);
```

---

## 5. Open Tasks (Related)

| Task | Priority | Description |
|------|----------|-------------|
| #191 | HIGH | Wire /send page to /api/transactions/remittance |
| #192 | HIGH | Wire /scan page to /api/transactions/qr-payment |
| #193 | HIGH | Wire /merchant page to real APIs |
| #198 | LOW | Delete mock-data.ts and orphaned components |