# AI Theme Builder — server setup (owner notes)

The Theme Builder engine (`theme-builder-lib.php`) runs entirely on
joltwp.com. The plugin submits a job to `api/theme-builder.php`, which
queues it; `tb-worker.php` runs the pipeline out of band and debits the
customer's token wallet. Customers pay by tokens (their own AI key pays the
raw LLM cost; the token packs are the platform charge). Available on any
paid plan.

## 1. Deploy files

Deploy as usual. New/changed server files:

- `theme-builder-lib.php` — the pipeline (crawl → redesign → theme + WXR + reports)
- `api/theme-builder.php` — plugin endpoint (start / status / file / revise / balance)
- `tb-worker.php` — background job runner
- `license-lib.php` — adds the token-wallet + jobs helpers
- `stripe-webhook.php` — credits the wallet on token-pack purchases
- `config.php` — `$powerupwp_tb_token_packs` (fill URLs in `config.local.php`)
- `account.php` — token balance + "buy tokens" packs per license

Requires `ext-zip` in addition to curl/dom/json. The engine writes builds to
`tb-builds/` under the webroot (auto-created, per-license hashed subdirs);
make sure that path is writable and **not** publicly served (deliverables are
streamed only through the authenticated endpoint).

## 2. Run the worker on cron

A full build takes minutes, so builds are queued and processed here. Add to
the server crontab (preferred):

```
* * * * * php /path/to/webroot/tb-worker.php >/dev/null 2>&1
```

or hit it from an external cron service — the bare URL works (public
trigger mode, like WordPress's wp-cron.php: it only processes already-queued
jobs, is throttled to one run per 45s, and reveals no job details):

```
https://joltwp.com/tb-worker.php
```

**Free cron timeouts are fine.** Over HTTP the worker replies with a tiny
200 in well under a second and then does the real work after the connection
closes (`ignore_user_abort` + early flush / `fastcgi_finish_request`), so a
cron service's 30-second timeout never sees a failure and can't kill a
build mid-run. Job results land in the DB as always — the response never
carried them anyway.

Adding `?secret=YOUR_ADMIN_SECRET&sync=1` waits and returns full job
details (debugging only — this one CAN exceed a cron service's timeout, so
run it from a browser or curl, not the cron).

If the host still kills long PHP processes (aggressive FPM
`request_terminate_timeout`), a job stuck in `running` for 30+ minutes is
automatically retried once on the next worker hit, then failed with a clear
message — customers are never left on an endless spinner. On such hosts
prefer the CLI crontab, which has no FPM timeout.

It processes up to 3 pending jobs per run. Customer AI keys are scrubbed from
the job row the moment a job finishes.

## 2c. Optional server config (config.local.php)

```php
// Premium models / routing overrides
define('POWERUPWP_TB_MODELS', ['claude' => 'claude-opus-4-6']); // dial generation back from Fable
define('POWERUPWP_TB_STEPS',  ['ideate' => 'claude']);          // move ideation off Gemini

// Font Awesome Pro kit — loaded into PREVIEWS only (they're served from
// joltwp.com, which your kit's domain allowlist covers). Delivered
// themes never reference it; they use inline SVG icons.
define('POWERUPWP_TB_FA_KIT', 'https://kit.fontawesome.com/xxxxxxxx.js');
```

## 3. Create the Stripe token packs

For each pack in `config.local.php` (`$powerupwp_tb_token_packs`), create a
Stripe **Payment Link** and:

1. Set metadata `tb_tokens` = the token count (e.g. `500000`).
2. Enable **"Let customers pass a client reference ID"** (the account page
   appends the license key as `client_reference_id`).
3. Paste the link into the matching pack's `url`.

The existing Stripe webhook (`checkout.session.completed`) already credits
the wallet — idempotent per checkout session.

Tune the economics in `license-lib.php`:

- `POWERUPWP_TB_STARTER_TOKENS` — free trial allowance (default 350,000 ≈ one build)
- `POWERUPWP_TB_MIN_START` / `POWERUPWP_TB_MIN_REVISE` — minimum balance to queue

## 4. Verify the deploy (self-test)

In wp-admin: **JoltWP → AI Content → AI Theme Builder → Run self-test**.
It checks, in order:

- Server extensions (zip / DOM / cURL) and that the build directory is writable
- The database tables exist
- **Worker heartbeat** — when `tb-worker.php` last ran (proves the cron is live)
- A live **1-page dry-run** through the real queue → worker → engine on the
  admin's own AI key (crawls one page + one tiny LLM call). This is free — no
  tokens are charged.

If the dry-run stays "pending" for ~2 minutes, the background worker isn't
running — fix the cron in step 2. Everything green = ready to sell.

## 5. Housekeeping & GitHub handoff

- The worker runs a daily retention sweep: build directories untouched for
  90 days are deleted; `_templates/`, `_library/` (sections, fonts, GitHub
  settings) are permanent; `_uploads/` stages clear after 7 days; job rows
  age out after 180 days.
- GitHub handoff stores each license's owner + fine-grained token in
  `_library/github.json` with the token AES-encrypted via the same secret
  used for platform keys (`powerupwp_encrypt_secret`) — the crypt key must
  be configured in config.local.php for it to work.

## 5b. Automatic follow-ups (nothing to configure)

The same daily sweep also runs two follow-ups:

- **Unopened-share nudge** — a client share link created 3+ days ago with
  zero opens triggers ONE email to the license owner (ready-to-forward
  nudge copy included). Marked in `share.json` so it never repeats.
- **Post-launch check** — when the plugin's one-click apply succeeds it
  pings `action=applied`; 7 days later the worker re-fetches the live
  homepage and up to 12 sampled `redirects.csv` paths and emails a
  pass/fail report (`launch-check.json` records it, once per build).

Both ride the existing tb-worker cron — if the worker runs, these run.

## 6. How billing works

The wallet is denominated in AI tokens. Each finished build/revision debits
the **actual** tokens the pipeline consumed (input + output across all
providers). Pack pricing sets your margin. Balance and packs show on
`account.php`; the plugin shows the balance and links customers there to top
up.
