sync: SEO canonical URLs, curation improvements, batch scripts, stats fix

- Dynamic canonical URLs and alternates for all pages (SEO fix)
- Shared seo.ts utility for canonical path generation
- Improved duplicate detection: standalone > aggregator priority, forks/created_at tie-breakers
- browseReadyFilter now includes unique aggregator skills
- Stats aligned with browseReadyFilter (was showing 16k instead of 62k+)
- Re-review mechanism: content_hash changes trigger needs-re-review
- review_status field added to skills schema
- Batch security scan and quality score scripts
- Indexer Dockerfile updated for curation deps
- Removed roadmap from README

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
airano
2026-02-21 23:40:03 +03:30
parent 77917bf91f
commit 3f599a23fb
30 changed files with 1092 additions and 50 deletions

View File

@@ -1,17 +1,8 @@
import type { MetadataRoute } from 'next';
import { createDb, skillQueries, categoryQueries } from '@skillhub/db';
const BASE_URL =
process.env.NEXT_PUBLIC_APP_URL || 'https://skills.palebluedot.live';
import { getCanonicalPath, primaryDomain as BASE_URL } from '@/lib/seo';
const locales = ['en', 'fa'] as const;
const DEFAULT_LOCALE = 'en';
/** Get canonical URL path for a locale (no prefix for default locale, matching localePrefix: 'as-needed') */
function canonicalPath(locale: string, route: string): string {
if (locale === DEFAULT_LOCALE) return route || '/';
return `/${locale}${route}`;
}
const staticRoutes = [
'',
@@ -43,13 +34,13 @@ function makeEntry(
}
): MetadataRoute.Sitemap[number] {
return {
url: `${BASE_URL}${canonicalPath(locale, route)}`,
url: `${BASE_URL}${getCanonicalPath(locale, route)}`,
lastModified: options?.lastModified,
changeFrequency: options?.changeFrequency,
priority: options?.priority,
alternates: {
languages: Object.fromEntries(
locales.map((l) => [l, `${BASE_URL}${canonicalPath(l, route)}`])
locales.map((l) => [l, `${BASE_URL}${getCanonicalPath(l, route)}`])
),
},
};