HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //tmp/dateweb_add_local_growth_automation.cjs
const fs = require('fs');

const localDistribution = String.raw`#!/usr/bin/env node
import fs from 'node:fs';
import path from 'node:path';

const baseUrl = process.env.DATEWEB_BASE_URL || 'https://dateweb.de';
const outDir = process.env.DATEWEB_LOCAL_DISTRIBUTION_DIR || '/home/dateweb.de/logs/dateweb-local-distribution';
const stamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\..+/, 'Z');
fs.mkdirSync(outDir, { recursive: true });

const cities = [
  ['muenchen', 'München', 'dating_muenchen', 'Dating in München', 'Singles ab 30 mit vollem Kalender und klaren Ansprüchen'],
  ['hamburg', 'Hamburg', 'dating_hamburg', 'Dating in Hamburg', 'Singles, die entspannte Treffen am Wasser und weniger Chat-Leerlauf suchen'],
  ['berlin', 'Berlin', 'dating_berlin', 'Dating in Berlin', 'Singles, die trotz großer Auswahl verbindlicher filtern wollen'],
  ['koeln', 'Köln', 'dating_koeln', 'Dating in Köln', 'Singles, die locker bleiben und trotzdem konkret treffen wollen'],
  ['frankfurt', 'Frankfurt', 'dating_frankfurt', 'Dating in Frankfurt', 'Zeitbewusste Singles mit beruflich dichtem Alltag'],
  ['duesseldorf', 'Düsseldorf', 'dating_duesseldorf', 'Dating in Düsseldorf', 'Singles, die Stil, Rhein-Nähe und klare Absicht verbinden wollen'],
  ['stuttgart', 'Stuttgart', 'dating_stuttgart', 'Dating in Stuttgart', 'Singles mit vollem Alltag und Qualitätsanspruch'],
  ['leipzig', 'Leipzig', 'dating_leipzig', 'Dating in Leipzig', 'Singles, die kreativ und entspannt, aber verbindlich starten wollen'],
  ['dortmund', 'Dortmund', 'dating_dortmund', 'Dating in Dortmund', 'Singles, die bodenständig und direkt kennenlernen wollen'],
  ['essen', 'Essen', 'dating_essen', 'Dating in Essen', 'Singles im Ruhrgebiet, die konkrete Treffen statt Chat-Schleifen suchen'],
  ['bremen', 'Bremen', 'dating_bremen', 'Dating in Bremen', 'Singles, die überschaubarer und persönlicher daten wollen'],
  ['dresden', 'Dresden', 'dating_dresden', 'Dating in Dresden', 'Singles, die Kultur und sichere erste Treffen verbinden wollen'],
  ['hannover', 'Hannover', 'dating_hannover', 'Dating in Hannover', 'Singles, die unaufgeregt und ehrlich kennenlernen wollen'],
  ['nuernberg', 'Nürnberg', 'dating_nuernberg', 'Dating in Nürnberg', 'Singles, die kurze sichere Treffen und ehrliche Profile suchen'],
  ['karlsruhe', 'Karlsruhe', 'dating_karlsruhe', 'Dating in Karlsruhe', 'Singles zwischen Studium, Technik, Beruf und Alltag'],
];

function campaignUrl(slug, source, medium, keyword) {
  const url = new URL('/dating/' + slug + '/', baseUrl);
  url.searchParams.set('mtm_campaign', 'local_' + keyword + '_launch');
  url.searchParams.set('mtm_source', source);
  url.searchParams.set('mtm_medium', medium);
  url.searchParams.set('mtm_keyword', keyword);
  return url.toString();
}

const lines = [];
lines.push('# dateweb.de Local Growth Distribution Plan');
lines.push('');
lines.push('- Zeitpunkt: ' + new Date().toISOString());
lines.push('- Basis-URL: ' + baseUrl);
lines.push('- Lokale URLs: ' + cities.length);
lines.push('');
lines.push('## IndexNow-/Sitemap-URLs');
lines.push('');
for (const [slug] of cities) lines.push('- ' + new URL('/dating/' + slug + '/', baseUrl).toString());
lines.push('');
lines.push('## Lokale Kampagnenlinks');
for (const [slug, name, keyword, title, audience] of cities) {
  lines.push('');
  lines.push('### ' + title);
  lines.push('- Stadt: ' + name);
  lines.push('- Zielgruppe: ' + audience);
  lines.push('- Direkt: ' + new URL('/dating/' + slug + '/', baseUrl).toString());
  lines.push('- Newsletter: ' + campaignUrl(slug, 'newsletter', 'owned', keyword));
  lines.push('- Social: ' + campaignUrl(slug, 'social', 'organic', keyword));
  lines.push('- Community: ' + campaignUrl(slug, 'community', 'organic', keyword));
  lines.push('- Anchor-Texte: Dating in ' + name + ' · Singles ab 30 in ' + name + ' · erstes Date in ' + name + ' planen');
  lines.push('Copy-Varianten:');
  lines.push('- Dating in ' + name + ': lokale Date-Ideen, klare Profilabsicht und ein ruhiger Weg vom Match zum ersten Treffen.');
  lines.push('- Für Singles ab 30 in ' + name + ': weniger Chat-Leerlauf, bessere erste Nachrichten und öffentliche Treffen mit klarer Dauer.');
}
lines.push('');
lines.push('## Operative Checks');
lines.push('');
lines.push('1. Sitemap muss alle lokalen URLs enthalten.');
lines.push('2. IndexNow muss die lokale URL-Liste nach Deploy mit einreichen.');
lines.push('3. Nach 48-72 Stunden Local Watch prüfen: Stadtseiten mit Requests priorisieren, Stadtseiten ohne Requests stärker intern und extern verteilen.');
lines.push('4. Städte mit Register-Referrern bekommen eigene CTA-Varianten auf Home, Tools und passenden Ratgebern.');

const reportPath = path.join(outDir, 'local-distribution-' + stamp + '.md');
fs.writeFileSync(reportPath, lines.join('\n') + '\n', 'utf8');
console.log(reportPath);
`;

const localWatch = String.raw`#!/usr/bin/env bash
set -euo pipefail

INSIGHTS_DIR="${DATEWEB_INSIGHTS_DIR:-/home/dateweb.de/logs/dateweb-growth-insights}"
DISTRIBUTION_DIR="${DATEWEB_LOCAL_DISTRIBUTION_DIR:-/home/dateweb.de/logs/dateweb-local-distribution}"
BACKLOG_DIR="${DATEWEB_BACKLOG_DIR:-/home/dateweb.de/logs/dateweb-growth-backlog}"
OUT_DIR="${DATEWEB_LOCAL_WATCH_DIR:-/home/dateweb.de/logs/dateweb-local-watch}"
mkdir -p "$OUT_DIR"
RUN_ID="$(date -u +%Y%m%d_%H%M%S)"
OUT="$OUT_DIR/local-watch-$RUN_ID.md"
LATEST_INSIGHTS="$(ls -t "$INSIGHTS_DIR"/growth-insights-*.md 2>/dev/null | head -1 || true)"
LATEST_DISTRIBUTION="$(ls -t "$DISTRIBUTION_DIR"/local-distribution-*.md 2>/dev/null | head -1 || true)"
LATEST_BACKLOG="$(ls -t "$BACKLOG_DIR"/growth-backlog-*.md 2>/dev/null | head -1 || true)"

cities=(muenchen hamburg berlin koeln frankfurt duesseldorf stuttgart leipzig dortmund essen bremen dresden hannover nuernberg karlsruhe)
city_names=(München Hamburg Berlin Köln Frankfurt Düsseldorf Stuttgart Leipzig Dortmund Essen Bremen Dresden Hannover Nürnberg Karlsruhe)

count_route() {
  local route="$1"
  local file="$2"
  if [ -z "$file" ] || [ ! -s "$file" ]; then printf '0'; return; fi
  awk -v route="\`$route\`" '$0 ~ /^\| / && $0 ~ route {gsub(/ /,"",$3); print $3; found=1} END{if(!found) print 0}' "$file" | head -1
}

{
  echo '# dateweb.de Local Watch'
  echo
  echo "- Zeitpunkt: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
  echo "- Insights: ${LATEST_INSIGHTS:-fehlt}"
  echo "- Distribution: ${LATEST_DISTRIBUTION:-fehlt}"
  echo "- Backlog: ${LATEST_BACKLOG:-fehlt}"
  echo
  echo '## Lokale Seiten: Requests'
  echo '| Stadt | Route | Requests | Status |'
  echo '| --- |--- |--- |--- |'
  total=0
  active=0
  for i in "${!cities[@]}"; do
    route="/dating/${cities[$i]}/"
    count="$(count_route "$route" "$LATEST_INSIGHTS")"
    total=$((total + count))
    if [ "$count" -gt 0 ]; then active=$((active + 1)); status='aktiv'; else status='beobachten'; fi
    echo "| ${city_names[$i]} | \`$route\` | $count | $status |"
  done
  echo
  echo '## Zusammenfassung'
  echo "- Lokale Gesamtrequests: $total"
  echo "- Städte mit Requests: $active / ${#cities[@]}"
  echo
  echo '## Nächste Aktionen'
  if [ "$total" -eq 0 ]; then
    echo '- Alle neuen lokalen Seiten weiter über Kampagnenlinks, Sitemap und interne Hubs verteilen; erstes Trafficfenster abwarten.'
  else
    echo '- Städte mit ersten Requests priorisieren: lokale CTA-Brücken, interne Links und Ratgeber-Verweise für diese Städte ausbauen.'
  fi
  echo '- Nach 48-72 Stunden Such- und Referrer-Signale prüfen; Städte ohne Signal stärker im Feed, Tools-Hub und passenden Ratgebern verlinken.'
} > "$OUT"

echo "local watch written: $OUT"
`;

fs.writeFileSync('scripts/local-distribution-plan.mjs', localDistribution, 'utf8');
fs.writeFileSync('scripts/local-pages-watch.sh', localWatch, 'utf8');
fs.chmodSync('scripts/local-pages-watch.sh', 0o755);

const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.scripts['ops:local-distribution'] = 'node scripts/local-distribution-plan.mjs';
pkg.scripts['ops:local-watch'] = 'bash scripts/local-pages-watch.sh';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n', 'utf8');

let cron = fs.readFileSync('scripts/install-growth-cron.sh', 'utf8');
if (!cron.includes('ops:local-distribution')) {
  cron = cron.replace('npm run ops:growth-distribution', 'npm run ops:growth-distribution && npm run ops:local-distribution');
}
if (!cron.includes('ops:local-watch')) {
  cron = cron.replace('npm run ops:cluster-watch', 'npm run ops:cluster-watch && npm run ops:local-watch');
}
fs.writeFileSync('scripts/install-growth-cron.sh', cron, 'utf8');