{#
Copyright (C) 2026 Garudex Labs.  All Rights Reserved.
Caracal, a product of Garudex Labs

Lynx Capital setup checklist for Caracal and provider configuration.
#}
{% extends "layout.html" %}
{% block title %}Setup — {{ company }}{% endblock %}

{% block content %}
<style>
  .setup-wrap { max-width: 720px; margin: 0 auto; padding: 32px 20px 48px; }
  h1 { font-size: 17px; font-weight: 600; margin-bottom: 4px; }
  .sub { color: #5a6478; font-size: 12px; margin-bottom: 24px; }
  .panel { border: 1px solid var(--border); border-radius: 4px; padding: 18px; background: #fff; margin-bottom: 16px; }
  .panel h2 { font-size: 13px; font-weight: 600; margin-bottom: 6px; }
  .panel p { font-size: 12px; color: #5a6478; margin-bottom: 12px; }
  .panel code { font-family: ui-monospace, monospace; font-size: 11px; background: #1a1f2e; color: #c9d1e0; padding: 1px 5px; border-radius: 2px; }
  pre.cmd { background: #1a1f2e; color: #c9d1e0; font-family: ui-monospace, monospace; font-size: 11px; padding: 10px 12px; border-radius: 3px; margin: 6px 0 10px; overflow-x: auto; }
  pre.cmd .c { color: #6c7689; }
  .validate-bar { display: flex; align-items: center; gap: 12px; margin-top: 20px; flex-wrap: wrap; }
  #validate-btn { background: var(--primary); color: #fff; border: none; padding: 8px 18px; font-size: 12px; font-weight: 600; border-radius: 3px; cursor: pointer; }
  #validate-btn:hover { opacity: 0.85; }
  #validate-btn:disabled { opacity: 0.5; cursor: not-allowed; }
  #start-demo-btn { background: var(--accent); color: #fff; border: none; padding: 8px 18px; font-size: 12px; font-weight: 600; border-radius: 3px; cursor: pointer; }
  #start-demo-btn:hover { opacity: 0.85; }
  #validate-out { width: 100%; margin-top: 8px; }
  .rs { display: flex; align-items: center; gap: 7px; font-size: 12px; padding: 4px 0; }
  .rs .badge { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 8px; font-weight: 800; }
  .badge-ok { background: var(--success); color: #fff; }
  .badge-fail { background: var(--danger); color: #fff; }
  .rd { font-size: 10px; color: #5a6478; margin-left: 21px; }
</style>

<div class="setup-wrap">
  <h1>Setup</h1>
  <p class="sub">Confirm your environment is ready to run the {{ company }} demo.</p>

  <div class="panel">
    <h2>1 · Connect Caracal through TUI + control API</h2>
    <p>Install the released CLI/TUI, start Caracal, then use <code>caracal-tui</code> to create or confirm the Lynx zone, control key, and protected resources.</p>
<pre class="cmd">curl -fsSL https://raw.githubusercontent.com/Garudex-Labs/caracal/main/install-cli.sh | sh
curl -fsSL https://raw.githubusercontent.com/Garudex-Labs/caracal/main/install-tui.sh | sh
caracal up
caracal-tui</pre>
    <p>In the TUI, open <strong>Control</strong> and confirm <strong>enable endpoint</strong> before creating the Lynx control key.</p>
  </div>

  <div class="panel">
    <h2>2 · Create the Lynx Caracal objects</h2>
    <p>In the TUI, create a <code>Lynx Capital</code> zone, create a <code>lynx-control</code> control key, copy its client secret once, and add one <code>lynx/&lt;provider&gt;</code> resource for each provider in <code>config/company.yaml</code>. REST resources should point upstream to the provider alias such as <code>http://mercury-bank.mock:8800</code>.</p>
<pre class="cmd"><span class="c"># Required resource identifiers</span>
lynx/mercury-bank
lynx/wise-payouts
lynx/stripe-treasury
lynx/quickbooks
lynx/netsuite
lynx/sap-erp
lynx/ocr-vision
lynx/close-engine
lynx/regulatory-filings
lynx/customer-billing
lynx/tax-rules
lynx/compliance-nexus
lynx/fx-rates
lynx/treasury-ops
lynx/vendor-portal</pre>
  </div>

  <div class="panel">
    <h2>3 · Write caracal.toml</h2>
    <p>Create <code>~/.config/caracal/caracal.toml</code> from the TUI values. The SDK reads this file directly, so keep the control key secret here and do not put Caracal credentials in <code>.env</code>.</p>
<pre class="cmd">zone_url = "http://127.0.0.1:8080"
sts_url = "http://127.0.0.1:8080"
coordinator_url = "http://127.0.0.1:4000"
gateway_url = "http://127.0.0.1:8081"
zone_id = "&lt;zone id from TUI&gt;"
application_id = "&lt;control key client_id&gt;"
app_client_secret = "&lt;control key client_secret&gt;"

[[credentials]]
env = "LYNX_MERCURY_BANK_TOKEN"
resource = "lynx/mercury-bank"
upstream_prefix = "http://127.0.0.1:8800"</pre>
  </div>

  <div class="panel">
    <h2>4 · Configure environment</h2>
    <p>Copy the template and fill in <code>OPENAI_API_KEY</code>. Provider credentials are normal integration settings; Caracal credentials come from <code>caracal.toml</code>.</p>
<pre class="cmd">cp .env.example .env
<span class="c"># edit .env → set OPENAI_API_KEY=sk-...</span></pre>
  </div>

  <div class="panel">
    <h2>5 · Start the local provider network</h2>
    <p>The local provider network is isolated under <code>_mock/</code>. The Lynx app still calls providers through its real registry and transport clients.</p>
<pre class="cmd">docker compose -f _mock/docker-compose.yml up -d --build --wait</pre>
  </div>

  <div class="panel">
    <h2>6 · Run Lynx Capital</h2>
<pre class="cmd">uv run uvicorn app.main:app --reload --port 8000</pre>
  </div>

  <div class="panel">
    <h2>7 · Validate</h2>
    <p>Confirms <code>OPENAI_API_KEY</code>, Caracal URLs, <code>caracal.toml</code> resource bindings, gateway/coordinator health, and provider webhook secrets.</p>

    <div class="validate-bar">
      <button id="validate-btn">Validate configuration</button>
      <button id="start-demo-btn" style="display:none">Start Demo →</button>
      <div id="validate-out"></div>
    </div>
  </div>
</div>

<script type="module">
  const validateBtn = document.getElementById('validate-btn');
  const startDemoBtn = document.getElementById('start-demo-btn');
  const validateOut = document.getElementById('validate-out');

  validateBtn.addEventListener('click', async () => {
    validateBtn.disabled = true;
    validateBtn.textContent = 'Checking...';
    validateOut.replaceChildren();
    startDemoBtn.style.display = 'none';
    try {
      const r = await fetch('/api/setup/validate');
      const data = await r.json();
      for (const s of data.steps) {
        const row = document.createElement('div');
        row.className = 'rs';
        const badge = document.createElement('div');
        badge.className = `badge ${s.ok ? 'badge-ok' : 'badge-fail'}`;
        badge.textContent = s.ok ? '✓' : '✗';
        const label = document.createElement('span');
        label.textContent = s.label;
        row.appendChild(badge);
        row.appendChild(label);
        validateOut.appendChild(row);
        if (s.detail) {
          const detail = document.createElement('div');
          detail.className = 'rd';
          detail.textContent = s.detail;
          validateOut.appendChild(detail);
        }
      }
      if (data.ok) startDemoBtn.style.display = 'inline-block';
    } catch (e) {
      validateOut.textContent = 'Validation failed: ' + e.message;
    } finally {
      validateBtn.disabled = false;
      validateBtn.textContent = 'Validate configuration';
    }
  });

  startDemoBtn.addEventListener('click', async () => {
    startDemoBtn.disabled = true;
    await fetch('/api/session/setup-complete', {method: 'POST'});
    window.location = '/demo';
  });
</script>
{% endblock %}
