# Stripe Integration Setup Guide

This guide walks you through setting up the Stripe integration for AlgaPSA license purchasing.

## Overview

The Stripe integration enables:
- **Phase 1 (Now):** Self-service license purchasing for existing AlgaPSA customers
- **Phase 2 (Future):** Multi-tenant billing where your customers can charge their clients

## Prerequisites

1. AlgaPSA installation with database access
2. Stripe account (sign up at [stripe.com](https://stripe.com))
3. Access to server environment variables

## Step-by-Step Setup

> **Note:** This integration is for **Enterprise Edition (Hosted)** only. The migration is located in `ee/server/migrations/`.

### 1. Database Migration

Run the EE Stripe integration migration:

```bash
cd ee/server
npm run migrate
```

This creates 6 tables:
- `stripe_accounts` - Tenant Stripe account configuration
- `stripe_customers` - Customer mapping
- `stripe_products` - Product catalog
- `stripe_prices` - Pricing information
- `stripe_subscriptions` - Active subscriptions
- `stripe_webhook_events` - Webhook idempotency tracking

### 2. Stripe Account Setup

#### 2.1 Create Stripe Account
1. Go to [stripe.com](https://stripe.com) and sign up
2. Complete business verification (required for production)
3. Keep the dashboard open for the next steps

#### 2.2 Get API Keys
1. Go to **Developers → API keys**
2. Copy the **Publishable key** (starts with `pk_test_` or `pk_live_`)
3. Click **Reveal test key** and copy the **Secret key** (starts with `sk_test_` or `sk_live_`)
4. Add to `server/.env`:
   ```bash
   STRIPE_SECRET_KEY=sk_test_...
   NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
   ```

### 3. Product Configuration

#### 3.1 Create License Product
1. Go to **Products → Create product**
2. Enter product details:
   - **Name:** AlgaPSA User License
   - **Description:** Monthly subscription for AlgaPSA user access
3. Add pricing:
   - **Pricing model:** Standard pricing
   - **Price:** $50.00 (or your pricing)
   - **Billing period:** Recurring - Monthly
4. Click **Save product**

#### 3.2 Copy Product IDs
After creating the product:
1. Click on the price and copy the **Price ID** (starts with `price_`)
3. Add to `server/.env`:
   ```bash
   STRIPE_PRO_PRICE_ID=price_...
   ```

### 4. Webhook Configuration

#### 4.1 Create Webhook Endpoint
1. Go to **Developers → Webhooks**
2. Click **Add endpoint**
3. Enter endpoint URL:
   - **Development:** Use Stripe CLI (see below)
   - **Production:** `https://your-domain.com/api/webhooks/stripe`

#### 4.2 Select Events
Add these events to your webhook:
- `checkout.session.completed`
- `customer.subscription.created`
- `customer.subscription.updated`
- `customer.subscription.deleted`

#### 4.3 Get Webhook Secret
1. After creating the endpoint, copy the **Signing secret** (starts with `whsec_`)
2. Add to `server/.env`:
   ```bash
   STRIPE_WEBHOOK_SECRET=whsec_...
   ```

### 5. Master Tenant Configuration

Find your organization's tenant ID:

```sql
SELECT tenant FROM tenants WHERE email = 'your-admin-email@domain.com';
```

Add to `server/.env`:
```bash
MASTER_BILLING_TENANT_ID=<your-tenant-uuid>
```

### 6. Application URL

Set your application's public URL:

```bash
# Development
NEXT_PUBLIC_APP_URL=http://localhost:3000

# Production
NEXT_PUBLIC_APP_URL=https://algapsa.yourdomain.com
```

### 7. Development: Stripe CLI (Optional but Recommended)

For local development, use the Stripe CLI to forward webhooks:

#### 7.1 Install Stripe CLI
```bash
# macOS
brew install stripe/stripe-cli/stripe

# Windows (Scoop)
scoop bucket add stripe https://github.com/stripe/scoop-stripe-cli.git
scoop install stripe

# Linux
# See https://stripe.com/docs/stripe-cli#install
```

#### 7.2 Authenticate
```bash
stripe login
```

#### 7.3 Forward Webhooks
```bash
stripe listen --forward-to localhost:3000/api/webhooks/stripe
```

This will output a webhook signing secret. Copy it to `STRIPE_WEBHOOK_SECRET`.

## Testing

### Test Card Numbers

Stripe provides test cards for development:

| Card Number         | Description                          |
|---------------------|--------------------------------------|
| 4242 4242 4242 4242 | Succeeds immediately                 |
| 4000 0025 0000 3155 | Requires authentication (3D Secure)  |
| 4000 0000 0000 9995 | Declined (insufficient funds)        |

Use:
- Any future expiry date (e.g., 12/34)
- Any 3-digit CVC (e.g., 123)
- Any billing ZIP code (e.g., 12345)

### Test Purchase Flow

1. Log in to AlgaPSA as an admin user
2. Navigate to **Settings → General → User Management**
3. Click **Add License** button
4. Select quantity and click **Purchase**
5. Complete checkout with test card
6. Verify:
   - License count updated in User Management
   - Subscription appears in Stripe Dashboard
   - Webhook events logged in database

### Verify Webhook

Check webhook delivery:
1. Go to **Stripe Dashboard → Developers → Webhooks**
2. Click on your webhook endpoint
3. View recent deliveries and their status

Check database:
```sql
SELECT * FROM stripe_webhook_events
ORDER BY created_at DESC
LIMIT 10;
```

## Production Deployment

### Before Going Live

1. **Switch to Live Mode:**
   - In Stripe Dashboard, toggle to "Live mode"
   - Get new API keys (live keys start with `pk_live_` and `sk_live_`)
   - Update environment variables

2. **Create Production Webhook:**
   - Configure webhook with production URL
   - Get new webhook secret
   - Update `STRIPE_WEBHOOK_SECRET`

3. **Security Checklist:**
   - [ ] Use HTTPS for all endpoints
   - [ ] Verify webhook signatures
   - [ ] Never log full API keys
   - [ ] Use environment variables (never hardcode)
   - [ ] Rotate keys periodically
   - [ ] Monitor webhook failures

4. **Testing in Production:**
   - Create a test subscription with a real card
   - Use Stripe's test mode customer to avoid charges
   - Cancel immediately after testing

### Monitoring

Monitor these in production:
- Webhook delivery failures (Stripe Dashboard)
- Database `stripe_webhook_events` for processing errors
- Application logs for Stripe API errors
- Subscription status changes

### Support

For Stripe-related questions:
- [Stripe Documentation](https://stripe.com/docs)
- [Stripe Support](https://support.stripe.com)
- [API Reference](https://stripe.com/docs/api)

For AlgaPSA integration issues, check:
- `server/logs/` for application errors
- Database `stripe_webhook_events` table for webhook processing
- StripeService logs in CloudWatch/your logging system

## Troubleshooting

### Webhook Not Receiving Events

1. Check webhook URL is correct and accessible
2. Verify `STRIPE_WEBHOOK_SECRET` matches Stripe Dashboard
3. Check webhook is in "Live mode" for production keys
4. Test with Stripe CLI: `stripe trigger checkout.session.completed`

### Signature Verification Failed

1. Ensure you're using raw request body (not parsed JSON)
2. Verify `STRIPE_WEBHOOK_SECRET` is correct
3. Check webhook secret matches the endpoint's secret in Stripe
4. For development, use Stripe CLI to get local secret

### Customer Import Failing

1. Verify tenant exists in database
2. Check Stripe customer has email matching tenant email
3. Ensure `MASTER_BILLING_TENANT_ID` is set correctly
4. Check logs for specific error messages

### License Count Not Updating

1. Verify webhook was received and processed
2. Check `stripe_webhook_events` table for errors
3. Verify subscription metadata includes `tenant_id`
4. Check `stripe_subscriptions` table for subscription record

## Next Steps

After setup:
1. Import existing Stripe customers (if any)
2. Configure email notifications for purchases
3. Set up monitoring and alerting
4. Plan for Phase 2 (multi-tenant billing)

## NM-Store Integration (Initial Customer Subscription)

### Overview

New AlgaPSA customers purchase their initial subscription through **nm-store** (the Nine Minds website), which creates both:
1. The Stripe subscription with initial license quantity
2. The tenant record in AlgaPSA database via Temporal workflow

The AlgaPSA Stripe integration then manages license changes after the initial purchase.

### Integration Requirements

#### 1. Temporal Workflow Updates

The tenant creation workflow (`createTenantWorkflow`) needs to be updated to accept and store Stripe subscription data:

**Input Parameters Required:**
```typescript
interface CreateTenantInput {
  // Existing fields...
  email: string;
  client_name: string;

  // NEW: Stripe subscription info from nm-store checkout
  stripe_customer_id?: string;        // Stripe customer ID (cus_...)
  stripe_subscription_id?: string;    // Stripe subscription ID (sub_...)
  initial_license_count?: number;     // Initial quantity from purchase
}
```

#### 2. Stripe Customer Record Creation

During tenant creation, if Stripe data is provided, the workflow should:

```typescript
// In createTenantWorkflow or a new activity
if (input.stripe_customer_id) {
  await knex('stripe_customers').insert({
    tenant: newTenant.tenant,
    stripe_customer_external_id: input.stripe_customer_id,
    billing_tenant: process.env.MASTER_BILLING_TENANT_ID,
    email: input.email,
    name: input.client_name,
    metadata: {
      source: 'nm_store_checkout',
      created_at: new Date().toISOString()
    }
  });
}
```

#### 3. Initial License Count

Set the `licensed_user_count` on the tenant record during creation:

```typescript
await knex('tenants')
  .where({ tenant: newTenant.tenant })
  .update({
    licensed_user_count: input.initial_license_count || null
  });
```

#### 4. Subscription Import

Optionally import the full subscription details:

```typescript
if (input.stripe_subscription_id) {
  // Call StripeService to import subscription details
  const stripeService = getStripeService();
  await stripeService.importSubscriptionById(
    newTenant.tenant,
    input.stripe_subscription_id
  );
}
```

### NM-Store Checkout Flow

The nm-store checkout should:

1. **Create Stripe Customer & Subscription**
   ```javascript
   const customer = await stripe.customers.create({
     email: customerEmail,
     name: clientName,
     metadata: {
       source: 'nm_store',
       pending_tenant: true
     }
   });

   const subscription = await stripe.subscriptions.create({
     customer: customer.id,
     items: [{ price: LICENSE_PRICE_ID, quantity: licenseCount }],
     metadata: {
       source: 'nm_store_checkout',
       client_name: clientName
     }
   });
   ```

2. **Trigger Temporal Workflow**
   ```javascript
   await temporalClient.workflow.start(createTenantWorkflow, {
     args: [{
       email: customerEmail,
       client_name: clientName,
       stripe_customer_id: customer.id,
       stripe_subscription_id: subscription.id,
       initial_license_count: licenseCount,
       // ... other tenant creation params
     }],
     taskQueue: 'alga-psa-workflows',
     workflowId: `create-tenant-${customer.id}`
   });
   ```

3. **Update Customer Metadata After Tenant Creation**
   ```javascript
   // After workflow completes successfully
   await stripe.customers.update(customer.id, {
     metadata: {
       tenant_id: newTenant.tenant,  // Link customer to tenant
       algapsa_url: `https://app.algapsa.com`,
       onboarded: true
     }
   });

   await stripe.subscriptions.update(subscription.id, {
     metadata: {
       tenant_id: newTenant.tenant  // Critical for webhook event routing
     }
   });
   ```

### Migration Script for Existing Customers

For customers who already have Stripe subscriptions but no database records:

```typescript
// scripts/sync-stripe-customers.ts
async function syncExistingStripeCustomers() {
  const tenants = await knex('tenants').select('*');

  for (const tenant of tenants) {
    // Search Stripe for customer by email
    const customers = await stripe.customers.list({
      email: tenant.email,
      limit: 1
    });

    if (customers.data.length > 0) {
      const customer = customers.data[0];

      // Import customer
      await knex('stripe_customers').insert({
        tenant: tenant.tenant,
        stripe_customer_external_id: customer.id,
        billing_tenant: MASTER_BILLING_TENANT_ID,
        email: customer.email,
        name: customer.name,
        metadata: { source: 'migration_import' }
      }).onConflict(['tenant', 'stripe_customer_external_id']).ignore();

      // Import active subscriptions
      const subscriptions = await stripe.subscriptions.list({
        customer: customer.id,
        status: 'active'
      });

      for (const sub of subscriptions.data) {
        // Use StripeService.importSubscription()
        await stripeService.importSubscription(
          tenant.tenant,
          customer.id,
          sub
        );

        // Update tenant license count
        const quantity = sub.items.data[0]?.quantity || 0;
        await knex('tenants')
          .where({ tenant: tenant.tenant })
          .update({ licensed_user_count: quantity });
      }
    }
  }
}
```

### Testing the Integration

1. **Test Tenant Creation with Stripe Data:**
   ```bash
   # Create test customer in Stripe
   stripe customers create \
     --email test@example.com \
     --name "Test Company" \
     --metadata[source]=nm_store_test

   # Create test subscription
   stripe subscriptions create \
     --customer cus_xxx \
     --items[0][price]=price_xxx \
     --items[0][quantity]=10

   # Trigger workflow with test data
   # Verify tenant created with correct licensed_user_count
   ```

2. **Verify Data Flow:**
   - Customer record in `stripe_customers` table
   - Subscription record in `stripe_subscriptions` table
   - Correct `licensed_user_count` on tenant
   - Metadata linking customer to tenant

### Important Notes

- **Always set `metadata.tenant_id`** on subscriptions - this is critical for webhook event routing
- The initial subscription is created by nm-store, subsequent changes via AlgaPSA UI
- License count in AlgaPSA = Stripe subscription quantity (not additive)
- Subscription updates in AlgaPSA update the same Stripe subscription

## Phase 2: Multi-Tenant Billing (Future)

Phase 2 will enable your customers to use their own Stripe accounts to charge their clients. This requires:
- Stripe Connect integration
- Vault for storing tenant Stripe keys
- UI for tenant Stripe account connection
- Platform fee configuration

This will be documented separately when Phase 2 is implemented.
