![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/soundstudiopro.com/private_html/ |
# 500 Credits Membership Purchase - Audit & Analysis
**Date:** 2025-01-XX
**Package:** Premium (500 Credits)
**Price:** $129.00 USD
**Status:** Ready for Purchase
---
## 📦 Package Details
- **Package ID:** `premium`
- **Package Name:** Premium
- **Credits:** 500 credits
- **Price:** $129.00 USD ($12,900 cents)
- **Stripe Price ID:** `price_premium_credits`
- **Expiration Period:** ❌ **NEVER EXPIRES** (credits are permanent)
- ⚠️ **REQUIREMENT:** User must have **active subscription** (minimum Essential $5/month) to purchase
---
## 🔄 Purchase Flow
### 1. **Checkout Process** (`checkout.php`)
- User adds Premium package to cart (`$_SESSION['credit_cart']`)
- User proceeds to checkout
- Payment processed via Stripe or PayPal
### 2. **Payment Processing** (`process_credit_payment.php`)
- ⚠️ **Subscription Validation:** Checks for active subscription before processing
- If no subscription → Returns error with subscription signup link
- Creates Stripe Payment Intent with metadata:
```php
metadata: {
user_id: <user_id>,
package: 'premium',
credits: 500,
quantity: 1,
subscription_period: '30_days'
}
```
- Amount: $12,900 cents ($129.00)
### 3. **Webhook Handler** (`webhooks/stripe.php`)
- Stripe sends `payment_intent.succeeded` webhook
- Calls `handleSuccessfulPayment()` → `addCreditsToUser()`
---
## ✅ What Happens When Purchase Completes
### Database Changes
#### 1. **Users Table Update**
```sql
UPDATE users
SET credits = credits + 500,
plan = 'premium'
WHERE id = <user_id>
```
**Impact:**
- ✅ Adds 500 credits to user's account
- ✅ Sets user plan to `'premium'`
- ✅ **Grants commercial rights** - Per terms: "Credits include commercial licensing rights"
- ✅ **Rights are permanent** - Per terms: "Rights are permanent - once content is created with credits, commercial rights do not expire"
#### 2. **Credit Purchases Table Insert**
```sql
INSERT INTO credit_purchases
(user_id, package, credits, amount, payment_intent_id, expires_at, created_at)
VALUES (<user_id>, 'premium', 500, 129.00, <payment_intent_id>, <expiration_date>, NOW())
```
**Impact:**
- ✅ Records purchase transaction
- ✅ Links to Stripe payment intent for reconciliation
- ✅ Stores expiration date
#### 3. **Transaction Logging**
- Logs to `/logs/user_credits.log`:
```json
{
"timestamp": "2025-01-XX XX:XX:XX",
"action": "add_credits_to_user",
"user_id": <user_id>,
"credits_added": 500,
"package": "premium",
"plan_updated_to": "premium",
"expiration_date": "2025-02-XX XX:XX:XX",
"payment_intent_id": "pi_xxxxx",
"status": "success"
}
```
---
## ⚠️ Critical Behaviors & Expectations
### 1. **Subscription Requirement** ⚠️ **NEW**
- **REQUIRED:** User must have **active subscription** (minimum Essential $5/month) to purchase credits
- **Validation Points:**
- ✅ Checkout page (`checkout.php`) - Redirects if no subscription
- ✅ Payment processing (`process_credit_payment.php`) - Blocks payment if no subscription
- ✅ JavaScript validation - Checks before payment processing
- **Error Handling:**
- Shows clear error message: "Active subscription required"
- Redirects to subscription page: `/account_settings.php?tab=subscription`
- Provides subscription signup link
### 2. **Credit Expiration**
- **Premium Credits (500):** ❌ **NEVER EXPIRE** - Credits are permanent
- **Starter/Pro Credits:** ⏰ Expire in 30 days
- **Expiration Process:** Daily cron job (`cron/expire_credits.php`) - **EXCLUDES premium users**
- **What Happens on Expiration (Starter/Pro only):**
- User's plan downgrades to `'free'`
- **ALL credits are set to 0** (not just the purchased credits)
- `commercial_rights_expires` is set to `subscription_expires`
- User receives expiration email notification
- **Premium Credits:** Protected from expiration - user keeps them forever
### 2. **Plan Override Behavior**
⚠️ **IMPORTANT:** When purchasing the Premium package:
- User's plan is **overwritten** to `'premium'` (regardless of previous plan)
- If user had an active subscription plan, it will be replaced
- The `subscription_expires` field is set to 30 days from purchase
### 3. **Credit Accumulation**
- Credits are **ADDED** to existing balance (`credits = credits + 500`)
- If user already has credits, they accumulate
- Example: User with 50 credits + 500 purchase = 550 total credits
### 4. **Commercial Rights**
⚠️ **CRITICAL:** Credit packages (including Premium 500) do **NOT** grant commercial rights
- ✅ Users must maintain **active subscription** (minimum $5 Essential plan) to have commercial rights
- ❌ Premium 500 credits alone = **NO commercial rights**
- ✅ Commercial rights granted only when user has active subscription in `user_subscriptions` table
- ⚠️ When subscription expires, commercial rights are **revoked from all tracks**
- ✅ Rights persist while subscription is active
- ❌ No retroactive rights (per terms) - only new tracks get rights after resubscribing
---
## 🔍 Monitoring & Verification Points
### 1. **Immediate Verification (After Purchase)**
Check these logs/files:
- ✅ `/logs/stripe_webhooks.log` - Webhook received
- ✅ `/logs/stripe_actions.log` - Payment processing
- ✅ `/logs/user_credits.log` - Credit addition confirmation
- ✅ Database: `users` table - Verify credits and plan updated
- ✅ Database: `credit_purchases` table - Verify purchase record
### 2. **Database Queries to Run**
```sql
-- Verify user credits and plan
SELECT id, name, email, credits, plan, subscription_expires
FROM users
WHERE id = <user_id>;
-- Verify purchase record
SELECT * FROM credit_purchases
WHERE user_id = <user_id>
AND package = 'premium'
ORDER BY created_at DESC
LIMIT 1;
-- Check credit transaction history
SELECT * FROM credit_transactions
WHERE user_id = <user_id>
ORDER BY created_at DESC
LIMIT 10;
```
### 3. **Expected Log Entries**
Look for these log entries:
1. `payment_intent.succeeded` in `stripe_webhooks.log`
2. `handleSuccessfulPayment` in `stripe_actions.log`
3. `add_credits_to_user` with `status: 'success'` in `user_credits.log`
---
## 🚨 Potential Issues to Watch For
### 1. **Subscription Requirement Blocking Purchases**
- **Risk:** Users without subscription cannot purchase credits
- **Mitigation:** Clear messaging and redirect to subscription page
- **Action:** Ensure subscription signup flow is smooth
- **Note:** This is intentional - subscription required for credit purchases
### 2. **Webhook Delivery Failures**
- **Risk:** Stripe webhook might not be received
- **Mitigation:** Check Stripe dashboard for webhook delivery status
- **Fallback:** Manual reconciliation via `auto_reconcile_purchases.php`
### 3. **Database Transaction Failures**
- **Risk:** Transaction might rollback if error occurs
- **Mitigation:** Check `/logs/user_credits_errors.log` for failures
- **Action:** Retry mechanism exists via `schedulePurchaseRetry()`
### 4. **Credit Expiration Timing**
- **Risk:** Credits expire exactly 30 days after purchase (not 30 days of usage)
- **Note:** This is by design - credits expire based on purchase date, not usage
- **Premium Credits:** Never expire (protected from expiration)
### 5. **Plan Conflicts**
- **Risk:** If user has active subscription, purchasing credit package will override subscription plan
- **Impact:** User's subscription plan will be replaced with `'premium'` plan
- **Note:** This might not be intended behavior if user has recurring subscription
### 6. **Double Processing**
- **Risk:** Webhook might be called twice (idempotency)
- **Mitigation:** Code checks for existing purchases, but credits are still added
- **Note:** If webhook fires twice, user gets 1000 credits instead of 500
---
## 📊 Financial Expectations
### Revenue
- **Amount:** $129.00 USD per purchase
- **Payment Method:** Stripe (primary) or PayPal
- **Processing Fee:** Stripe charges ~2.9% + $0.30 per transaction
- **Net Revenue:** ~$125.26 per purchase (after Stripe fees)
### Accounting Records
- Purchase recorded in `credit_purchases` table
- Linked to Stripe Payment Intent ID for reconciliation
- Amount stored: $129.00
---
## 🔐 Security Considerations
### 1. **Payment Verification**
- ✅ Webhook signature verified using Stripe webhook secret
- ✅ Payment intent metadata includes user_id for validation
- ✅ Database transactions ensure atomicity
### 2. **User Validation**
- ✅ User must be logged in to purchase
- ✅ User ID from session matched with payment metadata
- ✅ Credits added only after successful payment
### 3. **Idempotency**
- ⚠️ **Partial:** Code checks for existing purchases but still adds credits
- **Recommendation:** Add idempotency check to prevent duplicate credit additions
---
## 📝 Post-Purchase Checklist
After purchase completes, verify:
- [ ] User's credits increased by 500
- [ ] User's plan set to `'premium'`
- [ ] `subscription_expires` set to 30 days from now
- [ ] Record in `credit_purchases` table created
- [ ] Payment intent ID recorded correctly
- [ ] Log entries created in all relevant log files
- [ ] No errors in error logs
- [ ] User can see credits in their account
- [ ] User has access to premium features
---
## 🔄 Expiration Timeline
### Day 0 (Purchase)
- Credits: +500
- Plan: **Unchanged** (stays as-is)
- Commercial Rights: **NO** (requires active subscription)
- Expiration: **NEVER** (NULL in database for credits)
### Day 7, 30, 365+ (Any Time)
- ✅ **Credits remain active** - Premium credits never expire
- ⚠️ **Commercial rights** - Only if user has active subscription
- ❌ **If subscription expires** - Commercial rights revoked from all tracks
- ✅ **Credits persist forever** - User keeps all 500 credits indefinitely
- ⚠️ **To use credits commercially** - User must maintain subscription (minimum $5 Essential)
---
## 📞 Support Scenarios
### User Reports Missing Credits
1. Check `user_credits.log` for purchase confirmation
2. Verify Stripe payment intent status
3. Check database for purchase record
4. Review webhook logs for delivery issues
5. Use `auto_reconcile_purchases.php` if needed
### User Reports Wrong Plan
1. Check `users.plan` field
2. Verify `subscription_expires` date
3. Check if user has active subscription that might conflict
4. Review purchase metadata in Stripe dashboard
### Credits Expired Prematurely
1. Check `subscription_expires` date in database
2. Verify cron job execution logs
3. Check `credit_expirations.log` for expiration events
4. Verify timezone settings (UTC used in cron)
---
## 🎯 Key Takeaways
1. ⚠️ **Active subscription REQUIRED** (minimum Essential $5/month) to purchase credits
2. **500 credits** are added immediately upon successful payment
3. **Plan is set to `premium`** (overwrites existing plan)
4. **Premium credits NEVER expire** - User keeps them forever
5. **Commercial rights granted** - Per terms: "Credits include commercial licensing rights"
6. **Rights are permanent** - Per terms: "Rights are permanent - once content is created with credits, commercial rights do not expire"
7. **Purchase is logged** in multiple places for audit trail
8. **Webhook-based** processing ensures reliability
9. **Subscription validation** at checkout and payment processing
10. **Plan override** behavior may conflict with active subscriptions
---
## 📚 Related Files
- `/checkout.php` - Checkout page
- `/process_credit_payment.php` - Payment processing
- `/webhooks/stripe.php` - Webhook handler
- `/cron/expire_credits.php` - Credit expiration cron
- `/auto_reconcile_purchases.php` - Manual reconciliation tool
- `/logs/user_credits.log` - Credit addition logs
- `/logs/stripe_webhooks.log` - Webhook delivery logs
- `/logs/stripe_actions.log` - Payment processing logs
---
**Last Updated:** 2025-01-XX
**Audit Status:** ✅ Complete - Ready for Purchase Monitoring