# Building and sideloading Keysat

This repo ships three components that you'll bundle into a single installable `.s9pk`:

- `licensing-service/` — the Rust daemon (`keysat` binary).
- `licensing-service-startos/` — the StartOS 0.4.0.x wrapper (TypeScript manifest + actions + Dockerfile).
- `licensing-client-rust/` and `licensing-client-ts/` — SDKs for downstream software. Not bundled into the `.s9pk`; published separately when you cut a release.

The Rust service's on-disk folder name is still `licensing-service/` for continuity, but the crate, binary, and operator-visible branding are all **Keysat** now.

## Prerequisites

1. A working **StartOS 0.4.0.x development environment** on a Linux or macOS workstation. Follow [docs.start9.com](https://docs.start9.com) if you haven't set this up yet.
2. `start-cli` installed on your PATH, with `~/.startos/developer.key.pem` initialised (`start-cli init`).
3. **Node 20+** (for the StartOS SDK, TypeScript).
4. **Docker + buildx** (for multi-arch image builds).
5. Network reachability from your workstation to your Start9 server (LAN or Tor — whatever you usually use to `start-cli install`).
6. A running **BTCPay Server** on the same Start9 server (Keysat depends on it).

You do **not** need Rust locally — the Dockerfile pulls a pinned `rust:1.75-slim-bookworm` image.

## One-time setup

### 1. Fetch the shared build logic

Every 0.4.0.x wrapper includes `s9pk.mk`, which is maintained by the Start9 team. Fetch the current copy once:

```bash
cd licensing-service-startos
curl -o s9pk.mk https://raw.githubusercontent.com/Start9Labs/hello-world-startos/master/s9pk.mk
```

The `Makefile` `include s9pk.mk` line will error out until that file is in place.

### 2. Install TypeScript deps

```bash
cd licensing-service-startos
npm install
```

## Building

From `licensing-service-startos/`:

```bash
# Build for all supported architectures (x86_64 + aarch64)
make

# Or just the architecture your Start9 box runs
make arm        # Raspberry Pi / Apple Silicon
make x86        # x86_64 StartOS server
```

The resulting artifact lands in `licensing-service-startos/*.s9pk` — a single file you can sideload.

## Sideloading

```bash
cd licensing-service-startos
make install
```

This uses your `~/.startos/developer.key.pem` to push the package to the Start9 server it's registered against. First-run prompts for the Start9 dashboard password; subsequent installs reuse the cached session.

If you prefer to upload the `.s9pk` through the StartOS dashboard UI, copy the file off your workstation and drag it into **Sideload package** from the dashboard.

## First-boot checklist

Once installed, open **Keysat** in your StartOS dashboard and run these actions in order:

1. **Set operator name** — your display name, shown on the public homepage.
2. **Connect BTCPay** — opens a BTCPay consent page in your browser. Click Authorize; Keysat auto-detects your store and registers its inbound webhook.
3. **Check BTCPay connection** — confirms the authorize completed and the webhook is live.
4. **Create product** — one per thing you plan to sell.
5. **Create policy** — at least one per product, slugged `default`. Sets the shape of keys issued through the public purchase flow.

At this point your buyers can `POST /v1/purchase` against your Keysat URL, pay via BTCPay, and poll back for their license key.

## Testing it end-to-end

Keysat ships with a cross-check test suite that independently signs license keys with a Python reference implementation and replays them through the Rust and TypeScript SDK parsers. See `tests/crosscheck/README.md`.

The simplest smoke test against a live install:

```bash
# On your workstation, once the service is running on StartOS:
curl https://<your-keysat-url>/v1/pubkey
curl https://<your-keysat-url>/healthz
```

The first returns the Ed25519 public key you'll bake into downstream software. The second should just return `{"ok":true}`.

## Troubleshooting

- **"KEYSAT_ADMIN_API_KEY must be at least 32 characters"** — shouldn't happen from StartOS (the wrapper generates the key), but if you're running locally, `openssl rand -hex 32` gives a valid value.
- **"BTCPay not yet configured — purchases will return 503"** — run **Connect BTCPay** from the StartOS dashboard.
- **Rebuilds don't reflect Rust source changes** — Docker layer caching is aggressive; `make clean` before `make` to force a full rebuild.
- **Existing installs using `LICENSING_*` env vars** — the daemon still reads those as a fallback for one release cycle. New installs set `KEYSAT_*` directly.
