f036871111
Icon-render and the source-available license are intentionally not blockers.
81 lines
5.1 KiB
Markdown
81 lines
5.1 KiB
Markdown
# ROADMAP — Keysat
|
||
|
||
Longer-term backlog. Near-term state lives in `AGENTS.md` → Current state.
|
||
|
||
## Payments & subscriptions
|
||
|
||
- Per-profile SMTP override (schema fields exist from the keysat-smtp-emails plan; needs the form + send path).
|
||
- Rail-preference editing UI — only matters when two providers on one profile both serve the same rail; settable today via `PUT /v1/admin/merchant-profiles/:id/rail-preferences/:rail`.
|
||
- Keysat-side dedup cache for Zaprite contacts (same buyer purchasing recurring twice can create duplicate Zaprite contacts).
|
||
- Zaprite declined-card / expired-profile failure-body shapes are undocumented — harden `try_auto_charge_zaprite` once observed in production.
|
||
|
||
## Agent compatibility & scoped API keys
|
||
|
||
- **Agent-delegable payment-provider connect** (approved, not urgent — see
|
||
`plans/agent-payment-connect-scope.md`). Add an à-la-carte `payment_providers:write` scope
|
||
(never bundled into `merchant-onboard`), gated by a daemon-level **sandbox-mode flag** as the
|
||
outer gate (production daemons reject scoped connect entirely) with a **network gate** inner
|
||
defense (regtest/testnet/signet only, fail-closed to mainnet). BTCPay network is derived from
|
||
an on-chain address prefix (no `server/info` field exists).
|
||
- **Onboarding doc-harness — Stage 2 (Path 2, regtest buyer-pays).** Gated on slices 3–5 above.
|
||
Stage 1 (Path 1, no payments) shipped `completed-clean` this session — harness at
|
||
`licensing-service-startos/onboarding-harness/`, record in its `STAGE1-RESULT.md`. Stage 2
|
||
reuses the harness but boots the fixture with `KEYSAT_SANDBOX_MODE` on, stands up a Dockerized
|
||
BTCPay regtest stack (bitcoind regtest + NBXplorer + Postgres + BTCPay) as additional
|
||
disposable infra, and grants the agent `merchant-onboard` + `payment_providers:write`. Goal:
|
||
the agent connects BTCPay (regtest) over the API and drives a test buyer payment that activates
|
||
a license, with zero master-key steps. The walkthrough must be explicitly labeled
|
||
regtest/test-network and must state that connecting a real mainnet wallet is the one
|
||
operator-reserved step **by design** (a key that can redirect funds stays with the human) — a
|
||
security feature, not a gap.
|
||
|
||
## Packaging & distribution
|
||
|
||
- Start9 Community Registry submission — a 2026-06-17 spec check found the wrapper passes the functional
|
||
criteria (manifest, interfaces, health check, backup/restore, BTCPay dep, actions). Remaining gap before
|
||
submission: add a `prepare.sh` to set up a clean Debian box for the first build (copy the one from
|
||
`hello-world-startos`), then run the on-box manual verification (install / backup / restore / logs).
|
||
Submission criteria themselves remain unpublished; reach out to Start9 when ready. (Icon-render and the
|
||
source-available license are intentionally not treated as blockers.)
|
||
|
||
## Licensing model
|
||
|
||
- Evaluate Elastic License v2 vs the current custom `LicenseRef-Keysat-1.0` (parked decision).
|
||
|
||
## Validation
|
||
|
||
- Re-test `KEYSAT_INTEGRATION.md` against a fresh downstream app to confirm a clean one-shot SDK integration.
|
||
- End-to-end Zaprite sandbox pass on the multi-merchant-profile webhook routing before relying on it in production.
|
||
|
||
## Design (contract conformance)
|
||
|
||
The brand contract now lives in `design/DESIGN.md` + `design/tokens.tokens.json` (distilled
|
||
2026-06-16 from the prior Claude Design system, now archived in `design/_imports/`). A
|
||
`design-checker` audit (2026-06-16) found high fidelity overall, with these items where the
|
||
**code contradicts the contract's stated rules** or bypasses the token scale:
|
||
|
||
**Blockers (code violates a named "never" rule):**
|
||
- Gold used as an actionable *fill* (contract: gold is accent/border only, never a fill).
|
||
(a) admin SPA `.featured-pill-toggle.on` → `web/index.html:418`; (b) admin sidebar
|
||
upgrade CTA `#tier-banner-cta` → `web/index.html:537-542`. Fix to navy-fill or
|
||
gold-border/text.
|
||
- Primary buy CTA uses pill radius `999px` (contract: buttons are `r-md` 8px; pill is
|
||
badges-only) — `keysat-xyz-landing/index.html:384-385`. Set to 8px.
|
||
|
||
**Structural (headline):**
|
||
- All three surfaces inline their own copy of the CSS variables instead of importing the
|
||
canonical `design/brand/palette.css` (landing :33-56, docs.css :7-21, admin :9-25). Copies
|
||
are currently exact but one edit from drift. Consolidate onto `palette.css`.
|
||
|
||
**Token gaps / drift (decide: tokenize the as-built value, or snap to an existing token):**
|
||
- `14px` card radius used throughout the marketing landing — not a token (between `r-lg` 12
|
||
and `r-xl` 18). Snap to a token or add one.
|
||
- Wordmark letter-spacing is `0.30em` (landing) vs `0.28em` (docs/admin) and has no token —
|
||
pick one value, add a `letterSpacing.wordmark` token.
|
||
- Semantic badge *text* colors (`#205c47`/`#7a5814`/`#8a2828`) are darker one-offs with no
|
||
token — add `semantic.*-text` tokens or reference existing ones.
|
||
- Syntax-highlight colors hardcoded as hex (`#d4b985`=gold-400, `#a6b7cf`=navy-300) — switch
|
||
to `var()`. One admin hex `#f6f1e7` isn't a token (closest cream-50/100) — reconcile.
|
||
- Sticky-header backdrop on docs/admin (`blur(10px)`/`blur(8px)`) diverges from the contract's
|
||
`blur(12px)` — align if a single header treatment is wanted.
|