feat(Sitemap, SEO): update sitemap generation and SEO configurations
- Enhanced update-sitemap.sh to generate a new sitemap structure with lastmod dates for additional URLs. - Updated SEO configurations in server.js and seo.js to allow indexing for impressum and datenschutz pages. - Introduced a list of noindex prefixes to manage SEO settings dynamically based on route paths. - Added structured FAQ schema in index.html to improve search engine visibility and user engagement.
This commit is contained in:
@@ -111,15 +111,38 @@ const SEO_ROUTE_CONFIG = {
|
||||
'/impressum': {
|
||||
title: 'Impressum | Trainingstagebuch',
|
||||
description: 'Impressum von Trainingstagebuch.',
|
||||
robots: 'noindex,follow',
|
||||
robots: 'index,follow',
|
||||
},
|
||||
'/datenschutz': {
|
||||
title: 'Datenschutzerklärung | Trainingstagebuch',
|
||||
description: 'Datenschutzerklärung von Trainingstagebuch.',
|
||||
robots: 'noindex,follow',
|
||||
robots: 'index,follow',
|
||||
},
|
||||
};
|
||||
|
||||
const SEO_NOINDEX_PREFIXES = [
|
||||
'/createclub',
|
||||
'/showclub',
|
||||
'/members',
|
||||
'/diary',
|
||||
'/pending-approvals',
|
||||
'/schedule',
|
||||
'/tournaments',
|
||||
'/tournament-participations',
|
||||
'/training-stats',
|
||||
'/club-settings',
|
||||
'/predefined-activities',
|
||||
'/mytischtennis-account',
|
||||
'/clicktt-account',
|
||||
'/team-management',
|
||||
'/permissions',
|
||||
'/logs',
|
||||
'/clicktt',
|
||||
'/member-transfer-settings',
|
||||
'/personal-settings',
|
||||
'/orders',
|
||||
];
|
||||
|
||||
function normalizeSeoPath(pathname = '/') {
|
||||
if (!pathname || pathname === '') return '/';
|
||||
if (pathname === '/') return '/';
|
||||
@@ -132,9 +155,16 @@ function getSeoConfigForPath(pathname = '/') {
|
||||
.filter((routePath) => routePath !== '/' && normalizedPath.startsWith(routePath))
|
||||
.sort((a, b) => b.length - a.length)[0];
|
||||
|
||||
return (matchedPrefix && SEO_ROUTE_CONFIG[matchedPrefix])
|
||||
|| SEO_ROUTE_CONFIG[normalizedPath]
|
||||
|| { ...SEO_DEFAULTS, robots: 'noindex,follow' };
|
||||
const configuredSeo = (matchedPrefix && SEO_ROUTE_CONFIG[matchedPrefix]) || SEO_ROUTE_CONFIG[normalizedPath];
|
||||
if (configuredSeo) {
|
||||
return configuredSeo;
|
||||
}
|
||||
|
||||
const shouldNoindex = SEO_NOINDEX_PREFIXES.some((routePath) => normalizedPath.startsWith(routePath));
|
||||
return {
|
||||
...SEO_DEFAULTS,
|
||||
robots: shouldNoindex ? 'noindex,follow' : SEO_DEFAULTS.robots
|
||||
};
|
||||
}
|
||||
|
||||
function escapeHtmlAttribute(value = '') {
|
||||
|
||||
@@ -72,6 +72,54 @@
|
||||
"url": "https://tt-tagebuch.de/"
|
||||
}
|
||||
</script>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Ist die Nutzung kostenlos?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Ja, du kannst kostenlos starten. Erweiterungen können später folgen."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Wie steht es um den Datenschutz?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Wir setzen auf Datensparsamkeit, transparente Freigaben, rollenbasierte Zugriffe und vollständiges Aktivitätsprotokoll. Die Anwendung ist DSGVO-konform."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Benötige ich eine Installation?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Nein, es handelt sich um eine Web-Anwendung. Du nutzt sie direkt im Browser auf Desktop, Tablet und Smartphone."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Welche Turnierarten werden unterstützt?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Du kannst interne Turniere, offene Turniere und offizielle Turniere verwalten. Offizielle Turniere können importiert werden."
|
||||
}
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Funktioniert die MyTischtennis-Integration automatisch?",
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": "Ja, nach der Einrichtung synchronisiert sich die Anwendung automatisch mit MyTischtennis.de und importiert Spielergebnisse und Statistiken."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -5,8 +5,20 @@
|
||||
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||
<url>
|
||||
<loc>https://tt-tagebuch.de/</loc>
|
||||
<lastmod>2026-03-18</lastmod>
|
||||
<lastmod>2026-03-27</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://tt-tagebuch.de/impressum</loc>
|
||||
<lastmod>2026-03-27</lastmod>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://tt-tagebuch.de/datenschutz</loc>
|
||||
<lastmod>2026-03-27</lastmod>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
|
||||
@@ -42,15 +42,38 @@ const ROUTE_SEO = {
|
||||
'/impressum': {
|
||||
title: 'Impressum | Trainingstagebuch',
|
||||
description: 'Impressum von Trainingstagebuch.',
|
||||
robots: 'noindex,follow'
|
||||
robots: 'index,follow'
|
||||
},
|
||||
'/datenschutz': {
|
||||
title: 'Datenschutzerklärung | Trainingstagebuch',
|
||||
description: 'Datenschutzerklärung von Trainingstagebuch.',
|
||||
robots: 'noindex,follow'
|
||||
robots: 'index,follow'
|
||||
}
|
||||
};
|
||||
|
||||
const NOINDEX_PREFIXES = [
|
||||
'/createclub',
|
||||
'/showclub',
|
||||
'/members',
|
||||
'/diary',
|
||||
'/pending-approvals',
|
||||
'/schedule',
|
||||
'/tournaments',
|
||||
'/tournament-participations',
|
||||
'/training-stats',
|
||||
'/club-settings',
|
||||
'/predefined-activities',
|
||||
'/mytischtennis-account',
|
||||
'/clicktt-account',
|
||||
'/team-management',
|
||||
'/permissions',
|
||||
'/logs',
|
||||
'/clicktt',
|
||||
'/member-transfer-settings',
|
||||
'/personal-settings',
|
||||
'/orders'
|
||||
];
|
||||
|
||||
function normalizePath(path = '/') {
|
||||
if (!path || path === '') return '/';
|
||||
if (path === '/') return '/';
|
||||
@@ -63,13 +86,18 @@ export function getSeoConfigForPath(path) {
|
||||
.filter((routePath) => routePath !== '/' && normalizedPath.startsWith(routePath))
|
||||
.sort((a, b) => b.length - a.length)[0];
|
||||
|
||||
const routeSeo = (matchedPrefix && ROUTE_SEO[matchedPrefix]) || ROUTE_SEO[normalizedPath] || DEFAULT_SEO;
|
||||
const routeSeo = (matchedPrefix && ROUTE_SEO[matchedPrefix]) || ROUTE_SEO[normalizedPath];
|
||||
const canonicalPath = normalizedPath === '/' ? '' : normalizedPath;
|
||||
const shouldNoindex = !routeSeo && NOINDEX_PREFIXES.some((routePath) => normalizedPath.startsWith(routePath));
|
||||
const finalSeo = routeSeo || {
|
||||
...DEFAULT_SEO,
|
||||
robots: shouldNoindex ? 'noindex,follow' : DEFAULT_SEO.robots
|
||||
};
|
||||
|
||||
return {
|
||||
title: routeSeo.title || DEFAULT_SEO.title,
|
||||
description: routeSeo.description || DEFAULT_SEO.description,
|
||||
robots: routeSeo.robots || DEFAULT_SEO.robots,
|
||||
title: finalSeo.title || DEFAULT_SEO.title,
|
||||
description: finalSeo.description || DEFAULT_SEO.description,
|
||||
robots: finalSeo.robots || DEFAULT_SEO.robots,
|
||||
canonical: `${SITE_URL}${canonicalPath}`,
|
||||
url: `${SITE_URL}${canonicalPath}`,
|
||||
image: DEFAULT_IMAGE
|
||||
|
||||
@@ -15,8 +15,38 @@ fi
|
||||
|
||||
echo "Aktualisiere lastmod-Datum auf: $TODAY"
|
||||
|
||||
# Ersetze alle lastmod-Daten mit dem heutigen Datum
|
||||
sed -i "s/<lastmod>.*<\/lastmod>/<lastmod>${TODAY}<\/lastmod>/g" "$SITEMAP_FILE"
|
||||
URLS=(
|
||||
"https://tt-tagebuch.de/"
|
||||
"https://tt-tagebuch.de/impressum"
|
||||
"https://tt-tagebuch.de/datenschutz"
|
||||
)
|
||||
|
||||
cat > "$SITEMAP_FILE" <<EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
|
||||
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||
<url>
|
||||
<loc>${URLS[0]}</loc>
|
||||
<lastmod>${TODAY}</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>${URLS[1]}</loc>
|
||||
<lastmod>${TODAY}</lastmod>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>${URLS[2]}</loc>
|
||||
<lastmod>${TODAY}</lastmod>
|
||||
<changefreq>yearly</changefreq>
|
||||
<priority>0.3</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
EOF
|
||||
|
||||
echo "✓ Sitemap aktualisiert"
|
||||
echo ""
|
||||
@@ -31,4 +61,3 @@ echo " -> URL eingeben: https://tt-tagebuch.de/sitemap.xml"
|
||||
echo ""
|
||||
echo "3. Sitemap testen:"
|
||||
echo " curl https://tt-tagebuch.de/sitemap.xml"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user