fix: resolve project 404s with Directus fallback and upgrade 404 page
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Has been cancelled

Merged Directus and PostgreSQL project data, implemented single project fetch from CMS, and modernized the NotFound component with liquid design.
This commit is contained in:
2026-02-15 22:47:25 +01:00
parent 6998a0e7a1
commit cc8fff14d2
7 changed files with 370 additions and 237 deletions

View File

@@ -47,8 +47,9 @@ export async function GET(request: NextRequest) {
const locale = searchParams.get('locale') || 'en';
// Try Directus FIRST (Primary Source)
let directusProjects: any[] = [];
try {
const directusProjects = await getDirectusProjects(locale, {
const fetched = await getDirectusProjects(locale, {
featured: featured === 'true' ? true : featured === 'false' ? false : undefined,
published: published === 'true' ? true : published === 'false' ? false : undefined,
category: category || undefined,
@@ -57,54 +58,34 @@ export async function GET(request: NextRequest) {
limit
});
if (directusProjects && directusProjects.length > 0) {
return NextResponse.json({
projects: directusProjects,
total: directusProjects.length,
page: 1,
limit: directusProjects.length,
source: 'directus'
});
if (fetched) {
directusProjects = fetched;
}
} catch (directusError) {
console.log('Directus not available, trying PostgreSQL fallback');
console.log('Directus error, continuing with PostgreSQL');
}
// Fallback 1: Try PostgreSQL
try {
await prisma.$queryRaw`SELECT 1`;
} catch (dbError) {
console.log('PostgreSQL also not available, using empty fallback');
console.log('PostgreSQL not available');
if (directusProjects.length > 0) {
return NextResponse.json({
projects: directusProjects,
total: directusProjects.length,
source: 'directus'
});
}
// Fallback 2: Return empty (components should have hardcoded fallback)
return NextResponse.json({
projects: [],
total: 0,
page: 1,
limit,
source: 'fallback'
});
}
// Create cache parameters object
const cacheParams = {
page: page.toString(),
limit: limit.toString(),
category,
featured,
published,
difficulty,
search
};
// Check cache first
const cached = await apiCache.getProjects(cacheParams);
if (cached && !search) { // Don't cache search results
return NextResponse.json(cached);
}
const skip = (page - 1) * limit;
const where: Record<string, unknown> = {};
if (category) where.category = category;
@@ -116,12 +97,11 @@ export async function GET(request: NextRequest) {
where.OR = [
{ title: { contains: search, mode: 'insensitive' } },
{ description: { contains: search, mode: 'insensitive' } },
{ tags: { hasSome: [search] } },
{ content: { contains: search, mode: 'insensitive' } }
{ tags: { hasSome: [search] } }
];
}
const [projects, total] = await Promise.all([
const [dbProjects, total] = await Promise.all([
prisma.project.findMany({
where,
orderBy: { createdAt: 'desc' },
@@ -131,20 +111,21 @@ export async function GET(request: NextRequest) {
prisma.project.count({ where })
]);
const result = {
projects,
total,
pages: Math.ceil(total / limit),
currentPage: page,
source: 'postgresql'
};
// Cache the result (only for non-search queries)
if (!search) {
await apiCache.setProjects(cacheParams, result);
// Merge logic
const dbSlugs = new Set(dbProjects.map(p => p.slug));
const mergedProjects = [...dbProjects];
for (const dp of directusProjects) {
if (!dbSlugs.has(dp.slug)) {
mergedProjects.push(dp);
}
}
return NextResponse.json(result);
return NextResponse.json({
projects: mergedProjects,
total: total + (mergedProjects.length - dbProjects.length),
source: 'merged'
});
} catch (error) {
// Handle missing database table gracefully
if (error instanceof PrismaClientKnownRequestError && error.code === 'P2021') {