Files
tekton/docs/tekton-dash-knowledge-base.html
2026-05-19 17:30:29 +08:00

2191 lines
189 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Knowledge Base: Multi-Platform & Regional Production Deployment Blueprint</title>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<script>tailwind.config = { darkMode: "class" }</script>
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<!-- Flag Icons CSS CDN (Free Country Flags in SVG) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flag-icons/7.2.3/css/flag-icons.min.css" />
<style>
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght=300;400;500;600;700;800&family=JetBrains+Mono:wght=400;500;600&display=swap');
body {
font-family: 'JetBrains Mono', monospace;
}
.code-font {
font-family: 'JetBrains Mono', monospace;
}
/* Custom styles to refine the flag layout */
.fi {
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
vertical-align: middle;
}
</style>
</head>
<body class="bg-slate-50 dark:bg-slate-900 text-slate-800 dark:text-slate-100 min-h-screen antialiased selection:bg-sky-500 selection:text-slate-900 dark:text-white">
<!-- Header Navigation Bar -->
<header class="border-b border-slate-200 dark:border-slate-800 bg-white dark:bg-white/80 dark:bg-slate-950/80 backdrop-blur-md sticky top-0 z-50">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="bg-sky-500 p-2 rounded-lg text-slate-950">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/godot/default.svg" alt="Godot" class="w-6 h-6">
</div>
<div>
<span
class="font-bold text-lg tracking-tight bg-gradient-to-r from-sky-400 to-indigo-400 bg-clip-text text-transparent">Nakama
x Godot 4</span>
<span class="text-xs block text-slate-500 dark:text-slate-400 font-mono">Production Blueprint</span>
</div>
</div>
<div class="flex items-center space-x-4">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
<span class="w-1.5 h-1.5 mr-1.5 rounded-full bg-emerald-400 animate-pulse"></span>
Production Ready
</span>
<button id="theme-toggle" class="flex items-center justify-center p-2 rounded-lg text-slate-500 dark:text-slate-400 hover:bg-slate-100 dark:text-slate-600 dark:text-slate-400 dark:hover:bg-slate-200 dark:bg-slate-800 transition">
<i data-lucide="moon" class="w-5 h-5 hidden dark:block"></i>
<i data-lucide="sun" class="w-5 h-5 block dark:hidden"></i>
</button>
<button onclick="window.print()"
class="flex items-center space-x-2 bg-slate-200 dark:bg-slate-800 hover:bg-slate-300 dark:hover:bg-slate-700 text-slate-800 dark:text-slate-200 px-3.5 py-1.5 rounded-lg text-sm font-semibold transition border border-slate-700">
<i data-lucide="printer" class="w-4 h-4"></i>
<span>Export / Print</span>
</button>
</div>
</div>
<!-- Secondary Navigation Bar -->
<div class="border-t border-slate-200 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-900/50 hidden md:block">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<nav class="flex space-x-8 overflow-x-auto py-3 text-xs font-medium text-slate-600 dark:text-slate-400">
<a href="#infrastructure" class="hover:text-sky-500 dark:hover:text-sky-400 whitespace-nowrap transition">1. Regional Infrastructure</a>
<a href="#storefront" class="hover:text-sky-500 dark:hover:text-sky-400 whitespace-nowrap transition">2. Storefront Commissions</a>
<a href="#monetization" class="hover:text-sky-500 dark:hover:text-sky-400 whitespace-nowrap transition">3. Monetization Architecture</a>
<a href="#architecture" class="hover:text-sky-500 dark:hover:text-sky-400 whitespace-nowrap transition">4. Core Architecture</a>
<a href="#priority-board" class="hover:text-sky-500 dark:hover:text-sky-400 whitespace-nowrap transition">5. Priority Board</a>
</nav>
</div>
</div>
</header>
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-10">
<!-- Hero Section / Title -->
<div class="mb-12 border-b border-slate-200 dark:border-slate-800 pb-8">
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-extrabold text-slate-900 dark:text-white tracking-tight leading-none mb-4">
Knowledge Base & Production Deployment Blueprint
</h1>
<p class="text-slate-600 dark:text-slate-400 text-lg max-w-4xl">
A highly descriptive, production-centric strategy for engineering global, multi-store authentication,
transaction validation, and regulatory compliance networks utilizing Godot 4 and Heroic Labs Nakama.
</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-8">
<div class="bg-white dark:bg-slate-950 p-4 rounded-xl border border-slate-800 flex items-start space-x-3">
<div class="text-sky-400 p-2 bg-sky-500/5 rounded-lg"><i data-lucide="globe" class="w-5 h-5"></i>
</div>
<div>
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400">Core Jurisdictions
</h4>
<div class="flex items-center space-x-1.5 mt-1">
<span class="fi fi-eu" title="European Union"></span>
<span class="fi fi-cn" title="China"></span>
<span class="fi fi-hk" title="Hong Kong"></span>
<span class="fi fi-sg" title="Singapore"></span>
<span class="fi fi-jp" title="Japan"></span>
<span class="text-sm font-medium text-slate-700 dark:text-slate-300 ml-1">Europe, Mainland China Transit & APAC
Networks</span>
</div>
</div>
</div>
<div class="bg-white dark:bg-slate-950 p-4 rounded-xl border border-slate-800 flex items-start space-x-3">
<div class="text-emerald-400 p-2 bg-emerald-500/5 rounded-lg"><i data-lucide="credit-card"
class="w-5 h-5"></i></div>
<div>
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400">IAP Validation</h4>
<p class="text-sm font-medium text-slate-700 dark:text-slate-300">Asynchronous, Server-to-Server, Ledger-Signed
Receipt Verification</p>
</div>
</div>
<div class="bg-white dark:bg-slate-950 p-4 rounded-xl border border-slate-800 flex items-start space-x-3">
<div class="text-indigo-400 p-2 bg-indigo-500/5 rounded-lg"><i data-lucide="shield-check"
class="w-5 h-5"></i></div>
<div>
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400">Store Integration</h4>
<p class="text-sm font-medium text-slate-700 dark:text-slate-300">Steamworks, Google Play, Apple App Store, TapSDK
(Zero-Commission)</p>
</div>
</div>
</div>
</div>
<!-- Section 1: Regional Infrastructures & Compliance Mapping -->
<section id="infrastructure" class="mb-16 scroll-mt-28">
<div class="flex items-center space-x-2 mb-6">
<i data-lucide="map" class="text-sky-500 w-6 h-6"></i>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">1. Regional Infrastructure & Regulatory Compliance</h2>
</div>
<p class="text-slate-600 dark:text-slate-400 mb-6">
Deploying cross-border games requires careful partitioning of databases and game nodes to satisfy
extreme technical boundaries (e.g., latency issues caused by the Great Firewall) and data protection
statutes (e.g., GDPR, local municipal privacy mandates).
</p>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Europe card -->
<div class="bg-white dark:bg-slate-950 border border-slate-800 rounded-xl p-6 hover:border-slate-300 dark:hover:border-slate-700 transition">
<div class="flex justify-between items-start mb-4">
<div class="flex items-center space-x-2">
<span class="fi fi-eu w-5 h-5 rounded-sm"></span>
<span
class="text-xs font-mono px-2.5 py-1 rounded bg-sky-500/10 text-sky-400 border border-sky-500/20 font-semibold uppercase">Europe
(EU) - Webdock</span>
</div>
<i data-lucide="shield" class="text-sky-400 w-5 h-5"></i>
</div>
<h3 class="text-lg font-bold text-slate-800 dark:text-slate-200 mb-3">GDPR & DMA Pipeline</h3>
<ul class="space-y-2.5 text-sm text-slate-600 dark:text-slate-400">
<li class="flex items-start"><i data-lucide="check-circle-2"
class="text-emerald-500 w-4 h-4 mr-2 mt-0.5 shrink-0"></i> <span><strong>Central
Cluster:</strong> Host on high-density <strong>Webdock.io</strong> Ryzen-powered VPS
profiles located in Frankfurt or Vienna.</span></li>
<li class="flex items-start"><i data-lucide="check-circle-2"
class="text-emerald-500 w-4 h-4 mr-2 mt-0.5 shrink-0"></i>
<span><strong>Sovereignty:</strong> Webdock offers EU-owned infrastructure with strict
hardware insulation and zero overseas sub-processor data leaks.</span></li>
<li class="flex items-start"><i data-lucide="check-circle-2"
class="text-emerald-500 w-4 h-4 mr-2 mt-0.5 shrink-0"></i> <span><strong>User
Control:</strong> Integrate explicit game-level telemetry opt-out flags which halt
outgoing Nakama analytics scripts instantly.</span></li>
</ul>
</div>
<!-- China card (Repositioned to reflect China Transit priority routing) -->
<div class="bg-white dark:bg-slate-950 border border-slate-800 rounded-xl p-6 hover:border-slate-300 dark:hover:border-slate-700 transition">
<div class="flex justify-between items-start mb-4">
<div class="flex items-center space-x-2">
<span class="fi fi-cn w-5 h-5 rounded-sm"></span>
<span class="fi fi-hk w-5 h-5 rounded-sm"></span>
<span
class="text-xs font-mono px-2.5 py-1 rounded bg-rose-500/10 text-rose-400 border border-rose-500/20 font-semibold uppercase">China
Transit - HostHatch</span>
</div>
<i data-lucide="lock" class="text-rose-400 w-5 h-5"></i>
</div>
<h3 class="text-lg font-bold text-slate-800 dark:text-slate-200 mb-3">HostHatch HK Edge Gateway</h3>
<ul class="space-y-2.5 text-sm text-slate-600 dark:text-slate-400">
<li class="flex items-start"><i data-lucide="alert-triangle"
class="text-amber-500 w-4 h-4 mr-2 mt-0.5 shrink-0"></i> <span><strong>GFW
Proximity:</strong> Deploy regional proxy logic to <strong>HostHatch.com</strong>
Hong Kong nodes, featuring direct low-latency peering tunnels.</span></li>
<li class="flex items-start"><i data-lucide="alert-triangle"
class="text-amber-500 w-4 h-4 mr-2 mt-0.5 shrink-0"></i> <span><strong>Regulatory
Separation:</strong> Standalone DB instances keep Mainland China data segregated
from Western clusters while resolving network hops near the target audience.</span></li>
<li class="flex items-start"><i data-lucide="alert-triangle"
class="text-amber-500 w-4 h-4 mr-2 mt-0.5 shrink-0"></i> <span><strong>NPPA
Integrations:</strong> Route localized traffic from HK edge to Chinese validation
and anti-addiction registry backends efficiently.</span></li>
</ul>
</div>
<!-- Asia Ex-CN card (Now following CN, handling overflow and APAC routing) -->
<div class="bg-white dark:bg-slate-950 border border-slate-800 rounded-xl p-6 hover:border-slate-300 dark:hover:border-slate-700 transition">
<div class="flex justify-between items-start mb-4">
<div class="flex items-center space-x-2">
<span class="fi fi-sg w-5 h-5 rounded-sm"></span>
<span class="fi fi-jp w-5 h-5 rounded-sm"></span>
<span class="fi fi-kr w-5 h-5 rounded-sm"></span>
<span
class="text-xs font-mono px-2.5 py-1 rounded bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 font-semibold uppercase">Asia
(Ex-CN) - Following CN</span>
</div>
<i data-lucide="zap" class="text-emerald-400 w-5 h-5"></i>
</div>
<h3 class="text-lg font-bold text-slate-800 dark:text-slate-200 mb-3">APAC Edge Arrays</h3>
<ul class="space-y-2.5 text-sm text-slate-600 dark:text-slate-400">
<li class="flex items-start"><i data-lucide="check-circle-2"
class="text-emerald-500 w-4 h-4 mr-2 mt-0.5 shrink-0"></i> <span><strong>Transit
Integration:</strong> Set up edge nodes in Tokyo, Seoul, and Singapore configured to
capture traffic spills when cross-border HK connections are saturated.</span></li>
<li class="flex items-start"><i data-lucide="check-circle-2"
class="text-emerald-500 w-4 h-4 mr-2 mt-0.5 shrink-0"></i> <span><strong>Latency
Optimization:</strong> Run high-performance CockroachDB clusters to maintain global
synchronization while serving nearby regional users under 45ms.</span></li>
<li class="flex items-start"><i data-lucide="check-circle-2"
class="text-emerald-500 w-4 h-4 mr-2 mt-0.5 shrink-0"></i> <span><strong>Data
Privacy:</strong> Satisfy local guidelines (Japan's APPI, South Korea's PIPA) using
explicit user data deletion interfaces inside Nakama profile routes.</span></li>
</ul>
</div>
</div>
<!-- Warning Callout on China Firewall -->
<div class="mt-6 bg-amber-500/5 border border-amber-500/20 rounded-xl p-4 flex items-start space-x-3">
<i data-lucide="alert-circle" class="text-amber-500 w-5 h-5 shrink-0 mt-0.5"></i>
<div class="text-sm text-amber-300">
<strong class="font-semibold block">Critical GFW Operational Warning:</strong>
Real-time WebSocket and UDP connection signals across the Great Firewall suffer massive packet
losses (&ge; 25%). Incorporating HostHatch's Hong Kong node acts as an indispensable entry buffer;
however, complete logical segregation of the Chinese client backend instance is still mandatory.
</div>
</div>
</section>
<!-- Section 2: Financial Strategy, Licenses, & Commissions -->
<section id="storefront" class="mb-16 scroll-mt-28">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-2">
<i data-lucide="dollar-sign" class="text-emerald-500 w-6 h-6"></i>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">2. Storefront Commissions & Licensing Pipeline</h2>
</div>
</div>
<p class="text-slate-600 dark:text-slate-400 mb-6">
Operating margins rely on optimizing each storefront's fee parameters. Before collecting gross revenue,
publishers must clear the initial platform entry fees.
</p>
<!-- Upfront Fee Settlement Grid -->
<div class="mb-8 bg-white dark:bg-slate-950 border border-slate-800 rounded-xl p-6">
<h3 class="text-lg font-bold text-slate-800 dark:text-slate-200 mb-4 flex items-center">
<i data-lucide="wallet" class="text-sky-400 w-5 h-5 mr-2"></i>
Initial Publishing Costs & First Fee Settlement Grid
</h3>
<p class="text-slate-600 dark:text-slate-400 text-sm mb-6">
Below is the required capital breakdown needed to register your identity and prepare storefront
slots before pushing your initial Godot client build to production channels.
</p>
<div class="overflow-x-auto">
<table class="w-full text-left text-sm text-slate-700 dark:text-slate-300">
<thead class="bg-slate-50 dark:bg-slate-900 text-slate-600 dark:text-slate-400 text-xs font-mono uppercase tracking-wider">
<tr>
<th class="p-4 border-b border-slate-200 dark:border-slate-800">Platform</th>
<th class="p-4 border-b border-slate-200 dark:border-slate-800">First Fee Amount</th>
<th class="p-4 border-b border-slate-200 dark:border-slate-800 font-semibold text-center">Market Flag</th>
<th class="p-4 border-b border-slate-200 dark:border-slate-800">Fee Recurrence Type</th>
<th class="p-4 border-b border-slate-200 dark:border-slate-800">Refundability Status</th>
<th class="p-4 border-b border-slate-200 dark:border-slate-800">Settlement Methods</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200 dark:divide-slate-800">
<!-- Steam Row -->
<tr class="hover:bg-slate-50 dark:bg-slate-900/40">
<td class="p-4 font-semibold text-slate-900 dark:text-white">Steamworks (PC)</td>
<td class="p-4 font-mono text-emerald-400">$100.00 USD <span
class="text-slate-500 dark:text-slate-400 text-xs">(per product)</span></td>
<td class="p-4 text-center">
<span class="fi fi-us" title="United States / Global"></span>
</td>
<td class="p-4">One-time per App Slot</td>
<td class="p-4"><span class="text-emerald-400 font-semibold">Yes</span> <span
class="text-xs text-slate-500 dark:text-slate-400">(Refunded after $1,000 in gross sales)</span>
</td>
<td class="p-4 text-xs">Credit Card, PayPal, Steam Wallet, Wire Transfer</td>
</tr>
<!-- Itch Row -->
<tr class="hover:bg-slate-50 dark:bg-slate-900/40">
<td class="p-4 font-semibold text-slate-900 dark:text-white">Itch.io (PC)</td>
<td class="p-4 font-mono text-slate-600 dark:text-slate-400">$0.00 USD <span
class="text-slate-500 dark:text-slate-400 text-xs">(Zero entry fee)</span></td>
<td class="p-4 text-center">
<span class="fi fi-un" title="International / Open"></span>
</td>
<td class="p-4">None</td>
<td class="p-4 text-slate-500 dark:text-slate-400">Not Applicable</td>
<td class="p-4 text-xs">None (Optional tax documentation verification)</td>
</tr>
<!-- Google Row -->
<tr class="hover:bg-slate-50 dark:bg-slate-900/40">
<td class="p-4 font-semibold text-slate-900 dark:text-white">Google Play</td>
<td class="p-4 font-mono text-emerald-400">$25.00 USD</td>
<td class="p-4 text-center">
<span class="fi fi-us" title="United States / Global"></span>
</td>
<td class="p-4">One-time per Developer Identity</td>
<td class="p-4 text-rose-400 font-semibold">No</td>
<td class="p-4 text-xs">Credit/Debit Card (requires Google Pay Profile)</td>
</tr>
<!-- Apple Row -->
<tr class="hover:bg-slate-50 dark:bg-slate-900/40">
<td class="p-4 font-semibold text-slate-900 dark:text-white">Apple App Store</td>
<td class="p-4 font-mono text-emerald-400">$99.00 USD</td>
<td class="p-4 text-center">
<span class="fi fi-us" title="United States / Global"></span>
</td>
<td class="p-4">Annual Subscription Renewal</td>
<td class="p-4 text-rose-400 font-semibold">No</td>
<td class="p-4 text-xs">Credit Card (linked to Apple ID Developer Account)</td>
</tr>
<!-- TapTap Row -->
<tr class="hover:bg-slate-50 dark:bg-slate-900/40">
<td class="p-4 font-semibold text-slate-900 dark:text-white">TapTap Developer</td>
<td class="p-4 font-mono text-slate-600 dark:text-slate-400">$0.00 USD <span
class="text-slate-500 dark:text-slate-400 text-xs">(Corporate validation)</span></td>
<td class="p-4 text-center">
<span class="fi fi-cn mr-0.5" title="China"></span>
<span class="fi fi-sg" title="Singapore / APAC"></span>
</td>
<td class="p-4">None</td>
<td class="p-4 text-slate-500 dark:text-slate-400">Not Applicable</td>
<td class="p-4 text-xs">Requires legal corporate identity / ICP verification</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="bg-white dark:bg-slate-950 border border-slate-800 rounded-xl p-6 mb-8 text-center">
<span class="text-xs text-slate-500 dark:text-slate-400 uppercase tracking-widest font-mono">Net Yield Production
Formula</span>
<div class="text-2xl sm:text-3xl font-mono text-sky-400 my-3 select-all">
R_net = R_gross &times; (1 - C_store - T_tax) - F_fees
</div>
<p class="text-xs text-slate-500 dark:text-slate-400 max-w-xl mx-auto">
Where <span class="text-sky-400">C_store</span> matches the target store platform commission, <span
class="text-sky-400">T_tax</span> matches regional withholding taxes, and <span
class="text-sky-400">F_fees</span> encapsulates external server transaction margins and API
query operations.
</p>
</div>
<!-- Platform Detail Tabs -->
<div class="bg-white dark:bg-slate-950 border border-slate-800 rounded-xl overflow-hidden">
<div class="border-b border-slate-200 dark:border-slate-800 bg-slate-50 dark:bg-slate-900/40 p-1 flex overflow-x-auto scrollbar-none"
id="store-tabs">
<button onclick="switchTab('steam')"
class="tab-btn active px-4 py-2 text-sm font-semibold rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:text-white transition whitespace-nowrap bg-slate-200 dark:bg-slate-800 text-slate-900 dark:text-white flex items-center"
id="tab-steam">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/steam/default.svg" class="w-4 h-4 mr-1.5" alt="Steam">Steam (PC)
</button>
<button onclick="switchTab('itch')"
class="tab-btn px-4 py-2 text-sm font-semibold rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:text-white transition whitespace-nowrap flex items-center"
id="tab-itch">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/itchdotio/default.svg" class="w-4 h-4 mr-1.5 invert" alt="Itch.io">Itch.io (PC)
</button>
<button onclick="switchTab('google')"
class="tab-btn px-4 py-2 text-sm font-semibold rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:text-white transition whitespace-nowrap flex items-center"
id="tab-google">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/google-play/default.svg" class="w-4 h-4 mr-1.5" alt="Google Play">Google Play
</button>
<button onclick="switchTab('apple')"
class="tab-btn px-4 py-2 text-sm font-semibold rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:text-white transition whitespace-nowrap flex items-center"
id="tab-apple">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/apple/default.svg" class="w-4 h-4 mr-1.5 invert opacity-70" alt="Apple">App Store (iOS)
</button>
<button onclick="switchTab('taptap')"
class="tab-btn px-4 py-2 text-sm font-semibold rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:text-white transition whitespace-nowrap flex items-center"
id="tab-taptap">
<span class="fi fi-cn mr-1"></span><span class="fi fi-sg mr-1.5"></span>TapTap (Mobile)
</button>
</div>
<div class="p-6">
<!-- Steam Tab Content -->
<div id="content-steam" class="tab-content">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white mb-4">Steamworks Implementation Matrix</h3>
<table class="w-full text-sm">
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Commission Rate</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">30% (Default)</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Volume Scaling</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">25% at $10M | 20% at $50M</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">First Fee</td>
<td class="py-2 text-emerald-400 font-mono text-right">$100 USD (Steam Direct
App Deposit)</td>
</tr>
<tr>
<td class="py-2 text-slate-500 dark:text-slate-400">Nakama Verification</td>
<td class="py-2 text-emerald-400 font-mono text-right">Server Authenticated
Session Ticket</td>
</tr>
</table>
</div>
<div class="bg-slate-50 dark:bg-slate-900/40 p-5 rounded-lg border border-slate-800">
<h4 class="text-xs font-semibold tracking-wider text-slate-500 dark:text-slate-400 uppercase mb-2">Technical
Execution</h4>
<p class="text-sm text-slate-700 dark:text-slate-300 leading-relaxed mb-3">
Initialize <code class="text-sky-400 font-mono text-xs">GodotSteam</code>
dynamically inside your client. The user retrieves their secure hex session ticket
locally, passing it down to Nakama using the native client driver hook to eliminate
credential spoofing risks.
</p>
<span class="text-xs font-mono text-slate-500 dark:text-slate-400 block">Endpoint:
client.authenticate_steam_async(ticket)</span>
</div>
</div>
</div>
<!-- Itch Tab Content -->
<div id="content-itch" class="tab-content hidden">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white mb-4">Itch.io Standalone Blueprint</h3>
<table class="w-full text-sm">
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Commission Rate</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">10% (Open Slider to 0%)</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">First Fee</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">$0.00 USD (Completely Open
Portal)</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Target Core Assets</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">No External Platform Hooks</td>
</tr>
<tr>
<td class="py-2 text-slate-500 dark:text-slate-400">Nakama Verification</td>
<td class="py-2 text-emerald-400 font-mono text-right">Device Unique ID /
Hardware Hash</td>
</tr>
</table>
</div>
<div class="bg-slate-50 dark:bg-slate-900/40 p-5 rounded-lg border border-slate-800">
<h4 class="text-xs font-semibold tracking-wider text-slate-500 dark:text-slate-400 uppercase mb-2">Technical
Execution</h4>
<p class="text-sm text-slate-700 dark:text-slate-300 leading-relaxed mb-3">
Itch standalone builds must bypass Steam libraries completely. Query the hardware
hash utilizing Godot's <code
class="text-sky-400 font-mono text-xs">OS.get_unique_id()</code> call. Combine
with custom email authentication options inside your client UI for stable user
recovery.
</p>
<span class="text-xs font-mono text-slate-500 dark:text-slate-400 block">Endpoint:
client.authenticate_device_async(id)</span>
</div>
</div>
</div>
<!-- Google Play Tab Content -->
<div id="content-google" class="tab-content hidden">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white mb-4">Google Play Commerce Setup</h3>
<table class="w-full text-sm">
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Commission Rate</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">15% on first $1M USD annually
</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Standard Tier Rate</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">30% (If annual earnings exceed
$1M)</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">First Fee</td>
<td class="py-2 text-emerald-400 font-mono text-right">$25 USD (One-time Console
Setup)</td>
</tr>
<tr>
<td class="py-2 text-slate-500 dark:text-slate-400">Nakama Verification</td>
<td class="py-2 text-emerald-400 font-mono text-right">Google Play Games Server
Auth Code</td>
</tr>
</table>
</div>
<div class="bg-slate-50 dark:bg-slate-900/40 p-5 rounded-lg border border-slate-800">
<h4 class="text-xs font-semibold tracking-wider text-slate-500 dark:text-slate-400 uppercase mb-2">Technical
Execution</h4>
<p class="text-sm text-slate-700 dark:text-slate-300 leading-relaxed mb-3">
Integrate the Google Play Games GDExtension inside Godot. Retrieve the user's secure
authentication code on startup and transfer it to the Nakama server backend to
provision accounts asynchronously.
</p>
<span class="text-xs font-mono text-slate-500 dark:text-slate-400 block">Endpoint:
client.authenticate_google_async(token)</span>
</div>
</div>
</div>
<!-- Apple Tab Content -->
<div id="content-apple" class="tab-content hidden">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white mb-4">Apple App Store Integration</h3>
<table class="w-full text-sm">
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Commission Rate</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">15% via Small Business Program
</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Standard Tier Rate</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">30% (Standard Portfolio
Account)</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">First Fee</td>
<td class="py-2 text-emerald-400 font-mono text-right">$99 USD (Annual
Registration Program)</td>
</tr>
<tr>
<td class="py-2 text-slate-500 dark:text-slate-400">Nakama Verification</td>
<td class="py-2 text-emerald-400 font-mono text-right">Apple Identity Token or
Game Center</td>
</tr>
</table>
</div>
<div class="bg-slate-50 dark:bg-slate-900/40 p-5 rounded-lg border border-slate-800">
<h4 class="text-xs font-semibold tracking-wider text-slate-500 dark:text-slate-400 uppercase mb-2">Technical
Execution</h4>
<p class="text-sm text-slate-700 dark:text-slate-300 leading-relaxed mb-3">
Process authentication loops using Apple ID identity payloads via Sign In with
Apple. For Game Center, extract authentication signatures, timestamps, and salt
packets to execute secure matching processes.
</p>
<span class="text-xs font-mono text-slate-500 dark:text-slate-400 block">Endpoint:
client.authenticate_apple_async(token)</span>
</div>
</div>
</div>
<!-- TapTap Tab Content -->
<div id="content-taptap" class="tab-content hidden">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white mb-4">TapTap Developer Services Strategy</h3>
<table class="w-full text-sm">
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Commission Rate</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">0% (Completely Commission-Free)
</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">Target Core Markets</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">Mainland China & SEA Mobile
Communities</td>
</tr>
<tr class="border-b border-slate-200 dark:border-slate-800">
<td class="py-2 text-slate-500 dark:text-slate-400">First Fee</td>
<td class="py-2 text-slate-900 dark:text-white font-mono text-right">$0.00 USD (Entity verification
required)</td>
</tr>
<tr>
<td class="py-2 text-slate-500 dark:text-slate-400">Nakama Verification</td>
<td class="py-2 text-emerald-400 font-mono text-right">Custom Auth (via TapTap
OAuth Token)</td>
</tr>
</table>
</div>
<div class="bg-slate-50 dark:bg-slate-900/40 p-5 rounded-lg border border-slate-800">
<h4 class="text-xs font-semibold tracking-wider text-slate-500 dark:text-slate-400 uppercase mb-2">Technical
Execution</h4>
<p class="text-sm text-slate-700 dark:text-slate-300 leading-relaxed mb-3">
TapTap operates without a direct native Nakama SDK connector. Retrieve the user's
OAuth access token using the TapSDK inside Godot. Execute authentication by passing
the token directly to Nakama's custom endpoint, routing background network
validations securely.
</p>
<span class="text-xs font-mono text-slate-500 dark:text-slate-400 block">Endpoint:
client.authenticate_custom_async(tap_token)</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Section 3: Secure Server-to-Server Purchase Validation -->
<section id="monetization" class="mb-16 scroll-mt-28">
<div class="flex items-center space-x-2 mb-6">
<i data-lucide="shield-alert" class="text-sky-500 w-6 h-6"></i>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">3. Monetization Architecture & Secure IAP Loop</h2>
</div>
<p class="text-slate-600 dark:text-slate-400 mb-6">
Client-side reporting is inherently untrustworthy. Memory injectors (e.g., Lucky Patcher on Android,
memory editing tools on PC) can manipulate the client runtime to simulate successful purchases.
Implementing a robust, asynchronous verification cycle ensures validation is handled strictly by the
server.
</p>
<!-- Sequence Layout -->
<div class="bg-white dark:bg-slate-950 border border-slate-800 rounded-xl p-6 lg:p-8">
<h3 class="text-lg font-bold text-slate-900 dark:text-white mb-6 flex items-center"><i data-lucide="git-branch"
class="text-sky-400 w-5 h-5 mr-2"></i> Asynchronous Verification Topology</h3>
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 relative">
<!-- Step 1 -->
<div class="bg-slate-50 dark:bg-slate-900/50 p-5 rounded-lg border border-slate-800 relative">
<div
class="absolute -top-3 -left-3 w-8 h-8 rounded-full bg-sky-500 text-slate-950 flex items-center justify-center font-bold text-sm">
1</div>
<h4 class="text-sm font-semibold text-slate-800 dark:text-slate-200 mt-2 mb-2">Purchase & Tokenization</h4>
<p class="text-xs text-slate-600 dark:text-slate-400">The Godot client requests checkout. The player submits payment
to the store network, which issues an encrypted, signed platform transaction token.</p>
</div>
<!-- Step 2 -->
<div class="bg-slate-50 dark:bg-slate-900/50 p-5 rounded-lg border border-slate-800 relative">
<div
class="absolute -top-3 -left-3 w-8 h-8 rounded-full bg-sky-500 text-slate-950 flex items-center justify-center font-bold text-sm">
2</div>
<h4 class="text-sm font-semibold text-slate-800 dark:text-slate-200 mt-2 mb-2">Nakama RPC Ingestion</h4>
<p class="text-xs text-slate-600 dark:text-slate-400">The client forwards the raw transaction token securely to
Nakama via an RPC function call: <code class="text-sky-400">verify_purchase</code>.</p>
</div>
<!-- Step 3 -->
<div class="bg-slate-50 dark:bg-slate-900/50 p-5 rounded-lg border border-slate-800 relative">
<div
class="absolute -top-3 -left-3 w-8 h-8 rounded-full bg-sky-500 text-slate-950 flex items-center justify-center font-bold text-sm">
3</div>
<h4 class="text-sm font-semibold text-slate-800 dark:text-slate-200 mt-2 mb-2">Server Validation Check</h4>
<p class="text-xs text-slate-600 dark:text-slate-400">Nakama blocks immediate user manipulation. It connects
server-to-server with Google, Apple, or Steam APIs to verify status and signatures.</p>
</div>
<!-- Step 4 -->
<div class="bg-slate-50 dark:bg-slate-900/50 p-5 rounded-lg border border-slate-800 relative">
<div
class="absolute -top-3 -left-3 w-8 h-8 rounded-full bg-emerald-500 text-slate-950 flex items-center justify-center font-bold text-sm">
4</div>
<h4 class="text-sm font-semibold text-slate-800 dark:text-slate-200 mt-2 mb-2">Ledger Provisioning</h4>
<p class="text-xs text-slate-600 dark:text-slate-400">Upon verification, Nakama updates the persistent storage
wallet data and broadcasts confirmation back to the Godot client.</p>
</div>
</div>
</div>
</section>
<!-- Section 4: Architecture Autoload Script Blueprint -->
<section id="architecture" class="mb-16 scroll-mt-28">
<div class="flex items-center space-x-2 mb-6">
<i data-lucide="network" class="text-sky-500 w-6 h-6"></i>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">4. Core Architecture: Unified Identity Manager Decision Flow
Chart</h2>
</div>
<p class="text-slate-600 dark:text-slate-400 mb-6">
The Unified Identity Manager dynamically discovers platforms at runtime, resolving features and
singletons without breaking compilations on platforms lacking those SDK wrappers. Click the platform
modes below to preview the path execution, safety hooks, and token routing.
</p>
<!-- Dynamic Decision Flowchart Container -->
<div class="bg-white dark:bg-slate-950 border border-slate-800 rounded-xl p-6 lg:p-8">
<!-- Interactive Controls -->
<div
class="flex flex-wrap gap-2 mb-8 bg-slate-50 dark:bg-slate-900 p-1.5 rounded-xl border border-slate-800 max-w-2xl mx-auto justify-center">
<button onclick="highlightPath('all')"
class="path-ctrl-btn active px-4 py-2 text-xs font-semibold rounded-lg transition-all duration-300 bg-sky-500 text-slate-950 shadow-md flex items-center justify-center"
id="btn-path-all">
Show Full Tree
</button>
<button onclick="highlightPath('steam')"
class="path-ctrl-btn px-4 py-2 text-xs font-semibold rounded-lg transition-all duration-300 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:text-white flex items-center justify-center"
id="btn-path-steam">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/steam/default.svg" class="w-3.5 h-3.5 mr-1.5" alt="Steam">PC (Steam)
</button>
<button onclick="highlightPath('android')"
class="path-ctrl-btn px-4 py-2 text-xs font-semibold rounded-lg transition-all duration-300 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:text-white flex items-center justify-center"
id="btn-path-android">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/google-play/default.svg" class="w-3.5 h-3.5 mr-1.5" alt="Google Play">Android (Google/TapTap)
</button>
<button onclick="highlightPath('ios')"
class="path-ctrl-btn px-4 py-2 text-xs font-semibold rounded-lg transition-all duration-300 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:text-white flex items-center justify-center"
id="btn-path-ios">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/apple/default.svg" class="w-3.5 h-3.5 mr-1.5 invert opacity-70" alt="Apple">iOS (Apple/TapTap)
</button>
<button onclick="highlightPath('fallback')"
class="path-ctrl-btn px-4 py-2 text-xs font-semibold rounded-lg transition-all duration-300 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:text-white flex items-center justify-center"
id="btn-path-fallback">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/itchdotio/default.svg" class="w-3.5 h-3.5 mr-1.5 invert" alt="Itch.io">Itch.io / Standalone PC
</button>
</div>
<!-- Flowchart Graph Layout -->
<div class="flex flex-col space-y-8 relative">
<!-- Root Entry Point -->
<div class="flex justify-center transition-all duration-300" id="node-root">
<div
class="bg-slate-50 dark:bg-slate-900 border-2 border-slate-700 hover:border-sky-500 rounded-xl p-4 text-center max-w-xs shadow-lg transition-all duration-300">
<div class="text-xs font-mono font-bold text-sky-400 uppercase tracking-widest mb-1">Game
Initialization</div>
<h4 class="text-sm font-extrabold text-slate-900 dark:text-white">_ready() / dispatch_platform_auth()</h4>
<p class="text-xxs text-slate-500 dark:text-slate-400 mt-1">Queries environment architecture and singletons</p>
</div>
</div>
<!-- Connective Vertical Line from Root -->
<div class="flex justify-center h-6 -my-4 relative z-0">
<div class="w-0.5 bg-slate-200 dark:bg-slate-800 transition-all duration-300" id="line-root"></div>
</div>
<!-- Platform Routing Split Container -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 relative z-10">
<!-- Steam Branch -->
<div class="flex flex-col items-center bg-slate-50 dark:bg-slate-900/40 border border-slate-800 rounded-xl p-4 transition-all duration-300"
id="branch-steam">
<div class="flex items-center space-x-1.5 mb-3">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/steam/default.svg" class="w-4 h-4" alt="Steam">
<span
class="text-xxs font-mono font-semibold px-2 py-0.5 rounded bg-sky-500/10 text-sky-400 border border-sky-500/10">PC
Steam Target</span>
</div>
<div class="w-full text-center space-y-3">
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-slate-800 dark:text-slate-200">Class Check</div>
<code class="text-xxs text-amber-400">ClassDB.has_singleton("Steam")</code>
</div>
<div class="text-slate-600 text-center flex justify-center"><i data-lucide="arrow-down"
class="w-4 h-4"></i></div>
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-slate-800 dark:text-slate-200">Ticket Retrieval</div>
<p class="text-xxs text-slate-600 dark:text-slate-400 mt-0.5">Grabs session hex ticket asynchronously
</p>
</div>
<div class="text-slate-600 text-center flex justify-center"><i data-lucide="arrow-down"
class="w-4 h-4"></i></div>
<div class="bg-white dark:bg-slate-950 border border-sky-500/30 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-sky-400">Nakama Endpoint</div>
<code class="text-xxs text-slate-600 dark:text-slate-400">authenticate_steam_async()</code>
</div>
</div>
</div>
<!-- Android Branch -->
<div class="flex flex-col items-center bg-slate-50 dark:bg-slate-900/40 border border-slate-800 rounded-xl p-4 transition-all duration-300"
id="branch-android">
<div class="flex items-center space-x-1.5 mb-3">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/google-play/default.svg" class="w-4 h-4" alt="Google Play">
<span
class="text-xxs font-mono font-semibold px-2 py-0.5 rounded bg-emerald-500/10 text-emerald-400 border border-emerald-500/10">Android
OS Target</span>
</div>
<div class="w-full text-center space-y-3">
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-slate-800 dark:text-slate-200">Feature Gating</div>
<code class="text-xxs text-emerald-400">OS.has_feature("taptap")</code>
</div>
<div class="text-slate-600 text-center flex justify-center flex-row justify-around">
<span class="text-xxs text-emerald-500">Yes</span><span
class="text-xxs text-sky-500">No</span></div>
<div class="grid grid-cols-2 gap-2">
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-1.5 shadow text-xxs">
<div class="font-bold text-emerald-400">TapSDK</div>
<p class="text-[9px] text-slate-500 dark:text-slate-400 mt-0.5">Fetch OAuth Token</p>
</div>
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-1.5 shadow text-xxs">
<div class="font-bold text-sky-400">Google Play</div>
<p class="text-[9px] text-slate-500 dark:text-slate-400 mt-0.5">Fetch Auth Code</p>
</div>
</div>
<div class="text-slate-600 text-center flex justify-center"><i data-lucide="arrow-down"
class="w-4 h-4"></i></div>
<div class="bg-white dark:bg-slate-950 border border-sky-500/30 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-sky-400">Nakama Endpoint</div>
<code
class="text-xxs text-slate-600 dark:text-slate-400">authenticate_custom_async()<br>OR<br>authenticate_google_async()</code>
</div>
</div>
</div>
<!-- iOS Branch -->
<div class="flex flex-col items-center bg-slate-50 dark:bg-slate-900/40 border border-slate-800 rounded-xl p-4 transition-all duration-300"
id="branch-ios">
<div class="flex items-center space-x-1.5 mb-3">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/apple/default.svg" class="w-4 h-4 invert opacity-70" alt="Apple">
<span
class="text-xxs font-mono font-semibold px-2 py-0.5 rounded bg-violet-500/10 text-violet-400 border border-violet-500/10">iOS
OS Target</span>
</div>
<div class="w-full text-center space-y-3">
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-slate-800 dark:text-slate-200">Feature Gating</div>
<code class="text-xxs text-violet-400">OS.has_feature("taptap")</code>
</div>
<div class="text-slate-600 text-center flex justify-center flex-row justify-around">
<span class="text-xxs text-violet-500">Yes</span><span
class="text-xxs text-sky-500">No</span></div>
<div class="grid grid-cols-2 gap-2">
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-1.5 shadow text-xxs">
<div class="font-bold text-violet-400">TapSDK</div>
<p class="text-[9px] text-slate-500 dark:text-slate-400 mt-0.5">Fetch OAuth Token</p>
</div>
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-1.5 shadow text-xxs">
<div class="font-bold text-sky-400">Apple Auth</div>
<p class="text-[9px] text-slate-500 dark:text-slate-400 mt-0.5">Fetch Identity Token</p>
</div>
</div>
<div class="text-slate-600 text-center flex justify-center"><i data-lucide="arrow-down"
class="w-4 h-4"></i></div>
<div class="bg-white dark:bg-slate-950 border border-sky-500/30 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-sky-400">Nakama Endpoint</div>
<code
class="text-xxs text-slate-600 dark:text-slate-400">authenticate_custom_async()<br>OR<br>authenticate_apple_async()</code>
</div>
</div>
</div>
<!-- Fallback / Itch.io Standalone Branch -->
<div class="flex flex-col items-center bg-slate-50 dark:bg-slate-900/40 border border-slate-800 rounded-xl p-4 transition-all duration-300"
id="branch-fallback">
<div class="flex items-center space-x-1.5 mb-3">
<img src="https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/itchdotio/default.svg" class="w-4 h-4 invert" alt="Itch.io">
<span
class="text-xxs font-mono font-semibold px-2 py-0.5 rounded bg-rose-500/10 text-rose-400 border border-rose-500/10">PC/Itch.io
Standalone</span>
</div>
<div class="w-full text-center space-y-3">
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-slate-800 dark:text-slate-200">Device Hardware ID</div>
<code class="text-xxs text-rose-400">OS.get_unique_id()</code>
</div>
<div class="text-slate-600 text-center flex justify-center"><i data-lucide="arrow-down"
class="w-4 h-4"></i></div>
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-800 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-slate-800 dark:text-slate-200">Hardware Hashing</div>
<p class="text-xxs text-slate-600 dark:text-slate-400 mt-0.5">Generate hardware fingerprint</p>
</div>
<div class="text-slate-600 text-center flex justify-center"><i data-lucide="arrow-down"
class="w-4 h-4"></i></div>
<div class="bg-white dark:bg-slate-950 border border-sky-500/30 rounded-lg p-2.5 shadow text-xs">
<div class="font-bold text-sky-400">Nakama Endpoint</div>
<code class="text-xxs text-slate-600 dark:text-slate-400">authenticate_device_async()</code>
</div>
</div>
</div>
</div>
<!-- Connective Vertical Line to Target Server -->
<div class="flex justify-center h-6 -my-4 relative z-0">
<div class="w-0.5 bg-slate-200 dark:bg-slate-800 transition-all duration-300" id="line-terminal"></div>
</div>
<!-- Unified Target Server Block -->
<div class="flex justify-center transition-all duration-300" id="node-terminal">
<div
class="bg-slate-50 dark:bg-slate-900 border-2 border-emerald-500/60 rounded-xl p-5 text-center max-w-sm shadow-xl transition-all duration-300">
<div
class="flex items-center justify-center space-x-2 text-emerald-400 text-xs font-mono font-bold uppercase tracking-wider mb-2">
<span class="relative flex h-2 w-2">
<span
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
</span>
<span>Nakama Server Response Node</span>
</div>
<h4 class="text-sm font-extrabold text-slate-900 dark:text-white">NakamaSession Established</h4>
<p class="text-xxs text-slate-600 dark:text-slate-400 mt-1.5 leading-relaxed">
Session token decoded & validated, persistent profiles resolved, and socket pipelines
opened. Global matching/telemetry gates unlocked.
</p>
</div>
</div>
</div>
</div>
</section>
<!-- Section 5: Project Management (PR) Board -->
<!-- Section 5: Project Management (PR) Board -->
<section id="priority-board" class="mb-16 scroll-mt-28">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-2">
<i data-lucide="kanban-square" class="text-sky-500 w-6 h-6"></i>
<h2 class="text-2xl font-bold text-slate-900 dark:text-white">5. Project Management (PR) Board & AI Checklist</h2>
</div>
</div>
<p class="text-slate-600 dark:text-slate-400 mb-8">
This section serves as a fully detailed tracking board. It merges production readiness, backend reconstruction, gameflow audit, and Steam depot release tasks.
<strong>Every task is fully expanded with checklists and automated testing criteria so you can track AI execution seamlessly.</strong>
</p>
<div class="bg-rose-50 dark:bg-rose-500/5 border border-rose-200 dark:border-rose-500/25 rounded-xl p-5 mb-8">
<h3 class="text-md font-bold text-rose-700 dark:text-rose-200 mb-3 flex items-center"><i data-lucide="flame" class="w-4 h-4 mr-2"></i>Priority Rule</h3>
<p class="text-sm text-slate-700 dark:text-slate-300 leading-relaxed">
Do not spend release time on Steam depot upload, signing polish, or branch promotion until P0 backend authority
is fixed. Current audit found client-authoritative economy, gacha paths, and sync loopholes.
Those are launch blockers because they can corrupt wallet, inventory, match state, and account identity before first public build.
</p>
</div>
<!-- Detailed Task List (Expandable Accordions) -->
<div class="space-y-4">
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-rose-500/30 bg-rose-50 dark:bg-rose-500/10 text-rose-600 dark:text-rose-300 text-xs font-bold">P0</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-P0-1</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Economy Authority</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
server/nakama/tekton_admin.js, user_profile_manager.gd
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Stop trusting client prices, categories, package IDs. Reconstruct server-authoritative economy.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Create server catalog mapping item IDs to category, price, currency type, stack rules.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Change purchase request so client sends only item ID, quantity, and optional idempotency key.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Validate balance and inventory capacity server-side before mutation.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Replace fake currency purchase with receipt verification placeholder interface per platform.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Write wallet/inventory mutation audit entry with user ID, request ID, before/after values.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-P0-1">Analyze current Tekton economy flow in server/nakama/tekton_admin.js and Godot callers. Reconstruct shop purchase authority so the client no longer sends trusted price_gold, price_star, category, or reward data. Add a server-side item catalog and update rpcPurchaseItem to accept only item_id, quantity, and idempotency_key. Replace rpcBuyCurrency behavior with a receipt-verification-safe interface that records pending/verified transactions and never grants premium currency from package ID alone. Preserve existing profile/wallet behavior where possible. Add validation, normalized errors, and audit ledger writes. Update Godot callers to match new payload shape. Acceptance: no wallet or inventory mutation depends on client-submitted price/category/package intent; duplicate idempotency key does not duplicate grant; existing shop UI can still request purchases.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-P0-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Call `rpcPurchaseItem` with modified price/category from client. Assert server rejects or ignores client price and uses catalog price. Assert duplicate idempotency keys return the exact same transaction result without deducting twice.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-P0-1">**Completed [PRD-P0-1]: Economy Authority**
- **Goal:** Stop trusting client prices, categories, package IDs. Reconstruct server-authoritative economy.
- **Status:** Integrated & verified. Code changes applied to: server/nakama/tekton_admin.js, user_profile_manager.gd</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-P0-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-rose-500/30 bg-rose-50 dark:bg-rose-500/10 text-rose-600 dark:text-rose-300 text-xs font-bold">P0</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-P0-2</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Gacha Authority</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
gacha_manager.gd, Nakama economy RPCs
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Move RNG, pity, cost consume, and rewards server-side.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add server RPC for gacha pull with banner ID, pull count, and idempotency key.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Store pity and banner state server-side.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Server consumes cost, rolls reward, writes item/fragment result, and returns canonical result.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Client only animates returned result; no local grant or deduction.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add migration note for existing local pity/fragment data.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-P0-2">Refactor Tekton gacha so authority lives in Nakama. Read scripts/managers/gacha_manager.gd, user_profile_manager.gd, and server/nakama/tekton_admin.js before editing. Add server-side RPCs for gacha_pull and any needed banner/profile state. Server must own RNG, pity counter, cost deduction, reward choice, inventory/fragment writes, and audit/idempotency. Client must become presentation-only: it sends banner_id, pull_count, and idempotency_key, then animates the canonical server response. Remove local reward grant and local currency deduction from gacha_manager.gd. Acceptance: editing client RNG/pity code cannot change real rewards; duplicate pull request cannot duplicate rewards; profile refresh after pull shows server state.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-P0-2').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Trigger `rpcGachaPull`. Assert client currency deduction happens only upon server response. Assert client cannot specify reward or manipulate RNG seed.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-P0-2">**Completed [PRD-P0-2]: Gacha Authority**
- **Goal:** Move RNG, pity, cost consume, and rewards server-side.
- **Status:** Integrated & verified. Code changes applied to: gacha_manager.gd, Nakama economy RPCs</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-P0-2').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-rose-500/30 bg-rose-50 dark:bg-rose-500/10 text-rose-600 dark:text-rose-300 text-xs font-bold">P0</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-P0-3</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Auth & Secrets Lock</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
auth_manager.gd, nakama_manager.gd, project.godot
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Remove insecure Steam fallback, default App ID 480, hardcoded release secrets.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Replace production Steam App ID placeholder only when real ID exists.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Fail hard in Steam build if Steam ticket cannot be acquired.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Remove fallback email/custom auth from Steam release path.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Externalize server host, scheme, key, encryption key, and secrets.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Delete or environment-gate admin topup RPC and admin UI entry points.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-P0-3">Audit and harden Tekton authentication and admin mutation paths. Read project.godot, scripts/services/steamworks_manager.gd, scripts/managers/auth_manager.gd, scripts/nakama_manager.gd, scripts/ui/admin_panel.gd, and server/nakama/tekton_admin.js. Remove insecure Steam release fallback behavior so Steam builds authenticate only with valid Steam tickets. Add clear release guards for Steam App ID 480 so production export fails or warns loudly if still using test ID. Externalize backend config and local encryption material away from hardcoded production defaults. Remove or environment-gate rpcAdminTopupGold and ensure admin panel scenes/scripts are not included in player exports unless explicitly feature-flagged. Acceptance: Steam build cannot silently fall back to insecure auth; test App ID 480 is blocked for production; admin mint path is unavailable in production runtime.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-P0-3').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Export project with Steam features. Disconnect Steam client. Assert game fails to authenticate and does NOT fallback to custom/device auth. Assert admin UI is entirely hidden in release builds.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-P0-3">**Completed [PRD-P0-3]: Auth & Secrets Lock**
- **Goal:** Remove insecure Steam fallback, default App ID 480, hardcoded release secrets.
- **Status:** Integrated & verified. Code changes applied to: auth_manager.gd, nakama_manager.gd, project.godot</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-P0-3').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-rose-500/30 bg-rose-50 dark:bg-rose-500/10 text-rose-600 dark:text-rose-300 text-xs font-bold">P0</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-P0-4</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Backend Deploy Safety</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
server/, Nakama runtime module
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Replace manual module copy/restart with staging/prod deploy, health check, rollback.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Separate dev/staging/prod Nakama config and secrets.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Script module package/copy/restart with version label.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add health check RPC after deploy.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Keep previous module artifact for rollback.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add smoke checklist: auth, profile, shop, mail, gacha, friends, leaderboard.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-P0-4">Create a production-safe Nakama deployment workflow for Tekton. Review server/docker-compose.yaml, server/nakama/README.md, and current runtime module layout. Replace manual docker cp guidance with scripts or documented commands for staging and production deploys. Include environment-specific config/secrets, module version labeling, restart procedure, health check, smoke test commands, and rollback to previous module. Do not commit real secrets. Acceptance: a developer can deploy to staging, verify health, promote to production, and rollback using documented repeatable steps without manually editing containers.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-P0-4').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Run deploy script. Assert Nakama server restarts without losing data. Trigger health check RPC to verify new module loaded successfully.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-P0-4">**Completed [PRD-P0-4]: Backend Deploy Safety**
- **Goal:** Replace manual module copy/restart with staging/prod deploy, health check, rollback.
- **Status:** Integrated & verified. Code changes applied to: server/, Nakama runtime module</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-P0-4').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-rose-500/30 bg-rose-50 dark:bg-rose-500/10 text-rose-600 dark:text-rose-300 text-xs font-bold">P0</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-GF-P0-1</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Spawn/Sync Authority Lock</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
main.gd, player.gd
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Retain: deterministic pre-spawn sync. Remove: client-trusted teleport/update paths.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Keep deterministic pre-spawn strategy (client pre-creates lobby roster).</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Remove client-trusted position mutation path that can move authoritative state without server validation.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Introduce server-owned spawn_revision and state_revision integers.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Reject stale updates on client and server.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Ensure reconnect flow requests full player sync, then grid sync, then mode-specific sync.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-GF-P0-1">Audit and harden player spawn/sync authority in scenes/main.gd and scenes/player.gd. Keep deterministic pre-spawn strategy and existing server-authoritative item randomization pattern, but remove any client-trusted position mutation path that can move authoritative state without server validation. Introduce server-owned spawn_revision and state_revision integers sent with spawn and full-sync payloads. Reject stale updates on client and server. Ensure reconnect flow requests full player sync first, then full grid sync, then mode-specific sync (Stop n Go / Tekton Doors) with explicit ack step. Acceptance: client cannot force authoritative teleport; reconnecting client converges to identical player positions/goals/playerboards after one sync cycle; stale packets no longer overwrite newer state.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-GF-P0-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Simulate client sending stale spawn_revision. Assert server rejects. Reconnect mid-match, assert player converges to exact same grid position as before.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-GF-P0-1">**Completed [PRD-GF-P0-1]: Spawn/Sync Authority Lock**
- **Goal:** Retain: deterministic pre-spawn sync. Remove: client-trusted teleport/update paths.
- **Status:** Integrated & verified. Code changes applied to: main.gd, player.gd</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-GF-P0-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-rose-500/30 bg-rose-50 dark:bg-rose-500/10 text-rose-600 dark:text-rose-300 text-xs font-bold">P0</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-GF-P0-2</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Lobby Start Gate Hardening</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
lobby.gd, lobby_manager.gd
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Add preflight checklist RPC, check ready-state and host authority.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Preserve LAN/Nakama dual-mode behavior and tutorial fast path.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add preflight readiness checks before _on_game_starting transition.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Verify session valid, host authority true, all player records present, mode config validated.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add one typed preflight result object and render actionable errors.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-GF-P0-2">Rework lobby game-start gating in scenes/lobby.gd and scripts/managers/lobby_manager.gd. Preserve LAN/Nakama dual-mode behavior and tutorial fast path, but add preflight readiness checks before _on_game_starting transition: session valid (or explicit guest/LAN mode), host authority true, all required player records present, mode config validated, and scene dependencies reachable. Add one typed preflight result object and render actionable errors in connection_status/status_label. Acceptance: start button cannot trigger broken scene load with partial state; host and clients see same preflight result; loading screen transition only occurs after preflight pass.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-GF-P0-2').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Attempt to start match without full player records. Assert UI blocks start and shows specific error string from preflight check.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-GF-P0-2">**Completed [PRD-GF-P0-2]: Lobby Start Gate Hardening**
- **Goal:** Add preflight checklist RPC, check ready-state and host authority.
- **Status:** Integrated & verified. Code changes applied to: lobby.gd, lobby_manager.gd</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-GF-P0-2').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-rose-500/30 bg-rose-50 dark:bg-rose-500/10 text-rose-600 dark:text-rose-300 text-xs font-bold">P0</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-GF-P0-3</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">RPC Sender Identity & Contract Clamp</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
main.gd, player.gd, lobby_manager.gd
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Remove payload fields that claim identity. Validate sender natively.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Read all any_peer RPC entry points.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Remove payload fields that pretend to identify requester/authority (use get_remote_sender_id).</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Verify sender identity and authority explicitly for state-mutation RPCs.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Normalize RPC contracts to carry stable error codes.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-GF-P0-3">Clamp multiplayer RPC trust boundaries across scenes/main.gd, scenes/player.gd, and scripts/managers/lobby_manager.gd. Read all any_peer RPC entry points before editing. Keep fast RPC update flow, but remove payload fields that pretend to identify requester/authority when sender can be derived from multiplayer.get_remote_sender_id(). For room info, start flow, rematch, and state-mutation RPCs, verify sender identity and authority explicitly. Normalize RPC contracts so request payloads contain only data the caller is allowed to propose, and response payloads carry canonical server state plus stable error codes. Acceptance: spoofed requester IDs are ignored; unauthorized peers cannot mutate host/server-owned state; RPC errors are debuggable and consistent.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-GF-P0-3').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Call state-mutation RPC pretending to be another peer ID in payload. Assert server overrides payload with actual `get_remote_sender_id()` and blocks if unauthorized.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-GF-P0-3">**Completed [PRD-GF-P0-3]: RPC Sender Identity & Contract Clamp**
- **Goal:** Remove payload fields that claim identity. Validate sender natively.
- **Status:** Integrated & verified. Code changes applied to: main.gd, player.gd, lobby_manager.gd</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-GF-P0-3').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-rose-500/30 bg-rose-50 dark:bg-rose-500/10 text-rose-600 dark:text-rose-300 text-xs font-bold">P0</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-GF-P0-4</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Chat/DM Abuse Control</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
lobby.gd, Nakama chat
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Add moderation, throttling, sanitation, flood guard, and permission matrix.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Keep current channel UX, DM tabs, and history pull.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add per-user send cooldown and max payload length limits.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add command permission matrix (/clear admin only, all other slash commands explicit).</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Mark unsent/failed messages in UI with retry policy.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-GF-P0-4">Harden global chat and DM flow in scenes/lobby.gd and related Nakama chat policy. Keep current channel UX, DM tabs, and history pull, but add abuse controls: per-user send cooldown, max payload length, profanity/moderation hook placeholder, and command permission matrix (/clear admin only, all other slash commands explicit). Fix any DM append/state bug found during read-through. Prevent silent local-only divergence by marking unsent/failed messages in UI and retry policy. Acceptance: flood attempts are throttled; unauthorized command execution blocked server-side; message rendering sanitized and bounded; chat remains responsive under burst traffic.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-GF-P0-4').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Send 50 chat messages in 1 second. Assert Nakama throttles request and UI shows 'failed to send/cooldown' UI marker. Attempt `/clear` as non-admin, assert blocked.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-GF-P0-4">**Completed [PRD-GF-P0-4]: Chat/DM Abuse Control**
- **Goal:** Add moderation, throttling, sanitation, flood guard, and permission matrix.
- **Status:** Integrated & verified. Code changes applied to: lobby.gd, Nakama chat</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-GF-P0-4').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-amber-500/30 bg-amber-50 dark:bg-amber-500/10 text-amber-600 dark:text-amber-300 text-xs font-bold">P1</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-P1-1</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Module Split & RPC Validation</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
tekton_admin.js
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Split monolith into auth, economy, admin, mail, social, leaderboard, validation helpers.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Refactor tekton_admin.js into domain modules without changing external RPC names.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Create modules for auth, economy, admin, mail, social, leaderboard, storage, validation.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add central validators for payload shape, types, limits.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add normalized error responses with stable error codes.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-P1-1">Refactor server/nakama/tekton_admin.js into maintainable domain modules without changing external RPC names unless necessary. Create or plan modules for auth, economy, admin, mail, social, leaderboard, storage, and validation helpers. Add central validators for payload shape, types, limits, and allowed enum values. Add normalized error responses with stable error codes. Keep behavior compatible while moving code in small steps. Acceptance: RPC registration remains clear; each RPC validates payload before mutation; error responses are consistent; module split does not break existing smoke tests.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-P1-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Call split RPC with missing payload fields. Assert central validator catches it and returns `INVALID_ARGUMENT` standard error code.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-P1-1">**Completed [PRD-P1-1]: Module Split & RPC Validation**
- **Goal:** Split monolith into auth, economy, admin, mail, social, leaderboard, validation helpers.
- **Status:** Integrated & verified. Code changes applied to: tekton_admin.js</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-P1-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-amber-500/30 bg-amber-50 dark:bg-amber-500/10 text-amber-600 dark:text-amber-300 text-xs font-bold">P1</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-P1-2</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Ledger, Idempotency & Storage Model</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
Wallet, inventory, fragments, mail rewards
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Add mutation audit ledger, idempotency keys, and canonical fragment storage path.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Define one canonical fragment storage location and migration path.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add idempotency keys for mail claim, daily reward, purchase, gacha, and admin adjustments.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add audit records with source, user_id, mutation type, request_id.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Make mail claim transactional (claim, mark, return canonical state).</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-P1-2">Implement a canonical mutation ledger and idempotency policy for Tekton live-service rewards. Read server/nakama/tekton_admin.js, scripts/managers/user_profile_manager.gd, scripts/managers/mail_manager.gd, and gacha/profile storage code. Define one canonical fragment storage location and migration path. Add idempotency keys for mail claim, daily reward, purchase, gacha, and admin adjustments. Add audit records with source, user_id, mutation type, request_id, before/after summary, and timestamp. Make mail claim transactional: claim rewards, mark claimed, and return canonical updated state in one server response. Acceptance: repeated claim/purchase/reward requests do not duplicate grants; fragments read/write from one canonical path; mail UI refreshes from server-returned state.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-P1-2').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Send identical mail claim RPC twice simultaneously. Assert only one processes successfully and the second returns 'already claimed'.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-P1-2">**Completed [PRD-P1-2]: Ledger, Idempotency & Storage Model**
- **Goal:** Add mutation audit ledger, idempotency keys, and canonical fragment storage path.
- **Status:** Integrated & verified. Code changes applied to: Wallet, inventory, fragments, mail rewards</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-P1-2').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-amber-500/30 bg-amber-50 dark:bg-amber-500/10 text-amber-600 dark:text-amber-300 text-xs font-bold">P1</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-P1-3</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Client Backend Facade</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
nakama_manager.gd, auth_manager.gd, backend_service.gd
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Make one typed backend owner for session, socket, RPC calls, and central errors.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Decide whether BackendService becomes the sole typed backend facade or is deleted.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Implement one owner for client/session/socket.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add typed methods for RPCs, central error handling.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Remove direct UI RPC scatter for economy/auth/mail/gacha/social flows.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-P1-3">Clean up Tekton client backend ownership. Read scripts/nakama_manager.gd, scripts/managers/auth_manager.gd, scripts/services/backend_service.gd, and UI/manager scripts that call NakamaManager.client.rpc_async directly. Decide whether BackendService becomes the sole typed backend facade or is deleted. Implement chosen direction in small steps: one owner for client/session/socket, typed methods for RPCs, central error handling, and no direct UI RPC scatter for economy/auth/mail/gacha/social flows. Acceptance: UI calls typed service/manager methods, not raw client.rpc_async; session/socket ownership is clear; duplicate auth/bootstrap code is removed or delegated.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-P1-3').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Global search for `client.rpc_async` in `scripts/ui/`. Assert 0 results found (all go through facade).</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-P1-3">**Completed [PRD-P1-3]: Client Backend Facade**
- **Goal:** Make one typed backend owner for session, socket, RPC calls, and central errors.
- **Status:** Integrated & verified. Code changes applied to: nakama_manager.gd, auth_manager.gd, backend_service.gd</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-P1-3').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-amber-500/30 bg-amber-50 dark:bg-amber-500/10 text-amber-600 dark:text-amber-300 text-xs font-bold">P1</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-GF-P1-1</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Tutorial Isolation Contract</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
tutorial_manager.gd
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Remove multiplayer-side effects during pause/freeze phases. Isolate tutorial boundaries.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Keep onboarding sequence and camera storytelling.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Enforce contract: no persistent wallet/profile mutation during tutorial.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Ensure no shared lobby state leakage.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Ensure clean bot/timer restore on exit, deterministic return-to-lobby handshake.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Replace broad pause/freeze side effects with scoped tutorial-state toggles.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-GF-P1-1">Isolate tutorial runtime from multiplayer/session side effects. Review scripts/managers/tutorial_manager.gd and match lifecycle hooks. Keep onboarding sequence and camera storytelling, but enforce tutorial contract: no persistent wallet/profile mutation, no shared lobby state leakage, clean bot/timer restore on exit, deterministic return-to-lobby handshake. Replace broad pause/freeze side effects with scoped tutorial-state toggles where possible. Acceptance: exiting tutorial leaves no stale bot freeze, no leaked paused systems, and no corrupted room/session flags.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-GF-P1-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Abort tutorial midway. Assert main game tree is fully unpaused, bots are reset, and no 'tutorial_active' flags leak into lobby.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-GF-P1-1">**Completed [PRD-GF-P1-1]: Tutorial Isolation Contract**
- **Goal:** Remove multiplayer-side effects during pause/freeze phases. Isolate tutorial boundaries.
- **Status:** Integrated & verified. Code changes applied to: tutorial_manager.gd</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-GF-P1-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-amber-500/30 bg-amber-50 dark:bg-amber-500/10 text-amber-600 dark:text-amber-300 text-xs font-bold">P1</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-GF-P1-2</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Mode Config Completeness</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
main.gd, lobby mode configs
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Remove duplicated/inconsistent option toggles. Add schema-driven validation.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Keep existing Stop n Go custom UI.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Remove duplicated/fragile control toggles.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Implement Tekton Doors options with same host-authoritative lock and sync callbacks.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Introduce schema-driven config validation shared by host, client, and bootstrap.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-GF-P1-2">Complete mode-configuration parity between Stop n Go and Tekton Doors in lobby and match bootstrap flow. Keep existing Stop n Go custom UI, but remove duplicated/fragile control toggles and implement Tekton Doors options with same host-authoritative lock and sync callbacks. Introduce schema-driven config validation shared by host, client display logic, and match bootstrap. Acceptance: both modes expose full validated config; non-host clients always mirror host values; invalid config rejected before match start.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-GF-P1-2').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Join as client, attempt to spoof mode config RPC. Assert host rejects invalid mode config changes and overrides client.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-GF-P1-2">**Completed [PRD-GF-P1-2]: Mode Config Completeness**
- **Goal:** Remove duplicated/inconsistent option toggles. Add schema-driven validation.
- **Status:** Integrated & verified. Code changes applied to: main.gd, lobby mode configs</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-GF-P1-2').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-amber-500/30 bg-amber-50 dark:bg-amber-500/10 text-amber-600 dark:text-amber-300 text-xs font-bold">P1</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-GF-P1-3</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Backend Facade & Flow Decoupling</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
backend_service.gd, UI panels
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Improve service ownership and typed errors. Add one backend facade.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Identify remaining UI/manager scripts calling client.rpc_async.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Migrate calls to the central BackendService or unified manager.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Implement central error mapping and retry policy.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Verify all gameflow-adjacent UI uses new typed methods.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-GF-P1-3">Finish client backend decoupling for gameflow-adjacent live-service features. Read scripts/services/backend_service.gd plus UI/manager scripts that still call NakamaManager.client.rpc_async directly (profile, social, leaderboard, daily reward, mail, admin, friend flows). Decide whether BackendService becomes real facade or is removed. Implement one typed backend owner for auth/session/socket/RPC calls, central error mapping, and retry policy. Acceptance: gameflow-adjacent UI does not call raw client.rpc_async directly for production paths; backend ownership is obvious; future auth/RPC changes touch one service layer first, not many UI panels.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-GF-P1-3').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Trigger network failure during profile fetch. Assert BackendService retry policy handles it gracefully without UI hard-crashing.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-GF-P1-3">**Completed [PRD-GF-P1-3]: Backend Facade & Flow Decoupling**
- **Goal:** Improve service ownership and typed errors. Add one backend facade.
- **Status:** Integrated & verified. Code changes applied to: backend_service.gd, UI panels</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-GF-P1-3').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-amber-500/30 bg-amber-50 dark:bg-amber-500/10 text-amber-600 dark:text-amber-300 text-xs font-bold">P1</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-P1-4</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Versioning & Patch Integrity</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
tools/, export_presets.cfg, version.json
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Single release version source, checksums, compatibility rules, changelog archive.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Create one release version source (version.json or python script).</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Update project version, export versions, Android version deterministically.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Update patch manifest and changelog archive.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add patch integrity fields: checksum, size, minimum compatible app version.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-P1-4">Rebuild Tekton versioning workflow. Review tools/generate_version_json.py, tools/build_patch.gd, export_presets.cfg, project.godot, assets/data/version.json, README.md, and CHANGELOG_DRAFT.md. Create one release version source and update all platform metadata deterministically: project version, export versions, Android version/code, patch manifest, changelog archive, and Git tag instructions. Add patch integrity fields such as checksum, size, minimum compatible app version, and signature placeholder if signing is not available yet. Acceptance: one command or documented flow bumps release version; generated metadata matches across files; patch manifest can reject incompatible or corrupted patch.pck.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-P1-4').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Run version bump script. Assert export_presets.cfg Android version code increments correctly and patch manifest checksum is updated.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-P1-4">**Completed [PRD-P1-4]: Versioning & Patch Integrity**
- **Goal:** Single release version source, checksums, compatibility rules, changelog archive.
- **Status:** Integrated & verified. Code changes applied to: tools/, export_presets.cfg, version.json</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-P1-4').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-violet-500/30 bg-violet-50 dark:bg-violet-500/10 text-violet-600 dark:text-violet-300 text-xs font-bold">P2</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-P2-1</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Steam Depot & Store Packaging</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
tools/steam/, export presets
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Create SteamPipe VDFs, branch SOP, signing/notarization, platform filters.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Create tools/steam/app_build_<STEAM_APP_ID>.vdf and per-platform depot templates.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Document steamcmd upload command, branch promotion path.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Add guidance for Windows signing, macOS notarization, Android package name.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Configure store-specific export filters.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-P2-1">Add Steam and storefront release packaging workflow for Tekton after P0/P1 backend gates are complete. Review export_presets.cfg, docs/STEAMWORKS_SETUP.md, README.md, and current build output conventions. Create tools/steam/app_build_<STEAM_APP_ID>.vdf and per-platform depot VDF templates using placeholders only. Document steamcmd upload command, branch promotion path internal -> beta -> default, and smoke tests required before promotion. Add guidance for Windows signing, macOS bundle/team/notarization, Android final package name/version code, and store-specific export filters so Steam libraries are not shipped in non-Steam builds. Acceptance: no real IDs/secrets committed; SteamPipe templates exist; release checklist blocks default branch promotion until smoke tests pass.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-P2-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Trigger dry-run of SteamPipe VDF. Assert paths resolve to output directory without committing real credentials.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-P2-1">**Completed [PRD-P2-1]: Steam Depot & Store Packaging**
- **Goal:** Create SteamPipe VDFs, branch SOP, signing/notarization, platform filters.
- **Status:** Integrated & verified. Code changes applied to: tools/steam/, export presets</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-P2-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
<details class="group bg-white dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden" open>
<summary class="flex items-center justify-between p-4 cursor-pointer bg-slate-50 dark:bg-slate-900/50 hover:bg-slate-100 dark:hover:bg-slate-900 transition list-none outline-none">
<div class="flex items-center space-x-4">
<span class="px-2 py-1 rounded border border-violet-500/30 bg-violet-50 dark:bg-violet-500/10 text-violet-600 dark:text-violet-300 text-xs font-bold">P2</span>
<span class="font-mono text-xs text-slate-500 dark:text-slate-400">PRD-GF-P2-1</span>
<h3 class="text-md font-bold text-slate-900 dark:text-white">Dead Path, Debug Gate & Telemetry Cleanup</h3>
</div>
<div class="flex items-center space-x-3 text-slate-400">
<span class="text-xs font-semibold uppercase tracking-wider hidden md:inline-block border border-slate-200 dark:border-slate-700 px-2 py-1 rounded">TODO</span>
<i data-lucide="chevron-down" class="w-5 h-5 transition-transform group-open:rotate-180"></i>
</div>
</summary>
<div class="p-5 border-t border-slate-200 dark:border-slate-800 grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left Column: Details & Checklists -->
<div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Files / Areas</h4>
<div class="text-xs font-mono text-sky-600 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-2 py-1 rounded-md inline-block">
main.gd, player.gd, placeholders
</div>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Goal / Risk</h4>
<p class="text-sm text-slate-700 dark:text-slate-300">Remove release-noisy debug hooks. Add safe-remove candidate matrix + SLO dashboard.</p>
</div>
<div class="mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">Execution Checklist</h4>
<ul class="space-y-2 text-sm text-slate-700 dark:text-slate-300">
<li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Build matrix: keep, safe-remove, needs-runtime-proof, feature-flag.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Remove or feature-gate release-only noise (e.g., debug key hooks, excessive prints).</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Instrument events: room_joined, preflight_pass, loading_screen, match_sync.</span></li><li class="flex items-start"><i data-lucide="square" class="w-4 h-4 mr-2 mt-0.5 text-slate-400 shrink-0"></i> <span>Do not delete autoload/runtime-loaded scripts without proof.</span></li>
</ul>
</div>
</div>
<!-- Right Column: AI Prompt & Testing -->
<div class="flex flex-col space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/5 border border-indigo-200 dark:border-indigo-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400 mb-2 flex items-center"><i data-lucide="bot" class="w-4 h-4 mr-2"></i> AI Execution Prompt</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-mono h-32 overflow-y-auto" id="prompt-PRD-GF-P2-1">Create dead-path/debug-path cleanup and telemetry gates for lobby-to-match lifecycle. Review main.gd, player.gd, login_screen.gd, backend_service.gd, and other placeholders/debug hooks. Build matrix with columns: keep, safe-remove, needs-runtime-proof, feature-flag. Remove or feature-gate release-only noise such as debug key hooks and excessive prints, but do not delete autoload/runtime-loaded scripts without proof. Instrument events: room_joined, preflight_pass/fail, loading_screen_start/finish, match_sync_complete, reconnect_success/fail, match_end_summary. Acceptance: safe-remove candidates are evidence-backed; release export excludes debug-only hooks; branch promotion can check match-start and reconnect SLO metrics.</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('prompt-PRD-GF-P2-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Prompt">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="bg-emerald-50 dark:bg-emerald-500/5 border border-emerald-200 dark:border-emerald-500/20 rounded-lg p-4 mb-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-emerald-600 dark:text-emerald-400 mb-2 flex items-center"><i data-lucide="test-tube" class="w-4 h-4 mr-2"></i> Testing / Auto-Check</h4>
<p class="text-xs text-slate-700 dark:text-slate-300 font-mono leading-relaxed">AI AUTO-CHECK: Search codebase for `Input.is_key_pressed(KEY_F9)`. Assert wrapped in `OS.has_feature("debug")` or completely removed.</p>
</div>
<div class="bg-sky-50 dark:bg-sky-500/5 border border-sky-200 dark:border-sky-500/20 rounded-lg p-4">
<h4 class="text-xs font-semibold uppercase tracking-wider text-sky-600 dark:text-sky-400 mb-2 flex items-center"><i data-lucide="message-square" class="w-4 h-4 mr-2"></i> MS Teams Daily Report</h4>
<div class="relative group">
<pre class="text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans" id="teams-PRD-GF-P2-1">**Completed [PRD-GF-P2-1]: Dead Path, Debug Gate & Telemetry Cleanup**
- **Goal:** Remove release-noisy debug hooks. Add safe-remove candidate matrix + SLO dashboard.
- **Status:** Integrated & verified. Code changes applied to: main.gd, player.gd, placeholders</pre>
<button onclick="navigator.clipboard.writeText(document.getElementById('teams-PRD-GF-P2-1').textContent)" class="absolute top-0 right-0 p-1.5 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-md shadow-sm text-slate-500 hover:text-sky-500 opacity-0 group-hover:opacity-100 transition" title="Copy Teams Report">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
</details>
</div>
</section>
</main>
<!-- Footer -->
<footer class="border-t border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-950 py-10 mt-20 text-center">
<p class="text-xs text-slate-500 dark:text-slate-400 font-mono">
Blueprint released under MIT authorization. Secure server implementations are responsibility of the
deployment architecture team.
</p>
</footer>
<!-- Interactive Script Operations -->
<script>
// Init Lucide Icons
lucide.createIcons();
// Highlight flowchart pipelines
function highlightPath(target) {
// Remove selection formatting from all controls
document.querySelectorAll('.path-ctrl-btn').forEach(btn => {
btn.classList.remove('bg-sky-500', 'text-slate-950', 'shadow-md');
btn.classList.add('text-slate-600 dark:text-slate-400', 'hover:text-slate-900 dark:text-white');
});
// Assign selection styles to current target control
const activeBtn = document.getElementById('btn-path-' + target);
if (activeBtn) {
activeBtn.classList.add('bg-sky-500', 'text-slate-950', 'shadow-md');
activeBtn.classList.remove('text-slate-600 dark:text-slate-400', 'hover:text-slate-900 dark:text-white');
}
// Target elements to manipulate
const branches = {
steam: document.getElementById('branch-steam'),
android: document.getElementById('branch-android'),
ios: document.getElementById('branch-ios'),
fallback: document.getElementById('branch-fallback')
};
const root = document.getElementById('node-root');
const terminal = document.getElementById('node-terminal');
const lineRoot = document.getElementById('line-root');
const lineTerminal = document.getElementById('line-terminal');
// Apply opacity filters based on selection
if (target === 'all') {
Object.values(branches).forEach(b => {
b.classList.remove('opacity-25', 'border-sky-500/50');
b.classList.add('opacity-100');
});
root.classList.remove('opacity-50');
terminal.classList.remove('opacity-50');
lineRoot.classList.remove('bg-slate-200 dark:bg-slate-800/20');
lineTerminal.classList.remove('bg-slate-200 dark:bg-slate-800/20');
} else {
root.classList.remove('opacity-50');
terminal.classList.remove('opacity-50');
lineRoot.classList.remove('bg-slate-200 dark:bg-slate-800/20');
lineTerminal.classList.remove('bg-slate-200 dark:bg-slate-800/20');
Object.keys(branches).forEach(key => {
if (key === target) {
branches[key].classList.remove('opacity-25');
branches[key].classList.add('opacity-100', 'border-sky-500/50');
} else {
branches[key].classList.add('opacity-25');
branches[key].classList.remove('opacity-100', 'border-sky-500/50');
}
});
}
}
// Switch Store Tabs UI
function switchTab(platform) {
// Hide all contents
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.add('hidden');
});
// Show target
document.getElementById('content-' + platform).classList.remove('hidden');
// Deactivate all buttons
document.querySelectorAll('#store-tabs button').forEach(btn => {
btn.classList.remove('bg-slate-200 dark:bg-slate-800', 'text-slate-900 dark:text-white');
btn.classList.add('text-slate-600 dark:text-slate-400');
});
// Activate target button
const activeBtn = document.getElementById('tab-' + platform);
activeBtn.classList.remove('text-slate-600 dark:text-slate-400');
activeBtn.classList.add('bg-slate-200 dark:bg-slate-800', 'text-slate-900 dark:text-white');
}
</script>
<script>
// Init Lucide Icons
lucide.createIcons();
// Theme logic
function toggleTheme() {
if (document.documentElement.classList.contains('dark')) {
document.documentElement.classList.remove('dark');
localStorage.setItem('theme', 'light');
} else {
document.documentElement.classList.add('dark');
localStorage.setItem('theme', 'dark');
}
}
// Init theme
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
if (localStorage.theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
} else {
document.documentElement.classList.remove('dark');
}
document.getElementById('theme-toggle').addEventListener('click', toggleTheme);
</script>
</body>
</html>