> ## Documentation Index
> Fetch the complete documentation index at: https://uncoded.ch/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# SignalsBot — Your Inbound Webhook Gateway

> A small, focused webhook receiver that turns external signals into validated configuration changes — TradingView, your SignalEditor, or any authenticated source. The smallest, most security-sensitive surface in the stack — and on purpose.

<Info>
  **The SignalsBot is a tiny, security-focused webhook receiver.** It accepts signed HTTPS POSTs from your SignalEditor, from TradingView, or from any other source you authenticate, validates them carefully, and writes the resulting configuration changes into your local database — where the TradingBot picks them up.
</Info>

## What the SignalsBot does for you

The SignalsBot is the **single, validated entry point for external trade signals**. If you're publishing strategies from your SignalEditor, this is the receiver. If you're sending TradingView alerts to your bot, this is the receiver. If you have a custom script or a third-party signal provider, this is also the receiver.

Everything that wants to change your TradingBot's behavior from the outside passes through here — and nothing reaches your local database without being authenticated and validated first.

The SignalsBot is intentionally one of the smallest services in the stack. Its job is narrow, its surface is auditable, and its failure mode is contained.

<CardGroup cols={2}>
  <Card title="Receives webhooks securely" icon="lock">
    HMAC-SHA256 signature verification for cryptographic integrity, plus shared-secret token fallback for sources (like TradingView) that don't support HMAC.
  </Card>

  <Card title="Validates every payload" icon="shield-check">
    Type-checks every field, rejects malformed shapes, enforces array length consistency (e.g., `sellPercentages.length === buySplits`), and refuses unknown keys.
  </Card>

  <Card title="Writes to local database only" icon="database">
    Updates two specific tables with a defined set of allowed fields. Never touches your exchange, never holds your API keys.
  </Card>

  <Card title="Audits every accepted change" icon="clipboard-list">
    Every successful webhook is logged with source IP, timestamp, and the exact change applied. Every rejected webhook is logged with the precise reason.
  </Card>

  <Card title="Rate-limited at the door" icon="gauge">
    Global limit of `100` requests per `15`-minute window per IP. Misbehaving sources get throttled before they can flood your dashboard.
  </Card>

  <Card title="64 KB body cap" icon="weight-scale">
    Inbound JSON bodies are capped to prevent memory-flood attacks. Real signal payloads are typically a few hundred bytes — the cap is generous for legitimate use.
  </Card>

  <Card title="Standard security headers" icon="shield">
    Every response includes the standard set of security headers — content-type sniffing protection, frame protection, XSS protection. No surprises in misconfigured browsers.
  </Card>

  <Card title="Bounded surface area" icon="diagram-project">
    Two operations, four endpoints (`GET /`, `GET /health`, `GET /tradepairs`, `POST /webhook`). Every line of behaviour is auditable.
  </Card>
</CardGroup>

## Why this is its own service

You might wonder: why is the SignalsBot a separate container instead of an endpoint inside the TradingBot?

Two reasons.

**Security boundary.** The SignalsBot is the **only** internet-exposed component (besides the Dashboard). By making it a small, audit-clear, one-job service, the security-sensitive surface is minimized. The TradingBot — which holds your exchange API keys — is never internet-exposed.

**Independent failure mode.** If the SignalsBot crashes (or is being attacked), your trading is unaffected. The TradingBot continues running with its existing configuration. You get a webhook outage, not a trading outage.

<Warning>
  **The SignalsBot is the most security-sensitive surface in the unCoded stack.** It accepts external HTTP POSTs that — if validated successfully — change live trading configuration.

  Because of this, the bot is intentionally minimal. It does one thing: validate webhooks and apply specific, allowed configuration changes. No admin panel. No remote-management endpoint. No "add new connector" feature. Just one validated POST endpoint.

  Always put the SignalsBot behind a TLS reverse proxy (Caddy, nginx-proxy-manager, or similar). Never expose its raw HTTP port to the public internet.
</Warning>

## What you can change via webhook

The SignalsBot accepts two kinds of operations — and only these two.

<AccordionGroup>
  <Accordion title="Tradepair updates — which symbols to trade" icon="coins">
    A tradepair update controls which symbols your TradingBot is actively trading.

    The webhook can:

    * **Add a symbol** to the active set (e.g., start trading `ETHUSDT`)
    * **Remove a symbol** from the active set (e.g., stop trading `XRPUSDT`)
    * **Replace the entire active set** at once

    Behind the scenes, the SignalsBot updates a single `tradePairs` configuration entry that the TradingBot reads on every configuration poll. The change is picked up within seconds.

    **Use case examples**:

    * A "trend filter ON" strategy enables a symbol when conditions allow.
    * A "trend filter OFF" strategy disables a symbol when conditions degrade.
    * A daily script rotates the active set based on volatility ranks — high-vol symbols on, low-vol off.
    * An emergency-stop script removes all symbols at once when news hits.
  </Accordion>

  <Accordion title="Mode-settings updates — how to trade" icon="sliders">
    A mode-settings update changes the parameters of one or more pre-built modes — without affecting which symbols are active.

    Allowed fields include:

    * **`canBuy`, `canSell`** — enable or disable buying / selling for the mode
    * **`canBuyUp`, `canBuyDown`** — directional gating
    * **`start`** — the mode's starting reference price
    * **`buyPercentage`, `buySplits`, `buyVolumes`, `investmentPerBuy`, `investmentPercentMode`** — the buy-ladder shape
    * **`sellPercentages`, `sellActivateDistancePercentage`, `sellCancelDistancePercentage`** — the sell-ladder shape and trailing-stop activation
    * **`stopLoss`, `stopLossPercentage`** — the hard stop-loss
    * **`onlyMakerBuy`, `onlyMakerSell`** — enforce maker-only orders
    * **`sellTimeCurves`, `sellTimeCurveCheckIntervalMs`** — time-decay sell logic
    * **`name`, `description`** — labelling

    Any field not in this list is **rejected** by validation. There is no path for an arbitrary configuration change.

    **Use case examples**:

    * A "regime change" strategy widens the sell ladder when volatility expands.
    * A "news-mode" toggle enables `canBuy: false` for risky modes when high-impact news hits.
    * A maker-rebate mode adjusts the buy-ladder spacing dynamically.
    * A "weekend conservative" toggle reduces position sizing on Friday evening, restores Monday morning.
  </Accordion>
</AccordionGroup>

## How a webhook flows through the SignalsBot

<Steps>
  <Step title="HTTPS POST arrives at /webhook">
    Your reverse proxy terminates TLS and forwards the request to the SignalsBot. Standard security headers are already applied. The global rate limiter checks the source IP — if it's exceeded `100` requests in the last `15` minutes, the request is rejected with `429 Too Many Requests`.
  </Step>

  <Step title="Authentication">
    The SignalsBot looks for one of three credentials:

    * An `X-Signature` header (HMAC-SHA256 of the raw body)
    * An `X-TRADINGVIEW-TOKEN` header (shared secret)
    * A `secret` field inside the JSON body (shared secret)

    Any one of these passes authentication. None match → `401 Unauthorized` and the bot logs the rejection.
  </Step>

  <Step title="Payload classification">
    The bot inspects the body to decide what operation to perform:

    * If `tradePairs`, `pair`, or `symbol` is present → tradepair update.
    * If `mode` (or `modes`) is present along with allowed mode-settings keys → mode-settings update.
    * Both can be present — they're processed in order.
    * Neither match → `400 Bad Request` with a precise reason.
  </Step>

  <Step title="Validation">
    Every field is type-checked. Length consistency is enforced (e.g., the number of sell percentages must match the number of buy splits). Unknown keys are stripped. Out-of-range values are rejected.
  </Step>

  <Step title="Database write">
    The validated change is written to the local database — either to the `config.tradePairs` key, the `modes` table, or both. The configuration hash is updated, which is how the TradingBot detects "something changed, re-read."
  </Step>

  <Step title="Audit log">
    Every successful change is logged in the format `[AUDIT] <source IP> <action> <details>`. The audit log is preserved in the bot's logs and can be reviewed via the Dashboard's Logs panel.
  </Step>

  <Step title="Response">
    The bot returns `200 OK` with a JSON body summarising what was applied. Your webhook source (e.g., TradingView, the SignalEditor) gets immediate confirmation.
  </Step>
</Steps>

## The SignalsBot's three small endpoints (besides /webhook)

Beyond the main `/webhook` POST, the SignalsBot exposes three read-only endpoints — each minimal and inspectable.

<AccordionGroup>
  <Accordion title="GET / — landing-page response" icon="house">
    A simple "the SignalsBot is running" response. Useful for monitoring tools that just want to know "is this service alive?". No authentication required (and no sensitive information returned — just a static "running" message).
  </Accordion>

  <Accordion title="GET /health — health check" icon="heart-pulse">
    Confirms database connectivity by running a simple query. Returns `200 OK` if the bot can reach the database, `503 Service Unavailable` if it can't.

    Useful for:

    * Reverse-proxy health checks (Caddy, nginx-proxy-manager).
    * External monitoring (UptimeRobot, Better Uptime, similar).
    * Operator manual checks: `curl https://signals.yourdomain.com/health`.
  </Accordion>

  <Accordion title="GET /tradepairs — read-only inspection" icon="eye">
    Returns the current active trade-pair configuration as the SignalsBot sees it in the database. Read-only — no authentication required (the data is also visible in the Dashboard).

    Useful when debugging "did my webhook actually update the active pairs?" — call this endpoint after sending a webhook and confirm the value reflects your update.
  </Accordion>
</AccordionGroup>

That's it — the entire endpoint surface. There's no admin panel, no signal-history endpoint, no strategy-management endpoint, no exchange-connectivity endpoint. The minimalism is the security feature.

## What the SignalsBot does NOT do

<Warning>
  **The SignalsBot is intentionally one of the smallest services in the stack.**

  * ❌ **Does not subscribe to exchange data.** Webhook-only — never reads market data.
  * ❌ **Does not evaluate strategies.** That's the SignalEditor.
  * ❌ **Does not place orders.** That's the TradingBot.
  * ❌ **Does not author strategies.** That's the SignalEditor.
  * ❌ **Does not produce signals.** It only **receives** them.
  * ❌ **Does not have an admin panel.** Configuration changes happen via the Dashboard or the database, not via the SignalsBot.
  * ❌ **Does not retry failed webhook deliveries.** It's a receiver, not a sender — outbound retries are the upstream's responsibility.
  * ❌ **Does not maintain signal history beyond logs.** If you need a queryable signal history, the audit logs are your source.
  * ❌ **Does not transform payloads.** It validates them as-is and applies them as-is. No "interpret the signal" step.
  * ❌ **Does not call out to external services.** Once a webhook arrives, all subsequent action is local.

  This deliberate minimalism is the security feature. A small surface is an auditable surface.
</Warning>

## Webhook source patterns

Operators send webhooks from a variety of sources. Here's the standard pattern catalog.

<AccordionGroup>
  <Accordion title="SignalEditor → SignalsBot (the canonical local pattern)" icon="wand-magic-sparkles">
    Your locally-running SignalEditor's strategies POST to the SignalsBot's `/webhook` endpoint when triggers fire.

    Authentication: HMAC-SHA256 (the cryptographically stronger path). The shared secret is set in both the SignalEditor's environment and the SignalsBot's environment.

    Network: traffic stays on your VPS's internal Docker network. The webhook does not traverse the public internet.

    This is the most common pattern — almost every operator using the SignalEditor uses this path.
  </Accordion>

  <Accordion title="TradingView alert → SignalsBot (the external integration)" icon="chart-line">
    TradingView's alert system POSTs to your SignalsBot's `/webhook` endpoint when a Pine Script alert fires.

    Authentication: shared-secret token (TradingView doesn't support HMAC signing of webhook bodies). The secret is included in the alert message body as a `secret` field.

    Network: traffic traverses the public internet — TLS is mandatory.

    Setup: in TradingView's alert dialog, set the webhook URL to `https://signals.yourdomain.com/webhook`. In the alert message body, include a JSON shape like:

    ```text theme={null}
    {
      "secret": "your-shared-secret",
      "pair": "BTCUSDT",
      "mode": 4,
      "canBuy": true
    }
    ```

    TradingView's free tier supports webhook alerts on the higher subscription levels — check their pricing.
  </Accordion>

  <Accordion title="Custom script → SignalsBot (operator automation)" icon="code">
    Any script that can do an authenticated HTTPS POST can drive the SignalsBot. Common languages:

    * **Bash + curl**: simplest. One-liner for ad-hoc operator actions.
    * **Python**: most common for scheduled scripts (e.g., daily volatility-rank rotation).
    * **JavaScript**: if you have other JS-based infrastructure.

    Example Bash one-liner:

    ```text theme={null}
    curl -X POST https://signals.yourdomain.com/webhook \
      -H 'Content-Type: application/json' \
      -d '{"secret":"<shared>","pair":"BTCUSDT","mode":4,"canBuy":false}'
    ```

    Use case: emergency operator action without logging into the Dashboard. Or scheduled automation that depends on data outside the SignalEditor's reach (news APIs, on-chain data, social-sentiment feeds).
  </Accordion>

  <Accordion title="Third-party signal provider → SignalsBot (with caution)" icon="rss">
    Some commercial signal providers offer webhook delivery. The SignalsBot can accept their webhooks if they support a shared-secret in the body or a custom header.

    **Caveats**:

    * Trust assessment first. A signal provider with webhook access can affect your live trading. Vet them carefully.
    * Rate-limit at your reverse proxy as an additional layer. The SignalsBot's `100/15min` is a default; you can be more restrictive.
    * Audit the provider's signals weekly. If they start sending unexpected payloads, revoke immediately.

    Most operators don't go this route — they prefer to author their own strategies in the SignalEditor.
  </Accordion>
</AccordionGroup>

## Setting up TradingView integration

A common operator setup. Step-by-step.

<Steps>
  <Step title="Confirm your TradingView plan supports webhooks">
    Webhook alerts are a paid TradingView feature (Pro and above as of 2026). Confirm before proceeding.
  </Step>

  <Step title="Configure your reverse proxy">
    Put your SignalsBot behind a reverse proxy with a real DNS name and TLS. Caddy is the lowest-friction option:

    ```text theme={null}
    signals.yourdomain.com {
      reverse_proxy signalsbot:3000
    }
    ```

    Caddy auto-acquires Let's Encrypt certificates. Once running, `https://signals.yourdomain.com/health` should return OK.
  </Step>

  <Step title="Set the shared secret">
    Generate a long random shared secret on your VPS:

    ```text theme={null}
    openssl rand -hex 32
    ```

    Set the result as the `TRADINGVIEW_WEBHOOK_SECRET` environment variable in the SignalsBot container. Restart the container.

    Save this secret in your password manager. You'll need it in TradingView's alert configuration.
  </Step>

  <Step title="Create a TradingView alert">
    On TradingView, create an alert on your symbol of choice with your desired condition. In the alert dialog:

    * **Webhook URL**: `https://signals.yourdomain.com/webhook`
    * **Message body**: paste the JSON template you want the alert to send, including the `secret` field with your shared secret value.

    Example for "buy signal":

    ```text theme={null}
    {
      "secret": "<your-shared-secret>",
      "pair": "BTCUSDT",
      "mode": 4,
      "canBuy": true
    }
    ```
  </Step>

  <Step title="Test with a one-shot alert">
    Set up a one-shot alert that fires immediately (e.g., a price-touches-current-price condition). Confirm the SignalsBot's audit log shows the accepted webhook. Check the Dashboard to confirm the configuration change took effect.
  </Step>

  <Step title="Build out your alert pattern">
    Once one alert works, replicate the pattern for the other alerts you want. Common pattern: paired "buy signal" and "sell signal" alerts on the same condition.
  </Step>
</Steps>

## Operational footprint

<CardGroup cols={2}>
  <Card title="Resource cost" icon="microchip">
    `100–200 MB` RAM at idle. Sub-percent CPU. The bot is a lightweight HTTP server with one mutating endpoint and a small connection pool.
  </Card>

  <Card title="Network calls" icon="globe">
    **Inbound** on the webhook port (behind your TLS proxy). **No outbound** to the internet — all writes go to the local database. The audit ground truth is local.
  </Card>

  <Card title="Failure mode" icon="triangle-exclamation">
    If the SignalsBot crashes, **trading is unaffected** — the TradingBot continues with its current configuration. New webhook-driven changes pause until the SignalsBot is back.
  </Card>

  <Card title="Startup time" icon="stopwatch">
    Boots in seconds. Validates that the webhook secret is set; refuses to start otherwise. Validates database connectivity; backs off and retries if not ready.
  </Card>

  <Card title="Audit log size" icon="clipboard-list">
    Each accepted webhook produces \~1 line. Each rejected webhook produces \~1 line. Even at high webhook frequencies, log volume is modest. Forward to your preferred sink for long-term retention.
  </Card>

  <Card title="Internet exposure" icon="globe">
    The only inbound exposure is the `/webhook` endpoint. Behind a reverse proxy, configure your firewall to allow only the proxy's port. The bot itself listens on internal Docker network.
  </Card>
</CardGroup>

## Common questions

<AccordionGroup>
  <Accordion title="Do I need the SignalsBot to use unCoded?" icon="circle-question">
    **No.** If you only run pre-built modes (BasicMode, FullBullMarket, etc.), the SignalsBot is optional — those modes are static configuration that doesn't change unless you change them via the Dashboard.

    You need the SignalsBot if you're:

    * Running custom strategies in the SignalEditor (which posts webhooks here)
    * Receiving TradingView alerts
    * Driving configuration from external scripts or third-party signal providers

    Most operators turn it on after they start authoring custom strategies.
  </Accordion>

  <Accordion title="What's the right way to expose it to TradingView?" icon="circle-question">
    Put it behind a **TLS reverse proxy** with a real DNS name (e.g., `signals.yourdomain.com`). Caddy and nginx-proxy-manager are operator favorites because they automate Let's Encrypt certificates.

    In TradingView's alert creation dialog, set the webhook URL to `https://signals.yourdomain.com/webhook`, and include the alert message body with your shared secret in the `secret` field. The SignalsBot will accept the alert if the secret matches.

    **Never expose the raw HTTP port.** TradingView's webhooks travel over the public internet — without TLS, your shared secret is in the clear.
  </Accordion>

  <Accordion title="What's the difference between HMAC and shared-secret authentication?" icon="circle-question">
    **HMAC-SHA256** (the `X-Signature` header) is cryptographically stronger. The sender signs the raw request body with a shared key; the receiver re-computes the signature and rejects mismatches. An attacker who intercepts the request cannot forge new signed requests without the key.

    **Shared-secret tokens** (the `X-TRADINGVIEW-TOKEN` header or `body.secret` field) are simpler — the secret is just sent in the request. This is what TradingView supports natively, so unCoded supports it too.

    For SignalEditor → SignalsBot communication, **HMAC is used by default**. For TradingView, the shared-secret fallback applies. Both paths use the same secret stored in your environment.
  </Accordion>

  <Accordion title="Can I send webhooks from my own scripts?" icon="circle-question">
    **Yes.** Any script that can do an authenticated HTTPS POST can drive the SignalsBot. Send a JSON body with your `secret` plus the fields you want to change, POST to `/webhook`, and you're done.

    Use this for ad-hoc operator actions (e.g., disabling buying for a specific mode in response to news), for integrations with your own analytics, or for bridging from a signal provider that doesn't natively support webhooks.

    Operators with light dev backgrounds typically write a few small Bash + `curl` or Python scripts to wrap common actions (kill switch, mode reset, capital reallocation) — these become a reliable, version-controllable operator toolkit.
  </Accordion>

  <Accordion title="What happens if I send the same webhook twice?" icon="circle-question">
    The SignalsBot is **not idempotent at the request level**. If you send `enable buying for mode 4` twice in a row, the second one re-applies the same change (which is a no-op in this case) and emits two audit log lines.

    For ordinary configuration updates, this is fine — applying the same setting twice has no negative effect. For one-shot actions, your sender is responsible for de-duplication.

    For TradingView, this can occasionally happen during alert retries — TradingView retries failed webhook deliveries. The retries are usually idempotent (same content), so they're handled gracefully.
  </Accordion>

  <Accordion title="Why is there a 64 KB body cap?" icon="circle-question">
    Real signal payloads are typically a few hundred bytes — even a complex multi-mode update is well under `5 KB`. The `64 KB` cap is generous enough for any legitimate use, while protecting the bot from memory-flood attacks where a malicious source streams gigabytes of body.

    If you have a legitimate signal that exceeds `64 KB` (very unusual), contact support — the cap is configurable but rarely needs to change.
  </Accordion>

  <Accordion title="What does the audit log look like?" icon="circle-question">
    Every successful webhook produces a log line like:

    ```text theme={null}
    [AUDIT] 203.0.113.45 tradepairs_update added=BTCUSDT,ETHUSDT removed=XRPUSDT
    [AUDIT] 203.0.113.45 mode_update mode=4 changes={canBuy:false,sellPercentages:[0.5,1,2,3,4,5,7]}
    ```

    Every rejection logs with the precise reason:

    ```text theme={null}
    [REJECT] 198.51.100.7 reason=invalid_hmac
    [REJECT] 192.0.2.99 reason=mode_validation_failed details=sellPercentages.length(8)!=buySplits(7)
    ```

    The Dashboard's Logs panel surfaces these for review. For long-term retention, configure log shipping to your preferred sink.
  </Accordion>

  <Accordion title="Can I rotate the webhook secret?" icon="circle-question">
    **Yes — and you should, periodically.** Rotation pattern:

    1. Generate a new secret: `openssl rand -hex 32`.
    2. Update the SignalsBot's environment variable. Restart the container.
    3. Update every upstream sender (SignalEditor, TradingView alerts, custom scripts) to use the new secret.
    4. Verify a test webhook works.
    5. The old secret is dead.

    **Operator habit**: rotate quarterly. Mark the rotation in your operator log so you can correlate "did anything start failing right after the rotation?" if something does.
  </Accordion>

  <Accordion title="Can I have multiple SignalsBots?" icon="circle-question">
    **Yes — though most operators don't need to.** A single SignalsBot can handle webhooks from many sources (SignalEditor + TradingView + custom scripts) all in parallel.

    Reasons to run multiple SignalsBots:

    * Different webhook secrets per source (rotate independently).
    * Different rate limits per source (high-rate strategy source vs low-rate operator script).
    * Geographic distribution (a SignalsBot near each VPS).

    The pattern: each SignalsBot is configured with its own secret, points at the same shared database, listens on its own port (each with its own reverse-proxy domain).
  </Accordion>

  <Accordion title="What if a webhook is half-applied (network drops mid-write)?" icon="circle-question">
    Database writes are transactional. If a webhook starts a write and the connection drops mid-flight, the database transaction either commits fully or rolls back fully — no half-state.

    The webhook caller may not know the outcome (it never got a response). The standard pattern: the caller retries on connection failure. The SignalsBot accepts the retry, sees the change is already applied (idempotent at the data level for most operations), and acknowledges.
  </Accordion>

  <Accordion title="What if my reverse proxy fails?" icon="circle-question">
    If your reverse proxy crashes, inbound webhooks fail at the proxy layer — the SignalsBot never sees them. Your trading is unaffected (the TradingBot continues with current config), but new webhook-driven configuration changes don't propagate.

    Most reverse proxies (Caddy, nginx-proxy-manager) restart automatically. Total outage is usually seconds.

    For high-availability, run two reverse proxies behind a load balancer. Most operators don't bother — single-proxy is sufficient for typical workloads.
  </Accordion>
</AccordionGroup>

## Best practices

<Tip>
  * ✅ **Keep your webhook secret long and random** — generate it with `openssl rand -hex 32` or similar.
  * ✅ **Rotate the secret periodically** — once a quarter is reasonable. Rotation requires updating both the SignalsBot's environment and every upstream sender's configuration.
  * ✅ **Always use HTTPS** — never expose the raw HTTP port to the public internet.
  * ✅ **Watch the audit log weekly** — confirm only your expected sources are sending webhooks. Unknown source IPs are a flag worth investigating.
  * ✅ **Use HMAC where possible** — the SignalEditor → SignalsBot path uses it by default. For TradingView, the shared-secret fallback is acceptable but cryptographically weaker.
  * ✅ **Don't run the SignalsBot on the same VPS as untrusted services** — it's the most security-sensitive surface; keep its neighborhood clean.
  * ✅ **Set up monitoring on the `/health` endpoint** — UptimeRobot, Better Uptime, or your existing monitoring. Alert on any downtime.
  * ✅ **Allow-list source IPs at the reverse proxy** if you can — TradingView's IPs are public; your SignalEditor's IP is fixed. Restrict to known sources.
  * ✅ **Test webhook integrations during quiet hours** — a misconfigured webhook during a busy market session is harder to debug.
  * ✅ **Forward audit logs to a long-term sink** — for compliance and post-incident analysis.
  * ✅ **Document your webhook secret rotation cadence** in your operator runbook so you don't drift.
</Tip>

## What's next

<CardGroup cols={2}>
  <Card title="SignalEditor" icon="wand-magic-sparkles" href="/modules/signaleditor">
    The upstream that authors strategies and posts the webhooks the SignalsBot receives.
  </Card>

  <Card title="TradingBot" icon="robot" href="/modules/tradingbot">
    The downstream that picks up the configuration changes the SignalsBot writes.
  </Card>

  <Card title="Architecture" icon="server" href="/concepts/architecture">
    Where the SignalsBot sits in the overall network and security model.
  </Card>

  <Card title="Security Philosophy" icon="shield" href="/about/security-philosophy">
    Why the SignalsBot is intentionally tiny and audit-clear.
  </Card>

  <Card title="Dashboard" icon="gauge" href="/modules/dashboard">
    Where you see the audit log and the resulting configuration changes.
  </Card>

  <Card title="Strategy Recipes" icon="book" href="/strategies/recipes">
    Worked examples of strategies that drive the SignalsBot.
  </Card>
</CardGroup>
