Skip to content

Commit e99321b

Browse files
authored
Merge pull request #360 from codeunia-dev/fix/staledata
refactor: Update caching strategy across API routes and configuration…
2 parents c10601e + 9f1d8bb commit e99321b

File tree

10 files changed

+49
-203
lines changed

10 files changed

+49
-203
lines changed

app/[username]/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import { createClient } from '@/lib/supabase/server';
55
import Header from "@/components/header";
66
import Footer from "@/components/footer";
77

8+
// Force dynamic rendering to prevent stale data
9+
export const dynamic = 'force-dynamic';
10+
export const revalidate = 0;
11+
export const fetchCache = 'force-no-store';
12+
813
interface UsernamePageProps {
914
params: Promise<{
1015
username: string;

app/api/companies/[slug]/route.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,7 @@ export async function GET(
2020
try {
2121
const { slug } = await params
2222

23-
// Try to get from cache first
24-
const cacheKey = `company:${slug}`
25-
const cached = await UnifiedCache.get(cacheKey)
26-
27-
if (cached) {
28-
return UnifiedCache.createResponse(cached, 'API_STANDARD')
29-
}
30-
31-
// Fetch company
23+
// Fetch company - no caching to prevent stale data
3224
const company = await companyService.getCompanyBySlug(slug)
3325

3426
if (!company) {
@@ -110,10 +102,8 @@ export async function GET(
110102
total_participants: eventParticipants + hackathonParticipants,
111103
}
112104

113-
// Cache the result
114-
await UnifiedCache.set(cacheKey, { company: enrichedCompany }, 'API_STANDARD')
115-
116-
return UnifiedCache.createResponse({ company: enrichedCompany }, 'API_STANDARD')
105+
// Return with no-cache headers to prevent stale data
106+
return UnifiedCache.createResponse({ company: enrichedCompany }, 'USER_PRIVATE')
117107
} catch (error) {
118108
console.error('Error in GET /api/companies/[slug]:', error)
119109

app/api/companies/route.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,11 @@ export async function GET(request: NextRequest) {
2525
offset: parseInt(searchParams.get('offset') || '0'),
2626
}
2727

28-
// Try to get from cache first
29-
const cacheKey = `companies:list:${JSON.stringify(filters)}`
30-
const cached = await UnifiedCache.get(cacheKey)
31-
32-
if (cached) {
33-
return UnifiedCache.createResponse(cached, 'API_STANDARD')
34-
}
35-
36-
// Fetch from database
28+
// Fetch from database - no caching to prevent stale data
3729
const result = await companyService.listCompanies(filters)
3830

39-
// Cache the result
40-
await UnifiedCache.set(cacheKey, result, 'API_STANDARD')
41-
42-
return UnifiedCache.createResponse(result, 'API_STANDARD')
31+
// Return with no-cache headers to prevent stale data
32+
return UnifiedCache.createResponse(result, 'USER_PRIVATE')
4333
} catch (error) {
4434
console.error('Error in GET /api/companies:', error)
4535

app/api/events/[slug]/route.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,7 @@ export async function GET(
1515
try {
1616
const { slug } = await params;
1717

18-
// Try to get from cache first
19-
const cacheKey = `event:${slug}`;
20-
const cached = await UnifiedCache.get(cacheKey);
21-
22-
if (cached) {
23-
return UnifiedCache.createResponse(cached, 'API_STANDARD');
24-
}
25-
26-
// Fetch from database
18+
// Fetch from database - no caching to prevent stale data
2719
const event = await eventsService.getEventBySlug(slug);
2820

2921
if (!event) {
@@ -33,10 +25,8 @@ export async function GET(
3325
);
3426
}
3527

36-
// Cache the result
37-
await UnifiedCache.set(cacheKey, event, 'API_STANDARD');
38-
39-
return UnifiedCache.createResponse(event, 'API_STANDARD');
28+
// Return with no-cache headers to prevent stale data
29+
return UnifiedCache.createResponse(event, 'USER_PRIVATE');
4030

4131
} catch (error) {
4232
console.error('Error in GET /api/events/[slug]:', error);

app/api/events/featured/route.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,11 @@ export async function GET(request: NextRequest) {
1212
const { searchParams } = new URL(request.url);
1313
const limit = parseInt(searchParams.get('limit') || '5');
1414

15-
// Try to get from cache first
16-
const cacheKey = `featured_events:${limit}`;
17-
const cached = await UnifiedCache.get(cacheKey);
18-
19-
if (cached) {
20-
return UnifiedCache.createResponse({ events: cached }, 'API_STANDARD');
21-
}
22-
23-
// Fetch from database
15+
// Fetch from database - no caching to prevent stale data
2416
const events = await eventsService.getFeaturedEvents(limit);
25-
26-
// Cache the result
27-
await UnifiedCache.set(cacheKey, events, 'API_STANDARD');
2817

29-
return UnifiedCache.createResponse({ events }, 'API_STANDARD');
18+
// Return with no-cache headers to prevent stale data
19+
return UnifiedCache.createResponse({ events }, 'USER_PRIVATE');
3020

3121
} catch (error) {
3222
console.error('Error in GET /api/events/featured:', error);

app/api/events/route.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,11 @@ export async function GET(request: NextRequest) {
6868
offset: parseInt(searchParams.get('offset') || '0')
6969
};
7070

71-
// Try to get from cache first
72-
const cacheKey = `events:${JSON.stringify(filters)}`;
73-
const cached = await UnifiedCache.get(cacheKey);
74-
75-
if (cached) {
76-
return UnifiedCache.createResponse(cached, 'API_STANDARD');
77-
}
78-
79-
// Fetch from database
71+
// Fetch from database - no caching to prevent stale data
8072
const result = await eventsService.getEvents(filters);
81-
82-
// Cache the result
83-
await UnifiedCache.set(cacheKey, result, 'API_STANDARD');
8473

85-
return UnifiedCache.createResponse(result, 'API_STANDARD');
74+
// Return with no-cache headers to prevent stale data
75+
return UnifiedCache.createResponse(result, 'USER_PRIVATE');
8676

8777
} catch (error) {
8878
console.error('Error in GET /api/events:', error);

app/api/hackathons/route.ts

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,17 @@ export async function GET(request: NextRequest) {
6666
offset: searchParams.get('offset') ? parseInt(searchParams.get('offset')!) : undefined,
6767
};
6868

69-
// Create cache key based on filters
70-
const cacheKey = `hackathons-${JSON.stringify(filters)}`;
71-
72-
// Use unified cache system with DYNAMIC_CONTENT strategy for fast updates
73-
const result = await UnifiedCache.cachedQuery(
74-
cacheKey,
75-
async () => {
76-
// Add timeout to prevent hanging requests
77-
const timeoutPromise = new Promise<never>((_, reject) => {
78-
setTimeout(() => reject(new Error('Request timeout')), 8000);
79-
});
80-
81-
const resultPromise = hackathonsService.getHackathons(filters);
82-
return await Promise.race([resultPromise, timeoutPromise]);
83-
},
84-
'DYNAMIC_CONTENT' // Use dynamic content strategy for hackathons
85-
);
69+
// Fetch from database - no caching to prevent stale data
70+
// Add timeout to prevent hanging requests
71+
const timeoutPromise = new Promise<never>((_, reject) => {
72+
setTimeout(() => reject(new Error('Request timeout')), 8000);
73+
});
74+
75+
const resultPromise = hackathonsService.getHackathons(filters);
76+
const result = await Promise.race([resultPromise, timeoutPromise]);
8677

87-
return UnifiedCache.createResponse(result, 'DYNAMIC_CONTENT');
78+
// Return with no-cache headers to prevent stale data
79+
return UnifiedCache.createResponse(result, 'USER_PRIVATE');
8880

8981
} catch (error) {
9082
console.error('Error in GET /api/hackathons:', error);

app/api/leaderboard/route.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,11 @@ export async function GET(request: NextRequest) {
2121
const timeRange = searchParams.get('timeRange') || 'all';
2222
const badge = searchParams.get('badge') || null;
2323

24-
// Create cache key based on parameters
25-
const cacheKey = `leaderboard-${page}-${limit}-${timeRange}-${badge || 'all'}`;
26-
27-
// Use unified cache system
28-
const data = await UnifiedCache.cachedQuery(
29-
cacheKey,
30-
async () => {
31-
return await fetchLeaderboardData(page, limit, timeRange, badge);
32-
},
33-
'API_STANDARD'
34-
);
24+
// Fetch from database - no caching to prevent stale data
25+
const data = await fetchLeaderboardData(page, limit, timeRange, badge);
3526

36-
return UnifiedCache.createResponse(data, 'API_STANDARD');
27+
// Return with no-cache headers to prevent stale data
28+
return UnifiedCache.createResponse(data, 'USER_PRIVATE');
3729

3830
} catch (error) {
3931
console.error('Leaderboard API error:', error);

next.config.ts

Lines changed: 14 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,6 @@ const nextConfig: NextConfig = {
131131
key: 'Vary',
132132
value: 'Accept-Encoding',
133133
},
134-
{
135-
key: 'Cache-Tag',
136-
value: 'static',
137-
},
138134
],
139135
},
140136

@@ -152,86 +148,32 @@ const nextConfig: NextConfig = {
152148
key: 'CDN-Cache-Control',
153149
value: isProd ? 'public, max-age=2592000, immutable' : 'no-cache',
154150
},
155-
{
156-
key: 'Cache-Tag',
157-
value: 'media',
158-
},
159151
],
160152
},
161153

162-
// HOMEPAGE: No caching to ensure auth state is always fresh
154+
// ALL DYNAMIC PAGES: No caching to prevent stale data
163155
{
164-
source: '/',
156+
source: '/((?!_next|api).*)',
165157
headers: [
166158
{
167159
key: 'Cache-Control',
168-
value: 'no-cache, no-store, must-revalidate',
160+
value: 'no-cache, no-store, must-revalidate, max-age=0',
169161
},
170162
{
171163
key: 'CDN-Cache-Control',
172-
value: 'no-cache',
164+
value: 'no-cache, no-store, must-revalidate',
173165
},
174166
{
175167
key: 'Pragma',
176168
value: 'no-cache',
177169
},
178170
{
179-
key: 'Vary',
180-
value: 'Cookie, Accept-Encoding',
181-
},
182-
{
183-
key: 'X-Build-ID',
184-
value: buildId,
185-
},
186-
],
187-
},
188-
189-
// DYNAMIC CONTENT: Dynamic pages (events, hackathons, etc.)
190-
{
191-
source: '/(hackathons|events|leaderboard|opportunities)/:path*',
192-
headers: [
193-
{
194-
key: 'Cache-Control',
195-
value: isDev
196-
? 'no-cache, no-store, must-revalidate'
197-
: 'public, max-age=60, stale-while-revalidate=300', // 1min cache, 5min SWR
198-
},
199-
{
200-
key: 'CDN-Cache-Control',
201-
value: isProd ? 'public, max-age=60, stale-while-revalidate=300' : 'no-cache',
202-
},
203-
{
204-
key: 'X-Build-ID',
205-
value: buildId,
206-
},
207-
{
208-
key: 'Cache-Tag',
209-
value: 'content',
171+
key: 'Expires',
172+
value: '0',
210173
},
211174
{
212175
key: 'Vary',
213-
value: 'Cookie, Accept-Encoding',
214-
},
215-
],
216-
},
217-
218-
// DATABASE QUERIES: API routes that query database
219-
{
220-
source: '/api/(hackathons|leaderboard|tests|verify-certificate)/:path*',
221-
headers: [
222-
{
223-
key: 'Cache-Control',
224-
value: isDev
225-
? 'no-cache, no-store, must-revalidate'
226-
: 'public, max-age=300, stale-while-revalidate=600', // 5min cache, 10min SWR
227-
},
228-
{
229-
key: 'CDN-Cache-Control',
230-
value: isProd ? 'public, max-age=300, stale-while-revalidate=600' : 'no-cache',
231-
},
232-
{
233-
key: 'Cache-Tag',
234-
value: 'api',
176+
value: 'Cookie, Accept-Encoding, Authorization',
235177
},
236178
{
237179
key: 'X-Build-ID',
@@ -240,56 +182,30 @@ const nextConfig: NextConfig = {
240182
],
241183
},
242184

243-
// USER PRIVATE: Auth and user-specific routes
185+
// API ROUTES: No caching for dynamic data
244186
{
245-
source: '/(protected|admin|profile|dashboard|auth)/:path*',
187+
source: '/api/:path*',
246188
headers: [
247189
{
248190
key: 'Cache-Control',
249-
value: 'private, no-cache, no-store, must-revalidate',
191+
value: 'no-cache, no-store, must-revalidate, max-age=0',
250192
},
251193
{
252194
key: 'CDN-Cache-Control',
253-
value: 'no-cache',
195+
value: 'no-cache, no-store, must-revalidate',
254196
},
255197
{
256198
key: 'Pragma',
257199
value: 'no-cache',
258200
},
259-
],
260-
},
261-
262-
// API STANDARD: General API routes and public pages
263-
{
264-
source: '/((?!_next|protected|admin|profile|dashboard|auth).*)',
265-
headers: [
266-
{
267-
key: 'Cache-Control',
268-
value: isDev
269-
? 'no-cache, no-store, must-revalidate'
270-
: 'public, max-age=0, must-revalidate', // Always revalidate HTML
271-
},
272-
{
273-
key: 'CDN-Cache-Control',
274-
value: isProd ? 'public, max-age=60, stale-while-revalidate=300' : 'no-cache',
275-
},
276201
{
277-
key: 'Cache-Tag',
278-
value: 'pages',
279-
},
280-
{
281-
key: 'X-Build-ID',
282-
value: buildId,
202+
key: 'Expires',
203+
value: '0',
283204
},
284205
{
285206
key: 'Vary',
286-
value: 'Cookie, Accept-Encoding',
207+
value: 'Cookie, Accept-Encoding, Authorization',
287208
},
288-
// Security headers
289-
{ key: 'X-Content-Type-Options', value: 'nosniff' },
290-
{ key: 'X-Frame-Options', value: 'DENY' },
291-
{ key: 'X-XSS-Protection', value: '1; mode=block' },
292-
{ key: 'Referrer-Policy', value: 'origin-when-cross-origin' },
293209
],
294210
},
295211
]

vercel.json

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,7 @@
2525
"headers": [
2626
{
2727
"key": "Cache-Control",
28-
"value": "public, max-age=2592000, immutable"
29-
}
30-
]
31-
},
32-
{
33-
"source": "/cache-manifest.json",
34-
"headers": [
35-
{
36-
"key": "Cache-Control",
37-
"value": "public, max-age=0, must-revalidate"
28+
"value": "public, max-age=31536000, immutable"
3829
}
3930
]
4031
},

0 commit comments

Comments
 (0)