Add onboarding doc-test harness

Disposable rig that runs the global onboarding-tester agent against the
developer SDK-integration journey: boots a fresh keysat fixture, mints a
merchant-onboard scoped key, serves keysat-docs as the published corpus,
scaffolds a pristine Next.js/TS proof-of-work, and has the agent gate it
docs-only. Stage 1 (no payments) reached completed-clean over three runs;
see onboarding-harness/STAGE1-RESULT.md. Stage 2 (regtest buyer-pays) is
gated on the agent-payment-connect scope work.
This commit is contained in:
Grant
2026-06-16 22:48:09 -05:00
parent 3afac078d4
commit 7a1c70ab9b
19 changed files with 632 additions and 0 deletions
@@ -0,0 +1,5 @@
node_modules/
.next/
next-env.d.ts
*.tsbuildinfo
.env*.local
@@ -0,0 +1,34 @@
# Acme Reports — proof-of-work app
A deliberately tiny Next.js (App Router) + TypeScript app. It shows a small
analytics table for free and offers a **Pro export** (CSV download) at
`GET /api/export`.
**In its pristine state the Pro export is ungated** — anyone can download it.
Your job, as the integrator, is to put it behind a Keysat license: only a
holder of a valid license for this product should be able to export.
This README describes *your own app* — you may read it freely. It tells you
nothing about how Keysat works; for that, use only the Keysat docs you were
pointed at.
## Run it
```sh
npm install # already done for you in the sandbox
npm run dev # starts on http://localhost:4311
```
- `GET http://localhost:4311/` — the free report view.
- `GET http://localhost:4311/api/export` — the Pro export (CSV). Currently free.
## What "done" looks like
After integration:
- `GET /api/export` returns the CSV **only** when a valid license is present.
- With **no** license, or a **tampered/invalid** one, `/api/export` is blocked
(a 4xx, not the CSV).
How the app learns the user's license key (env var, file, header) is your
call — pick whatever the Keysat docs suggest and note it.
@@ -0,0 +1,20 @@
import { ROWS, toCsv } from "@/lib/reports";
// The "Pro export" endpoint.
//
// PRISTINE STATE: this feature is currently FREE — anyone who hits it gets the
// CSV. The goal of this proof-of-work is to gate it behind a valid Keysat
// license so that only paying customers can export.
//
// (How you wire that in is up to the integrator following the Keysat docs.)
export async function GET() {
const csv = toCsv(ROWS);
return new Response(csv, {
status: 200,
headers: {
"Content-Type": "text/csv",
"Content-Disposition": 'attachment; filename="acme-report.csv"',
},
});
}
@@ -0,0 +1,16 @@
import type { ReactNode } from "react";
export const metadata = {
title: "Acme Reports",
description: "A tiny analytics tool with a paid Pro export.",
};
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body style={{ fontFamily: "system-ui, sans-serif", maxWidth: 640, margin: "3rem auto", padding: "0 1rem" }}>
{children}
</body>
</html>
);
}
@@ -0,0 +1,34 @@
import { ROWS } from "@/lib/reports";
export default function Home() {
return (
<main>
<h1>Acme Reports</h1>
<p>Your signups and revenue by region. Viewing is free.</p>
<table cellPadding={6} style={{ borderCollapse: "collapse" }}>
<thead>
<tr>
<th align="left">Region</th>
<th align="right">Signups</th>
<th align="right">Revenue (sats)</th>
</tr>
</thead>
<tbody>
{ROWS.map((r) => (
<tr key={r.region}>
<td>{r.region}</td>
<td align="right">{r.signups}</td>
<td align="right">{r.revenueSats.toLocaleString()}</td>
</tr>
))}
</tbody>
</table>
<h2 style={{ marginTop: "2rem" }}>Pro export</h2>
<p>
Download the full dataset as CSV. This is a paid feature:{" "}
<a href="/api/export">/api/export</a>.
</p>
</main>
);
}
@@ -0,0 +1,18 @@
// The "data" behind Acme Reports. The free tier lets you view it on screen;
// the paid "Pro export" feature lets you download it as CSV. That export is
// the feature we want to gate behind a Keysat license.
export type Row = { region: string; signups: number; revenueSats: number };
export const ROWS: Row[] = [
{ region: "North", signups: 412, revenueSats: 1_240_000 },
{ region: "South", signups: 318, revenueSats: 980_500 },
{ region: "East", signups: 521, revenueSats: 1_702_300 },
{ region: "West", signups: 274, revenueSats: 731_900 },
];
export function toCsv(rows: Row[]): string {
const header = "region,signups,revenue_sats";
const body = rows.map((r) => `${r.region},${r.signups},${r.revenueSats}`);
return [header, ...body].join("\n") + "\n";
}
@@ -0,0 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
// Keep the proof-of-work app deliberately boring: no experimental flags,
// so any onboarding friction is attributable to Keysat, not to Next.js.
};
export default nextConfig;
@@ -0,0 +1,22 @@
{
"name": "acme-reports",
"version": "0.1.0",
"private": true,
"description": "Pristine proof-of-work app for the Keysat onboarding harness. A tiny Next.js report tool whose 'Pro export' feature is meant to be gated behind a Keysat license.",
"scripts": {
"dev": "next dev -p 4311",
"build": "next build",
"start": "next start -p 4311"
},
"dependencies": {
"next": "15.1.6",
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@types/node": "22.10.7",
"@types/react": "19.0.7",
"@types/react-dom": "19.0.3",
"typescript": "5.7.3"
}
}
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": { "@/*": ["./*"] }
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}