This commit is contained in:
Torsten Schulz (notebook)
2026-05-12 10:32:14 +02:00
13 changed files with 890 additions and 62 deletions

View File

@@ -419,8 +419,18 @@ export function setupBroadcast(io, __dirname) {
if (sub === 'today') {
const day = new Date().toISOString().slice(0, 10);
const dayRecords = records.filter((r) => r.day === day);
const uniqueUsersToday = Array.from(new Set(dayRecords.map((r) => r.userName)))
.sort((a, b) => a.localeCompare(b, 'de'));
const latestByUserToday = new Map();
dayRecords
.slice()
.sort((a, b) => b.date - a.date)
.forEach((record) => {
if (!latestByUserToday.has(record.userName)) {
latestByUserToday.set(record.userName, record);
}
});
const uniqueUsersToday = Array.from(latestByUserToday.values())
.sort((a, b) => a.userName.localeCompare(b.userName, 'de'))
.map((r) => `${r.userName} (${r.age})`);
sendCommandTable(socket, 'Statistik: Heute', ['Metrik', 'Wert'], [
['Tag', day],
['Logins', dayRecords.length],
@@ -473,12 +483,12 @@ export function setupBroadcast(io, __dirname) {
sendCommandTable(
socket,
`Statistik: Namen (gesamt verschieden: ${new Set(records.map((r) => r.userName)).size})`,
['Name', 'Anzahl', 'Letzter Login'],
['Name', 'Alter', 'Anzahl', 'Letzter Login'],
topNames.map(([name, count]) => {
const latestRecord = records
.filter((r) => r.userName === name)
.sort((a, b) => b.date - a.date)[0];
return [name, count, latestRecord ? latestRecord.timestamp : '-'];
return [name, latestRecord ? latestRecord.age : '-', count, latestRecord ? latestRecord.timestamp : '-'];
})
);
return;

View File

@@ -174,7 +174,21 @@ setupBroadcast(io, __dirname);
// SPA-Fallback muss nach allen anderen Routen stehen
if (IS_PRODUCTION) {
const distPath = join(__dirname, '../docroot/dist');
const KNOWN_SPA_ROUTES = new Set(['/', '/partners', '/feedback', '/faq', '/regeln', '/sicherheit', '/datenschutz', '/mockup-redesign']);
const KNOWN_SPA_ROUTES = new Set([
'/',
'/partners',
'/feedback',
'/faq',
'/regeln',
'/sicherheit',
'/datenschutz',
'/ratgeber',
'/ratgeber/erste-nachricht',
'/ratgeber/profil-tipps',
'/ratgeber/sicher-chatten',
'/ratgeber/red-flags',
'/mockup-redesign'
]);
app.use(express.static(distPath));
// Fallback für Vue Router (SPA) - muss am Ende stehen
app.get('*', (req, res) => {

View File

@@ -18,7 +18,7 @@ const SEO_LOCALES = [
const LOCALE_SEO_META = {
de: {
title: 'SingleChat: Kostenloser Single Chat, privat & anonym',
description: 'Kostenloser Single Chat für private und anonyme Gespräche. Lerne neue Kontakte kennen und teile Bilder sicher online.',
description: 'Kostenloser Single Chat für private und anonyme Gespräche. Lerne neue Kontakte kennen und teile Bilder sicher online.',
keywords: 'single chat, kostenloser chat, privat chatten, anonym chat, free chat, private chat, anonymous chat, online chat'
},
en: {
@@ -27,14 +27,14 @@ const LOCALE_SEO_META = {
keywords: 'single chat, free chat, private chat, anonymous chat, online chat, meet singles'
},
fr: {
title: 'SingleChat: Chat célibataire gratuit, privé et anonyme',
description: 'Chat célibataire gratuit pour des conversations privées et anonymes. Rencontrez de nouvelles personnes en toute sécurité.',
keywords: 'chat célibataire, chat gratuit, chat privé, chat anonyme, rencontre en ligne'
title: 'SingleChat: Chat célibataire gratuit, privé et anonyme',
description: 'Chat célibataire gratuit pour des conversations privées et anonymes. Rencontrez de nouvelles personnes en toute sécurité.',
keywords: 'chat célibataire, chat gratuit, chat privé, chat anonyme, rencontre en ligne'
},
es: {
title: 'SingleChat: Chat gratis, privado y anónimo',
description: 'Chat gratis para solteros con conversaciones privadas y anónimas. Conoce gente nueva y comparte imágenes de forma segura.',
keywords: 'chat gratis, chat privado, chat anónimo, chat para solteros, conocer gente'
title: 'SingleChat: Chat gratis, privado y anónimo',
description: 'Chat gratis para solteros con conversaciones privadas y anónimas. Conoce gente nueva y comparte imágenes de forma segura.',
keywords: 'chat gratis, chat privado, chat anónimo, chat para solteros, conocer gente'
},
it: {
title: 'SingleChat: Chat single gratis, privata e anonima',
@@ -42,19 +42,19 @@ const LOCALE_SEO_META = {
keywords: 'chat single, chat gratis, chat privata, chat anonima, incontri online'
},
ja: {
title: 'SingleChat: 無料・匿名・プライベートのシングルチャット',
description: '無料で使えるシングルチャット。匿名かつプライベートに会話でき、画像共有も安全です。',
keywords: 'シングルチャット, 無料チャット, 匿名チャット, プライベートチャット, オンラインチャット'
title: 'SingleChat: 無料・匿名・プライベートのシングルチャット',
description: '無料で使えるシングルチャット。匿名かつプライベートに会話でき、画像共有も安全です。',
keywords: 'シングルチャット, 無料チャット, 匿名チャット, プライベートチャット, オンラインチャット'
},
zh: {
title: 'SingleChat:免费、私密、匿名的单身聊天',
description: '免费单身聊天,支持私密和匿名交流,安全分享图片并结识新朋友。',
keywords: '单身聊天, 免费聊天, 私密聊天, 匿名聊天, 在线聊天'
title: 'SingleChat:免费、私密、匿名的单身聊天',
description: '免费单身聊天,支持私密和匿名交流,安全分享图片并结识新朋友。',
keywords: '单身聊天, 免费聊天, 私密聊天, 匿名聊天, 在线聊天'
},
th: {
title: 'SingleChat: แชตคนโสดฟรี แบบส่วนตัวและไม่ระบุตัวตน',
description: 'แชตคนโสดฟรี สำหรับการสนทนาแบบส่วนตัวและไม่ระบุตัวตน พบผู้คนใหม่ ๆ และแชร์รูปได้อย่างปลอดภัย',
keywords: 'แชตคนโสด, แชตฟรี, แชตส่วนตัว, แชตไม่ระบุตัวตน, แชตออนไลน์'
title: 'SingleChat: แชตคนโสดฟรี แบบส่วนตัวและไม่ระบุตัวตน',
description: 'แชตคนโสดฟรี สำหรับการสนทนาแบบส่วนตัวและไม่ระบุตัวตน พบผู้คนใหม่ ๆ และแชร์รูปได้อย่างปลอดภัย',
keywords: 'แชตคนโสด, แชตฟรี, แชตส่วนตัว, แชตไม่ระบุตัวตน, แชตออนไลน์'
},
tl: {
title: 'SingleChat: Libreng private at anonymous na single chat',
@@ -66,7 +66,7 @@ const LOCALE_SEO_META = {
const seoData = {
'/': {
title: 'SingleChat: Kostenloser Single Chat, privat & anonym',
description: 'Kostenloser Single Chat für private und anonyme Gespräche. Lerne neue Kontakte kennen und teile Bilder sicher online.',
description: 'Kostenloser Single Chat für private und anonyme Gespräche. Lerne neue Kontakte kennen und teile Bilder sicher online.',
keywords: 'single chat, kostenloser chat, privat chatten, anonym chat, free chat, private chat, anonymous chat, online chat',
ogTitle: 'SingleChat: Kostenloser Single Chat, privat & anonym',
ogDescription: 'Kostenlos chatten, privat bleiben und neue Kontakte kennenlernen - mit sicherem Bildaustausch.',
@@ -79,15 +79,15 @@ const seoData = {
'@type': 'WebSite',
name: 'SingleChat',
url: `${SITE_URL}/`,
description: 'Kostenloser Single Chat für private und anonyme Gespräche. Lerne neue Kontakte kennen und tausche Bilder sicher aus.',
description: 'Kostenloser Single Chat für private und anonyme Gespräche. Lerne neue Kontakte kennen und tausche Bilder sicher aus.',
inLanguage: 'de-DE'
}
},
'/partners': {
title: 'Partner für Single Chat & Community - SingleChat',
title: 'Partner für Single Chat & Community - SingleChat',
description: 'Partnerseiten rund um Single Chat, Community und Online-Kontakte. Entdecke weitere Angebote und hilfreiche Ressourcen.',
keywords: 'single chat partner, chat community, kontaktseiten, single-chat links, online dating chat',
ogTitle: 'Partner für Single Chat & Community - SingleChat',
ogTitle: 'Partner für Single Chat & Community - SingleChat',
ogDescription: 'Befreundete Seiten und Ressourcen rund um Chat, Kontakte und Community.',
ogType: 'website',
ogUrl: `${SITE_URL}/partners`,
@@ -109,10 +109,10 @@ const seoData = {
},
'/feedback': {
title: 'Feedback zur Chat-Plattform - SingleChat',
description: 'Öffentliches Feedback zu SingleChat: Meinungen, Vorschläge und Erfahrungsberichte für einen besseren privaten Chat.',
keywords: 'chat feedback, single chat erfahrungen, rückmeldung chat, verbesserungsvorschläge',
description: 'Öffentliches Feedback zu SingleChat: Meinungen, Vorschläge und Erfahrungsberichte für einen besseren privaten Chat.',
keywords: 'chat feedback, single chat erfahrungen, rückmeldung chat, verbesserungsvorschläge',
ogTitle: 'Feedback zur Chat-Plattform - SingleChat',
ogDescription: 'Teile deine Erfahrungen und Verbesserungsvorschläge für SingleChat.',
ogDescription: 'Teile deine Erfahrungen und Verbesserungsvorschläge für SingleChat.',
ogType: 'website',
ogUrl: `${SITE_URL}/feedback`,
ogImage: DEFAULT_IMAGE,
@@ -122,7 +122,7 @@ const seoData = {
'@type': 'CollectionPage',
name: 'Feedback - SingleChat',
url: `${SITE_URL}/feedback`,
description: 'Öffentliches Feedback zu SingleChat: Meinungen, Vorschläge und Erfahrungsberichte für einen besseren privaten Chat.',
description: 'Öffentliches Feedback zu SingleChat: Meinungen, Vorschläge und Erfahrungsberichte für einen besseren privaten Chat.',
isPartOf: {
'@type': 'WebSite',
name: 'SingleChat',
@@ -133,10 +133,10 @@ const seoData = {
},
'/faq': {
title: 'FAQ: Kostenlos, privat und anonym chatten - SingleChat',
description: 'FAQ zum kostenlosen Single Chat: anonym chatten, Privatsphäre schützen, Bilder sicher teilen und Nutzer blockieren.',
description: 'FAQ zum kostenlosen Single Chat: anonym chatten, Privatsphäre schützen, Bilder sicher teilen und Nutzer blockieren.',
keywords: 'single chat faq, kostenlos chatten, anonym chatten, privater chat, safe chat',
ogTitle: 'FAQ: Kostenlos, privat und anonym chatten - SingleChat',
ogDescription: 'Antworten auf Fragen zu Sicherheit, Privatsphäre und Funktionen im Single Chat.',
ogDescription: 'Antworten auf Fragen zu Sicherheit, Privatsphäre und Funktionen im Single Chat.',
ogType: 'website',
ogUrl: `${SITE_URL}/faq`,
ogImage: DEFAULT_IMAGE,
@@ -146,7 +146,7 @@ const seoData = {
'@type': 'FAQPage',
name: 'FAQ - SingleChat',
url: `${SITE_URL}/faq`,
description: 'FAQ zum kostenlosen Single Chat: anonym chatten, Privatsphäre schützen, Bilder sicher teilen und Nutzer blockieren.',
description: 'FAQ zum kostenlosen Single Chat: anonym chatten, Privatsphäre schützen, Bilder sicher teilen und Nutzer blockieren.',
isPartOf: {
'@type': 'WebSite',
name: 'SingleChat',
@@ -156,11 +156,11 @@ const seoData = {
}
},
'/regeln': {
title: 'Chat-Regeln für sicheren Single Chat - SingleChat',
description: 'Regeln für respektvollen, privaten und sicheren Single Chat. Hinweise zu Verhalten, Spam und verbotenen Inhalten.',
title: 'Chat-Regeln für sicheren Single Chat - SingleChat',
description: 'Regeln für respektvollen, privaten und sicheren Single Chat. Hinweise zu Verhalten, Spam und verbotenen Inhalten.',
keywords: 'chat regeln, single chat regeln, sicher chatten, spam vermeiden, community richtlinien',
ogTitle: 'Chat-Regeln für sicheren Single Chat - SingleChat',
ogDescription: 'Unsere Richtlinien für respektvolle und sichere Gespräche im Chat.',
ogTitle: 'Chat-Regeln für sicheren Single Chat - SingleChat',
ogDescription: 'Unsere Richtlinien für respektvolle und sichere Gespräche im Chat.',
ogType: 'website',
ogUrl: `${SITE_URL}/regeln`,
ogImage: DEFAULT_IMAGE,
@@ -170,7 +170,7 @@ const seoData = {
'@type': 'WebPage',
name: 'Regeln - SingleChat',
url: `${SITE_URL}/regeln`,
description: 'Regeln für respektvollen, privaten und sicheren Single Chat. Hinweise zu Verhalten, Spam und verbotenen Inhalten.',
description: 'Regeln für respektvollen, privaten und sicheren Single Chat. Hinweise zu Verhalten, Spam und verbotenen Inhalten.',
isPartOf: {
'@type': 'WebSite',
name: 'SingleChat',
@@ -180,11 +180,11 @@ const seoData = {
}
},
'/sicherheit': {
title: 'Sicherheit & Privatsphäre im privaten Chat - SingleChat',
description: 'Sicherheitsseite für privaten und anonymen Chat: Privatsphäre, Schutz vor Spam, Blockieren und Melden.',
keywords: 'privatsphäre chat, anonym chat sicherheit, blockieren melden, private chat safety',
ogTitle: 'Sicherheit & Privatsphäre im privaten Chat - SingleChat',
ogDescription: 'So schützt du deine Daten und chattest sicher und anonym.',
title: 'Sicherheit & Privatsphäre im privaten Chat - SingleChat',
description: 'Sicherheitsseite für privaten und anonymen Chat: Privatsphäre, Schutz vor Spam, Blockieren und Melden.',
keywords: 'privatsphäre chat, anonym chat sicherheit, blockieren melden, private chat safety',
ogTitle: 'Sicherheit & Privatsphäre im privaten Chat - SingleChat',
ogDescription: 'So schützt du deine Daten und chattest sicher und anonym.',
ogType: 'website',
ogUrl: `${SITE_URL}/sicherheit`,
ogImage: DEFAULT_IMAGE,
@@ -192,9 +192,9 @@ const seoData = {
schema: {
'@context': 'https://schema.org',
'@type': 'WebPage',
name: 'Sicherheit & Privatsphäre - SingleChat',
name: 'Sicherheit & Privatsphäre - SingleChat',
url: `${SITE_URL}/sicherheit`,
description: 'Sicherheitsseite für privaten und anonymen Chat: Privatsphäre, Schutz vor Spam, Blockieren und Melden.',
description: 'Sicherheitsseite für privaten und anonymen Chat: Privatsphäre, Schutz vor Spam, Blockieren und Melden.',
isPartOf: {
'@type': 'WebSite',
name: 'SingleChat',
@@ -204,10 +204,10 @@ const seoData = {
}
},
'/datenschutz': {
title: 'Datenschutzerklärung für Website und App - SingleChat',
description: 'Datenschutzerklärung für SingleChat und die Android-App mit Informationen zu Profilangaben, Nachrichten, Bildern und Sitzungsdaten.',
title: 'Datenschutzerklärung für Website und App - SingleChat',
description: 'Datenschutzerklärung für SingleChat und die Android-App mit Informationen zu Profilangaben, Nachrichten, Bildern und Sitzungsdaten.',
keywords: 'datenschutz singlechat, privacy policy chat app, chat datenschutz, android app datenschutz',
ogTitle: 'Datenschutzerklärung für Website und App - SingleChat',
ogTitle: 'Datenschutzerklärung für Website und App - SingleChat',
ogDescription: 'Informationen zur Datenverarbeitung bei SingleChat und in der Android-App.',
ogType: 'website',
ogUrl: `${SITE_URL}/datenschutz`,
@@ -218,7 +218,7 @@ const seoData = {
'@type': 'WebPage',
name: 'Datenschutz - SingleChat',
url: `${SITE_URL}/datenschutz`,
description: 'Datenschutzerklärung für SingleChat und die Android-App mit Informationen zu Profilangaben, Nachrichten, Bildern und Sitzungsdaten.',
description: 'Datenschutzerklärung für SingleChat und die Android-App mit Informationen zu Profilangaben, Nachrichten, Bildern und Sitzungsdaten.',
isPartOf: {
'@type': 'WebSite',
name: 'SingleChat',
@@ -226,6 +226,73 @@ const seoData = {
},
inLanguage: 'de-DE'
}
},
'/ratgeber': {
title: 'Ratgeber fuer privaten Single Chat - SingleChat',
description: 'Praxisnahe Ratgeberartikel zu Chat-Einstieg, Profiloptimierung, Sicherheit und Red Flags im Online-Chat.',
keywords: 'chat ratgeber, single chat tipps, profil tipps, sicher chatten, online chat red flags',
ogTitle: 'Ratgeber fuer privaten Single Chat - SingleChat',
ogDescription: 'Hilfreiche Leitfaeden fuer bessere Gespraeche und mehr Sicherheit im Chat.',
ogType: 'website',
ogUrl: `${SITE_URL}/ratgeber`,
ogImage: DEFAULT_IMAGE,
robots: 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1',
schema: {
'@context': 'https://schema.org',
'@type': 'CollectionPage',
name: 'Ratgeber - SingleChat',
url: `${SITE_URL}/ratgeber`,
description: 'Ratgeber mit Tipps zu erster Nachricht, Profilgestaltung, Datenschutz und sicheren Gespraechen im Single Chat.',
inLanguage: 'de-DE'
}
},
'/ratgeber/erste-nachricht': {
title: 'Die erste Nachricht im Chat - Tipps & Beispiele',
description: 'So gelingt die erste Nachricht im Single Chat: konkrete Beispiele, typische Fehler und einfache Vorlagen.',
keywords: 'erste nachricht chat, anschreiben tipps, chat beispiele, single chat einstieg',
ogTitle: 'Die erste Nachricht im Chat - Tipps & Beispiele',
ogDescription: 'Konkrete Beispiele fuer einen natuerlichen und respektvollen Chat-Einstieg.',
ogType: 'article',
ogUrl: `${SITE_URL}/ratgeber/erste-nachricht`,
ogImage: DEFAULT_IMAGE,
robots: 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1',
schema: null
},
'/ratgeber/profil-tipps': {
title: 'Profil verbessern fuer bessere Chats - SingleChat',
description: 'Verbessere dein Chat-Profil mit klaren, ehrlichen Angaben und starte leichter passende Gespraeche.',
keywords: 'profil tipps chat, online profil verbessern, single chat profil',
ogTitle: 'Profil verbessern fuer bessere Chats - SingleChat',
ogDescription: 'Einfache Schritte fuer ein besseres Profil und passendere Unterhaltungen.',
ogType: 'article',
ogUrl: `${SITE_URL}/ratgeber/profil-tipps`,
ogImage: DEFAULT_IMAGE,
robots: 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1',
schema: null
},
'/ratgeber/sicher-chatten': {
title: 'Sicher chatten und Daten schuetzen - SingleChat',
description: 'Datenschutz-Tipps fuer anonymes Chatten: Welche Informationen du teilen kannst und welche nicht.',
keywords: 'sicher chatten, datenschutz chat, anonym chat tipps',
ogTitle: 'Sicher chatten und Daten schuetzen - SingleChat',
ogDescription: 'Praktische Regeln fuer mehr Sicherheit und Privatsphaere im Online-Chat.',
ogType: 'article',
ogUrl: `${SITE_URL}/ratgeber/sicher-chatten`,
ogImage: DEFAULT_IMAGE,
robots: 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1',
schema: null
},
'/ratgeber/red-flags': {
title: 'Red Flags im Online-Chat erkennen - SingleChat',
description: 'Warnzeichen bei Spam und Manipulation im Chat erkennen und richtig reagieren.',
keywords: 'red flags chat, online chat sicherheit, betrug chat erkennen',
ogTitle: 'Red Flags im Online-Chat erkennen - SingleChat',
ogDescription: 'Fruehe Warnsignale im Chat erkennen und sich wirksam schuetzen.',
ogType: 'article',
ogUrl: `${SITE_URL}/ratgeber/red-flags`,
ogImage: DEFAULT_IMAGE,
robots: 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1',
schema: null
}
};
@@ -415,7 +482,7 @@ function generateHTML(route, meta, __dirname) {
const feedbackMarkup = feedbackItems.length > 0
? feedbackItems.map((item) => {
const metaLine = [item.country, item.age, item.gender].filter(Boolean).join(' · ');
const metaLine = [item.country, item.age, item.gender].filter(Boolean).join(' · ');
return `<article style="border:1px solid #d7dfd9;border-radius:12px;padding:14px 16px;margin-bottom:12px;background:#fff;">
<strong style="display:block;color:#18201b;">${escapeHtml(item.name || 'Anonym')}</strong>
${metaLine ? `<div style="font-size:12px;color:#637067;margin-top:4px;">${escapeHtml(metaLine)}</div>` : ''}
@@ -447,7 +514,7 @@ export function setupSEORoutes(app, __dirname) {
app.get(route, (req, res) => {
const html = generateHTML(route, meta, __dirname);
if (html) {
// Zusätzliches kanonisches Signal (neben link rel= im HTML) hilft Google bei der Zuordnung.
// Zusätzliches kanonisches Signal (neben link rel= im HTML) – hilft Google bei der Zuordnung.
res.set('Link', `<${meta.ogUrl}>; rel="canonical"`);
res.send(html);
return;
@@ -460,7 +527,7 @@ export function setupSEORoutes(app, __dirname) {
}
console.error('FEHLER: Gebaute index.html nicht gefunden:', distIndexPath);
res.status(500).send('Gebaute index.html nicht gefunden. Bitte führe "npm run build" aus.');
res.status(500).send('Gebaute index.html nicht gefunden. Bitte führe "npm run build" aus.');
});
});
}
@@ -473,7 +540,12 @@ Allow: /feedback
Allow: /faq
Allow: /regeln
Allow: /sicherheit
Allow: /datenschutz
<<Allow: /datenschutz
Allow: /ratgeber
Allow: /ratgeber/erste-nachricht
Allow: /ratgeber/profil-tipps
Allow: /ratgeber/sicher-chatten
Allow: /ratgeber/red-flags
Disallow: /api/
Disallow: /static/logs/
Disallow: /mockup-redesign
@@ -484,6 +556,11 @@ Sitemap: ${SITE_URL}/sitemap.xml
res.send(robotsTxt);
});
app.get('/ads.txt', (req, res) => {
res.type('text/plain');
res.send('google.com, pub-1104166651501135, DIRECT, f08c47fec0942fa0\n');
});
app.get('/sitemap.xml', (req, res) => {
try {
const sitemap = buildSitemapXml();