@lenne.tech/cli
Version:
lenne.Tech CLI: lt
604 lines (564 loc) • 46.3 kB
HTML
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>lt dev × lt ticket — Parallel entwickeln ohne Reibung</title>
<style>
:root {
--indigo:#6366f1; --indigo-d:#4f46e5; --violet:#8b5cf6;
--cyan:#06b6d4; --emerald:#10b981; --amber:#f59e0b; --rose:#f43f5e;
--ink:#0f172a; --ink-2:#334155; --muted:#64748b; --line:#e2e8f0;
--bg:#ffffff; --bg-soft:#f8fafc; --bg-soft2:#f1f5f9;
--code-bg:#0f172a; --code-ink:#e2e8f0;
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "Noto Sans", sans-serif;
--mono: "SF Mono", "JetBrains Mono", "Fira Code", Menlo, Consolas, monospace;
}
* { box-sizing:border-box; }
html { -webkit-print-color-adjust:exact; print-color-adjust:exact; }
body {
margin:0; font-family:var(--font); color:var(--ink); background:var(--bg);
line-height:1.6; font-size:15px; letter-spacing:.1px;
}
.page { max-width:980px; margin:0 auto; padding:0 40px; }
h1,h2,h3 { line-height:1.18; letter-spacing:-.02em; }
h2 { font-size:30px; margin:6px 0 4px; }
h3 { font-size:20px; margin:26px 0 8px; }
p { margin:10px 0; color:var(--ink-2); }
a { color:var(--indigo-d); text-decoration:none; }
code, .mono { font-family:var(--mono); font-size:.88em; }
:not(pre) > code { background:var(--bg-soft2); border:1px solid var(--line); border-radius:6px; padding:1px 6px; color:#0b2545; white-space:nowrap; }
.lead { font-size:18px; color:var(--ink-2); }
.small { font-size:13px; }
.muted { color:var(--muted); }
/* ---------- HERO ---------- */
.hero {
background:
radial-gradient(1200px 500px at 85% -10%, rgba(6,182,212,.35), transparent 60%),
radial-gradient(900px 500px at 5% 120%, rgba(139,92,246,.40), transparent 55%),
linear-gradient(135deg, #1e1b4b 0%, #312e81 48%, #155e75 100%);
color:#fff; padding:64px 0 56px; position:relative; overflow:hidden;
}
.hero .page { position:relative; z-index:2; }
.hero .kicker { text-transform:uppercase; letter-spacing:.28em; font-size:12px; font-weight:700; color:#a5f3fc; opacity:.95; }
.hero h1 { font-size:50px; margin:14px 0 10px; font-weight:800; color:#fff; }
.hero h1 .grad { background:linear-gradient(90deg,#a5b4fc,#67e8f9 60%,#6ee7b7); -webkit-background-clip:text; background-clip:text; color:transparent; }
.hero .sub { font-size:19px; color:#dbeafe; max-width:760px; }
.hero .badges { margin-top:24px; display:flex; flex-wrap:wrap; gap:10px; }
.pill { display:inline-flex; align-items:center; gap:7px; font-size:13px; font-weight:600;
background:rgba(255,255,255,.10); border:1px solid rgba(255,255,255,.22); color:#f0f9ff;
padding:7px 13px; border-radius:999px; backdrop-filter:blur(6px); }
.pill .dot { width:8px; height:8px; border-radius:50%; }
.meta-row { margin-top:30px; display:flex; gap:26px; flex-wrap:wrap; color:#c7d2fe; font-size:13px; }
.meta-row b { color:#fff; }
/* ---------- LAYOUT BLOCKS ---------- */
section { padding:40px 0; border-bottom:1px solid var(--line); }
section.alt { background:var(--bg-soft); }
.eyebrow { display:inline-block; font-size:12px; font-weight:800; letter-spacing:.22em; text-transform:uppercase;
color:var(--indigo-d); background:#eef2ff; border:1px solid #e0e7ff; padding:4px 11px; border-radius:999px; margin-bottom:10px; }
.grid { display:grid; gap:18px; }
.g2 { grid-template-columns:1fr 1fr; }
.g3 { grid-template-columns:1fr 1fr 1fr; }
@media (max-width:760px){ .g2,.g3 { grid-template-columns:1fr; } }
.card { background:var(--bg); border:1px solid var(--line); border-radius:16px; padding:20px 22px;
box-shadow:0 1px 2px rgba(15,23,42,.04), 0 8px 24px -16px rgba(15,23,42,.18); }
.card h3 { margin-top:0; }
.card .ico { width:42px; height:42px; border-radius:12px; display:flex; align-items:center; justify-content:center;
font-size:20px; margin-bottom:12px; color:#fff; }
.badge { display:inline-block; font-size:11px; font-weight:800; letter-spacing:.04em; padding:2px 9px; border-radius:999px; vertical-align:middle; }
.b-indigo{ background:#eef2ff; color:#4338ca; } .b-cyan{ background:#ecfeff; color:#0e7490; }
.b-emerald{ background:#ecfdf5; color:#047857; } .b-amber{ background:#fffbeb; color:#b45309; }
.b-rose{ background:#fff1f2; color:#be123c; } .b-slate{ background:#f1f5f9; color:#334155; }
/* ---------- CODE ---------- */
pre { background:var(--code-bg); color:var(--code-ink); border-radius:14px; padding:18px 20px; overflow:auto;
font-family:var(--mono); font-size:13px; line-height:1.7; margin:14px 0; border:1px solid #1e293b; }
pre .c { color:#7c93b3; } /* comment */
pre .k { color:#67e8f9; } /* command */
pre .a { color:#fcd34d; } /* arg/flag */
pre .s { color:#86efac; } /* string/url */
pre .m { color:#c4b5fd; } /* meta */
/* ---------- TABLE ---------- */
table { width:100%; border-collapse:collapse; margin:14px 0; font-size:14px; }
th,td { text-align:left; padding:11px 14px; border-bottom:1px solid var(--line); vertical-align:top; }
th { font-size:12px; text-transform:uppercase; letter-spacing:.06em; color:var(--muted); background:var(--bg-soft); }
tbody tr:nth-child(even){ background:var(--bg-soft); }
td code { font-size:.86em; }
/* ---------- CALLOUTS ---------- */
.note { border-radius:14px; padding:16px 18px 16px 18px; margin:16px 0; border:1px solid; display:flex; gap:13px; }
.note .ni { font-size:20px; line-height:1; }
.note.tip { background:#f0fdfa; border-color:#99f6e4; }
.note.warn { background:#fffbeb; border-color:#fde68a; }
.note.key { background:#eef2ff; border-color:#c7d2fe; }
.note b { color:var(--ink); }
.steps { counter-reset:s; display:grid; gap:14px; }
.step { display:flex; gap:15px; align-items:flex-start; }
.step .n { counter-increment:s; flex:0 0 34px; height:34px; border-radius:50%;
background:linear-gradient(135deg,var(--indigo),var(--violet)); color:#fff; font-weight:800;
display:flex; align-items:center; justify-content:center; font-size:15px; }
.step .n::before { content:counter(s); }
.kpi { display:grid; grid-template-columns:repeat(4,1fr); gap:16px; margin:18px 0; }
@media (max-width:760px){ .kpi { grid-template-columns:1fr 1fr; } }
.kpi .k { background:var(--bg); border:1px solid var(--line); border-radius:14px; padding:16px; text-align:center; }
.kpi .big { font-size:30px; font-weight:800; background:linear-gradient(135deg,var(--indigo),var(--cyan)); -webkit-background-clip:text; background-clip:text; color:transparent; }
.kpi .lbl { font-size:12px; color:var(--muted); margin-top:2px; }
figure { margin:18px 0 6px; }
figure svg { width:100%; height:auto; display:block; border:1px solid var(--line); border-radius:16px; background:#fff; }
figcaption { font-size:12.5px; color:var(--muted); margin-top:8px; text-align:center; }
.footer { padding:30px 0 50px; color:var(--muted); font-size:13px; }
.footer .brand { font-weight:800; color:var(--ink); letter-spacing:-.01em; }
/* ---------- PRINT ---------- */
@page { size:A4; margin:14mm 0; }
@media print {
body { font-size:11.4pt; }
.page { max-width:none; padding:0 16mm; }
section { padding:18px 0; }
.hero { padding:30mm 0 22mm; }
.hero h1 { font-size:34pt; }
.no-print { display:none ; }
.card, figure svg, pre, .note, .kpi .k { box-shadow:none; }
pre { white-space:pre-wrap; word-break:break-word; font-size:9.5pt; line-height:1.55; }
h2, h3 { break-after:avoid; }
.card, .note, figure, table, pre, .step { break-inside:avoid; }
.break { break-before:page; }
}
</style>
</head>
<body>
<!-- ============================ HERO ============================ -->
<header class="hero">
<div class="page">
<div class="kicker">lenne.Tech · Developer Workflow Guide</div>
<h1>Parallel entwickeln —<br><span class="grad">ohne Reibung, ohne Kollisionen.</span></h1>
<p class="sub">Mit <b>lt dev</b> und <b>lt ticket</b> betreibst du beliebig viele Projekte <i>und</i> beliebig viele Tickets gleichzeitig — jedes mit eigener URL, eigener Datenbank, eigenen Ports. Ein Befehl, und du legst los.</p>
<div class="badges">
<span class="pill"><span class="dot" style="background:#67e8f9"></span> Pro Projekt isoliert</span>
<span class="pill"><span class="dot" style="background:#a5b4fc"></span> Pro Ticket isoliert</span>
<span class="pill"><span class="dot" style="background:#6ee7b7"></span> Parallele E2E-Tests</span>
<span class="pill"><span class="dot" style="background:#fcd34d"></span> Claude-aware</span>
<span class="pill"><span class="dot" style="background:#fda4af"></span> Schutz vor Datenverlust</span>
</div>
<div class="meta-row">
<div>Voraussetzung <b>lt CLI ≥ 1.28.0 · neuestes lt-dev Plugin</b></div>
<div>Stack <b>Nest Server · Nuxt Base</b></div>
<div>Routing <b>Caddy · *.localhost (HTTPS)</b></div>
<div>Zielgruppe <b>lenne.Tech Entwickler:innen</b></div>
</div>
</div>
</header>
<!-- ============================ WARUM ============================ -->
<section class="alt">
<div class="page">
<span class="eyebrow">Warum das alles?</span>
<h2>Schluss mit „erst runterfahren, dann das andere starten"</h2>
<p class="lead">Bisher band jedes Projekt die Framework-Default-Ports <code>3000</code>/<code>3001</code>. Zwei Projekte gleichzeitig? Port-Kollision. Auth über Cookies? Cross-wiring. Ein zweites Ticket testen, während das erste läuft? Ging nicht.</p>
<div class="grid g2" style="margin-top:18px">
<div class="card" style="border-color:#fecaca; background:#fff7f7">
<span class="badge b-rose">VORHER</span>
<h3 style="margin-top:8px">Sequenziell & fragil</h3>
<p style="margin:6px 0 0">Ein Projekt zur Zeit. Feste Ports kollidieren. Branch wechseln heißt: Server neu starten, DB-Zustand verlieren, Kontext verlieren. Tickets parallel? Nur über getrennte Klone — langsam und unübersichtlich.</p>
</div>
<div class="card" style="border-color:#bbf7d0; background:#f3fdf7">
<span class="badge b-emerald">NACHHER</span>
<h3 style="margin-top:8px">Parallel & isoliert</h3>
<p style="margin:6px 0 0">Jedes Projekt und jedes Ticket läuft hinter Caddy unter <code>https://<name>.localhost</code> — eigene Ports, eigene DB, eigener Caddy-Block. Mehrere Browser-Tabs, mehrere Claude-Sessions, mehrere Test-Läufe — alles gleichzeitig, nichts beeinflusst sich.</p>
</div>
</div>
<div class="kpi">
<div class="k"><div class="big">0 s</div><div class="lbl">Worktree anlegen (geteiltes .git)</div></div>
<div class="k"><div class="big">1</div><div class="lbl">Befehl bis „läuft im Browser"</div></div>
<div class="k"><div class="big">N</div><div class="lbl">Tickets & Projekte gleichzeitig</div></div>
<div class="k"><div class="big">~2×</div><div class="lbl">schnellere E2E durch Sharding</div></div>
</div>
</div>
</section>
<!-- ============================ VORAUSSETZUNGEN ============================ -->
<section>
<div class="page">
<span class="eyebrow">Voraussetzungen</span>
<h2>Bevor du loslegst — einmal aktuell ziehen</h2>
<p class="lead">Dieser Workflow braucht die <b>lt CLI ≥ 1.28.0</b> (enthält <code>lt dev</code> + <code>lt ticket</code>) und das <b>neueste lt-dev Claude Plugin</b> (macht Claude ticket-aware). Beides ist in Sekunden installiert bzw. aktualisiert.</p>
<div class="grid g2" style="margin-top:16px">
<div class="card">
<div class="ico" style="background:linear-gradient(135deg,#6366f1,#4338ca)">⬇️</div>
<h3>lt CLI <span class="badge b-indigo">≥ 1.28.0</span></h3>
<p class="small" style="margin-top:4px">Version prüfen mit <code>lt --version</code> — muss <b>1.28.0 oder neuer</b> sein.</p>
<pre><span class="c"># Neu installieren (global)</span>
<span class="k">npm</span> <span class="a">install -g</span> <span class="s">@lenne.tech/cli</span>
<span class="c"># Auf die neueste Version aktualisieren</span>
<span class="k">lt update</span>
<span class="c"># Version prüfen (≥ 1.28.0)</span>
<span class="k">lt</span> <span class="a">--version</span></pre>
</div>
<div class="card">
<div class="ico" style="background:linear-gradient(135deg,#06b6d4,#0e7490)">🧩</div>
<h3>Neuestes lt-dev Plugin</h3>
<p class="small" style="margin-top:4px">Aus dem <b>lenne-tech Marketplace</b> ziehen — installiert/aktualisiert lt-dev (+ weitere lt-Plugins) und richtet die Berechtigungen ein.</p>
<pre><span class="c"># lt-dev Claude Plugin installieren / aktualisieren</span>
<span class="k">lt claude plugins</span></pre>
<p class="small muted" style="margin-top:8px">Aktualisiert sich zusätzlich automatisch beim Start einer Claude-Code-Session.</p>
</div>
</div>
<div class="note key"><div class="ni">🚀</div><div><b>In 3 Schritten startklar:</b> <code>lt update</code> (CLI auf ≥ 1.28.0) → <code>lt claude plugins</code> (Plugin ziehen) → im Projekt <code>lt dev init</code>, dann <code>lt ticket start <ticket></code>.</div></div>
</div>
</section>
<!-- ============================ LT DEV ============================ -->
<section class="alt">
<div class="page">
<span class="eyebrow">Baustein 1</span>
<h2><code style="font-size:.8em">lt dev</code> — der isolierte Stack pro Projekt</h2>
<p class="lead">Ein Projekt, eine eigene Welt. <b>lt dev up</b> startet API + App hinter Caddy unter projekteigenen URLs — beliebig viele Projekte nebeneinander, garantiert kollisionsfrei.</p>
<figure>
<!-- DIAGRAM A: multi-project isolation -->
<svg viewBox="0 0 920 360" role="img" aria-label="Mehrere Projekte hinter Caddy, jeweils mit eigenen URLs, Ports und Datenbank">
<defs>
<linearGradient id="gCaddy" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#6366f1"/><stop offset="1" stop-color="#06b6d4"/>
</linearGradient>
<marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 z" fill="#94a3b8"/>
</marker>
</defs>
<rect x="0" y="0" width="920" height="360" fill="#ffffff"/>
<!-- Caddy bar -->
<rect x="60" y="36" width="800" height="56" rx="14" fill="url(#gCaddy)"/>
<text x="460" y="60" text-anchor="middle" fill="#fff" font-family="sans-serif" font-size="16" font-weight="700">Caddy · Reverse Proxy · HTTPS auf *.localhost</text>
<text x="460" y="80" text-anchor="middle" fill="#e0e7ff" font-family="sans-serif" font-size="12">eine lokale CA · keine Port-Angabe in URLs · automatisch verwaltet</text>
<!-- three project columns -->
<g font-family="sans-serif">
<!-- helper via repeated groups -->
<g>
<line x1="200" y1="92" x2="200" y2="140" stroke="#94a3b8" stroke-width="2" marker-end="url(#arr)"/>
<rect x="80" y="140" width="240" height="170" rx="14" fill="#f8fafc" stroke="#e2e8f0"/>
<text x="100" y="168" font-size="15" font-weight="800" fill="#0f172a">Projekt „crm"</text>
<text x="100" y="194" font-size="12.5" fill="#0e7490" font-family="monospace">crm.localhost</text>
<text x="100" y="214" font-size="12.5" fill="#0e7490" font-family="monospace">api.crm.localhost</text>
<text x="100" y="240" font-size="12" fill="#475569" font-family="monospace">DB crm-local</text>
<text x="100" y="262" font-size="12" fill="#475569" font-family="monospace">Ports 4000/4001</text>
<rect x="100" y="276" width="120" height="20" rx="10" fill="#ecfdf5"/><text x="160" y="290" text-anchor="middle" font-size="11" font-weight="700" fill="#047857">● up</text>
</g>
<g>
<line x1="460" y1="92" x2="460" y2="140" stroke="#94a3b8" stroke-width="2" marker-end="url(#arr)"/>
<rect x="340" y="140" width="240" height="170" rx="14" fill="#f8fafc" stroke="#e2e8f0"/>
<text x="360" y="168" font-size="15" font-weight="800" fill="#0f172a">Projekt „svl"</text>
<text x="360" y="194" font-size="12.5" fill="#0e7490" font-family="monospace">svl.localhost</text>
<text x="360" y="214" font-size="12.5" fill="#0e7490" font-family="monospace">api.svl.localhost</text>
<text x="360" y="240" font-size="12" fill="#475569" font-family="monospace">DB svl-…-local</text>
<text x="360" y="262" font-size="12" fill="#475569" font-family="monospace">Ports 4002/4003</text>
<rect x="360" y="276" width="120" height="20" rx="10" fill="#ecfdf5"/><text x="420" y="290" text-anchor="middle" font-size="11" font-weight="700" fill="#047857">● up</text>
</g>
<g>
<line x1="720" y1="92" x2="720" y2="140" stroke="#94a3b8" stroke-width="2" marker-end="url(#arr)"/>
<rect x="600" y="140" width="240" height="170" rx="14" fill="#f8fafc" stroke="#e2e8f0"/>
<text x="620" y="168" font-size="15" font-weight="800" fill="#0f172a">Projekt „shop"</text>
<text x="620" y="194" font-size="12.5" fill="#0e7490" font-family="monospace">shop.localhost</text>
<text x="620" y="214" font-size="12.5" fill="#0e7490" font-family="monospace">api.shop.localhost</text>
<text x="620" y="240" font-size="12" fill="#475569" font-family="monospace">DB shop-local</text>
<text x="620" y="262" font-size="12" fill="#475569" font-family="monospace">Ports 4004/4005</text>
<rect x="620" y="276" width="120" height="20" rx="10" fill="#ecfdf5"/><text x="680" y="290" text-anchor="middle" font-size="11" font-weight="700" fill="#047857">● up</text>
</g>
</g>
</svg>
<figcaption>Drei Projekte, gleichzeitig „up" — eigene URLs, eigene DBs, eigene Ports. Caddy routet alles über HTTPS, ganz ohne Port-Angabe.</figcaption>
</figure>
<h3>Der Lebenszyklus</h3>
<pre><span class="c"># Einmal pro Rechner</span>
<span class="k">lt dev install</span> <span class="c"># Caddy + lokale CA + Service einrichten</span>
<span class="c"># Einmal pro Projekt (idempotent)</span>
<span class="k">lt dev init</span> <span class="c"># env-aware patchen + registrieren (idempotent)</span>
<span class="c"># Täglich</span>
<span class="k">lt dev up</span> <span class="c">→ <span class="s">https://svl.localhost</span> · <span class="s">https://api.svl.localhost</span></span>
<span class="k">lt dev status</span> <span class="a">--all</span> <span class="c"># was läuft gerade? (alle Projekte)</span>
<span class="k">lt dev down</span> <span class="c"># sauber stoppen + Caddy-Block entfernen</span></pre>
<h3>Befehlsübersicht</h3>
<table>
<thead><tr><th>Befehl</th><th>Was es tut</th></tr></thead>
<tbody>
<tr><td><code>lt dev install</code></td><td>Einmal pro Rechner: Caddy, lokale CA und Hintergrund-Service einrichten.</td></tr>
<tr><td><code>lt dev init</code></td><td>Einmal pro Projekt: Ports env-aware machen, registrieren, <code>ignoreHTTPSErrors</code> + shard-aware Test-Timeouts injizieren. Idempotent.</td></tr>
<tr><td><code>lt dev up</code></td><td>API + App hinter Caddy starten: <code>https://<slug>.localhost</code> / <code>api.<slug>.localhost</code>, DB <code><slug>-local</code>.</td></tr>
<tr><td><code>lt dev down</code></td><td>Prozesse stoppen, Caddy-Block entfernen, etwaige Test-Stacks abräumen.</td></tr>
<tr><td><code>lt dev status</code> · <code>--all</code></td><td>URLs, Ports, PIDs, Live-Zustand — fürs aktuelle Projekt oder alle registrierten.</td></tr>
<tr><td><code>lt dev doctor</code></td><td>Caddy/CA/DNS/Ports prüfen — <span class="badge b-cyan">NEU</span> warnt auch, wenn ein DB-löschendes <code>global-setup</code> die Ticket-/Shard-Test-DBs nicht zurücksetzen würde.</td></tr>
<tr><td><code>lt dev test</code></td><td>E2E in einem <b>isolierten, parallelen</b> Stack auf dedizierter DB <code><slug>-test</code> — restfreier Auto-Teardown.</td></tr>
<tr><td><code>lt dev test --shard N</code></td><td>Suite auf N isolierte Stacks aufteilen (Default 2) — lokale CI-Parität, ~2× schneller.</td></tr>
<tr><td><code>lt dev tunnel</code></td><td>Öffentliche <code>*.trycloudflare.com</code>-URL für ein laufendes Projekt (Demo/Review).</td></tr>
</tbody>
</table>
<div class="note key"><div class="ni">🔌</div><div><b>Nie wieder <code>localhost:3000</code>.</b> Alle URLs kommen von <code>lt dev</code> über die Env-Bridge (<code>.lt-dev/.env</code>) — Playwright, IDE und Skripte ziehen sie automatisch.</div></div>
</div>
</section>
<!-- ============================ LT TICKET ============================ -->
<section class="break">
<div class="page">
<span class="eyebrow">Baustein 2</span>
<h2><code style="font-size:.8em">lt ticket</code> — mehrere Tickets gleichzeitig</h2>
<p class="lead">Ein Repo, beliebig viele Tickets — jedes in einem eigenen <b>git worktree</b> mit eigenem <code>lt dev</code>-Stack. Frisch aus <code>origin/dev</code>, in Sekunden startklar, voneinander komplett unabhängig.</p>
<figure>
<!-- DIAGRAM B: one repo -> N worktrees -> N stacks -->
<svg viewBox="0 0 920 380" role="img" aria-label="Ein Repository, mehrere Worktrees, jeweils mit eigenem Stack">
<defs>
<marker id="arr2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 z" fill="#a78bfa"/>
</marker>
<linearGradient id="gRepo" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#312e81"/><stop offset="1" stop-color="#4338ca"/></linearGradient>
</defs>
<rect x="0" y="0" width="920" height="380" fill="#ffffff"/>
<!-- repo -->
<rect x="40" y="150" width="180" height="90" rx="14" fill="url(#gRepo)"/>
<text x="130" y="184" text-anchor="middle" fill="#fff" font-size="15" font-weight="800" font-family="sans-serif">svl-sports-system</text>
<text x="130" y="206" text-anchor="middle" fill="#c7d2fe" font-size="12" font-family="monospace">ein .git (geteilt)</text>
<text x="130" y="224" text-anchor="middle" fill="#a5b4fc" font-size="11.5" font-family="monospace">branch: dev</text>
<!-- 3 worktrees + stacks -->
<g font-family="sans-serif">
<g>
<path d="M220 178 C 280 130, 300 110, 360 110" stroke="#a78bfa" stroke-width="2" fill="none" marker-end="url(#arr2)"/>
<rect x="360" y="78" width="210" height="66" rx="12" fill="#f5f3ff" stroke="#ddd6fe"/>
<text x="376" y="104" font-size="13.5" font-weight="800" fill="#5b21b6">worktree · svl-2200</text>
<text x="376" y="124" font-size="11.5" fill="#6d28d9" font-family="monospace">branch feat/DEV-2200</text>
<path d="M570 111 H 610" stroke="#94a3b8" stroke-width="2" marker-end="url(#arr2)"/>
<rect x="610" y="78" width="270" height="66" rx="12" fill="#ecfeff" stroke="#a5f3fc"/>
<text x="626" y="100" font-size="12" fill="#0e7490" font-family="monospace">svl-2200.localhost</text>
<text x="626" y="118" font-size="12" fill="#0e7490" font-family="monospace">api.svl-2200.localhost</text>
<text x="626" y="136" font-size="11.5" fill="#475569" font-family="monospace">DB svl-…-2200 · Ports 40xx</text>
</g>
<g>
<path d="M220 195 H 360" stroke="#a78bfa" stroke-width="2" fill="none" marker-end="url(#arr2)"/>
<rect x="360" y="162" width="210" height="66" rx="12" fill="#f5f3ff" stroke="#ddd6fe"/>
<text x="376" y="188" font-size="13.5" font-weight="800" fill="#5b21b6">worktree · svl-2201</text>
<text x="376" y="208" font-size="11.5" fill="#6d28d9" font-family="monospace">branch feat/DEV-2201</text>
<path d="M570 195 H 610" stroke="#94a3b8" stroke-width="2" marker-end="url(#arr2)"/>
<rect x="610" y="162" width="270" height="66" rx="12" fill="#ecfeff" stroke="#a5f3fc"/>
<text x="626" y="184" font-size="12" fill="#0e7490" font-family="monospace">svl-2201.localhost</text>
<text x="626" y="202" font-size="12" fill="#0e7490" font-family="monospace">api.svl-2201.localhost</text>
<text x="626" y="220" font-size="11.5" fill="#475569" font-family="monospace">DB svl-…-2201 · Ports 40xx</text>
</g>
<g>
<path d="M220 212 C 280 260, 300 280, 360 280" stroke="#a78bfa" stroke-width="2" fill="none" marker-end="url(#arr2)"/>
<rect x="360" y="246" width="210" height="66" rx="12" fill="#f5f3ff" stroke="#ddd6fe"/>
<text x="376" y="272" font-size="13.5" font-weight="800" fill="#5b21b6">worktree · svl-login-fix</text>
<text x="376" y="292" font-size="11.5" fill="#6d28d9" font-family="monospace">branch feat/login-fix</text>
<path d="M570 279 H 610" stroke="#94a3b8" stroke-width="2" marker-end="url(#arr2)"/>
<rect x="610" y="246" width="270" height="66" rx="12" fill="#ecfeff" stroke="#a5f3fc"/>
<text x="626" y="268" font-size="12" fill="#0e7490" font-family="monospace">svl-login-fix.localhost</text>
<text x="626" y="286" font-size="12" fill="#0e7490" font-family="monospace">api.svl-login-fix.localhost</text>
<text x="626" y="304" font-size="11.5" fill="#475569" font-family="monospace">DB svl-…-login-fix · Ports 40xx</text>
</g>
</g>
<text x="460" y="356" text-anchor="middle" font-size="12.5" fill="#64748b" font-family="sans-serif">Ticket-ID auch ohne Ticket möglich: ein freier Feature-Name funktioniert genauso (z. B. „login-fix").</text>
</svg>
<figcaption>Ein Repo → mehrere Worktrees (geteiltes <code>.git</code>, sofort) → je ein vollständig isolierter Stack. Ordnername = URL = DB = Ticket — du weißt immer, wo du bist.</figcaption>
</figure>
<h3>So einfach geht's</h3>
<pre><span class="k">lt ticket start</span> <span class="a">DEV-2200</span> <span class="c"># fetch + worktree aus origin/dev + install + lt dev up</span>
<span class="c">→ <span class="s">https://svl-2200.localhost</span> · DB svl-…-2200 (leer)</span>
<span class="k">lt ticket start</span> <span class="a">login-fix</span> <span class="c"># kein Ticket? freier Name → svl-login-fix.localhost</span>
<span class="k">lt ticket start</span> <span class="a">DEV-2200 --as cof</span> <span class="c"># Kurzname überschreiben; --branch / --base ebenso</span>
<span class="k">lt ticket list</span> <span class="c"># Dashboard: alle Tickets + URLs + Branch + Status + DB</span>
<span class="k">lt ticket switch</span> <span class="a">2200</span> <span class="c"># Pfad zeigen + im Editor öffnen</span>
<span class="k">lt ticket test</span> <span class="a">2200 --shard 2</span> <span class="c"># E2E im isolierten Ticket-Stack/-DB</span>
<span class="k">lt ticket stop</span> <span class="a">2200 --drop-db</span> <span class="c"># down + worktree entfernen (Branch bleibt); --drop-db löscht DBs</span></pre>
<div class="grid g3" style="margin-top:8px">
<div class="card"><div class="ico" style="background:linear-gradient(135deg,#6366f1,#8b5cf6)">🎯</div>
<h3>Eigene Identität, überall</h3>
<p class="small">Jedes Ticket bekommt <code><slug>-<id></code> in URL, DB, Ports, Caddy-Block, Ordnername. Verwechslung ausgeschlossen.</p></div>
<div class="card"><div class="ico" style="background:linear-gradient(135deg,#06b6d4,#0e7490)">🌱</div>
<h3>Immer frisch aus dev</h3>
<p class="small">Jeder Start macht <code>git fetch</code> und zweigt von <code>origin/dev</code> ab — alle Tickets unabhängig. <code>--base</code> für Ausnahmen.</p></div>
<div class="card"><div class="ico" style="background:linear-gradient(135deg,#10b981,#047857)">⚡</div>
<h3>0 s & leicht</h3>
<p class="small">Worktree teilt das <code>.git</code> — kein Re-Clone. Ein <code>git fetch</code> aktualisiert alle. pnpm hardlinkt aus dem Store.</p></div>
</div>
</div>
</section>
<!-- ============================ WORKFLOW VISUELL ============================ -->
<section class="alt">
<div class="page">
<span class="eyebrow">Ablauf</span>
<h2>Ein Ticket — von „los" bis „weg"</h2>
<figure>
<!-- DIAGRAM C: lifecycle -->
<svg viewBox="0 0 920 200" role="img" aria-label="Ticket-Lebenszyklus: start, arbeiten, testen, stop">
<defs>
<marker id="arr3" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0 0 L10 5 L0 10 z" fill="#cbd5e1"/></marker>
</defs>
<rect width="920" height="200" fill="#f8fafc"/>
<g font-family="sans-serif" text-anchor="middle">
<!-- 1 start -->
<circle cx="120" cy="80" r="40" fill="#eef2ff" stroke="#c7d2fe"/>
<text x="120" y="74" font-size="22">🚀</text>
<text x="120" y="100" font-size="11.5" font-weight="700" fill="#4338ca">start</text>
<text x="120" y="150" font-size="12" fill="#334155" font-weight="700">lt ticket start</text>
<text x="120" y="168" font-size="11" fill="#64748b">Worktree + Stack</text>
<line x1="168" y1="80" x2="232" y2="80" stroke="#cbd5e1" stroke-width="3" marker-end="url(#arr3)"/>
<!-- 2 develop -->
<circle cx="280" cy="80" r="40" fill="#ecfeff" stroke="#a5f3fc"/>
<text x="280" y="74" font-size="22">💻</text>
<text x="280" y="100" font-size="11.5" font-weight="700" fill="#0e7490">entwickeln</text>
<text x="280" y="150" font-size="12" fill="#334155" font-weight="700">Browser + Claude</text>
<text x="280" y="168" font-size="11" fill="#64748b">eigene URL, eigene Session</text>
<line x1="328" y1="80" x2="392" y2="80" stroke="#cbd5e1" stroke-width="3" marker-end="url(#arr3)"/>
<!-- 3 test -->
<circle cx="440" cy="80" r="40" fill="#f5f3ff" stroke="#ddd6fe"/>
<text x="440" y="74" font-size="22">🧪</text>
<text x="440" y="100" font-size="11.5" font-weight="700" fill="#6d28d9">testen</text>
<text x="440" y="150" font-size="12" fill="#334155" font-weight="700">lt ticket test</text>
<text x="440" y="168" font-size="11" fill="#64748b">isolierte Test-DB</text>
<line x1="488" y1="80" x2="552" y2="80" stroke="#cbd5e1" stroke-width="3" marker-end="url(#arr3)"/>
<!-- 4 commit/push -->
<circle cx="600" cy="80" r="40" fill="#ecfdf5" stroke="#a7f3d0"/>
<text x="600" y="74" font-size="22">⬆️</text>
<text x="600" y="100" font-size="11.5" font-weight="700" fill="#047857">abliefern</text>
<text x="600" y="150" font-size="11" font-weight="700" fill="#334155">/lt-dev:git:ship</text>
<text x="600" y="168" font-size="11" fill="#64748b">rebase → MR → merge</text>
<line x1="648" y1="80" x2="712" y2="80" stroke="#cbd5e1" stroke-width="3" marker-end="url(#arr3)"/>
<!-- 5 stop -->
<circle cx="760" cy="80" r="40" fill="#fff1f2" stroke="#fecdd3"/>
<text x="760" y="74" font-size="22">🧹</text>
<text x="760" y="100" font-size="11.5" font-weight="700" fill="#be123c">stop</text>
<text x="760" y="150" font-size="12" fill="#334155" font-weight="700">lt ticket stop</text>
<text x="760" y="168" font-size="11" fill="#64748b">restfrei aufgeräumt</text>
</g>
</svg>
<figcaption>Vor dem Aufräumen warnt <code>lt ticket stop</code>, falls noch <b>uncommittete</b> oder <b>ungepushte</b> Arbeit existiert — nichts geht versehentlich verloren.</figcaption>
</figure>
<div class="note key"><div class="ni">🚢</div><div><b>Ein Befehl bis in <code>dev</code> — der Claude-Command <code>/lt-dev:git:ship</code>.</b> Bringt deinen fertig entwickelten Ticket-Branch <b>autonom</b> nach <code>dev</code>: <code>check</code>-Skript grün → committen → auf <code>dev</code> <b>rebasen</b> → testen → <b>Merge Request</b> (Squash + Auto-Merge) → wartet auf die CI-Pipeline (<b>Auto-Retry</b> bei Fehlschlag) → <b>squash-merged</b> → löscht den Branch. Die automatisierte <b>Schlussklammer</b> zu <code>/lt-dev:take-ticket</code> — genau der Ablauf, den du sonst von Hand machst. Flags: <code>--base=<branch></code>, <code>--no-squash</code>, <code>--keep-branch</code>, <code>--max-pipeline-retries=<n></code>.</div></div>
<h3>Ein Tag mit drei Tickets — gleichzeitig</h3>
<div class="steps">
<div class="step"><div class="n"></div><div><b>Morgens:</b> <code>lt ticket start DEV-2200</code>, <code>lt ticket start DEV-2201</code>, <code>lt ticket start login-fix</code> — drei Tabs, drei VS-Code-Fenster, drei Claude-Sessions. Jede Umgebung ist sofort im Browser unter ihrer eigenen URL.</div></div>
<div class="step"><div class="n"></div><div><b>Mittags:</b> Review-Feedback zu 2201 kommt rein — du wechselst per <code>lt ticket switch 2201</code>, fixst, <code>lt ticket test 2201</code> läuft <i>parallel</i> während 2200 weiter im Browser offen ist.</div></div>
<div class="step"><div class="n"></div><div><b>Nachmittags:</b> 2200 ist fertig → committen, pushen, MR. <code>lt ticket stop 2200 --drop-db</code> räumt restlos auf. 2201 und login-fix laufen ungestört weiter.</div></div>
<div class="step"><div class="n"></div><div><b>Überblick jederzeit:</b> <code>lt ticket list</code> zeigt alle Umgebungen mit URLs, Branch, Status und DB — du verlierst nie den Faden.</div></div>
</div>
</div>
</section>
<!-- ============================ OHNE WORKTREE / TAKE-TICKET ============================ -->
<section>
<div class="page">
<span class="eyebrow">Auch ohne neues Verzeichnis</span>
<h2>Schnell mal ein Ticket im aktuellen Checkout</h2>
<p class="lead">Nicht jedes Ticket braucht einen eigenen Worktree. Willst du <i>im aktuellen</i> Projektverzeichnis ein Ticket angehen — ohne neuen Ordner — startest du es direkt mit dem Claude-Command <code>/lt-dev:take-ticket</code>.</p>
<div class="grid g2" style="margin-top:8px">
<div class="card" style="border-color:#c7d2fe; background:#fbfbff">
<span class="badge b-indigo">PARALLEL</span>
<h3 style="margin-top:8px"><code>lt ticket start</code></h3>
<p class="small" style="margin-top:6px">Eigener Worktree + eigener Stack. <b>Wenn du mehrere Tickets gleichzeitig</b> bearbeiten, im Browser vergleichen oder parallel testen willst. Volle Isolation, ein Befehl.</p>
</div>
<div class="card" style="border-color:#a5f3fc; background:#fbffff">
<span class="badge b-cyan">IN-PLACE</span>
<h3 style="margin-top:8px"><code>/lt-dev:take-ticket</code></h3>
<p class="small" style="margin-top:6px">Im <b>aktuellen</b> Verzeichnis & Branch — kein neuer Ordner. Claude holt sich Ticket-Kontext (Linear, Figma, Flows), plant und setzt um. Ideal für <b>ein</b> Ticket nacheinander, ohne Worktree-Overhead.</p>
</div>
</div>
<div class="note tip"><div class="ni">🧭</div><div><b>Faustregel:</b> Mehrere Tickets gleichzeitig oder im Browser nebeneinander testen → <code>lt ticket</code>. Ein Ticket fokussiert im aktuellen Checkout → <code>/lt-dev:take-ticket</code>. Beide nutzen denselben isolierten <code>lt dev</code>-Unterbau.</div></div>
</div>
</section>
<!-- ============================ PARALLELE TESTS ============================ -->
<section class="alt break">
<div class="page">
<span class="eyebrow">Tests</span>
<h2>Parallele E2E — pro Ticket <i>und</i> per Sharding</h2>
<p class="lead">Jeder Ticket-Test fährt seinen <b>eigenen</b> Test-Stack hoch — eigene Test-DB <code><base>-<id>-test</code>, eigene Ports. Ein Registry-Lock garantiert atomare Port-Vergabe, sodass selbst zwei <i>gleichzeitig</i> gestartete Test-Läufe nie kollidieren.</p>
<figure>
<!-- DIAGRAM D: parallel tests -->
<svg viewBox="0 0 920 250" role="img" aria-label="Zwei Ticket-Test-Stacks parallel mit eigenen DBs und Ports">
<rect width="920" height="250" fill="#ffffff"/>
<g font-family="sans-serif">
<rect x="60" y="40" width="370" height="170" rx="16" fill="#f5f3ff" stroke="#ddd6fe"/>
<text x="84" y="72" font-size="15" font-weight="800" fill="#5b21b6">Ticket 2200 · Test-Stack</text>
<rect x="84" y="92" width="150" height="26" rx="8" fill="#fff" stroke="#ddd6fe"/><text x="159" y="110" text-anchor="middle" font-size="12" fill="#6d28d9" font-family="monospace">api · Port 4500</text>
<rect x="248" y="92" width="150" height="26" rx="8" fill="#fff" stroke="#ddd6fe"/><text x="323" y="110" text-anchor="middle" font-size="12" fill="#6d28d9" font-family="monospace">app · Port 4501</text>
<rect x="84" y="128" width="314" height="26" rx="8" fill="#ede9fe"/><text x="241" y="146" text-anchor="middle" font-size="12" fill="#5b21b6" font-family="monospace">DB svl-…-2200-test (eigener Reset)</text>
<rect x="84" y="166" width="314" height="26" rx="8" fill="#ecfdf5"/><text x="241" y="184" text-anchor="middle" font-size="12" font-weight="700" fill="#047857">✓ 2 passed</text>
<rect x="490" y="40" width="370" height="170" rx="16" fill="#ecfeff" stroke="#a5f3fc"/>
<text x="514" y="72" font-size="15" font-weight="800" fill="#0e7490">Ticket 2201 · Test-Stack</text>
<rect x="514" y="92" width="150" height="26" rx="8" fill="#fff" stroke="#a5f3fc"/><text x="589" y="110" text-anchor="middle" font-size="12" fill="#0e7490" font-family="monospace">api · Port 4502</text>
<rect x="678" y="92" width="150" height="26" rx="8" fill="#fff" stroke="#a5f3fc"/><text x="753" y="110" text-anchor="middle" font-size="12" fill="#0e7490" font-family="monospace">app · Port 4503</text>
<rect x="514" y="128" width="314" height="26" rx="8" fill="#cffafe"/><text x="671" y="146" text-anchor="middle" font-size="12" fill="#0e7490" font-family="monospace">DB svl-…-2201-test (eigener Reset)</text>
<rect x="514" y="166" width="314" height="26" rx="8" fill="#ecfdf5"/><text x="671" y="184" text-anchor="middle" font-size="12" font-weight="700" fill="#047857">✓ 2 passed</text>
</g>
<text x="460" y="234" text-anchor="middle" font-size="12.5" fill="#64748b" font-family="sans-serif">Gleichzeitig gebunden · distinkte Ports 4500/4501 vs. 4502/4503 · keine Kollision (live verifiziert)</text>
</svg>
<figcaption>Zwei Ticket-Test-Suites liefen gleichzeitig auf distinkten Ports und eigenen Test-DBs — beide grün, null Interferenz.</figcaption>
</figure>
<div class="grid g2">
<div class="card"><h3>Sharding <span class="badge b-indigo">in einem Stack</span></h3>
<p class="small"><code>lt dev test --shard N</code> teilt die Suite auf N isolierte Stacks (Default 2) — die lokale Entsprechung der CI-Matrix, ~2× schneller. Die Timeouts werden nur unter Shard-Last gelockert (CI bleibt schnell).</p></div>
<div class="card"><h3>Pro Ticket <span class="badge b-cyan">über Worktrees</span></h3>
<p class="small"><code>lt ticket test <id></code> testet im eigenen Ticket-Stack mit eigener Test-DB. Mehrere Tickets können <b>gleichzeitig</b> testen — atomare Port-Vergabe per Lock verhindert jede Kollision.</p></div>
</div>
<div class="note warn"><div class="ni">⚠️</div><div><b>Voraussetzung für DB-Reset:</b> Projekte mit DB-löschendem <code>global-setup</code> müssen die Allow-List ticket-/shard-sicher halten (<code>/^<base>-(?:[a-z0-9-]+-)?test(?:-\d+)?$/</code>). <code>lt dev doctor</code> warnt, falls nicht — neue Projekte aus dem Starter brauchen hier nichts.</div></div>
</div>
</section>
<!-- ============================ SICHERHEIT & KOMFORT ============================ -->
<section>
<div class="page">
<span class="eyebrow">Eingebaut</span>
<h2>Sicherheit & Komfort, ohne dass du dran denkst</h2>
<div class="grid g2">
<div class="card"><div class="ico" style="background:linear-gradient(135deg,#f43f5e,#be123c)">🛡️</div>
<h3>Kein versehentlicher Datenverlust</h3>
<p class="small"><code>lt ticket stop</code> verweigert das Entfernen, solange <b>uncommittete</b> oder <b>ungepushte</b> Arbeit existiert — mit klarer Auflistung. <code>--force</code> überschreibt bewusst. Generierte Dateien (<code>.nuxtrc</code> & Co.) blockieren nicht.</p></div>
<div class="card"><div class="ico" style="background:linear-gradient(135deg,#f59e0b,#b45309)">🩺</div>
<h3>Selbstdiagnose</h3>
<p class="small"><code>lt dev doctor</code> prüft Caddy, CA, DNS, Ports — und warnt, wenn ein <code>global-setup</code> Ticket-Test-DBs nicht zurücksetzen würde, samt exaktem Fix.</p></div>
<div class="card"><div class="ico" style="background:linear-gradient(135deg,#6366f1,#4338ca)">🤖</div>
<h3>Claude weiß Bescheid</h3>
<p class="small">Jede Claude-Session in einem Ticket-Worktree erkennt am <code>.lt-dev/ticket</code>-Marker automatisch ihr Ticket — und sieht jede Runde Ticket-ID, URLs und DB. Keine getrackte Datei wird verändert.</p></div>
<div class="card"><div class="ico" style="background:linear-gradient(135deg,#10b981,#047857)">🧹</div>
<h3>Restfreier Teardown</h3>
<p class="small">Prozesse, Caddy-Block, Session, Registry-Eintrag, Ports — alles wird sauber zurückgegeben. <code>lt ticket stop</code> ohne ID räumt sogar das <i>aktuelle</i> Worktree auf.</p></div>
</div>
</div>
</section>
<!-- ============================ CHEAT SHEET ============================ -->
<section class="alt break">
<div class="page">
<span class="eyebrow">Spickzettel</span>
<h2>Alles auf einen Blick</h2>
<div class="grid g2">
<div>
<h3>Setup & Projekt</h3>
<pre><span class="k">lt dev install</span> <span class="c"># 1× pro Rechner</span>
<span class="k">lt dev init</span> <span class="c"># 1× pro Projekt</span>
<span class="k">lt dev up</span> / <span class="k">down</span> <span class="c"># Stack an/aus</span>
<span class="k">lt dev status</span> <span class="a">--all</span> <span class="c"># Überblick</span>
<span class="k">lt dev doctor</span> <span class="c"># Diagnose</span>
<span class="k">lt dev test</span> <span class="a">--shard 2</span> <span class="c"># schnelle E2E</span>
<span class="k">lt dev tunnel</span> <span class="c"># öffentliche URL</span></pre>
</div>
<div>
<h3>Tickets parallel</h3>
<pre><span class="k">lt ticket start</span> <span class="a">DEV-2200</span> <span class="c"># neues Ticket-Env</span>
<span class="k">lt ticket start</span> <span class="a">login-fix</span> <span class="c"># freier Name</span>
<span class="k">lt ticket list</span> <span class="c"># Dashboard</span>
<span class="k">lt ticket switch</span> <span class="a">2200</span> <span class="c"># öffnen</span>
<span class="k">lt ticket test</span> <span class="a">2200</span> <span class="c"># isolierte E2E</span>
<span class="k">lt ticket stop</span> <span class="a">2200</span> <span class="c"># aufräumen (Branch bleibt)</span>
<span class="m">/lt-dev:take-ticket</span> <span class="c"># Ticket im aktuellen Checkout</span>
<span class="m">/lt-dev:git:ship</span> <span class="c"># fertig → autonom nach dev</span></pre>
</div>
</div>
<div class="note key"><div class="ni">🚦</div><div><b>In 3 Schritten startklar:</b> <code>lt dev install</code> (einmalig) → im Projekt <code>lt dev init</code> → <code>lt ticket start <ticket></code>. Fertig — die URL steht im Terminal und in <code>lt ticket list</code>.</div></div>
</div>
</section>
<!-- ============================ WARUM SCHNELLER ============================ -->
<section>
<div class="page">
<span class="eyebrow">Der Gewinn</span>
<h2>Warum dich das spürbar schneller macht</h2>
<div class="grid g3">
<div class="card"><h3>🧠 Kein Kontext-Verlust</h3><p class="small">Jedes Ticket behält seinen eigenen, laufenden Zustand — Server, DB, Browser-Tab, Claude-Session. Du springst zwischen Tickets, ohne irgendetwas neu aufzusetzen.</p></div>
<div class="card"><h3>⏱️ Kein Warten</h3><p class="small">Worktrees entstehen in 0 s, Stacks starten in Sekunden, Tests laufen parallel statt nacheinander. Review-Feedback fixst du sofort, ohne dein Hauptticket zu unterbrechen.</p></div>
<div class="card"><h3>🛟 Kein Risiko</h3><p class="small">Volle Isolation + Schutz vor Datenverlust + Selbstdiagnose. Du experimentierst frei — die Werkzeuge fangen die Fehler ab, bevor sie wehtun.</p></div>
</div>
<div class="note tip" style="margin-top:22px"><div class="ni">✨</div><div><b>Probier es heute:</b> Such dir zwei offene Tickets und starte sie parallel mit <code>lt ticket start</code>. Du wirst nicht mehr zurückwollen.</div></div>
</div>
</section>
<footer class="footer">
<div class="page">
<span class="brand">lenne.Tech</span> · <code>lt dev</code> × <code>lt ticket</code> — Parallel entwickeln ohne Reibung.<br>
Lebendes Dokument in der lt CLI unter <code>docs/lt-dev-ticket-workflow.html</code> — Beiträge & Erweiterungen willkommen.
</div>
</footer>
</body>
</html>