Update legal documents and localization for compliance and clarity
- Updated .env.example with legal operator details for compliance. - Refactored Impressum, Privacy, and Terms pages to utilize a new LegalDocument component for improved structure and maintainability. - Enhanced localization files to include legal content in both German and English, ensuring accurate representation of legal information. - Improved i18n handling to support locale detection from Accept-Language headers.
This commit is contained in:
@@ -325,3 +325,82 @@ footer nav {
|
||||
footer a:hover {
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.legal-layout {
|
||||
display: grid;
|
||||
gap: 2rem;
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.legal-layout {
|
||||
grid-template-columns: 220px 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.legal-nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.legal-nav-title {
|
||||
margin: 0 0 0.5rem;
|
||||
padding: 0 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
.legal-nav a {
|
||||
border-radius: calc(var(--radius) - 2px);
|
||||
padding: 0.375rem 0.5rem;
|
||||
}
|
||||
|
||||
.legal-nav a:hover,
|
||||
.legal-nav a.active {
|
||||
background: var(--muted);
|
||||
}
|
||||
|
||||
.legal-article h1 {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 1.875rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.legal-updated {
|
||||
margin: 0 0 1.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
.legal-section {
|
||||
margin-bottom: 1.75rem;
|
||||
}
|
||||
|
||||
.legal-section h2 {
|
||||
margin: 0 0 0.75rem;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.legal-section p,
|
||||
.legal-section li {
|
||||
margin: 0 0 0.75rem;
|
||||
font-size: 0.9375rem;
|
||||
color: var(--muted-foreground);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.legal-section ul {
|
||||
margin: 0 0 0.75rem;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
|
||||
.legal-lines {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@ return [
|
||||
// Live stats from the WebUI public API (falls back to placeholders on failure)
|
||||
'stats_api_url' => 'https://dashboard.nexumi.de/api/public/stats',
|
||||
|
||||
// Footer legal pages (still hosted on the dashboard app)
|
||||
// Bot status page (dashboard)
|
||||
'status_url' => 'https://dashboard.nexumi.de/status',
|
||||
'impressum_url' => 'https://dashboard.nexumi.de/impressum',
|
||||
'privacy_url' => 'https://dashboard.nexumi.de/privacy',
|
||||
'terms_url' => 'https://dashboard.nexumi.de/terms',
|
||||
];
|
||||
|
||||
9
landingpage/datenschutz.php
Normal file
9
landingpage/datenschutz.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/includes/bootstrap.php';
|
||||
require __DIR__ . '/includes/layout.php';
|
||||
|
||||
$locale = detect_locale();
|
||||
$messages = load_messages($locale);
|
||||
render_legal_page($config, $messages, $locale, 'privacy');
|
||||
9
landingpage/impressum.php
Normal file
9
landingpage/impressum.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/includes/bootstrap.php';
|
||||
require __DIR__ . '/includes/layout.php';
|
||||
|
||||
$locale = detect_locale();
|
||||
$messages = load_messages($locale);
|
||||
render_legal_page($config, $messages, $locale, 'impressum');
|
||||
77
landingpage/includes/bootstrap.php
Normal file
77
landingpage/includes/bootstrap.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
$config = require dirname(__DIR__) . '/config.php';
|
||||
|
||||
function h(?string $value): string
|
||||
{
|
||||
return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 'de'|'en'
|
||||
*/
|
||||
function detect_locale(): string
|
||||
{
|
||||
if (isset($_GET['lang']) && ($_GET['lang'] === 'de' || $_GET['lang'] === 'en')) {
|
||||
return $_GET['lang'];
|
||||
}
|
||||
|
||||
$header = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
|
||||
if ($header === '') {
|
||||
return 'de';
|
||||
}
|
||||
|
||||
$preferred = [];
|
||||
foreach (explode(',', $header) as $part) {
|
||||
$part = trim($part);
|
||||
if ($part === '') {
|
||||
continue;
|
||||
}
|
||||
[$tag, $q] = array_pad(explode(';q=', $part, 2), 2, '1');
|
||||
$lang = strtolower(substr(trim($tag), 0, 2));
|
||||
$preferred[$lang] = (float) $q;
|
||||
}
|
||||
|
||||
arsort($preferred);
|
||||
foreach (array_keys($preferred) as $lang) {
|
||||
if ($lang === 'de' || $lang === 'en') {
|
||||
return $lang;
|
||||
}
|
||||
}
|
||||
|
||||
return 'de';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
function load_messages(string $locale): array
|
||||
{
|
||||
$path = dirname(__DIR__) . '/lang/' . $locale . '.php';
|
||||
/** @var array<string, mixed> $messages */
|
||||
$messages = require $path;
|
||||
return $messages;
|
||||
}
|
||||
|
||||
function t(array $messages, string $key, ?string $fallback = null): string
|
||||
{
|
||||
$parts = explode('.', $key);
|
||||
$value = $messages;
|
||||
foreach ($parts as $part) {
|
||||
if (!is_array($value) || !array_key_exists($part, $value)) {
|
||||
return $fallback ?? $key;
|
||||
}
|
||||
$value = $value[$part];
|
||||
}
|
||||
return is_string($value) ? $value : ($fallback ?? $key);
|
||||
}
|
||||
|
||||
function bot_invite_url(array $config): string
|
||||
{
|
||||
return 'https://discord.com/api/oauth2/authorize?' . http_build_query([
|
||||
'client_id' => (string) $config['bot_client_id'],
|
||||
'permissions' => '8',
|
||||
'scope' => 'bot applications.commands',
|
||||
], '', '&', PHP_QUERY_RFC3986);
|
||||
}
|
||||
143
landingpage/includes/layout.php
Normal file
143
landingpage/includes/layout.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $config
|
||||
* @param array<string, mixed> $messages
|
||||
* @param 'de'|'en' $locale
|
||||
*/
|
||||
function render_header(array $config, array $messages, string $locale, string $title, string $description): void
|
||||
{
|
||||
$inviteUrl = bot_invite_url($config);
|
||||
$dashboardUrl = rtrim((string) $config['dashboard_url'], '/');
|
||||
$loginUrl = $dashboardUrl . '/login';
|
||||
$supportUrl = isset($config['support_url']) && $config['support_url'] !== ''
|
||||
? (string) $config['support_url']
|
||||
: null;
|
||||
$statusUrl = (string) $config['status_url'];
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?= h($locale) ?>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?= h($title) ?></title>
|
||||
<meta name="description" content="<?= h($description) ?>">
|
||||
<link rel="icon" href="assets/nexumi-logo.svg" type="image/svg+xml">
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<header class="border-b">
|
||||
<div class="container bar">
|
||||
<a class="brand" href="index.php">
|
||||
<img src="assets/nexumi-logo.svg" alt="Nexumi" width="28" height="28">
|
||||
Nexumi
|
||||
</a>
|
||||
<nav>
|
||||
<a class="btn btn-ghost" href="<?= h($statusUrl) ?>"><?= h(t($messages, 'nav.status')) ?></a>
|
||||
<a class="btn btn-ghost" href="<?= h($inviteUrl) ?>" target="_blank" rel="noreferrer"><?= h(t($messages, 'nav.invite')) ?></a>
|
||||
<?php if ($supportUrl): ?>
|
||||
<a class="btn btn-ghost" href="<?= h($supportUrl) ?>" target="_blank" rel="noreferrer"><?= h(t($messages, 'nav.support')) ?></a>
|
||||
<?php endif; ?>
|
||||
<a class="btn btn-primary" href="<?= h($loginUrl) ?>"><?= h(t($messages, 'nav.login')) ?></a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $config
|
||||
* @param array<string, mixed> $messages
|
||||
*/
|
||||
function render_footer(array $config, array $messages): void
|
||||
{
|
||||
$dashboardUrl = rtrim((string) $config['dashboard_url'], '/');
|
||||
$year = (int) date('Y');
|
||||
?>
|
||||
</main>
|
||||
<footer class="border-t">
|
||||
<div class="container bar">
|
||||
<p>© <?= $year ?> Nexumi</p>
|
||||
<nav>
|
||||
<a href="<?= h((string) $config['status_url']) ?>"><?= h(t($messages, 'nav.status')) ?></a>
|
||||
<a href="impressum.php"><?= h(t($messages, 'nav.impressum')) ?></a>
|
||||
<a href="datenschutz.php"><?= h(t($messages, 'nav.privacy')) ?></a>
|
||||
<a href="nutzungsbedingungen.php"><?= h(t($messages, 'nav.terms')) ?></a>
|
||||
<a href="<?= h($dashboardUrl . '/dashboard') ?>"><?= h(t($messages, 'nav.dashboard')) ?></a>
|
||||
</nav>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $sections
|
||||
*/
|
||||
function render_legal_sections(array $sections): void
|
||||
{
|
||||
foreach ($sections as $section) {
|
||||
$heading = (string) ($section['heading'] ?? '');
|
||||
echo '<section class="legal-section">';
|
||||
if ($heading !== '') {
|
||||
echo '<h2>' . h($heading) . '</h2>';
|
||||
}
|
||||
foreach (($section['paragraphs'] ?? []) as $paragraph) {
|
||||
echo '<p>' . h((string) $paragraph) . '</p>';
|
||||
}
|
||||
if (!empty($section['lines']) && is_array($section['lines'])) {
|
||||
echo '<p class="legal-lines">';
|
||||
foreach ($section['lines'] as $i => $line) {
|
||||
if ($i > 0) {
|
||||
echo '<br>';
|
||||
}
|
||||
echo h((string) $line);
|
||||
}
|
||||
echo '</p>';
|
||||
}
|
||||
if (!empty($section['list']) && is_array($section['list'])) {
|
||||
echo '<ul>';
|
||||
foreach ($section['list'] as $item) {
|
||||
echo '<li>' . h((string) $item) . '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
}
|
||||
echo '</section>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $config
|
||||
* @param array<string, mixed> $messages
|
||||
* @param 'de'|'en' $locale
|
||||
* @param 'impressum'|'privacy'|'terms' $pageKey
|
||||
*/
|
||||
function render_legal_page(array $config, array $messages, string $locale, string $pageKey): void
|
||||
{
|
||||
/** @var array<string, mixed> $page */
|
||||
$page = $messages['legal'][$pageKey];
|
||||
$title = (string) $page['title'];
|
||||
$description = t($messages, 'meta.description');
|
||||
render_header($config, $messages, $locale, $title . ' · Nexumi', $description);
|
||||
?>
|
||||
<div class="container legal-layout">
|
||||
<aside class="legal-nav">
|
||||
<p class="legal-nav-title"><?= h(t($messages, 'legal.nav_title')) ?></p>
|
||||
<a href="impressum.php" class="<?= $pageKey === 'impressum' ? 'active' : '' ?>"><?= h(t($messages, 'nav.impressum')) ?></a>
|
||||
<a href="datenschutz.php" class="<?= $pageKey === 'privacy' ? 'active' : '' ?>"><?= h(t($messages, 'nav.privacy')) ?></a>
|
||||
<a href="nutzungsbedingungen.php" class="<?= $pageKey === 'terms' ? 'active' : '' ?>"><?= h(t($messages, 'nav.terms')) ?></a>
|
||||
</aside>
|
||||
<article class="legal-article">
|
||||
<h1><?= h($title) ?></h1>
|
||||
<p class="legal-updated"><?= h(t($messages, 'legal.updated')) ?></p>
|
||||
<?php render_legal_sections($page['sections']); ?>
|
||||
</article>
|
||||
</div>
|
||||
<?php
|
||||
render_footer($config, $messages);
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
$config = require __DIR__ . '/config.php';
|
||||
require __DIR__ . '/includes/bootstrap.php';
|
||||
require __DIR__ . '/includes/layout.php';
|
||||
|
||||
$clientId = (string) $config['bot_client_id'];
|
||||
$inviteUrl = 'https://discord.com/api/oauth2/authorize?' . http_build_query([
|
||||
'client_id' => $clientId,
|
||||
'permissions' => '8',
|
||||
'scope' => 'bot applications.commands',
|
||||
], '', '&', PHP_QUERY_RFC3986);
|
||||
$locale = detect_locale();
|
||||
$messages = load_messages($locale);
|
||||
|
||||
$inviteUrl = bot_invite_url($config);
|
||||
$dashboardUrl = rtrim((string) $config['dashboard_url'], '/');
|
||||
$loginUrl = $dashboardUrl . '/login';
|
||||
$supportUrl = isset($config['support_url']) && $config['support_url'] !== ''
|
||||
@@ -18,7 +16,6 @@ $supportUrl = isset($config['support_url']) && $config['support_url'] !== ''
|
||||
|
||||
$guildCount = 0;
|
||||
$userCount = 0;
|
||||
|
||||
$statsApi = (string) ($config['stats_api_url'] ?? '');
|
||||
if ($statsApi !== '') {
|
||||
$ctx = stream_context_create([
|
||||
@@ -37,103 +34,41 @@ if ($statsApi !== '') {
|
||||
}
|
||||
}
|
||||
|
||||
$year = (int) date('Y');
|
||||
$numberLocale = $locale === 'de' ? 'de_DE' : 'en_US';
|
||||
$formatNumber = static function (int $value) use ($numberLocale): string {
|
||||
if (class_exists(NumberFormatter::class)) {
|
||||
$formatter = new NumberFormatter($numberLocale, NumberFormatter::DECIMAL);
|
||||
$formatted = $formatter->format($value);
|
||||
if ($formatted !== false) {
|
||||
return $formatted;
|
||||
}
|
||||
}
|
||||
return number_format($value, 0, $locale === 'de' ? ',' : '.', $locale === 'de' ? '.' : ',');
|
||||
};
|
||||
|
||||
$groups = [
|
||||
'moderation' => [
|
||||
'label' => 'Moderation',
|
||||
'modules' => [
|
||||
['label' => 'Moderation', 'description' => 'Bans, Verwarnungen, Timeouts und das Fall-System'],
|
||||
['label' => 'Auto-Moderation', 'description' => 'Spam-, Raid- und Nuke-Schutz'],
|
||||
['label' => 'Logging', 'description' => 'Log-Kanäle für Server-Events'],
|
||||
],
|
||||
],
|
||||
'engagement' => [
|
||||
'label' => 'Engagement',
|
||||
'modules' => [
|
||||
['label' => 'Willkommen & Abschied', 'description' => 'Join- und Leave-Nachrichten, Autoroles'],
|
||||
['label' => 'Verifizierung', 'description' => 'Button- und Captcha-Verifizierung'],
|
||||
['label' => 'Leveling & XP', 'description' => 'Text- und Voice-XP, Rollen-Belohnungen'],
|
||||
['label' => 'Economy', 'description' => 'Währung, Shop und Spiele'],
|
||||
['label' => 'Fun & Spiele', 'description' => 'Minispiele und Medien-Commands'],
|
||||
],
|
||||
],
|
||||
'community' => [
|
||||
'label' => 'Community',
|
||||
'modules' => [
|
||||
['label' => 'Giveaways', 'description' => 'Button-basierte Giveaways'],
|
||||
['label' => 'Tickets', 'description' => 'Support-Ticket-Panels und Transkripte'],
|
||||
['label' => 'Self Roles', 'description' => 'Reaktions-, Button- und Dropdown-Rollenpanels'],
|
||||
['label' => 'Starboard', 'description' => 'Beliebte Nachrichten hervorheben'],
|
||||
['label' => 'Vorschläge', 'description' => 'Community-Vorschläge mit Abstimmung'],
|
||||
['label' => 'Geburtstage', 'description' => 'Geburtstags-Ankündigungen und -Rollen'],
|
||||
],
|
||||
],
|
||||
'utility' => [
|
||||
'label' => 'Utility',
|
||||
'modules' => [
|
||||
['label' => 'Tags', 'description' => 'Custom Commands und Auto-Responder'],
|
||||
['label' => 'Temp-Voice', 'description' => 'Join-to-Create Voice-Kanäle'],
|
||||
],
|
||||
],
|
||||
'integrations' => [
|
||||
'label' => 'Integrationen',
|
||||
'modules' => [
|
||||
['label' => 'Server-Statistiken', 'description' => 'Automatische Statistik-Kanäle und Invites'],
|
||||
['label' => 'Social Feeds', 'description' => 'Twitch-, YouTube-, RSS- und Reddit-Benachrichtigungen'],
|
||||
['label' => 'Scheduler', 'description' => 'Geplante und wiederkehrende Ankündigungen'],
|
||||
['label' => 'Backups', 'description' => 'Server-Backup und -Wiederherstellung'],
|
||||
],
|
||||
],
|
||||
];
|
||||
/** @var array<string, array{label: string, modules: list<array{label: string, description: string}>}> $groups */
|
||||
$groups = $messages['module_groups'];
|
||||
|
||||
function h(?string $value): string
|
||||
{
|
||||
return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||
}
|
||||
render_header(
|
||||
$config,
|
||||
$messages,
|
||||
$locale,
|
||||
'Nexumi',
|
||||
t($messages, 'meta.description')
|
||||
);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Nexumi</title>
|
||||
<meta name="description" content="Discord-Bot mit Moderations-, Community- und Integrationsmodulen sowie Web-Dashboard.">
|
||||
<link rel="icon" href="assets/nexumi-logo.svg" type="image/svg+xml">
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<header class="border-b">
|
||||
<div class="container bar">
|
||||
<a class="brand" href="/">
|
||||
<img src="assets/nexumi-logo.svg" alt="Nexumi" width="28" height="28">
|
||||
Nexumi
|
||||
</a>
|
||||
<nav>
|
||||
<a class="btn btn-ghost" href="<?= h((string) $config['status_url']) ?>">Status</a>
|
||||
<a class="btn btn-ghost" href="<?= h($inviteUrl) ?>" target="_blank" rel="noreferrer">Einladen</a>
|
||||
<?php if ($supportUrl): ?>
|
||||
<a class="btn btn-ghost" href="<?= h($supportUrl) ?>" target="_blank" rel="noreferrer">Support</a>
|
||||
<?php endif; ?>
|
||||
<a class="btn btn-primary" href="<?= h($loginUrl) ?>">Anmelden</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="border-b">
|
||||
<div class="container hero">
|
||||
<div class="hero-brand">
|
||||
<img src="assets/nexumi-logo.svg" alt="" width="48" height="48">
|
||||
<h1>Nexumi</h1>
|
||||
</div>
|
||||
<p>Discord-Bot mit Moderations-, Community- und Integrationsmodulen sowie Web-Dashboard.</p>
|
||||
<p><?= h(t($messages, 'landing.subtitle')) ?></p>
|
||||
<div class="actions">
|
||||
<a class="btn btn-lg btn-primary" href="<?= h($inviteUrl) ?>" target="_blank" rel="noreferrer">Bot einladen</a>
|
||||
<a class="btn btn-lg btn-secondary" href="<?= h($loginUrl) ?>">Zum Dashboard</a>
|
||||
<a class="btn btn-lg btn-primary" href="<?= h($inviteUrl) ?>" target="_blank" rel="noreferrer"><?= h(t($messages, 'landing.invite')) ?></a>
|
||||
<a class="btn btn-lg btn-secondary" href="<?= h($loginUrl) ?>"><?= h(t($messages, 'landing.login')) ?></a>
|
||||
<?php if ($supportUrl): ?>
|
||||
<a class="btn btn-lg btn-outline" href="<?= h($supportUrl) ?>" target="_blank" rel="noreferrer">Support-Server</a>
|
||||
<a class="btn btn-lg btn-outline" href="<?= h($supportUrl) ?>" target="_blank" rel="noreferrer"><?= h(t($messages, 'landing.support')) ?></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -142,12 +77,12 @@ function h(?string $value): string
|
||||
<section class="border-b">
|
||||
<div class="container stats">
|
||||
<div class="card">
|
||||
<p class="card-label">Server</p>
|
||||
<p class="card-value"><?= h(number_format($guildCount, 0, ',', '.')) ?></p>
|
||||
<p class="card-label"><?= h(t($messages, 'landing.stats_guilds')) ?></p>
|
||||
<p class="card-value"><?= h($formatNumber($guildCount)) ?></p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="card-label">Nutzer (ca.)</p>
|
||||
<p class="card-value"><?= h(number_format($userCount, 0, ',', '.')) ?></p>
|
||||
<p class="card-label"><?= h(t($messages, 'landing.stats_users')) ?></p>
|
||||
<p class="card-value"><?= h($formatNumber($userCount)) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -155,8 +90,8 @@ function h(?string $value): string
|
||||
<section>
|
||||
<div class="container features">
|
||||
<div class="intro">
|
||||
<h2>Module</h2>
|
||||
<p>Funktionen, die Nexumi pro Server bereitstellt.</p>
|
||||
<h2><?= h(t($messages, 'landing.features_title')) ?></h2>
|
||||
<p><?= h(t($messages, 'landing.features_subtitle')) ?></p>
|
||||
</div>
|
||||
<?php foreach ($groups as $group): ?>
|
||||
<div class="group">
|
||||
@@ -173,20 +108,5 @@ function h(?string $value): string
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="border-t">
|
||||
<div class="container bar">
|
||||
<p>© <?= $year ?> Nexumi</p>
|
||||
<nav>
|
||||
<a href="<?= h((string) $config['status_url']) ?>">Status</a>
|
||||
<a href="<?= h((string) $config['impressum_url']) ?>">Impressum</a>
|
||||
<a href="<?= h((string) $config['privacy_url']) ?>">Datenschutz</a>
|
||||
<a href="<?= h((string) $config['terms_url']) ?>">Nutzungsbedingungen</a>
|
||||
<a href="<?= h($dashboardUrl . '/dashboard') ?>">Dashboard</a>
|
||||
</nav>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
render_footer($config, $messages);
|
||||
|
||||
346
landingpage/lang/de.php
Normal file
346
landingpage/lang/de.php
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'meta' => [
|
||||
'description' => 'Discord-Bot mit Moderations-, Community- und Integrationsmodulen sowie Web-Dashboard.',
|
||||
],
|
||||
'nav' => [
|
||||
'status' => 'Status',
|
||||
'invite' => 'Einladen',
|
||||
'support' => 'Support',
|
||||
'login' => 'Anmelden',
|
||||
'impressum' => 'Impressum',
|
||||
'privacy' => 'Datenschutz',
|
||||
'terms' => 'Nutzungsbedingungen',
|
||||
'dashboard' => 'Dashboard',
|
||||
],
|
||||
'landing' => [
|
||||
'subtitle' => 'Discord-Bot mit Moderations-, Community- und Integrationsmodulen sowie Web-Dashboard.',
|
||||
'invite' => 'Bot einladen',
|
||||
'login' => 'Zum Dashboard',
|
||||
'support' => 'Support-Server',
|
||||
'stats_guilds' => 'Server',
|
||||
'stats_users' => 'Nutzer (ca.)',
|
||||
'features_title' => 'Module',
|
||||
'features_subtitle' => 'Funktionen, die Nexumi pro Server bereitstellt.',
|
||||
],
|
||||
'module_groups' => [
|
||||
'moderation' => [
|
||||
'label' => 'Moderation',
|
||||
'modules' => [
|
||||
['label' => 'Moderation', 'description' => 'Bans, Verwarnungen, Timeouts und das Fall-System'],
|
||||
['label' => 'Auto-Moderation', 'description' => 'Spam-, Raid- und Nuke-Schutz'],
|
||||
['label' => 'Logging', 'description' => 'Log-Kanäle für Server-Events'],
|
||||
],
|
||||
],
|
||||
'engagement' => [
|
||||
'label' => 'Engagement',
|
||||
'modules' => [
|
||||
['label' => 'Willkommen & Abschied', 'description' => 'Join- und Leave-Nachrichten, Autoroles'],
|
||||
['label' => 'Verifizierung', 'description' => 'Button- und Captcha-Verifizierung'],
|
||||
['label' => 'Leveling & XP', 'description' => 'Text- und Voice-XP, Rollen-Belohnungen'],
|
||||
['label' => 'Economy', 'description' => 'Währung, Shop und Spiele'],
|
||||
['label' => 'Fun & Spiele', 'description' => 'Minispiele und Medien-Commands'],
|
||||
],
|
||||
],
|
||||
'community' => [
|
||||
'label' => 'Community',
|
||||
'modules' => [
|
||||
['label' => 'Giveaways', 'description' => 'Button-basierte Giveaways'],
|
||||
['label' => 'Tickets', 'description' => 'Support-Ticket-Panels und Transkripte'],
|
||||
['label' => 'Self Roles', 'description' => 'Reaktions-, Button- und Dropdown-Rollenpanels'],
|
||||
['label' => 'Starboard', 'description' => 'Beliebte Nachrichten hervorheben'],
|
||||
['label' => 'Vorschläge', 'description' => 'Community-Vorschläge mit Abstimmung'],
|
||||
['label' => 'Geburtstage', 'description' => 'Geburtstags-Ankündigungen und -Rollen'],
|
||||
],
|
||||
],
|
||||
'utility' => [
|
||||
'label' => 'Utility',
|
||||
'modules' => [
|
||||
['label' => 'Tags', 'description' => 'Custom Commands und Auto-Responder'],
|
||||
['label' => 'Temp-Voice', 'description' => 'Join-to-Create Voice-Kanäle'],
|
||||
],
|
||||
],
|
||||
'integrations' => [
|
||||
'label' => 'Integrationen',
|
||||
'modules' => [
|
||||
['label' => 'Server-Statistiken', 'description' => 'Automatische Statistik-Kanäle und Invites'],
|
||||
['label' => 'Social Feeds', 'description' => 'Twitch-, YouTube-, RSS- und Reddit-Benachrichtigungen'],
|
||||
['label' => 'Scheduler', 'description' => 'Geplante und wiederkehrende Ankündigungen'],
|
||||
['label' => 'Backups', 'description' => 'Server-Backup und -Wiederherstellung'],
|
||||
],
|
||||
],
|
||||
],
|
||||
'legal' => [
|
||||
'nav_title' => 'Rechtliches',
|
||||
'updated' => 'Stand: Juli 2026',
|
||||
'impressum' => [
|
||||
'title' => 'Impressum',
|
||||
'sections' => [
|
||||
[
|
||||
'heading' => 'Angaben gemäß § 5 DDG',
|
||||
'paragraphs' => [
|
||||
'Diensteanbieter und verantwortlich für Nexumi (Website, Discord-Bot und Dashboard):',
|
||||
],
|
||||
'lines' => [
|
||||
'HexaHost',
|
||||
'Inh. Samuel Müller',
|
||||
'Richard-Miller-Straße 1',
|
||||
'94051 Hauzenberg',
|
||||
'Deutschland',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Kontakt',
|
||||
'lines' => [
|
||||
'Telefon: +49 15566 175855',
|
||||
'E-Mail: info@hexahost.de',
|
||||
'Website des Betreibers: https://www.hexahost.de',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Umsatzsteuer-ID',
|
||||
'paragraphs' => [
|
||||
'Umsatzsteuer-Identifikationsnummer gemäß § 27a Umsatzsteuergesetz: DE458741546',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Redaktionell verantwortlich',
|
||||
'lines' => [
|
||||
'Samuel Müller',
|
||||
'Richard-Miller-Straße 1',
|
||||
'94051 Hauzenberg',
|
||||
'Deutschland',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'EU-Streitschlichtung',
|
||||
'paragraphs' => [
|
||||
'Die Europäische Kommission stellt eine Plattform zur Online-Streitbeilegung (OS) bereit: https://ec.europa.eu/consumers/odr/',
|
||||
'Unsere E-Mail-Adresse finden Sie oben im Impressum.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Verbraucherstreitbeilegung / Universalschlichtungsstelle',
|
||||
'paragraphs' => [
|
||||
'Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Haftung für Inhalte',
|
||||
'paragraphs' => [
|
||||
'Als Diensteanbieter sind wir gemäß § 7 Abs. 1 DDG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 DDG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen.',
|
||||
'Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Haftung für Links',
|
||||
'paragraphs' => [
|
||||
'Unser Angebot enthält Links zu externen Websites Dritter (einschließlich Discord und weiterer Dienste), auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich.',
|
||||
'Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Urheberrecht',
|
||||
'paragraphs' => [
|
||||
'Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten (einschließlich Marke, Logo, Texte und Software von Nexumi) unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers.',
|
||||
'Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'privacy' => [
|
||||
'title' => 'Datenschutzerklärung',
|
||||
'sections' => [
|
||||
[
|
||||
'heading' => '1. Verantwortlicher',
|
||||
'paragraphs' => [
|
||||
'Verantwortlicher im Sinne der Datenschutz-Grundverordnung (DSGVO) für den Betrieb von Nexumi (Website, Discord-Bot und Web-Dashboard) ist:',
|
||||
],
|
||||
'lines' => [
|
||||
'HexaHost',
|
||||
'Inh. Samuel Müller',
|
||||
'Richard-Miller-Straße 1',
|
||||
'94051 Hauzenberg',
|
||||
'Deutschland',
|
||||
'Telefon: +49 15566 175855',
|
||||
'E-Mail: info@hexahost.de',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '2. Allgemeine Hinweise',
|
||||
'paragraphs' => [
|
||||
'Wir nehmen den Schutz Ihrer persönlichen Daten ernst. Wir behandeln personenbezogene Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften sowie dieser Datenschutzerklärung.',
|
||||
'Diese Erklärung gilt für die öffentliche Website von Nexumi, den Discord-Bot sowie das zugehörige Web-Dashboard. Für allgemeine Informationen zum Betreiber siehe auch https://www.hexahost.de/datenschutz – die folgenden Abschnitte sind speziell auf Nexumi und Discord angepasst.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '3. Rechtsgrundlagen',
|
||||
'paragraphs' => [
|
||||
'Die Verarbeitung personenbezogener Daten erfolgt insbesondere auf Basis von:',
|
||||
],
|
||||
'list' => [
|
||||
'Art. 6 Abs. 1 lit. a DSGVO – Einwilligung (soweit ausdrücklich eingeholt)',
|
||||
'Art. 6 Abs. 1 lit. b DSGVO – Erfüllung eines Vertrags bzw. vorvertraglicher Maßnahmen (Nutzung von Bot und Dashboard auf einem Discord-Server)',
|
||||
'Art. 6 Abs. 1 lit. c DSGVO – Erfüllung rechtlicher Verpflichtungen',
|
||||
'Art. 6 Abs. 1 lit. f DSGVO – berechtigtes Interesse an sicherem, stabilem Betrieb, Missbrauchsprävention und Support',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '4. Welche Daten werden verarbeitet?',
|
||||
'paragraphs' => [
|
||||
'Je nach genutztem Modul können insbesondere folgende Datenkategorien verarbeitet werden:',
|
||||
],
|
||||
'list' => [
|
||||
'Discord-Nutzer-IDs, Servernamen/-IDs, Kanal- und Rollen-IDs',
|
||||
'Nachrichteninhalte oder Metadaten, soweit ein Modul dies erfordert (z. B. Moderation, Logging, Tickets, Vorschläge)',
|
||||
'Moderationsfälle, Verwarnungen, Timeouts, Bans und Audit-Einträge',
|
||||
'Modul- und Server-Einstellungen, die im Dashboard konfiguriert werden',
|
||||
'Wirtschafts-/Level-/Statistikdaten, sofern die jeweiligen Module aktiviert sind',
|
||||
'Technische Logdaten (Zeitstempel, Fehler, Job-Status) zum Betrieb der Infrastruktur',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '5. Dashboard-Login (Discord OAuth2)',
|
||||
'paragraphs' => [
|
||||
'Die Anmeldung am Web-Dashboard erfolgt über Discord OAuth2. Dabei werden in der Regel die Scopes „identify“ und „guilds“ genutzt, um Ihre Discord-Identität und die Liste Ihrer Server zu ermitteln und den Zugriff auf berechtigte Server freizugeben.',
|
||||
'Sitzungsdaten werden serverseitig (u. a. in Redis) gespeichert. Session-Cookies sind für die Authentifizierung technisch erforderlich.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '6. Speicherung und Hosting',
|
||||
'paragraphs' => [
|
||||
'Die Anwendungsdaten von Nexumi werden in einer von uns betriebenen PostgreSQL-Datenbank gespeichert. Zwischenspeicher, Sessions und Job-Warteschlangen nutzen Redis. Server und Datenverarbeitung befinden sich im Verantwortungsbereich von HexaHost.',
|
||||
'Aufbewahrungsdauern können je Modul konfigurierbar sein (z. B. Log-Retention). Lösch- oder Anonymisierungsanfragen können über den Bot-Command /gdpr (soweit verfügbar) oder per Kontaktaufnahme an die oben genannte Adresse gestellt werden.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '7. Empfänger und Auftragsverarbeitung',
|
||||
'paragraphs' => [
|
||||
'Zur Erbringung des Dienstes werden Daten an Discord (Discord Inc. / verbundene Unternehmen) übermittelt, soweit dies für Bot-Funktionen und OAuth technisch erforderlich ist. Es gelten ergänzend die Datenschutzbestimmungen von Discord.',
|
||||
'Optional kann Fehlerüberwachung (z. B. Sentry) eingesetzt werden; dabei können technische Fehlerinformationen inklusive begrenzter Kontextinformationen verarbeitet werden.',
|
||||
'Eine Weitergabe zu Werbezwecken an Dritte findet nicht statt.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '8. Server-Logfiles der Website',
|
||||
'paragraphs' => [
|
||||
'Beim Besuch der Website können Server-Logfiles erhoben werden (z. B. IP-Adresse, Browser, Zeitpunkt, aufgerufene URL). Die Verarbeitung erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO zur Sicherstellung eines störungsfreien Betriebs und zur Abwehr von Missbrauch. Logfiles werden regelmäßig gelöscht, sobald sie nicht mehr benötigt werden.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '9. Cookies',
|
||||
'paragraphs' => [
|
||||
'Auf der öffentlichen Website werden, soweit technisch nötig, nur notwendige Cookies bzw. vergleichbare Technologien eingesetzt. Das Dashboard setzt Session-Cookies zur Anmeldung. Analyse- oder Marketing-Cookies werden von Nexumi standardmäßig nicht eingesetzt.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '10. Speicherdauer',
|
||||
'paragraphs' => [
|
||||
'Personenbezogene Daten werden nur so lange gespeichert, wie es für die jeweiligen Zwecke erforderlich ist oder gesetzliche Aufbewahrungspflichten bestehen. Nach Wegfall des Zwecks werden Daten gelöscht oder anonymisiert, sofern keine gesetzlichen Pflichten entgegenstehen.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '11. Ihre Rechte',
|
||||
'paragraphs' => [
|
||||
'Ihnen stehen insbesondere die Rechte auf Auskunft, Berichtigung, Löschung, Einschränkung der Verarbeitung, Datenübertragbarkeit sowie Widerspruch gegen Verarbeitungen auf Basis berechtigter Interessen zu. Erteilte Einwilligungen können Sie jederzeit mit Wirkung für die Zukunft widerrufen.',
|
||||
'Zur Ausübung Ihrer Rechte kontaktieren Sie uns unter den Angaben im Impressum oder nutzen Sie – soweit verfügbar – den Bot-Command /gdpr.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '12. Beschwerderecht',
|
||||
'paragraphs' => [
|
||||
'Sie haben das Recht, sich bei einer Datenschutz-Aufsichtsbehörde zu beschweren. Zuständig für Bayern ist u. a. das Bayerische Landesamt für Datenschutzaufsicht (BayLDA), Promenade 18, 91522 Ansbach, https://www.lda.bayern.de',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '13. Datensicherheit',
|
||||
'paragraphs' => [
|
||||
'Wir setzen technische und organisatorische Maßnahmen ein, um personenbezogene Daten gegen Verlust, Manipulation und unbefugten Zugriff zu schützen. Die Übertragung erfolgt in der Regel über TLS/HTTPS bzw. verschlüsselte Verbindungen zu Discord.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '14. Aktualität',
|
||||
'paragraphs' => [
|
||||
'Diese Datenschutzerklärung hat den Stand Juli 2026 und kann bei Änderungen am Angebot oder an Rechtsvorschriften angepasst werden. Die jeweils aktuelle Fassung ist auf dieser Website abrufbar.',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'terms' => [
|
||||
'title' => 'Nutzungsbedingungen',
|
||||
'sections' => [
|
||||
[
|
||||
'heading' => '1. Geltungsbereich',
|
||||
'paragraphs' => [
|
||||
'Diese Nutzungsbedingungen gelten für die Nutzung des Discord-Bots Nexumi, des zugehörigen Web-Dashboards und der öffentlichen Website. Anbieter ist HexaHost Inh. Samuel Müller.',
|
||||
'Mit dem Einladen des Bots auf einen Discord-Server, der Nutzung von Commands oder dem Login am Dashboard akzeptieren Sie diese Bedingungen.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '2. Leistungsbeschreibung',
|
||||
'paragraphs' => [
|
||||
'Nexumi stellt Moderations-, Community-, Utility- und Integrationsfunktionen für Discord-Server bereit. Der Funktionsumfang kann sich weiterentwickeln; einzelne Module können aktiviert, deaktiviert oder eingeschränkt werden (einschließlich Premium-Limits, soweit angeboten).',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '3. Voraussetzungen und Pflichten der Nutzer',
|
||||
'paragraphs' => [
|
||||
'Sie dürfen Nexumi nur nutzen, wenn Sie die erforderlichen Rechte auf dem jeweiligen Discord-Server besitzen und die Discord Terms of Service sowie Community Guidelines einhalten.',
|
||||
'Server-Administratoren sind dafür verantwortlich, dass der Einsatz des Bots und die konfigurierten Module mit geltendem Recht und den Rechten der Servermitglieder vereinbar sind (einschließlich Transparenz gegenüber Mitgliedern).',
|
||||
],
|
||||
'list' => [
|
||||
'Kein Missbrauch, Spam, Belästigung oder Umgehung von Sicherheitsmechanismen',
|
||||
'Keine Nutzung zur Begehung oder Erleichterung rechtswidriger Handlungen',
|
||||
'Keine Versuche, Systeme unbefugt auszulesen, zu stören oder zu überlasten',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '4. Verfügbarkeit',
|
||||
'paragraphs' => [
|
||||
'Wir bemühen uns um einen möglichst unterbrechungsfreien Betrieb, schulden jedoch keine absolute Verfügbarkeit. Wartungsarbeiten, Störungen bei Discord oder Infrastrukturprobleme können die Nutzung vorübergehend einschränken. Geplante Wartungen werden nach Möglichkeit angekündigt.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '5. Sperrung und Beendigung',
|
||||
'paragraphs' => [
|
||||
'Bei Verstößen gegen diese Bedingungen, gegen Recht oder gegen die Discord-Regeln können wir den Zugang zum Bot bzw. Dashboard für Nutzer oder Server einschränken oder sperren (einschließlich Blacklist). Sie können den Bot jederzeit von Ihrem Server entfernen; damit endet die Nutzung für diesen Server.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '6. Haftung',
|
||||
'paragraphs' => [
|
||||
'Für Schäden aus der Verletzung des Lebens, des Körpers oder der Gesundheit sowie nach dem Produkthaftungsgesetz haften wir nach den gesetzlichen Vorschriften. Für sonstige Schäden haften wir nur bei Vorsatz und grober Fahrlässigkeit sowie bei Verletzung wesentlicher Vertragspflichten (Kardinalpflichten), wobei die Haftung bei leichter Fahrlässigkeit auf den vorhersehbaren, vertragstypischen Schaden begrenzt ist.',
|
||||
'Für Inhalte, die Nutzer oder Servermitglieder über Discord erzeugen oder speichern, sind die jeweiligen Verantwortlichen vor Ort zuständig. Wir übernehmen keine Haftung für Entscheidungen, die Server-Teams anhand von Moderationsdaten treffen.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '7. Urheberrecht und Marken',
|
||||
'paragraphs' => [
|
||||
'Software, Design, Texte und Kennzeichen von Nexumi sind urheber- bzw. kennzeichenrechtlich geschützt. Eine Nutzung außerhalb der bestimmungsgemäßen Verwendung des Dienstes bedarf unserer vorherigen Zustimmung.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '8. Änderungen',
|
||||
'paragraphs' => [
|
||||
'Wir können diese Nutzungsbedingungen anpassen, wenn dies aus rechtlichen, technischen oder betrieblichen Gründen erforderlich ist. Die aktuelle Fassung wird auf der Website bzw. im Dashboard veröffentlicht. Wesentliche Änderungen werden nach Möglichkeit geeignet kommuniziert.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '9. Anwendbares Recht',
|
||||
'paragraphs' => [
|
||||
'Es gilt das Recht der Bundesrepublik Deutschland unter Ausschluss des UN-Kaufrechts, soweit zwingende Verbraucherschutzvorschriften nichts anderes vorsehen.',
|
||||
'Sollten einzelne Bestimmungen unwirksam sein, bleibt die Wirksamkeit der übrigen Bestimmungen unberührt.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '10. Kontakt',
|
||||
'paragraphs' => [
|
||||
'Fragen zu diesen Bedingungen richten Sie bitte an die im Impressum genannten Kontaktdaten.',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
346
landingpage/lang/en.php
Normal file
346
landingpage/lang/en.php
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'meta' => [
|
||||
'description' => 'Discord bot with moderation, community, and integration modules plus a web dashboard.',
|
||||
],
|
||||
'nav' => [
|
||||
'status' => 'Status',
|
||||
'invite' => 'Invite',
|
||||
'support' => 'Support',
|
||||
'login' => 'Log in',
|
||||
'impressum' => 'Legal notice',
|
||||
'privacy' => 'Privacy',
|
||||
'terms' => 'Terms of service',
|
||||
'dashboard' => 'Dashboard',
|
||||
],
|
||||
'landing' => [
|
||||
'subtitle' => 'Discord bot with moderation, community, and integration modules plus a web dashboard.',
|
||||
'invite' => 'Invite bot',
|
||||
'login' => 'Open dashboard',
|
||||
'support' => 'Support server',
|
||||
'stats_guilds' => 'Servers',
|
||||
'stats_users' => 'Users (approx.)',
|
||||
'features_title' => 'Modules',
|
||||
'features_subtitle' => 'Features Nexumi provides per server.',
|
||||
],
|
||||
'module_groups' => [
|
||||
'moderation' => [
|
||||
'label' => 'Moderation',
|
||||
'modules' => [
|
||||
['label' => 'Moderation', 'description' => 'Bans, warnings, timeouts, and the case system'],
|
||||
['label' => 'Auto-moderation', 'description' => 'Spam, raid, and nuke protection'],
|
||||
['label' => 'Logging', 'description' => 'Log channels for server events'],
|
||||
],
|
||||
],
|
||||
'engagement' => [
|
||||
'label' => 'Engagement',
|
||||
'modules' => [
|
||||
['label' => 'Welcome & goodbye', 'description' => 'Join and leave messages, autoroles'],
|
||||
['label' => 'Verification', 'description' => 'Button and captcha verification'],
|
||||
['label' => 'Leveling & XP', 'description' => 'Text and voice XP, role rewards'],
|
||||
['label' => 'Economy', 'description' => 'Currency, shop, and games'],
|
||||
['label' => 'Fun & games', 'description' => 'Minigames and media commands'],
|
||||
],
|
||||
],
|
||||
'community' => [
|
||||
'label' => 'Community',
|
||||
'modules' => [
|
||||
['label' => 'Giveaways', 'description' => 'Button-based giveaways'],
|
||||
['label' => 'Tickets', 'description' => 'Support ticket panels and transcripts'],
|
||||
['label' => 'Self roles', 'description' => 'Reaction, button, and dropdown role panels'],
|
||||
['label' => 'Starboard', 'description' => 'Highlight popular messages'],
|
||||
['label' => 'Suggestions', 'description' => 'Community suggestions with voting'],
|
||||
['label' => 'Birthdays', 'description' => 'Birthday announcements and roles'],
|
||||
],
|
||||
],
|
||||
'utility' => [
|
||||
'label' => 'Utility',
|
||||
'modules' => [
|
||||
['label' => 'Tags', 'description' => 'Custom commands and auto-responders'],
|
||||
['label' => 'Temp voice', 'description' => 'Join-to-create voice channels'],
|
||||
],
|
||||
],
|
||||
'integrations' => [
|
||||
'label' => 'Integrations',
|
||||
'modules' => [
|
||||
['label' => 'Server statistics', 'description' => 'Automatic stats channels and invites'],
|
||||
['label' => 'Social feeds', 'description' => 'Twitch, YouTube, RSS, and Reddit notifications'],
|
||||
['label' => 'Scheduler', 'description' => 'Scheduled and recurring announcements'],
|
||||
['label' => 'Backups', 'description' => 'Server backup and restore'],
|
||||
],
|
||||
],
|
||||
],
|
||||
'legal' => [
|
||||
'nav_title' => 'Legal',
|
||||
'updated' => 'Last updated: July 2026',
|
||||
'impressum' => [
|
||||
'title' => 'Legal notice (Impressum)',
|
||||
'sections' => [
|
||||
[
|
||||
'heading' => 'Information pursuant to Section 5 DDG (Germany)',
|
||||
'paragraphs' => [
|
||||
'Service provider and operator of Nexumi (website, Discord bot, and dashboard):',
|
||||
],
|
||||
'lines' => [
|
||||
'HexaHost',
|
||||
'Proprietor: Samuel Müller',
|
||||
'Richard-Miller-Straße 1',
|
||||
'94051 Hauzenberg',
|
||||
'Germany',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Contact',
|
||||
'lines' => [
|
||||
'Phone: +49 15566 175855',
|
||||
'Email: info@hexahost.de',
|
||||
'Operator website: https://www.hexahost.de',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'VAT ID',
|
||||
'paragraphs' => [
|
||||
'VAT identification number pursuant to Section 27a of the German VAT Act: DE458741546',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Responsible for content',
|
||||
'lines' => [
|
||||
'Samuel Müller',
|
||||
'Richard-Miller-Straße 1',
|
||||
'94051 Hauzenberg',
|
||||
'Germany',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'EU dispute resolution',
|
||||
'paragraphs' => [
|
||||
'The European Commission provides a platform for online dispute resolution (ODR): https://ec.europa.eu/consumers/odr/',
|
||||
'You can find our email address in the legal notice above.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Consumer dispute resolution',
|
||||
'paragraphs' => [
|
||||
'We are neither willing nor obliged to participate in dispute resolution proceedings before a consumer arbitration board.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Liability for content',
|
||||
'paragraphs' => [
|
||||
'As a service provider, we are responsible for our own content on these pages in accordance with general laws (Section 7 (1) DDG). Under Sections 8 to 10 DDG, we are not obliged to monitor transmitted or stored third-party information or to investigate circumstances indicating illegal activity.',
|
||||
'Obligations to remove or block the use of information under general laws remain unaffected. Liability in this regard is only possible from the time we become aware of a specific infringement. Upon becoming aware of such infringements, we will remove such content without delay.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Liability for links',
|
||||
'paragraphs' => [
|
||||
'Our offering contains links to external third-party websites (including Discord and other services) over whose content we have no influence. Therefore, we cannot assume any liability for such external content. The respective provider or operator of the linked pages is always responsible for their content.',
|
||||
'The linked pages were checked for possible legal violations at the time of linking. Illegal content was not recognizable at that time. Permanent monitoring of linked pages is not reasonable without concrete indications of a violation. Upon becoming aware of legal violations, we will remove such links without delay.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => 'Copyright',
|
||||
'paragraphs' => [
|
||||
'Content and works created by the site operators on these pages (including Nexumi branding, logo, texts, and software) are subject to German copyright law. Reproduction, editing, distribution, and any kind of exploitation outside the limits of copyright require the written consent of the respective author or creator.',
|
||||
'Where content on this site was not created by the operator, third-party copyrights are respected. In particular, third-party content is marked as such. If you nevertheless become aware of a copyright infringement, please notify us. Upon becoming aware of infringements, we will remove such content without delay.',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'privacy' => [
|
||||
'title' => 'Privacy policy',
|
||||
'sections' => [
|
||||
[
|
||||
'heading' => '1. Controller',
|
||||
'paragraphs' => [
|
||||
'The controller within the meaning of the GDPR for operating Nexumi (website, Discord bot, and web dashboard) is:',
|
||||
],
|
||||
'lines' => [
|
||||
'HexaHost',
|
||||
'Proprietor: Samuel Müller',
|
||||
'Richard-Miller-Straße 1',
|
||||
'94051 Hauzenberg',
|
||||
'Germany',
|
||||
'Phone: +49 15566 175855',
|
||||
'Email: info@hexahost.de',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '2. General information',
|
||||
'paragraphs' => [
|
||||
'We take the protection of your personal data seriously. We process personal data confidentially and in accordance with statutory data protection rules and this privacy policy.',
|
||||
'This policy applies to the public Nexumi website, the Discord bot, and the related web dashboard. For general information about the operator, see also https://www.hexahost.de/datenschutz – the following sections are specifically adapted for Nexumi and Discord.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '3. Legal bases',
|
||||
'paragraphs' => [
|
||||
'Personal data is processed in particular on the basis of:',
|
||||
],
|
||||
'list' => [
|
||||
'Art. 6 (1)(a) GDPR – consent (where expressly obtained)',
|
||||
'Art. 6 (1)(b) GDPR – performance of a contract or pre-contractual steps (use of bot and dashboard on a Discord server)',
|
||||
'Art. 6 (1)(c) GDPR – compliance with a legal obligation',
|
||||
'Art. 6 (1)(f) GDPR – legitimate interests in secure, stable operations, abuse prevention, and support',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '4. What data do we process?',
|
||||
'paragraphs' => [
|
||||
'Depending on the modules used, the following categories of data may be processed in particular:',
|
||||
],
|
||||
'list' => [
|
||||
'Discord user IDs, guild names/IDs, channel and role IDs',
|
||||
'Message content or metadata where a module requires it (e.g. moderation, logging, tickets, suggestions)',
|
||||
'Moderation cases, warnings, timeouts, bans, and audit entries',
|
||||
'Module and server settings configured in the dashboard',
|
||||
'Economy/level/statistics data if the respective modules are enabled',
|
||||
'Technical logs (timestamps, errors, job status) for operating the infrastructure',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '5. Dashboard login (Discord OAuth2)',
|
||||
'paragraphs' => [
|
||||
'Login to the web dashboard uses Discord OAuth2. Typically the “identify” and “guilds” scopes are used to determine your Discord identity and your server list and to grant access to authorized servers.',
|
||||
'Session data is stored server-side (including in Redis). Session cookies are technically required for authentication.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '6. Storage and hosting',
|
||||
'paragraphs' => [
|
||||
'Nexumi application data is stored in a PostgreSQL database operated by us. Cache, sessions, and job queues use Redis. Servers and processing are under the responsibility of HexaHost.',
|
||||
'Retention periods may be configurable per module (e.g. log retention). Deletion or anonymization requests can be made via the bot command /gdpr (where available) or by contacting us using the details above.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '7. Recipients and processors',
|
||||
'paragraphs' => [
|
||||
'To provide the service, data is transmitted to Discord (Discord Inc. / affiliates) as technically required for bot features and OAuth. Discord’s privacy terms apply in addition.',
|
||||
'Optional error monitoring (e.g. Sentry) may process technical error information including limited context.',
|
||||
'We do not share data with third parties for advertising purposes.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '8. Website server log files',
|
||||
'paragraphs' => [
|
||||
'When you visit the website, server log files may be collected (e.g. IP address, browser, time, requested URL). Processing is based on Art. 6 (1)(f) GDPR to ensure uninterrupted operation and to prevent abuse. Log files are deleted regularly when no longer needed.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '9. Cookies',
|
||||
'paragraphs' => [
|
||||
'On the public website we only use necessary cookies or similar technologies where technically required. The dashboard sets session cookies for login. Nexumi does not use analytics or marketing cookies by default.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '10. Retention',
|
||||
'paragraphs' => [
|
||||
'Personal data is stored only as long as necessary for the respective purposes or as required by law. After the purpose ceases, data is deleted or anonymized unless legal obligations require otherwise.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '11. Your rights',
|
||||
'paragraphs' => [
|
||||
'You have the rights of access, rectification, erasure, restriction of processing, data portability, and objection to processing based on legitimate interests. You may withdraw consent at any time with effect for the future.',
|
||||
'To exercise your rights, contact us using the details in the legal notice or – where available – use the bot command /gdpr.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '12. Right to lodge a complaint',
|
||||
'paragraphs' => [
|
||||
'You have the right to lodge a complaint with a data protection supervisory authority. For Bavaria this includes the Bavarian Data Protection Authority (BayLDA), Promenade 18, 91522 Ansbach, https://www.lda.bayern.de',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '13. Security',
|
||||
'paragraphs' => [
|
||||
'We implement technical and organizational measures to protect personal data against loss, manipulation, and unauthorized access. Transmission usually uses TLS/HTTPS and encrypted connections to Discord.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '14. Updates',
|
||||
'paragraphs' => [
|
||||
'This privacy policy is current as of July 2026 and may be updated if the service or legal requirements change. The current version is available on this website.',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'terms' => [
|
||||
'title' => 'Terms of service',
|
||||
'sections' => [
|
||||
[
|
||||
'heading' => '1. Scope',
|
||||
'paragraphs' => [
|
||||
'These terms apply to use of the Nexumi Discord bot, the related web dashboard, and the public website. The provider is HexaHost, proprietor Samuel Müller.',
|
||||
'By inviting the bot to a Discord server, using commands, or logging into the dashboard, you accept these terms.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '2. Service description',
|
||||
'paragraphs' => [
|
||||
'Nexumi provides moderation, community, utility, and integration features for Discord servers. The feature set may evolve; individual modules may be enabled, disabled, or limited (including premium limits where offered).',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '3. User requirements and obligations',
|
||||
'paragraphs' => [
|
||||
'You may use Nexumi only if you have the required permissions on the respective Discord server and comply with Discord’s Terms of Service and Community Guidelines.',
|
||||
'Server administrators are responsible for ensuring that bot usage and configured modules comply with applicable law and the rights of server members (including transparency toward members).',
|
||||
],
|
||||
'list' => [
|
||||
'No abuse, spam, harassment, or circumvention of security mechanisms',
|
||||
'No use to commit or facilitate unlawful acts',
|
||||
'No attempts to access, disrupt, or overload systems without authorization',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '4. Availability',
|
||||
'paragraphs' => [
|
||||
'We aim for continuous operation but do not guarantee absolute availability. Maintenance, Discord outages, or infrastructure issues may temporarily limit use. Planned maintenance will be announced where reasonably possible.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '5. Suspension and termination',
|
||||
'paragraphs' => [
|
||||
'If you violate these terms, the law, or Discord rules, we may restrict or block access to the bot or dashboard for users or servers (including blacklisting). You may remove the bot from your server at any time; use for that server then ends.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '6. Liability',
|
||||
'paragraphs' => [
|
||||
'We are liable according to statute for injury to life, body, or health and under the German Product Liability Act. For other damages we are liable only for intent and gross negligence and for breach of essential contractual duties (cardinal duties); in cases of slight negligence liability is limited to foreseeable, typical damages.',
|
||||
'Users and local server teams remain responsible for content created or stored via Discord. We are not liable for decisions server teams make based on moderation data.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '7. Copyright and trademarks',
|
||||
'paragraphs' => [
|
||||
'Nexumi software, design, texts, and marks are protected by copyright and/or trademark law. Use outside the intended use of the service requires our prior consent.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '8. Changes',
|
||||
'paragraphs' => [
|
||||
'We may update these terms for legal, technical, or operational reasons. The current version will be published on the website or dashboard. Material changes will be communicated where reasonably possible.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '9. Governing law',
|
||||
'paragraphs' => [
|
||||
'German law applies, excluding the UN Convention on Contracts for the International Sale of Goods, unless mandatory consumer protection rules require otherwise.',
|
||||
'If any provision is invalid, the remaining provisions remain in effect.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'heading' => '10. Contact',
|
||||
'paragraphs' => [
|
||||
'Questions about these terms should be sent using the contact details in the legal notice.',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
9
landingpage/nutzungsbedingungen.php
Normal file
9
landingpage/nutzungsbedingungen.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/includes/bootstrap.php';
|
||||
require __DIR__ . '/includes/layout.php';
|
||||
|
||||
$locale = detect_locale();
|
||||
$messages = load_messages($locale);
|
||||
render_legal_page($config, $messages, $locale, 'terms');
|
||||
Reference in New Issue
Block a user