Skip to content

Commit 90906a5

Browse files
authored
Merge pull request #76 from sousa-dev/pay-for-no-ads
Pay for no ads
2 parents c4f5c5c + f219e87 commit 90906a5

25 files changed

Lines changed: 3068 additions & 11 deletions

FRONTEND_INTEGRATION_GUIDE.md

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
# 📱 Frontend Integration Guide - Subscription Verification API
2+
3+
## 🎯 Overview
4+
5+
This guide explains how the subscription verification API works and how your frontend should integrate with it to handle subscription-based features like ad removal and premium content.
6+
7+
## 🌐 API Endpoint Details
8+
9+
### Primary Verification Endpoint
10+
- **URL**: `POST /api/v1/subscription/verify`
11+
- **Method**: `POST`
12+
- **Content-Type**: `application/json`
13+
- **Purpose**: Verify if an email has an active subscription
14+
15+
### Request Format
16+
```json
17+
{
18+
"email": "user@example.com"
19+
}
20+
```
21+
22+
### Response Format (Always HTTP 200 for valid requests)
23+
```json
24+
{
25+
"hasActiveSubscription": boolean,
26+
"subscriptionType": string | null,
27+
"expiresAt": string | null,
28+
"features": string[],
29+
"message": string | null
30+
}
31+
```
32+
33+
## 📋 Response Scenarios
34+
35+
### 1. ✅ Active Subscription Found
36+
**Scenario**: Email exists in database with `is_active: true`
37+
38+
```json
39+
{
40+
"hasActiveSubscription": true,
41+
"subscriptionType": "premium",
42+
"expiresAt": null,
43+
"features": ["ad_removal", "priority_support"],
44+
"message": null
45+
}
46+
```
47+
48+
**Frontend Action**: Enable premium features, hide ads
49+
50+
### 2. ❌ No Active Subscription (Email Exists but Inactive)
51+
**Scenario**: Email exists in database with `is_active: false`
52+
53+
```json
54+
{
55+
"hasActiveSubscription": false,
56+
"subscriptionType": null,
57+
"expiresAt": null,
58+
"features": [],
59+
"message": "No active subscription found for this email"
60+
}
61+
```
62+
63+
**Frontend Action**: Show ads, disable premium features
64+
65+
### 3. ❌ Email Doesn't Exist in Database
66+
**Scenario**: Email has never been registered for any subscription
67+
68+
```json
69+
{
70+
"hasActiveSubscription": false,
71+
"subscriptionType": null,
72+
"expiresAt": null,
73+
"features": [],
74+
"message": "No active subscription found for this email"
75+
}
76+
```
77+
78+
**Frontend Action**: Show ads, disable premium features
79+
80+
### 4. ⚠️ Invalid Email Format
81+
**Scenario**: Malformed email address submitted
82+
83+
```json
84+
{
85+
"error": "Invalid request data",
86+
"details": {
87+
"email": ["Enter a valid email address."]
88+
}
89+
}
90+
```
91+
**HTTP Status**: `400 Bad Request`
92+
**Frontend Action**: Show validation error to user
93+
94+
## 🔧 Frontend Implementation Logic
95+
96+
### Basic Integration Flow
97+
98+
```javascript
99+
async function checkSubscriptionStatus(email) {
100+
try {
101+
const response = await fetch('/api/v1/subscription/verify', {
102+
method: 'POST',
103+
headers: {
104+
'Content-Type': 'application/json',
105+
},
106+
body: JSON.stringify({ email: email })
107+
});
108+
109+
if (response.ok) {
110+
const data = await response.json();
111+
112+
// Check if response has error (400 status for invalid email)
113+
if (data.error) {
114+
console.error('Validation error:', data.details);
115+
return { hasSubscription: false, error: data.details };
116+
}
117+
118+
// Normal response - check subscription status
119+
return {
120+
hasSubscription: data.hasActiveSubscription,
121+
features: data.features || [],
122+
subscriptionType: data.subscriptionType,
123+
message: data.message
124+
};
125+
} else {
126+
console.error('API request failed:', response.status);
127+
return { hasSubscription: false, error: 'API request failed' };
128+
}
129+
} catch (error) {
130+
console.error('Network error:', error);
131+
return { hasSubscription: false, error: 'Network error' };
132+
}
133+
}
134+
```
135+
136+
### Feature Control Logic
137+
138+
```javascript
139+
function applySubscriptionFeatures(subscriptionData) {
140+
const { hasSubscription, features } = subscriptionData;
141+
142+
if (hasSubscription) {
143+
// User has active subscription
144+
if (features.includes('ad_removal')) {
145+
hideAllAds();
146+
}
147+
if (features.includes('priority_support')) {
148+
enablePrioritySupport();
149+
}
150+
showPremiumBadge();
151+
} else {
152+
// User doesn't have active subscription
153+
showAllAds();
154+
disablePremiumFeatures();
155+
hidePremiumBadge();
156+
}
157+
}
158+
159+
function hideAllAds() {
160+
document.querySelectorAll('.advertisement').forEach(ad => {
161+
ad.style.display = 'none';
162+
});
163+
}
164+
165+
function showAllAds() {
166+
document.querySelectorAll('.advertisement').forEach(ad => {
167+
ad.style.display = 'block';
168+
});
169+
}
170+
```
171+
172+
### Complete Usage Example
173+
174+
```javascript
175+
// Example usage in your app
176+
async function initializeUserExperience(userEmail) {
177+
// Show loading state
178+
showLoadingSpinner();
179+
180+
// Check subscription status
181+
const subscriptionResult = await checkSubscriptionStatus(userEmail);
182+
183+
if (subscriptionResult.error) {
184+
// Handle errors (invalid email, network issues, etc.)
185+
showErrorMessage('Unable to verify subscription status');
186+
// Default to showing ads on error
187+
showAllAds();
188+
} else {
189+
// Apply subscription-based features
190+
applySubscriptionFeatures(subscriptionResult);
191+
192+
// Optional: Show subscription status to user
193+
if (subscriptionResult.hasSubscription) {
194+
showSubscriptionStatus('Premium Active ✨');
195+
}
196+
}
197+
198+
hideLoadingSpinner();
199+
}
200+
```
201+
202+
## ⚠️ Important Behavior Notes
203+
204+
### 1. **No Errors for Non-Existent Emails**
205+
- ✅ Non-existent emails return `hasActiveSubscription: false`
206+
- ✅ HTTP status is always `200 OK` for valid email formats
207+
- ✅ No exceptions or 404 errors are thrown
208+
- **Frontend should treat this the same as inactive subscriptions**
209+
210+
### 2. **Email Validation**
211+
- ❌ Invalid email formats return `400 Bad Request`
212+
- Check for `data.error` in response to handle validation errors
213+
- Display user-friendly validation messages
214+
215+
### 3. **Features Array**
216+
- Current features: `["ad_removal", "priority_support"]`
217+
- Check for specific features instead of assuming all premium features
218+
- Future-proof for additional feature types
219+
220+
### 4. **Subscription Types**
221+
- Currently only `"premium"` or `null`
222+
- Future versions may include different subscription tiers
223+
224+
## 🔄 Recommended Error Handling
225+
226+
```javascript
227+
function handleSubscriptionResponse(data, response) {
228+
// Case 1: Validation error (400 status)
229+
if (!response.ok && data.error) {
230+
return {
231+
status: 'validation_error',
232+
message: 'Please enter a valid email address',
233+
hasSubscription: false
234+
};
235+
}
236+
237+
// Case 2: Network/server error (500, etc.)
238+
if (!response.ok) {
239+
return {
240+
status: 'server_error',
241+
message: 'Unable to verify subscription. Please try again.',
242+
hasSubscription: false // Default to no subscription on errors
243+
};
244+
}
245+
246+
// Case 3: Successful response
247+
return {
248+
status: 'success',
249+
hasSubscription: data.hasActiveSubscription,
250+
features: data.features,
251+
subscriptionType: data.subscriptionType,
252+
message: data.message
253+
};
254+
}
255+
```
256+
257+
## 🧪 Testing Your Frontend Integration
258+
259+
### Test Cases to Verify
260+
261+
1. **Active Subscription**:
262+
- Test with: `premium_user@saomiguelbus.com`
263+
- Expected: Ads hidden, premium features enabled
264+
265+
2. **Inactive Subscription**:
266+
- Test with: `cancelled_user@example.com`
267+
- Expected: Ads shown, premium features disabled
268+
269+
3. **Non-Existent Email**:
270+
- Test with: `nonexistent@test.com`
271+
- Expected: Ads shown, premium features disabled (same as inactive)
272+
273+
4. **Invalid Email**:
274+
- Test with: `invalid-email`
275+
- Expected: Validation error message, ads shown
276+
277+
5. **Network Error**:
278+
- Test with API offline
279+
- Expected: Error message, ads shown (fail-safe)
280+
281+
## 📊 Sample Test Data
282+
283+
The API currently has these test subscriptions available:
284+
285+
```javascript
286+
// Active subscriptions (should hide ads)
287+
const activeEmails = [
288+
'premium_user@saomiguelbus.com',
289+
'paid_user@example.com',
290+
'vip_user@premium.com'
291+
];
292+
293+
// Inactive subscriptions (should show ads)
294+
const inactiveEmails = [
295+
'cancelled_user@example.com',
296+
'inactive_user@test.com'
297+
];
298+
299+
// Non-existent emails (should show ads)
300+
const nonExistentEmails = [
301+
'random@test.com',
302+
'user@nowhere.com'
303+
];
304+
```
305+
306+
## 🎯 Key Frontend Checklist
307+
308+
- [ ] Handle `hasActiveSubscription: false` for both non-existent and inactive emails
309+
- [ ] Check `features` array for specific capabilities
310+
- [ ] Handle validation errors for invalid email formats
311+
- [ ] Implement fail-safe behavior (show ads on API errors)
312+
- [ ] Test all scenarios with sample data
313+
- [ ] Show appropriate loading states during API calls
314+
- [ ] Provide user feedback for subscription status
315+
316+
## 🚀 Performance Tips
317+
318+
1. **Cache subscription status** for the session to avoid repeated API calls
319+
2. **Implement timeout** for API requests (5-10 seconds recommended)
320+
3. **Show ads immediately on timeout** for better user experience
321+
4. **Preload subscription check** when user email is available
322+
323+
## 🔒 Security Considerations
324+
325+
- API endpoints are public (no authentication required)
326+
- Only email verification, no sensitive data exposed
327+
- Rate limiting may apply (implement request throttling if needed)
328+
- Always validate email format client-side before API calls
329+
330+
---
331+
332+
This API provides a simple, reliable way to verify subscription status and control premium features in your frontend application. The consistent response format and error handling make it easy to integrate and maintain.

0 commit comments

Comments
 (0)