Skip to content

Commit 0cd22b0

Browse files
committed
fix: CORS and database connection issues
CORS Configuration: - Add multiple allowed origins including worrybox.gigaelk.com - Support both production and development URLs - Enable credentials for cross-origin requests Database Connection Resilience: - Add /api/wake endpoint to wake up sleeping databases - Implement retry logic in subscription service - Add fallback subscription tiers when API unavailable - Increase API timeout to 30 seconds Frontend Error Handling: - Make subscription loading non-blocking for login - Add graceful fallbacks for failed API calls - Improve error logging and user experience - Separate subscription loading from authentication flow This fixes the login issues caused by CORS blocks and sleeping databases on free hosting services like Render. Users can now login even when the subscription API is temporarily unavailable!
1 parent 5034791 commit 0cd22b0

File tree

4 files changed

+81
-8
lines changed

4 files changed

+81
-8
lines changed

backend/src/index.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ const PORT = process.env.PORT || 5000;
2424
// Security middleware
2525
app.use(helmet());
2626
app.use(cors({
27-
origin: process.env.FRONTEND_URL || 'http://localhost:3000',
27+
origin: [
28+
process.env.FRONTEND_URL || 'http://localhost:3000',
29+
'https://worrybox.gigaelk.com',
30+
'http://localhost:3000',
31+
'http://localhost:5173', // Vite dev server
32+
],
2833
credentials: true,
2934
}));
3035

@@ -65,6 +70,31 @@ app.get('/health', async (req, res) => {
6570
res.status(isHealthy ? 200 : 503).send(isHealthy ? 'OK' : 'UNHEALTHY');
6671
});
6772

73+
// Database wake-up endpoint
74+
app.get('/api/wake', async (req, res) => {
75+
try {
76+
// Simple database query to wake up the connection
77+
const { PrismaClient } = await import('@prisma/client');
78+
const prisma = new PrismaClient();
79+
await prisma.$queryRaw`SELECT 1`;
80+
await prisma.$disconnect();
81+
82+
res.json({
83+
status: 'awake',
84+
message: 'Database connection established',
85+
timestamp: new Date().toISOString()
86+
});
87+
} catch (error: any) {
88+
logger.error('Database wake-up failed', error);
89+
res.status(503).json({
90+
status: 'sleeping',
91+
message: 'Database connection failed',
92+
error: error.message,
93+
timestamp: new Date().toISOString()
94+
});
95+
}
96+
});
97+
6898
// Import routes
6999
import authRoutes from './routes/auth';
70100
import userRoutes from './routes/users';

frontend/src/contexts/SubscriptionContext.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,30 @@ export const SubscriptionProvider: React.FC<SubscriptionProviderProps> = ({ chil
3535
setIsLoading(true)
3636
setError(null)
3737

38-
// Load subscription tiers (always available)
39-
const tiersData = await subscriptionService.getSubscriptionTiers()
40-
setTiers(tiersData)
38+
// Load subscription tiers (always available) - with retry logic
39+
try {
40+
const tiersData = await subscriptionService.getSubscriptionTiers()
41+
setTiers(tiersData)
42+
} catch (tiersError: any) {
43+
console.warn('Failed to load subscription tiers, using fallback:', tiersError)
44+
// Fallback tiers if API is unavailable
45+
setTiers([
46+
{ id: 'free', name: 'Free', price: 0, features: ['Basic features'] },
47+
{ id: 'supporter', name: 'Supporter', price: 4.99, features: ['All Free features', 'Premium support'] },
48+
{ id: 'premium', name: 'Premium', price: 9.99, features: ['All Supporter features', 'Advanced analytics', 'Priority support'] }
49+
])
50+
}
4151

4252
// Load user subscription if authenticated
4353
if (user) {
44-
const subscriptionData = await subscriptionService.getCurrentSubscription()
45-
setSubscription(subscriptionData)
54+
try {
55+
const subscriptionData = await subscriptionService.getCurrentSubscription()
56+
setSubscription(subscriptionData)
57+
} catch (subError: any) {
58+
console.warn('Failed to load user subscription:', subError)
59+
// Don't block login for subscription loading failures
60+
setSubscription(null)
61+
}
4662
} else {
4763
setSubscription(null)
4864
}

frontend/src/services/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:5000/api'
55
// Create axios instance
66
const api = axios.create({
77
baseURL: API_BASE_URL,
8+
timeout: 30000, // 30 second timeout
89
headers: {
910
'Content-Type': 'application/json',
1011
},

frontend/src/services/subscriptionService.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,36 @@ export interface FeatureAccess {
3333
}
3434

3535
export const subscriptionService = {
36+
// Wake up the database (useful for sleeping databases on free hosting)
37+
async wakeUpDatabase(): Promise<void> {
38+
try {
39+
await api.get('/wake')
40+
} catch (error) {
41+
console.warn('Database wake-up failed:', error)
42+
// Don't throw - this is just a helper
43+
}
44+
},
45+
3646
// Get available subscription tiers
3747
async getSubscriptionTiers(): Promise<SubscriptionTier[]> {
38-
const response = await api.get('/subscriptions/tiers')
39-
return response.data.data
48+
try {
49+
const response = await api.get('/subscriptions/tiers')
50+
return response.data.data
51+
} catch (error: any) {
52+
// If the first request fails, try waking up the database and retry once
53+
if (error.code === 'ERR_NETWORK' || error.response?.status >= 500) {
54+
console.log('Attempting to wake up database and retry...')
55+
await this.wakeUpDatabase()
56+
57+
// Wait a moment for the database to wake up
58+
await new Promise(resolve => setTimeout(resolve, 2000))
59+
60+
// Retry the request
61+
const response = await api.get('/subscriptions/tiers')
62+
return response.data.data
63+
}
64+
throw error
65+
}
4066
},
4167

4268
// Get current user's subscription

0 commit comments

Comments
 (0)