# 07. Deployment runbook (server)

## Server paths (as used in config)
- Tenants: `/home/mytown/blog.mytown.ink/tenants`
- Kit template zip: `/home/mytown/blog.mytown.ink/assets/blogger-kit.zip`
- App package tarball: `/home/mytown/blog.mytown.ink/packages/blogger-app-v1.tar.gz`

## Virtual hosts
- `blogger.mytown.ink` should serve `blogger_web/`
- `api.blogger.mytown.ink` should serve `blogger_api/`

## Required PHP extensions
- `curl`
- `openssl`
- `zip`
- `pdo_sqlite` (optional for content-bot reference or if store.php is used)

## Environment variables (recommended)
- `YOCO_SECRET_KEY`
- `YOCO_WEBHOOK_SECRET`
- (optional) override config values via env as needed
- `WP_MASTER_KEY_B64` (base64-encoded 32-byte AES key or a readable file path that contains the base64 string; prefer a file path in production so the same value works for WP + OpenAI encryption tooling)

## File permissions
- `tenants_dir` must be writable by the PHP user
- `.secrets/` must be readable by the API PHP user and not web-exposed

## Secret Hygiene
- **What must never be committed**: `.env` files (only `.env.example` is tracked), private key files (`*.key`, `*.pem`, `*.p12`, `*.b64`), SQLite stores (`*.sqlite*`, `_store.sqlite`), `.secrets/` folders, `tenants/` data, and logs (`error_log`, `*.log`, `*.bak*`, `*.save`) that may contain credentials.
- **Where secrets should live**: in real environment variables (e.g., `YOCO_SECRET_KEY`, `YOCO_WEBHOOK_SECRET`, OpenAI keys, WordPress `APP_PASSWORD`s) injected by your deployment tooling rather than committed to the repo.
- **What to rotate if a leak is suspected**: re-issue any exposed credentials (OpenAI `sk-` keys, `YOCO_SECRET_KEY`, `YOCO_WEBHOOK_SECRET`, WordPress application passwords, `WP_MASTER_KEY_B64`, etc.) via the provider console or WordPress admin, then redeploy with the updated env vars.
- **How to verify**: run `bash scripts/secret_scan.sh` from the repo root. A clean scan prints `secret_scan: PASSED` and exits `0`; anything else prints matching files with `secret_scan: FAILED (<n> issue(s) found)` and exits non-zero, so remove the flagged secrets and rerun until it passes.

## Smoke tests
1. `GET https://api.blogger.mytown.ink/ping.php`
2. Create checkout (test email) and confirm redirectUrl returned
3. Trigger webhook (via Yoco sandbox) and confirm:
   - tenant folder exists
   - active.json status is `active`
4. Open paid link:
   - download kit
5. Unzip kit locally and run installer
6. Connect WP and run test post to confirm REST auth

### Scripted smoke checks
- `BLOGGER_API_URL` (or `BLOGGER_API_BASE_URL`) and `BLOGGER_WEB_URL` (or `BLOGGER_WEB_BASE_URL`) can be exported before running the scripts; they default to `http://localhost`.
- `bash scripts/run_smoke_tests.sh` invokes each scripted check and reports success/failure for:
  - `scripts/smoke_checkout.sh` (POST `/checkout/create.php` with an invalid email, expects HTTP `400` and `Valid email required`).
  - `scripts/smoke_webhooks.sh` (POST `/webhooks/yoco.php` without and with bad signature headers, expects HTTP `401` + `Invalid signature`).
  - `scripts/smoke_download.sh` (GET `/download.php` without a token and with an improperly formatted token, expects HTTP `400` with the corresponding error message).
  - `scripts/smoke_wp.sh` (exercise WP connect, status, and test_post with empty payloads, expecting HTTP `400` rejections such as `Missing required fields`, `Invalid ref`, and `Invalid tenant_ref`).
- The helper `scripts/helpers.sh` ensures the scripts share the same base URLs and prints human-friendly log lines for each assertion.

## Logs
- `blogger_api/config.php` points webhook log to `/home/mytown/blog.mytown.ink/tenants/_yoco_webhook.log`
- download log to `/home/mytown/blog.mytown.ink/tenants/_download.log`
- kit package log defaults to `/home/mytown/blog.mytown.ink/tenants/_kit_package.log`
