feat: auto-update sitemap when events are added/updated/removed

- Use tag-based cache for sitemap event list (events-sitemap)
- Add POST /api/revalidate endpoint (secret-protected) to trigger revalidation
- Backend calls revalidation after event create/update/delete
- Add REVALIDATE_SECRET to .env.example (frontend + backend)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Michilis
2026-02-12 03:51:00 +00:00
parent 74464b0a7a
commit af94c99fd2
5 changed files with 67 additions and 1 deletions

View File

@@ -21,6 +21,10 @@ NEXT_PUBLIC_EMAIL=hola@spanglish.com.py
NEXT_PUBLIC_TELEGRAM=spanglish_py
NEXT_PUBLIC_TIKTOK=spanglishsocialpy
# Revalidation secret (shared between frontend and backend for on-demand cache revalidation)
# Must match the REVALIDATE_SECRET in backend/.env
REVALIDATE_SECRET=change-me-to-a-random-secret
# Plausible Analytics (optional - leave empty to disable tracking)
NEXT_PUBLIC_PLAUSIBLE_URL=https://analytics.azzamo.net
NEXT_PUBLIC_PLAUSIBLE_DOMAIN=spanglishcommunity.com

View File

@@ -0,0 +1,27 @@
import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { secret, tag } = body;
// Validate the revalidation secret
const revalidateSecret = process.env.REVALIDATE_SECRET;
if (!revalidateSecret || secret !== revalidateSecret) {
return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });
}
// Validate tag
const allowedTags = ['events-sitemap'];
if (!tag || !allowedTags.includes(tag)) {
return NextResponse.json({ error: 'Invalid tag' }, { status: 400 });
}
revalidateTag(tag);
return NextResponse.json({ revalidated: true, tag, now: Date.now() });
} catch {
return NextResponse.json({ error: 'Failed to revalidate' }, { status: 500 });
}
}

View File

@@ -12,7 +12,7 @@ interface Event {
async function getPublishedEvents(): Promise<Event[]> {
try {
const response = await fetch(`${apiUrl}/api/events?status=published`, {
next: { revalidate: 3600 }, // Cache for 1 hour
next: { tags: ['events-sitemap'] },
});
if (!response.ok) return [];
const data = await response.json();