# Beacon

See [OPERATIONS.md](OPERATIONS.md) for command effects and prerequisites; run
`node scripts/operations.mjs describe` from an exported edition to inspect them.

Read [first-release acceptance](ACCEPTANCE.md) for purpose, unmet release obligations, preserved requirements and the evidence decision rule.

Beacon is an installable conversation desk for one business, composed from the shared base, Support family, and selected email modules. Incoming conversations can remain at zero cases. Operators use the native inbox to review a reply, explicitly send it, and inspect its persisted delivery state.

This is a working, bounded Support pilot, not the complete 1.0 product. The hosted widget journey has passed; the contract registry keeps unfinished requirements visible.

## Guided local installation

Run `node scripts/install.mjs` before installing application dependencies for the
shared Base setup experience with Beacon's own fields and background. It asks only for missing workspace, owner and first-inbox details,
then one approval creates a real empty local database and starts Beacon. Git
identity and previously recorded setup answers are suggestions; the Northstar
demonstration is never treated as the new owner's identity. `--no-prefill`
starts an empty form; `--answers /absolute/answers.json` accepts known nonsecret
answers; `--resume` restores saved answers. The agent handoff uses the same
local installer and requires its browser session.

Local installation creates an operator and inbox through `bootstrap-operator
--local --config … --persist-to …`. It enables `BEACON_LOCAL_SIGNIN=true` with
`BEACON_SAMPLE_DATA=false`: requesting a sign-in link returns a one-use native
link only on a local loopback host. It sends no email. The installed source's
`src/ext/config.ts` receives the approved workspace identity and colour.
`pnpm dev` reopens this installation using ignored `.seed/beacon-local*` state.
Bootstrap refuses an existing workspace; inspect failures before trying again.
This installer supports local installation; hosted setup remains the explicit
commands below. Beacon has no installed workspace-art consumer, so setup offers
no artwork generation control.

The editable background is `public/setup/beacon.svg`. Shared onboarding bytes are
selected locally in `edition.json` under `runeditrun/onboarding`; changes are
adopted from Base's `onboarding/` into `scripts/base-onboarding/`. No parent
checkout is imported at runtime and no unpublished source revision is claimed.

## Local development

Use Node 26.8.1 (`.nvmrc`) and pnpm:

```bash
pnpm install
pnpm dev
```

Open <http://127.0.0.1:18474/>. The local sample environment offers `maya@northstar.example` and a one-use sign-in link. Its exchange uses native D1 sessions; loopback delivery is local. Sample data requires both `BEACON_SAMPLE_DATA=true` and a loopback request host. Configure the public owner page in `src/ext/config.ts`.

## Set up and deploy

Configure the public origin and the variables declared in `seed.json`. Use `pnpm run setup`, because bare `pnpm setup` is pnpm's own shell command.

```bash
pnpm run setup -- --dry-run --environment preview
pnpm run setup -- --environment production
pnpm run bootstrap-operator -- --environment production --name "Your name" --email you@example.com
pnpm run deploy -- --dry-run --environment production
pnpm run deploy -- --environment production
```

Setup provisions D1, R2 and the job/dead-letter queues, then writes ignored deployment identifiers and Wrangler configuration. Bootstrap applies migrations and atomically creates the first operator, Support inbox, grants and due-time policy; it refuses an existing workspace. Deploy applies migrations, builds the Worker, deploys it and checks health. `BEACON_DEPLOY_NAMESPACE` isolates resource names and deployment caches for a separate installation. Secrets belong in Cloudflare, not generated configuration.

## Widget and reviewed replies

Create a widget installation with its exact allowed host origin through the authenticated `/api/v1/widget/installations` administration API. Embed the Worker’s `/widget/v1.js` script with the returned one-time workspace key in `data-beacon-key`; the pilot harness demonstrates this setup. The widget starts visitor interaction on demand, persists incoming messages, and restores conversation history. In the authenticated Inbox, save a reviewed reply and select **Send reviewed reply**. The widget reads the reply and acknowledges it under the exact visitor session; the operator sees the recorded delivery state. This journey creates no case. Duplicate messages remain one record, and denied or failed sends expose their state.

The hosted pilot at [Beacon on JustEvery](https://beacon-support-pilot-20260912.james-d16.workers.dev) passed this journey, including reconnect, duplicate handling and access denials. Its operator browser used a short-lived native session fixture, subsequently revoked. One actual magic-link email request received SendGrid acceptance; mailbox delivery and a real emailed-token exchange were not established. See `HANDOVER.md` and `tests/pilot/README.md` for evidence and the reusable acceptance harness.

## Select outbound mail

`MAIL_PROVIDER=resend` is the default. `MAIL_PROVIDER=sendgrid` selects SendGrid using `SENDGRID_API_KEY`, `MAIL_FROM`, distinct `NOTICE_FROM`, and `BEACON_PUBLIC_ORIGIN`. Resend ingress is independently configured and requires its own credentials; widget ingress does not require Resend. Required configuration fails by name at startup.

Provider acceptance retains its message ID and does not establish delivery. SendGrid has no idempotency guarantee: ambiguous submissions remain reviewable without automatic resubmission, including recovery after a process loss or provider change. The pilot does not establish live Resend ingress, SendGrid delivery webhooks or complete offline email fallback.

## Verification and limits

```bash
pnpm verify
```

Verification checks types, contract metadata, baseline provenance, real Worker/D1 integration, the production build, emitted artifacts and Chromium journeys. The latest pilot stages passed 247 Worker tests with 189 explicit TODOs, 10 artifact checks and 19 browser tests. `test-results/baseline-report.json` records incomplete clauses; `pnpm baseline:strict` requires complete or accepted-superseded baseline evidence.

Credential-free verification CI does not deploy. The 1.0 buyer-artifact command deliberately refuses this incomplete checkpoint. External operations remain unavailable, and a real Intercom import has not been accepted. `CONTRACT.md` defines the complete intended product; `HANDOVER.md` records current implementation, evidence and remaining work. `seed.json` declares capabilities and configuration. `visual/` holds interface evidence; `design/` retains visual provenance rather than application code.

## Author and publish source

This repository is Beacon's authoritative edition source. All source is editable,
including shared components, core behavior, schema, UI and infrastructure.
`edition.json` records independently selected source origins; `sources.lock.json`
records effective bytes and retained comparison baselines. The historical
`composition.lock.json` records the former assembly only and is not a writer or
an assertion that present local source equals that assembly.

```sh
node scripts/operations.mjs describe
pnpm source:inspect
pnpm source:check
# After editing, stage the intended source before recording its new identity:
git add <changed-paths>
pnpm source:changes
pnpm source:lock
git add sources.lock.json .edition/sources
git commit -m 'Describe the accepted product change'
pnpm source:check
# From a clean commit, create a new portable source repository:
pnpm source:release -- /absolute/new-source-repository
```

The adjacent `.release.json` receipt travels separately from Git. Verify it with
`node scripts/edition-authoring/cli.mjs receipt /absolute/source.release.json`.
Source publication does not deploy resources. Run the same frozen install,
verification and operating commands in a clone or release. Comparison origins
provide update context; the owner's agent chooses integration and verifies
recorded intent, applicable guarantees and prior-data transitions. Preserve
already-applied migration bytes. Complete product acceptance remains governed
by ACCEPTANCE.md and the existing incomplete clause registry.
