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

# StateSet Worker

> Run the StateSet iCommerce engine in a Cloudflare Sandbox

# StateSet Worker

Run the [StateSet](https://stateset.io/) iCommerce engine in a [Cloudflare Sandbox](https://developers.cloudflare.com/sandbox/) — `wrangler deploy` and you have a full commerce engine with messaging channels, MCP tools, and an admin UI.

## Architecture

```
Browser / AI Agent / Messaging Platform
        │
┌───────┴──────────────────────────────────┐
│  Cloudflare Worker (Hono.js)             │
│  - CF Access auth                        │
│  - Admin UI (React SPA)                  │
│  - HTTP/WebSocket proxy to container     │
│  - Cron: SQLite backup to R2             │
└───────┬──────────────────────────────────┘
        │
┌───────┴──────────────────────────────────┐
│  CF Container (Durable Object)           │
│  - @stateset/cli (stateset-channels.js)  │
│  - @stateset/embedded (Rust/SQLite)      │
│  - 6 messaging channels                 │
│  - MCP server (87 tools)                 │
│  - HTTP gateway on port 8080             │
│  - R2 mounted at /data/stateset          │
└──────────────────────────────────────────┘
```

## Requirements

* [Workers Paid plan](https://www.cloudflare.com/plans/developer-platform/) (\$5 USD/month) — required for Cloudflare Sandbox containers
* [Anthropic API key](https://console.anthropic.com/) — or use [AI Gateway](https://developers.cloudflare.com/ai-gateway/) for routing and analytics

Free-tier Cloudflare features used:

* Cloudflare Access (authentication)
* AI Gateway (optional, for API routing/analytics)
* R2 Storage (optional, for persistence)

## Quick Start

```bash theme={null}
# Install dependencies
npm install

# Set your API key
npx wrangler secret put ANTHROPIC_API_KEY

# Deploy
npm run deploy
```

After deploying, your commerce engine is live at `https://stateset-sandbox.your-subdomain.workers.dev/`.

The first request takes 1-2 minutes while the container boots. A loading page is shown during startup.

To use the admin UI and protected routes, you'll need to:

1. [Set up Cloudflare Access](#setting-up-cloudflare-access) for authentication
2. [Enable R2 storage](#persistent-storage-r2) so commerce data persists (recommended)

## Setting Up Cloudflare Access

The admin UI at `/_admin/` and all `/api/admin/*` routes require Cloudflare Access authentication.

### 1. Enable Access on workers.dev

1. Go to the [Workers & Pages dashboard](https://dash.cloudflare.com/?to=/:account/workers-and-pages)
2. Select your Worker (`stateset-sandbox`)
3. In **Settings** > **Domains & Routes**, click the `...` menu on the workers.dev row
4. Click **Enable Cloudflare Access**
5. Configure who can access (email allow list, Google, GitHub, etc.)
6. Copy the **Application Audience (AUD)** tag

### 2. Set Access Secrets

```bash theme={null}
npx wrangler secret put CF_ACCESS_TEAM_DOMAIN
# Enter: myteam.cloudflareaccess.com

npx wrangler secret put CF_ACCESS_AUD
# Enter: your-application-audience-tag
```

Find your team domain in the [Zero Trust Dashboard](https://one.dash.cloudflare.com/) under **Settings** > **Custom Pages**.

### 3. Redeploy

```bash theme={null}
npm run deploy
```

Now `/_admin/` requires Cloudflare Access authentication.

## Persistent Storage (R2)

By default, commerce data (SQLite database, config) is lost when the container restarts. R2 storage enables persistence.

### Setup

1. Go to **R2** > **Overview** in the [Cloudflare Dashboard](https://dash.cloudflare.com/)
2. Click **Manage R2 API Tokens**
3. Create a token with **Object Read & Write** permissions for the `stateset-data` bucket

```bash theme={null}
npx wrangler secret put R2_ACCESS_KEY_ID
npx wrangler secret put R2_SECRET_ACCESS_KEY
npx wrangler secret put CF_ACCOUNT_ID
```

### How It Works

**SQLite backup** — The commerce database is backed up safely using SQLite's built-in `.backup` API, which handles concurrent writes correctly. A cron job runs every 5 minutes.

**Config sync** — Gateway configuration is synced to R2 via rsync.

**Restore on boot** — On container startup, data is restored from R2 if the backup is newer than local data. An integrity check verifies the database before restoring.

**Manual backup** — Trigger an immediate backup from the admin UI Storage tab or via `POST /api/admin/storage/sync`.

## Admin UI

Access the admin UI at `/_admin/` with three tabs:

* **Overview** — Gateway status, commerce stats (customers, orders, returns, products), channel summary, restart controls
* **Channels** — Per-channel status cards for all 6 messaging channels (Telegram, Discord, Slack, WhatsApp, Email, SMS)
* **Storage** — R2 configuration status, last backup time, manual backup button, backup strategy info

## Messaging Channels

Configure channels via environment secrets. Each channel is enabled automatically when its token is set.

### Telegram

```bash theme={null}
npx wrangler secret put TELEGRAM_BOT_TOKEN
```

### Discord

```bash theme={null}
npx wrangler secret put DISCORD_BOT_TOKEN
```

### Slack

```bash theme={null}
npx wrangler secret put SLACK_BOT_TOKEN
npx wrangler secret put SLACK_APP_TOKEN
```

### WhatsApp

```bash theme={null}
npx wrangler secret put WHATSAPP_TOKEN
```

### Email

```bash theme={null}
npx wrangler secret put EMAIL_SMTP_HOST
```

### SMS (Twilio)

```bash theme={null}
npx wrangler secret put TWILIO_ACCOUNT_SID
```

## Commerce Settings

```bash theme={null}
# Enable apply mode
npx wrangler secret put ALLOW_APPLY
# Enter: true

# Override default AI model
npx wrangler secret put DEFAULT_MODEL
# Enter: claude-opus-4-5
```

## AI Gateway (Optional)

Route API requests through [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) for caching, rate limiting, and analytics:

```bash theme={null}
npx wrangler secret put AI_GATEWAY_API_KEY
npx wrangler secret put AI_GATEWAY_BASE_URL
# Enter: https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/anthropic
```

AI Gateway variables take precedence over direct `ANTHROPIC_API_KEY` if both are set.

## Container Lifecycle

By default, the container stays alive indefinitely. To sleep after inactivity (reduces cost, adds cold start latency):

```bash theme={null}
npx wrangler secret put SANDBOX_SLEEP_AFTER
# Enter: 10m (or 1h, 30m, etc.)
```

With R2 configured, data persists across restarts.

## Debug Endpoints

Enable with `DEBUG_ROUTES=true` (requires Cloudflare Access):

| Endpoint                      | Description                                           |
| ----------------------------- | ----------------------------------------------------- |
| `GET /debug/version`          | Container and stateset version info                   |
| `GET /debug/processes`        | All container processes (add `?logs=true` for output) |
| `GET /debug/cli?cmd=...`      | Run a CLI command in the container                    |
| `GET /debug/logs?id=...`      | Logs for a specific process                           |
| `GET /debug/env`              | Sanitized environment configuration                   |
| `GET /debug/container-config` | Gateway config from inside the container              |

## Local Development

```bash theme={null}
cp .dev.vars.example .dev.vars
# Edit .dev.vars with your ANTHROPIC_API_KEY
npm install
npm run dev
```

Set `DEV_MODE=true` in `.dev.vars` to skip Cloudflare Access auth.

## All Secrets Reference

| Secret                   | Required | Description                                              |
| ------------------------ | -------- | -------------------------------------------------------- |
| `ANTHROPIC_API_KEY`      | Yes\*    | Anthropic API key (or use AI Gateway)                    |
| `AI_GATEWAY_API_KEY`     | Yes\*    | AI Gateway provider key (requires `AI_GATEWAY_BASE_URL`) |
| `AI_GATEWAY_BASE_URL`    | No       | AI Gateway endpoint URL                                  |
| `OPENAI_API_KEY`         | No       | OpenAI API key (alternative provider)                    |
| `CF_ACCESS_TEAM_DOMAIN`  | Yes      | Cloudflare Access team domain                            |
| `CF_ACCESS_AUD`          | Yes      | Cloudflare Access application audience                   |
| `STATESET_GATEWAY_TOKEN` | No       | Gateway auth token                                       |
| `R2_ACCESS_KEY_ID`       | No       | R2 access key for persistent storage                     |
| `R2_SECRET_ACCESS_KEY`   | No       | R2 secret key for persistent storage                     |
| `CF_ACCOUNT_ID`          | No       | Cloudflare account ID (required for R2)                  |
| `TELEGRAM_BOT_TOKEN`     | No       | Telegram channel                                         |
| `DISCORD_BOT_TOKEN`      | No       | Discord channel                                          |
| `SLACK_BOT_TOKEN`        | No       | Slack channel                                            |
| `SLACK_APP_TOKEN`        | No       | Slack channel (required with SLACK\_BOT\_TOKEN)          |
| `WHATSAPP_TOKEN`         | No       | WhatsApp channel                                         |
| `EMAIL_SMTP_HOST`        | No       | Email channel                                            |
| `TWILIO_ACCOUNT_SID`     | No       | SMS channel (Twilio)                                     |
| `ALLOW_APPLY`            | No       | Set to `true` to enable apply mode                       |
| `DEFAULT_MODEL`          | No       | Override default AI model                                |
| `DEV_MODE`               | No       | Set to `true` for local dev (skips auth)                 |
| `DEBUG_ROUTES`           | No       | Set to `true` to enable `/debug/*` routes                |
| `SANDBOX_SLEEP_AFTER`    | No       | Container sleep timeout: `never` (default), `10m`, `1h`  |

\* One of `ANTHROPIC_API_KEY` or `AI_GATEWAY_API_KEY` is required.

## Troubleshooting

**Container fails to start:** Check `npx wrangler tail` for logs. Verify `ANTHROPIC_API_KEY` is set.

**R2 not mounting:** Ensure all three secrets are set (`R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `CF_ACCOUNT_ID`). R2 mounting only works in production.

**Access denied on admin routes:** Verify `CF_ACCESS_TEAM_DOMAIN` and `CF_ACCESS_AUD` are set correctly.

**Slow first request:** Cold starts take 1-2 minutes. A loading page is shown automatically.

**Config changes not working:** Update the Dockerfile cache bust comment and redeploy.

## Links

* [StateSet](https://stateset.io/)
* [Cloudflare Sandbox Docs](https://developers.cloudflare.com/sandbox/)
* [Cloudflare Access Docs](https://developers.cloudflare.com/cloudflare-one/policies/access/)
* [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/)
