mirror of
https://github.com/lawrencehook/remove-youtube-suggestions.git
synced 2026-07-25 06:54:31 +00:00
Remove TESTING.md and DEPLOYMENT.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
-521
@@ -1,521 +0,0 @@
|
|||||||
# RYS Premium Server Deployment Guide
|
|
||||||
|
|
||||||
Complete guide to deploying the premium subscription server and testing the monetization flow.
|
|
||||||
|
|
||||||
**Server URL:** `https://server.lawrencehook.com/rys/`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
1. [Prerequisites](#prerequisites)
|
|
||||||
2. [Stripe Setup](#stripe-setup)
|
|
||||||
3. [AWS SES Setup](#aws-ses-setup)
|
|
||||||
4. [Server Deployment](#server-deployment)
|
|
||||||
5. [Apache Configuration](#apache-configuration)
|
|
||||||
6. [Extension Setup](#extension-setup)
|
|
||||||
7. [Testing](#testing)
|
|
||||||
8. [Troubleshooting](#troubleshooting)
|
|
||||||
9. [Maintenance](#maintenance)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- AWS Lightsail instance (Bitnami stack)
|
|
||||||
- Node.js v20+
|
|
||||||
- Stripe account (test mode for development)
|
|
||||||
- AWS SES configured for sending emails
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Stripe Setup
|
|
||||||
|
|
||||||
### Create Products
|
|
||||||
|
|
||||||
1. Go to https://dashboard.stripe.com/test/products
|
|
||||||
2. Click **"+ Add product"**
|
|
||||||
|
|
||||||
**Monthly Plan:**
|
|
||||||
- Name: `RYS Premium Monthly`
|
|
||||||
- Pricing: `$3.00 USD` / `month` / `recurring`
|
|
||||||
- Save and copy the **Price ID** (starts with `price_...`)
|
|
||||||
|
|
||||||
**Yearly Plan:**
|
|
||||||
- Name: `RYS Premium Yearly`
|
|
||||||
- Pricing: `$24.00 USD` / `year` / `recurring`
|
|
||||||
- Save and copy the **Price ID**
|
|
||||||
|
|
||||||
### Get API Keys
|
|
||||||
|
|
||||||
1. Go to https://dashboard.stripe.com/test/apikeys
|
|
||||||
2. Copy the **Secret key** (starts with `sk_test_...`)
|
|
||||||
|
|
||||||
### Configure Billing Portal
|
|
||||||
|
|
||||||
1. Go to Settings → Billing → Customer portal
|
|
||||||
2. Enable the customer portal
|
|
||||||
3. Configure allowed actions:
|
|
||||||
- [x] Update payment methods
|
|
||||||
- [x] View invoice history
|
|
||||||
- [x] Cancel subscriptions
|
|
||||||
4. Save changes
|
|
||||||
|
|
||||||
### Create Webhook Endpoint
|
|
||||||
|
|
||||||
1. Go to https://dashboard.stripe.com/test/webhooks
|
|
||||||
2. Click **"+ Add endpoint"**
|
|
||||||
3. Endpoint URL: `https://server.lawrencehook.com/rys/webhook/stripe`
|
|
||||||
4. Select events:
|
|
||||||
- `checkout.session.completed`
|
|
||||||
- `customer.subscription.created`
|
|
||||||
- `customer.subscription.updated`
|
|
||||||
- `customer.subscription.deleted`
|
|
||||||
- `invoice.payment_failed`
|
|
||||||
- `invoice.payment_succeeded`
|
|
||||||
5. Click **"Add endpoint"**
|
|
||||||
6. Copy the **Signing secret** (starts with `whsec_...`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## AWS SES Setup
|
|
||||||
|
|
||||||
### Verify Sender Email/Domain
|
|
||||||
|
|
||||||
1. In AWS Console → SES → Verified identities
|
|
||||||
2. Click "Create identity"
|
|
||||||
3. For email: click the verification link sent to you
|
|
||||||
4. For domain: add the DNS records provided
|
|
||||||
|
|
||||||
### Request Production Access
|
|
||||||
|
|
||||||
SES starts in sandbox mode (can only send to verified emails).
|
|
||||||
|
|
||||||
1. Go to SES → Account dashboard
|
|
||||||
2. Click "Request production access"
|
|
||||||
3. Fill out the form explaining your use case
|
|
||||||
4. Wait for approval (usually 24-48 hours)
|
|
||||||
|
|
||||||
### IAM Credentials
|
|
||||||
|
|
||||||
If not using instance roles, create IAM credentials:
|
|
||||||
|
|
||||||
1. Create a new user (e.g., `rys-premium-ses`)
|
|
||||||
2. Attach policy: `AmazonSESFullAccess`
|
|
||||||
3. Create access keys
|
|
||||||
4. Copy the **Access Key ID** and **Secret Access Key**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Server Deployment
|
|
||||||
|
|
||||||
### SSH to Lightsail Instance
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ssh bitnami@your-instance-ip
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install Node.js 20+ (if needed)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
|
||||||
sudo apt-get install -y nodejs
|
|
||||||
node --version # Should show v20.x.x
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install PM2
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo npm install -g pm2
|
|
||||||
```
|
|
||||||
|
|
||||||
### Clone and Setup Repository
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/github
|
|
||||||
git clone https://github.com/lawrencehook/remove-youtube-suggestions.git
|
|
||||||
cd remove-youtube-suggestions
|
|
||||||
git checkout feature/monetize
|
|
||||||
cd server
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create Environment File
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nano .env
|
|
||||||
```
|
|
||||||
|
|
||||||
Paste the following (fill in your values):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Server
|
|
||||||
PORT=3005
|
|
||||||
BASE_URL=https://server.lawrencehook.com/rys
|
|
||||||
|
|
||||||
# JWT (generate with: openssl rand -base64 32)
|
|
||||||
JWT_SECRET=your-random-secret-at-least-32-characters-long
|
|
||||||
|
|
||||||
# Stripe
|
|
||||||
STRIPE_SECRET_KEY=sk_test_YOUR_KEY
|
|
||||||
STRIPE_PRICE_MONTHLY=price_YOUR_MONTHLY_ID
|
|
||||||
STRIPE_PRICE_YEARLY=price_YOUR_YEARLY_ID
|
|
||||||
STRIPE_WEBHOOK_SECRET=whsec_YOUR_WEBHOOK_SECRET
|
|
||||||
|
|
||||||
# AWS SES (uses instance role, no explicit credentials needed)
|
|
||||||
AWS_REGION=us-east-1
|
|
||||||
EMAIL_FROM=noreply@lawrencehook.com
|
|
||||||
```
|
|
||||||
|
|
||||||
Save: `Ctrl+O`, `Enter`, `Ctrl+X`
|
|
||||||
|
|
||||||
### Create Data Directory
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir -p data
|
|
||||||
echo '[]' > data/grandfathered.json
|
|
||||||
```
|
|
||||||
|
|
||||||
To add grandfathered users (past donors with lifetime access):
|
|
||||||
```bash
|
|
||||||
echo '["donor1@example.com", "donor2@example.com"]' > data/grandfathered.json
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Server Starts
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
Expected output:
|
|
||||||
```
|
|
||||||
Loaded X grandfathered emails
|
|
||||||
RYS Premium Server running on port 3005
|
|
||||||
Base URL: https://server.lawrencehook.com/rys
|
|
||||||
```
|
|
||||||
|
|
||||||
Press `Ctrl+C` to stop.
|
|
||||||
|
|
||||||
### Start with PM2
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pm2 start src/index.js --name rys-premium
|
|
||||||
pm2 save
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configure PM2 Auto-Start on Reboot
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pm2 startup
|
|
||||||
# Run the command it outputs (starts with: sudo env PATH=...)
|
|
||||||
pm2 save
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Apache Configuration
|
|
||||||
|
|
||||||
Your Lightsail instance uses Bitnami's Apache with path-based proxying.
|
|
||||||
|
|
||||||
### Edit SSL Config
|
|
||||||
|
|
||||||
Edit your local deployments repo:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nano ~/github/deployments/opt/bitnami/apache/conf/bitnami/bitnami-ssl.conf
|
|
||||||
```
|
|
||||||
|
|
||||||
Add these lines inside the `<VirtualHost _default_:443>` block:
|
|
||||||
|
|
||||||
```apache
|
|
||||||
ProxyPass /rys/ http://localhost:3005/
|
|
||||||
ProxyPassReverse /rys/ http://localhost:3005/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Deploy Apache Config
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Local machine
|
|
||||||
cd ~/github/deployments
|
|
||||||
git add -A && git commit -m "Add RYS Premium server proxy config" && git push
|
|
||||||
|
|
||||||
# On server
|
|
||||||
cd ~/github/deployments && git pull
|
|
||||||
./update_apache_conf.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Extension Setup
|
|
||||||
|
|
||||||
### Verify Config Points to Production
|
|
||||||
|
|
||||||
Check `src/shared/config.js`:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const PREMIUM_CONFIG = {
|
|
||||||
SERVER_URL: 'https://server.lawrencehook.com/rys',
|
|
||||||
// ...
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build the Extension
|
|
||||||
|
|
||||||
**For Chrome:**
|
|
||||||
```bash
|
|
||||||
./make_chrome.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
**For Firefox:**
|
|
||||||
```bash
|
|
||||||
./make_firefox.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Load in Chrome
|
|
||||||
|
|
||||||
1. Navigate to `chrome://extensions/`
|
|
||||||
2. Enable **"Developer mode"** (toggle in top-right)
|
|
||||||
3. Click **"Load unpacked"**
|
|
||||||
4. Select: `chrome_extension/`
|
|
||||||
|
|
||||||
### Load in Firefox
|
|
||||||
|
|
||||||
1. Navigate to `about:debugging#/runtime/this-firefox`
|
|
||||||
2. Click **"Load Temporary Add-on..."**
|
|
||||||
3. Select: `src/firefox_manifest.json`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
### Automated Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd server
|
|
||||||
npm test
|
|
||||||
```
|
|
||||||
|
|
||||||
All tests should pass (currently 46).
|
|
||||||
|
|
||||||
### Health Check
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl https://server.lawrencehook.com/rys/health
|
|
||||||
# Expected: {"status":"ok","timestamp":"..."}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Magic Link Flow
|
|
||||||
|
|
||||||
**Via curl:**
|
|
||||||
```bash
|
|
||||||
curl -X POST https://server.lawrencehook.com/rys/auth/send-magic-link \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"email":"your-email@example.com"}'
|
|
||||||
# Expected: {"request_id":"abc123-..."}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Via extension:**
|
|
||||||
1. Go to any YouTube page
|
|
||||||
2. Click the RYS extension icon
|
|
||||||
3. Click the gear icon (settings menu)
|
|
||||||
4. Click **"Sign In"**
|
|
||||||
5. Enter your email and click **"Send Sign-In Link"**
|
|
||||||
6. Check your email and click the magic link
|
|
||||||
7. Return to extension — should show "Signed in successfully"
|
|
||||||
|
|
||||||
### License Check
|
|
||||||
|
|
||||||
After signing in:
|
|
||||||
1. Click gear icon → **"Account"**
|
|
||||||
2. Should show your email and status: **"Free"**
|
|
||||||
|
|
||||||
**For grandfathered users:**
|
|
||||||
- Add email to `data/grandfathered.json` on server
|
|
||||||
- Restart: `pm2 restart rys-premium`
|
|
||||||
- Sign out and sign back in
|
|
||||||
- Status should show: **"Premium (Lifetime)"**
|
|
||||||
|
|
||||||
### Checkout Flow
|
|
||||||
|
|
||||||
1. Open Account modal
|
|
||||||
2. Click **"Upgrade to Premium"**
|
|
||||||
3. Select a plan (Monthly or Yearly)
|
|
||||||
4. Click **"Continue to Checkout"**
|
|
||||||
5. Complete payment with test card:
|
|
||||||
- Card: `4242 4242 4242 4242`
|
|
||||||
- Expiry: Any future date (e.g., `12/34`)
|
|
||||||
- CVC: Any 3 digits (e.g., `123`)
|
|
||||||
- ZIP: Any valid ZIP (e.g., `12345`)
|
|
||||||
6. After success page, return to extension
|
|
||||||
7. Open Account — status should show **"Premium Active"**
|
|
||||||
|
|
||||||
### Billing Portal
|
|
||||||
|
|
||||||
1. With an active subscription, open Account modal
|
|
||||||
2. Click **"Manage Subscription"**
|
|
||||||
3. Stripe billing portal opens in new tab
|
|
||||||
4. Can cancel subscription here for testing
|
|
||||||
|
|
||||||
### Webhook Verification
|
|
||||||
|
|
||||||
1. Go to Stripe Dashboard → Webhooks → your endpoint
|
|
||||||
2. Click **"Send test webhook"**
|
|
||||||
3. Select `checkout.session.completed`
|
|
||||||
4. Check server logs: `pm2 logs rys-premium`
|
|
||||||
|
|
||||||
### Extension Smoke Tests
|
|
||||||
|
|
||||||
- **Sign-in flow:** Send magic link → click link → see "Signed in successfully"
|
|
||||||
- **Poll cancel:** Start sign-in → hit Cancel → spinner stops, no sign-in after cancel
|
|
||||||
- **Premium gate:** Mark option as premium → non-premium click opens upgrade modal
|
|
||||||
- **License refresh:** Open Account → premium label reflects correct status
|
|
||||||
- **Upgrade flow:** Choose plan → click checkout → Stripe checkout opens
|
|
||||||
- **Billing portal:** With subscription → click "Manage Subscription" → portal opens
|
|
||||||
|
|
||||||
### Pre-Launch Checklist
|
|
||||||
|
|
||||||
- [ ] All automated tests pass
|
|
||||||
- [ ] Server starts without errors
|
|
||||||
- [ ] `/health` endpoint returns OK
|
|
||||||
- [ ] Magic link emails are received
|
|
||||||
- [ ] Magic link verification works
|
|
||||||
- [ ] Grandfathered users show as premium
|
|
||||||
- [ ] Stripe checkout creates a session
|
|
||||||
- [ ] Stripe webhook is configured and verified
|
|
||||||
- [ ] Billing portal is accessible
|
|
||||||
- [ ] SSL certificate is valid
|
|
||||||
- [ ] CORS works from extension origins
|
|
||||||
|
|
||||||
### Test Cards Reference
|
|
||||||
|
|
||||||
| Card | Result |
|
|
||||||
|------|--------|
|
|
||||||
| `4242 4242 4242 4242` | Success |
|
|
||||||
| `4000 0000 0000 0002` | Declined |
|
|
||||||
| `4000 0025 0000 3155` | Requires authentication |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Server won't start
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pm2 logs rys-premium --lines 50
|
|
||||||
```
|
|
||||||
|
|
||||||
Common issues:
|
|
||||||
- Missing .env variables
|
|
||||||
- JWT_SECRET too short (needs 32+ chars)
|
|
||||||
- Port already in use
|
|
||||||
|
|
||||||
### Magic link emails not sending
|
|
||||||
|
|
||||||
- Check SES is configured
|
|
||||||
- Verify EMAIL_FROM domain is verified in SES
|
|
||||||
- If in SES sandbox, recipient must also be verified
|
|
||||||
|
|
||||||
### CORS errors in extension
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Verify server is running
|
|
||||||
curl http://localhost:3005/health
|
|
||||||
```
|
|
||||||
|
|
||||||
### SSL certificate issues
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo /opt/bitnami/bncert-tool # regenerate if needed
|
|
||||||
```
|
|
||||||
|
|
||||||
### Extension can't connect
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Test endpoint
|
|
||||||
curl https://server.lawrencehook.com/rys/health
|
|
||||||
|
|
||||||
# Check Apache config
|
|
||||||
sudo apachectl configtest
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Maintenance
|
|
||||||
|
|
||||||
### Update Server Code
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/github/remove-youtube-suggestions
|
|
||||||
git pull
|
|
||||||
git checkout feature/monetize
|
|
||||||
cd server
|
|
||||||
npm install
|
|
||||||
pm2 restart rys-premium
|
|
||||||
```
|
|
||||||
|
|
||||||
### View Logs
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pm2 logs rys-premium # Tail logs
|
|
||||||
pm2 logs rys-premium --lines 100 # Last 100 lines
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pm2 restart rys-premium # Restart
|
|
||||||
pm2 stop rys-premium # Stop
|
|
||||||
pm2 status # Check status
|
|
||||||
```
|
|
||||||
|
|
||||||
### Add to Deployment Script
|
|
||||||
|
|
||||||
Add to `~/github/deployments/run`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# RYS Premium Server (pm2)
|
|
||||||
cd /home/bitnami/github/remove-youtube-suggestions && git checkout -- . && git pull && git checkout feature/monetize;
|
|
||||||
cd server && npm install && npm audit fix;
|
|
||||||
pm2 restart rys-premium || pm2 start src/index.js --name rys-premium;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Updating Grandfathered List
|
|
||||||
|
|
||||||
1. Edit `data/grandfathered.json`
|
|
||||||
2. Restart: `pm2 restart rys-premium`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Environment Variables Reference
|
|
||||||
|
|
||||||
| Variable | Description | Example |
|
|
||||||
|----------|-------------|---------|
|
|
||||||
| `PORT` | Server port | `3005` |
|
|
||||||
| `BASE_URL` | Public URL | `https://server.lawrencehook.com/rys` |
|
|
||||||
| `JWT_SECRET` | 32+ char secret | (generate with `openssl rand -base64 32`) |
|
|
||||||
| `STRIPE_SECRET_KEY` | Stripe API secret | `sk_test_...` |
|
|
||||||
| `STRIPE_PRICE_MONTHLY` | Monthly plan price ID | `price_...` |
|
|
||||||
| `STRIPE_PRICE_YEARLY` | Yearly plan price ID | `price_...` |
|
|
||||||
| `STRIPE_WEBHOOK_SECRET` | Webhook signing secret | `whsec_...` |
|
|
||||||
| `AWS_REGION` | AWS region for SES | `us-east-1` |
|
|
||||||
| `EMAIL_FROM` | Sender email address | `noreply@lawrencehook.com` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API Endpoints Reference
|
|
||||||
|
|
||||||
| Endpoint | Method | Auth | Description |
|
|
||||||
|----------|--------|------|-------------|
|
|
||||||
| `/health` | GET | No | Health check |
|
|
||||||
| `/auth/send-magic-link` | POST | No | Send magic link email |
|
|
||||||
| `/auth/verify` | GET | No | Magic link target (HTML) |
|
|
||||||
| `/auth/poll` | GET | No | Poll for auth status |
|
|
||||||
| `/license/check` | GET | Yes | Check premium status |
|
|
||||||
| `/checkout/create` | POST | Yes | Create Stripe checkout |
|
|
||||||
| `/checkout/success` | GET | No | Success page (HTML) |
|
|
||||||
| `/checkout/cancel` | GET | No | Cancel page (HTML) |
|
|
||||||
| `/billing/portal` | POST | Yes | Create billing portal session |
|
|
||||||
| `/billing/return` | GET | No | Return page (HTML) |
|
|
||||||
| `/webhook/stripe` | POST | No* | Stripe webhook |
|
|
||||||
|
|
||||||
*Authenticated via Stripe signature
|
|
||||||
-357
@@ -1,357 +0,0 @@
|
|||||||
# Manual Testing Guide — Premium Subscription
|
|
||||||
|
|
||||||
This document covers all manual testing paths for the premium monetization feature.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- Extension loaded unpacked in Chrome (or Firefox)
|
|
||||||
- Server running locally or deployed to `server.lawrencehook.com`
|
|
||||||
- Stripe test mode configured with test price IDs
|
|
||||||
- AWS SES configured (or use a local email trap)
|
|
||||||
- At least one email in `data/grandfathered.json` for grandfathered testing
|
|
||||||
- A separate non-grandfathered email for regular user testing
|
|
||||||
- Stripe CLI installed for webhook testing (`stripe listen --forward-to localhost:3000/rys/webhook/stripe`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Initial State (Not Signed In)
|
|
||||||
|
|
||||||
### 1.1 Options page loads correctly
|
|
||||||
- [ ] Open extension popup — settings menu shows "Sign In" (not "Account")
|
|
||||||
- [ ] "Donate" link visible in header, links to PayPal
|
|
||||||
|
|
||||||
### 1.2 Free features work without sign-in
|
|
||||||
- [ ] Toggle a non-premium feature (e.g., "Hide homepage recommendations")
|
|
||||||
- [ ] Verify it takes effect on YouTube
|
|
||||||
|
|
||||||
### 1.3 Premium feature click — not signed in
|
|
||||||
- [ ] Click any premium-gated toggle (marked with a lock/premium indicator)
|
|
||||||
- [ ] Verify the "Premium Required" modal appears
|
|
||||||
- [ ] Click "Cancel" — modal closes, setting unchanged
|
|
||||||
- [ ] Click the premium toggle again, then click "Sign In" in the modal
|
|
||||||
- [ ] Verify a new tab opens to `main.html?signin=1` and the popup closes
|
|
||||||
|
|
||||||
### 1.4 Schedule and Password (premium settings menu items)
|
|
||||||
- [ ] Click "Schedule" in the settings menu — Premium Required modal appears
|
|
||||||
- [ ] Click "Password" in the settings menu — Premium Required modal appears
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Sign-In Flow
|
|
||||||
|
|
||||||
### 2.1 Happy path — sign in from new tab
|
|
||||||
- [ ] From the options tab (`main.html?signin=1`), sign-in modal opens automatically
|
|
||||||
- [ ] Enter a valid email, press Enter (or click send button)
|
|
||||||
- [ ] Modal transitions to waiting state with countdown timer
|
|
||||||
- [ ] Check email — magic link email received from the configured sender
|
|
||||||
- [ ] Click magic link — browser opens server success page ("You're signed in!")
|
|
||||||
- [ ] Return to extension tab — modal closes, status shows "Signed in successfully"
|
|
||||||
- [ ] Header now shows "Account" instead of "Sign In"
|
|
||||||
|
|
||||||
### 2.2 Sign in from popup
|
|
||||||
- [ ] Open extension popup, click "Sign In"
|
|
||||||
- [ ] Verify popup closes and a new tab opens to `main.html?signin=1`
|
|
||||||
- [ ] Complete the sign-in flow in the new tab
|
|
||||||
|
|
||||||
### 2.3 Invalid email
|
|
||||||
- [ ] Enter an invalid email (no @ symbol)
|
|
||||||
- [ ] Verify "Please enter a valid email" status message appears
|
|
||||||
- [ ] No network request is made
|
|
||||||
|
|
||||||
### 2.4 Rate limiting
|
|
||||||
- [ ] Send 5 magic link requests for the same email in rapid succession
|
|
||||||
- [ ] On the 6th attempt, verify a rate limit error message appears
|
|
||||||
- [ ] Wait for the rate limit window to pass (or clear rate limit data on server)
|
|
||||||
|
|
||||||
### 2.5 Cancel during polling
|
|
||||||
- [ ] Start sign-in flow, reach waiting state
|
|
||||||
- [ ] Click "Cancel" button
|
|
||||||
- [ ] Verify modal closes and polling stops (no continued network requests)
|
|
||||||
- [ ] Verify user is still not signed in
|
|
||||||
|
|
||||||
### 2.6 Poll timeout
|
|
||||||
- [ ] Start sign-in flow but do NOT click the magic link
|
|
||||||
- [ ] Wait for the 16-minute countdown to reach 0
|
|
||||||
- [ ] Verify error state appears with "Verification timed out" message
|
|
||||||
- [ ] Click "Retry" — email form reappears
|
|
||||||
|
|
||||||
### 2.7 Expired magic link
|
|
||||||
- [ ] Start sign-in flow, wait >15 minutes, then click the magic link
|
|
||||||
- [ ] Verify the server shows an error page (link expired)
|
|
||||||
- [ ] Extension should show error state when poll detects 404
|
|
||||||
|
|
||||||
### 2.8 Multiple sign-in attempts
|
|
||||||
- [ ] Start sign-in, reach waiting state
|
|
||||||
- [ ] Close modal, reopen, start a new sign-in with a different email
|
|
||||||
- [ ] Verify the previous polling is aborted (no interference)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Signed-In, Free User
|
|
||||||
|
|
||||||
### 3.1 Account modal
|
|
||||||
- [ ] Click "Account" in settings menu
|
|
||||||
- [ ] Verify Account modal opens showing:
|
|
||||||
- Your email address
|
|
||||||
- "Free Plan" status
|
|
||||||
- "Upgrade" button visible
|
|
||||||
- "Billing" button hidden
|
|
||||||
- "Sign Out" button visible
|
|
||||||
|
|
||||||
### 3.2 Premium feature click — signed in, not premium
|
|
||||||
- [ ] Click a premium feature toggle
|
|
||||||
- [ ] Verify the Upgrade modal appears (NOT the Premium Required modal)
|
|
||||||
|
|
||||||
### 3.3 Upgrade modal
|
|
||||||
- [ ] Verify Upgrade modal shows plan selection (Monthly / Yearly)
|
|
||||||
- [ ] Verify Yearly is selected by default
|
|
||||||
- [ ] Click Monthly — verify it becomes selected
|
|
||||||
- [ ] Click Yearly — verify it becomes selected
|
|
||||||
- [ ] Click "Cancel" — modal closes
|
|
||||||
|
|
||||||
### 3.4 License check — no subscription
|
|
||||||
- [ ] Open DevTools, check console for `[license] email -> free` on server
|
|
||||||
- [ ] Verify `is_premium` attribute on `<html>` is `"false"`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Checkout / Purchase Flow
|
|
||||||
|
|
||||||
### 4.1 Monthly subscription
|
|
||||||
- [ ] Click a premium feature → Upgrade modal
|
|
||||||
- [ ] Select "Monthly", click "Subscribe"
|
|
||||||
- [ ] Verify Stripe Checkout opens in a new tab
|
|
||||||
- [ ] Complete payment with Stripe test card (`4242 4242 4242 4242`)
|
|
||||||
- [ ] Verify Stripe success page appears
|
|
||||||
- [ ] Return to extension tab (click on it or close Stripe tab)
|
|
||||||
- [ ] Verify extension auto-refreshes license (visibility/focus event triggers refresh)
|
|
||||||
- [ ] Verify the premium feature you clicked is now enabled
|
|
||||||
- [ ] Verify "Donate" link changed to "Premium" in header
|
|
||||||
|
|
||||||
### 4.2 Yearly subscription
|
|
||||||
- [ ] Sign out, sign in with a different email
|
|
||||||
- [ ] Repeat checkout flow selecting "Yearly"
|
|
||||||
- [ ] Verify Stripe Checkout shows the yearly price
|
|
||||||
- [ ] Complete payment and verify premium activates
|
|
||||||
|
|
||||||
### 4.3 Cancel checkout
|
|
||||||
- [ ] Open Upgrade modal, click "Subscribe"
|
|
||||||
- [ ] On Stripe Checkout page, click back or close the tab
|
|
||||||
- [ ] Return to extension — verify user is still on Free Plan
|
|
||||||
- [ ] Verify no error messages appear
|
|
||||||
|
|
||||||
### 4.4 Checkout with expired session
|
|
||||||
- [ ] Clear `session_token` from `chrome.storage.local` manually (DevTools → Application → Local Storage)
|
|
||||||
- [ ] Try to subscribe — verify error about session expired
|
|
||||||
- [ ] Verify user is signed out and prompted to sign in again
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Premium User Experience
|
|
||||||
|
|
||||||
### 5.1 All premium features accessible
|
|
||||||
- [ ] Toggle several premium features on — verify they take effect on YouTube
|
|
||||||
- [ ] Toggle them off — verify they revert
|
|
||||||
|
|
||||||
### 5.2 Account modal — premium subscriber
|
|
||||||
- [ ] Open Account modal
|
|
||||||
- [ ] Verify it shows:
|
|
||||||
- Your email
|
|
||||||
- "Premium Active" status
|
|
||||||
- "Billing" button visible
|
|
||||||
- "Upgrade" button hidden
|
|
||||||
- "Sign Out" button
|
|
||||||
|
|
||||||
### 5.3 Billing portal
|
|
||||||
- [ ] Click "Billing" button in Account modal
|
|
||||||
- [ ] Verify Stripe billing portal opens in new tab
|
|
||||||
- [ ] Verify you can see subscription details, update payment method, cancel
|
|
||||||
- [ ] Close billing portal tab, return to extension
|
|
||||||
|
|
||||||
### 5.4 Schedule (premium feature)
|
|
||||||
- [ ] Click "Schedule" in settings menu
|
|
||||||
- [ ] Verify Schedule modal opens (not blocked by premium gate)
|
|
||||||
- [ ] Configure a schedule and verify it works
|
|
||||||
|
|
||||||
### 5.5 Password (premium feature)
|
|
||||||
- [ ] Click "Password" in settings menu
|
|
||||||
- [ ] Verify Password modal opens (not blocked by premium gate)
|
|
||||||
- [ ] Set a password, close settings, reopen — verify password prompt appears
|
|
||||||
- [ ] Enter correct password — verify unlock works
|
|
||||||
- [ ] Disable password — verify it's removed
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Grandfathered User
|
|
||||||
|
|
||||||
### 6.1 Sign in with grandfathered email
|
|
||||||
- [ ] Sign in with an email that's in `data/grandfathered.json`
|
|
||||||
- [ ] Verify license check returns `grandfathered: true`
|
|
||||||
|
|
||||||
### 6.2 Account modal — grandfathered
|
|
||||||
- [ ] Open Account modal
|
|
||||||
- [ ] Verify it shows:
|
|
||||||
- Your email
|
|
||||||
- "Lifetime Premium" status
|
|
||||||
- "Billing" button hidden (no subscription to manage)
|
|
||||||
- "Upgrade" button hidden
|
|
||||||
- "Sign Out" button
|
|
||||||
|
|
||||||
### 6.3 Premium features work
|
|
||||||
- [ ] Verify all premium features are accessible
|
|
||||||
- [ ] Verify "Donate" link shows "Premium"
|
|
||||||
|
|
||||||
### 6.4 Case-insensitive matching
|
|
||||||
- [ ] Add `test@example.com` to `grandfathered.json`
|
|
||||||
- [ ] Sign in with `Test@Example.com` (different case)
|
|
||||||
- [ ] Verify user is recognized as grandfathered
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Sign Out
|
|
||||||
|
|
||||||
### 7.1 Sign out clears state
|
|
||||||
- [ ] While signed in (premium or free), click "Sign Out" in Account modal
|
|
||||||
- [ ] Verify header changes back to "Sign In"
|
|
||||||
- [ ] Verify "Donate" link reappears (if was showing "Premium")
|
|
||||||
- [ ] Verify premium features are re-gated
|
|
||||||
|
|
||||||
### 7.2 Storage is cleared
|
|
||||||
- [ ] After sign-out, check `chrome.storage.local` in DevTools
|
|
||||||
- [ ] Verify `session_token`, `license_token`, and `user_email` are removed
|
|
||||||
- [ ] Verify YouTube settings (non-premium) are NOT affected
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Session Expiry
|
|
||||||
|
|
||||||
### 8.1 Expired session token
|
|
||||||
- [ ] Sign in, then manually modify the `session_token` in storage to an expired JWT
|
|
||||||
- [ ] Open Account modal (or trigger a license check)
|
|
||||||
- [ ] Verify "Session expired. Please sign in again." message appears
|
|
||||||
- [ ] Verify user is automatically signed out
|
|
||||||
- [ ] Verify sign-in modal opens
|
|
||||||
|
|
||||||
### 8.2 Invalid session token
|
|
||||||
- [ ] Replace `session_token` with garbage string in storage
|
|
||||||
- [ ] Trigger a license check
|
|
||||||
- [ ] Verify 401 from server causes automatic sign-out
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. License Token Caching & Refresh
|
|
||||||
|
|
||||||
### 9.1 Cached token is used
|
|
||||||
- [ ] Sign in as premium user, verify license check succeeds
|
|
||||||
- [ ] Disconnect from network (or stop the server)
|
|
||||||
- [ ] Close and reopen extension popup
|
|
||||||
- [ ] Verify premium features are still accessible (cached license token is valid)
|
|
||||||
|
|
||||||
### 9.2 Expired cached token without network
|
|
||||||
- [ ] Manually set `license_token` to an expired JWT in storage
|
|
||||||
- [ ] With server unreachable, open extension
|
|
||||||
- [ ] Verify user shows as non-premium (expired cache, can't refresh)
|
|
||||||
|
|
||||||
### 9.3 Token refresh near expiry
|
|
||||||
- [ ] Set a license token that expires within 24 hours (modify JWT payload)
|
|
||||||
- [ ] Open extension with server running
|
|
||||||
- [ ] Verify a fresh license check is triggered (not using cache)
|
|
||||||
|
|
||||||
### 9.4 Force refresh after checkout
|
|
||||||
- [ ] Complete a checkout flow
|
|
||||||
- [ ] Verify the extension calls `checkLicense(true)` (force refresh)
|
|
||||||
- [ ] Monitor network tab — a `/license/check` request should fire immediately on tab focus
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. Subscription Lifecycle
|
|
||||||
|
|
||||||
### 10.1 Cancel subscription via billing portal
|
|
||||||
- [ ] As a premium user, open Billing portal
|
|
||||||
- [ ] Cancel the subscription in Stripe
|
|
||||||
- [ ] Return to extension, close and reopen popup
|
|
||||||
- [ ] Wait for license token to expire (or force refresh)
|
|
||||||
- [ ] Verify user shows as "Free Plan" after refresh
|
|
||||||
- [ ] Verify premium features are re-gated
|
|
||||||
|
|
||||||
### 10.2 Resubscribe after cancellation
|
|
||||||
- [ ] After cancellation, click a premium feature
|
|
||||||
- [ ] Go through checkout flow again
|
|
||||||
- [ ] Verify premium re-activates
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 11. Stripe Webhooks
|
|
||||||
|
|
||||||
### 11.1 Webhook receives events
|
|
||||||
- [ ] With Stripe CLI forwarding, complete a checkout
|
|
||||||
- [ ] Verify `checkout.session.completed` event is logged on server
|
|
||||||
- [ ] Cancel subscription — verify `customer.subscription.deleted` is logged
|
|
||||||
|
|
||||||
### 11.2 Invalid webhook signature
|
|
||||||
- [ ] Send a POST to `/webhook/stripe` with invalid/missing `Stripe-Signature` header
|
|
||||||
- [ ] Verify 400 response
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 12. Cross-Browser
|
|
||||||
|
|
||||||
### 12.1 Chrome
|
|
||||||
- [ ] Run through sign-in, checkout, and premium feature flows on Chrome
|
|
||||||
|
|
||||||
### 12.2 Firefox
|
|
||||||
- [ ] Load extension in Firefox
|
|
||||||
- [ ] Verify sign-in flow works (popup-to-tab handoff, polling)
|
|
||||||
- [ ] Verify premium features gate correctly
|
|
||||||
- [ ] Verify `browser.storage.local` API works as expected
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 13. Edge Cases
|
|
||||||
|
|
||||||
### 13.1 Multiple tabs
|
|
||||||
- [ ] Open extension settings in two tabs
|
|
||||||
- [ ] Sign in on one tab
|
|
||||||
- [ ] Refresh the second tab — verify it reflects signed-in state
|
|
||||||
|
|
||||||
### 13.2 Rapid feature toggle clicks
|
|
||||||
- [ ] Click a premium feature rapidly multiple times
|
|
||||||
- [ ] Verify only one modal opens, no duplicate modals or errors
|
|
||||||
|
|
||||||
### 13.3 Network failure during sign-in
|
|
||||||
- [ ] Start sign-in, disconnect network after magic link is sent
|
|
||||||
- [ ] Verify polling handles network errors gracefully (retries silently)
|
|
||||||
- [ ] Reconnect network — verify polling resumes and succeeds when link is clicked
|
|
||||||
|
|
||||||
### 13.4 Server down during license check
|
|
||||||
- [ ] Sign in successfully, then stop the server
|
|
||||||
- [ ] Trigger a license check (reopen popup)
|
|
||||||
- [ ] Verify cached license token is used if still valid
|
|
||||||
- [ ] Verify no error shown to user
|
|
||||||
|
|
||||||
### 13.5 Extension update while signed in
|
|
||||||
- [ ] Sign in and get premium status
|
|
||||||
- [ ] Reload the extension (simulate update)
|
|
||||||
- [ ] Verify session and license tokens persist across reload
|
|
||||||
- [ ] Verify premium status is maintained
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 14. Analytics Verification
|
|
||||||
|
|
||||||
Use Mixpanel (or check console logs) to verify events fire correctly:
|
|
||||||
|
|
||||||
- [ ] `Sign In Started` — when email is submitted
|
|
||||||
- [ ] `Magic Link Sent` — after server responds
|
|
||||||
- [ ] `Sign In Success` — after verification completes
|
|
||||||
- [ ] `Sign In Canceled` — when user cancels polling
|
|
||||||
- [ ] `Sign In Error` — on timeout or failure
|
|
||||||
- [ ] `Premium Feature Click` — with correct `signedIn` flag
|
|
||||||
- [ ] `Upgrade Modal Opened` — when upgrade modal shows
|
|
||||||
- [ ] `Checkout Started` — with correct `plan` value
|
|
||||||
- [ ] `Checkout Completed` — after returning from successful checkout
|
|
||||||
- [ ] `Account Modal Opened` — with `isPremium` and `source`
|
|
||||||
- [ ] `Billing Portal Opened` — when billing portal opens
|
|
||||||
- [ ] `Session Expired` — when 401 triggers sign-out
|
|
||||||
- [ ] `Sign Out` — when user signs out
|
|
||||||
- [ ] `License Check` — with `cached`, `offline`, `isPremium` properties
|
|
||||||
Reference in New Issue
Block a user