fix(nginx): serve .txt as UTF-8 and make AI-discovery files reachable

llms.txt and robots.txt were served without a charset, so browsers
decoded the valid UTF-8 as Windows-1252 and showed mojibake (â€", für).

- Add `charset utf-8;` (+ charset_types) so text responses carry
  `; charset=utf-8`.
- Add an explicit `location ~* \.txt$` that serves the file as plain
  text, returns 404 instead of falling back to index.html, and sets
  `Access-Control-Allow-Origin: *` so any AI crawler/tool can fetch
  llms.txt cross-origin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-24 12:00:43 +02:00
parent 561b20323c
commit 94644894b1
4 changed files with 1510 additions and 0 deletions

75
website/dashboard.html Normal file
View File

@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Profice OS Dashboard</title>
<meta name="robots" content="noindex" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<style>
:root{--bg:#050505;--bg-2:#111111;--gold:#F57C00;--gold-light:#FF9E3D;--text:#F5F5F5;--muted:#A3A3A3;--line:rgba(255,255,255,.12);--line-strong:rgba(245, 124, 0,.35);--radius:14px;--maxw:1200px;--pad:clamp(20px,5vw,40px);}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--text);font-family:"Inter",system-ui,-apple-system,sans-serif;line-height:1.6;-webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--pad)}
header{position:sticky;top:0;z-index:100;background:rgba(5,5,5,.72);backdrop-filter:blur(14px);border-bottom:1px solid var(--line)}
.nav{display:flex;align-items:center;justify-content:space-between;height:70px}
.logo{font-weight:700;font-size:1.2rem;letter-spacing:-.02em}
.logo .dot{color:var(--gold)} .logo .os{color:var(--gold);font-weight:500;font-size:.95rem;margin-left:8px;letter-spacing:.05em}
.btn{display:inline-flex;align-items:center;gap:10px;padding:11px 20px;border-radius:10px;font-weight:600;font-size:.9rem;cursor:pointer;border:1px solid var(--line);background:transparent;color:var(--text);font-family:inherit;transition:all .2s}
.btn:hover{border-color:var(--line-strong);background:rgba(245, 124, 0,.06)}
.head{padding:clamp(40px,7vw,80px) 0 26px}
.eyebrow{display:inline-flex;align-items:center;gap:10px;font-size:.78rem;letter-spacing:.18em;text-transform:uppercase;color:var(--gold);font-weight:500;margin-bottom:18px}
.eyebrow::before{content:"";width:26px;height:1px;background:var(--gold)}
h1{font-size:clamp(1.8rem,4vw,2.6rem);font-weight:700;letter-spacing:-.02em}
h1 span{color:var(--gold)}
.head p{color:var(--muted);margin-top:12px;max-width:640px}
.note{border:1px dashed var(--line-strong);border-radius:var(--radius);padding:18px 22px;color:var(--muted);font-size:.9rem;margin-bottom:30px;background:rgba(245, 124, 0,.04)}
.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;padding-bottom:70px}
.tile{background:var(--bg-2);border:1px solid var(--line);border-radius:var(--radius);padding:24px;min-height:160px;display:flex;flex-direction:column;justify-content:space-between;transition:border-color .3s,transform .3s}
.tile:hover{border-color:var(--line-strong);transform:translateY(-3px)}
.tile .ic{width:40px;height:40px;border-radius:10px;background:rgba(245, 124, 0,.12);border:1px solid var(--line-strong);display:grid;place-items:center;color:var(--gold);font-size:1.1rem}
.tile h3{font-size:1.05rem;margin-top:16px;font-weight:600}
.tile .st{font-size:.82rem;color:var(--muted);margin-top:4px}
.tile .soon{font-size:.64rem;letter-spacing:.1em;text-transform:uppercase;color:var(--gold);border:1px solid var(--line-strong);border-radius:20px;padding:3px 10px;align-self:flex-start;margin-top:14px}
@media(max-width:900px){.grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.grid{grid-template-columns:1fr}}
</style>
</head>
<body>
<header><div class="wrap nav">
<a href="profice-os.html" class="logo">Profice<span class="dot">.</span><span class="os">OS</span></a>
<button class="btn" id="logoutBtn" type="button">Abmelden</button>
</div></header>
<main class="wrap">
<div class="head">
<span class="eyebrow">Dashboard</span>
<h1>Willkommen zurück, <span id="userName"></span>.</h1>
<p>Ihre zentrale Steuerungsebene. Hier laufen Kommunikation, Wissen, Automatisierung und KI-Agenten zusammen.</p>
</div>
<div class="note">Hinweis: Frontend-Vorschau des Dashboards. Echte Konten, Login und Live-Daten folgen mit der Backend-Anbindung.</div>
<div class="grid">
<div class="tile"><span class="ic"></span><div><h3>Kommunikation</h3><div class="st">12 offene Vorgänge</div></div><span class="soon">Bald</span></div>
<div class="tile"><span class="ic"></span><div><h3>Wissensbasis</h3><div class="st">aktuell</div></div><span class="soon">Bald</span></div>
<div class="tile"><span class="ic"></span><div><h3>KI-Agenten</h3><div class="st">4 aktiv</div></div><span class="soon">Bald</span></div>
<div class="tile"><span class="ic"></span><div><h3>Automation</h3><div class="st">9 Workflows</div></div><span class="soon">Bald</span></div>
<div class="tile"><span class="ic"></span><div><h3>Dokumente</h3><div class="st">strukturiert</div></div><span class="soon">Bald</span></div>
<div class="tile"><span class="ic"></span><div><h3>Geschäftsführung</h3><div class="st">Live-Sicht</div></div><span class="soon">Bald</span></div>
</div>
</main>
<script>
(function () {
var KEY = 'proficeos_user', u = null;
try { u = JSON.parse(localStorage.getItem(KEY) || 'null'); } catch (e) {}
if (!u || !u.email) { window.location.replace('profice-os.html'); return; }
document.getElementById('userName').textContent = u.name || u.email.split('@')[0];
document.getElementById('logoutBtn').addEventListener('click', function () {
try { localStorage.removeItem(KEY); } catch (e) {}
window.location.href = 'profice-os.html';
});
})();
</script>
</body>
</html>