forked from Mike/freno-dev
`marketing/metrics/weekly.md` has been a placeholder since the marketing tree landed — it promised a funnel and the one thing that moved, and nothing produced it. This adds the producer: one command reads the live databases and rewrites the file. `scripts/weekly-metrics.ts` writes `marketing/metrics/weekly.md` from `VisitorAnalytics` (visits, downloads, campaigns) and the-nook's `trials`, `licenses`, `activations` (the paid funnel). It needs four env vars — TURSO_DB_URL/TOKEN and NOOK_DB_URL/TOKEN — and imports no server env, so the job runs from a checkout that has no Stripe or Apple secrets. `src/server/weekly-metrics.ts` holds the queries and the renderer, taking both connections as arguments; the tests run them against an in-memory SQLite shaped like production, the same way the backfill suite does. The campaign breakdown groups exactly as `getAnalyticsSummary.topCampaigns` does (top 10, untagged excluded), so the weekly read and /analytics cannot drift into different label sets. The first real report says more about the instrumentation than about demand, and the renderer computes that rather than asserting it: - every addressed row the table has ever held (12,035 of 12,048) is loopback, so "unique visitors" is one host and per-channel reach cannot be read; - the landing door and the file route both write `/api/downloads/thenook`, so "download click" and "DMG served" are one label — one served click writes two rows, a failed click one, a Sparkle update one; - `POST /api/the-nook/checkout` records nothing, so checkout start is only a page-view proxy; - `VisitorAnalytics` has no host dimension, so the Nook's `/` is freno.me's `/`. Those three gaps are reported beside the numbers, not papered over. Week 0 (2026-10-22 → 2026-10-29): visit 61, download 156, trial 2, checkout 0, purchase 0, activation 0 — and the one thing that moved is the download stage, 0 → 156, because the label was introduced that week. Tests: `bun test src/server/weekly-metrics.test.ts` — 12 pass, 0 fail. The full suite's 15 failures are pre-existing: this checkout's .env lacks NOOK_LICENSE_PRIVATE_KEY, NOOK_STRIPE_SK/WEBHOOK/PRICE and LINEAGE_JWT_SECRET, and every failure is that env validation. Scripts/ is gitignored, so `scripts/weekly-metrics.ts` was added with `-f`, the way the existing tracked scripts are. FRE-202
75 lines
2.5 KiB
JSON
75 lines
2.5 KiB
JSON
{
|
|
"name": "freno.(dev/me)",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vinxi dev",
|
|
"dev-flush": "vinxi dev --env-file=.env",
|
|
"build": "vinxi build",
|
|
"start": "NODE_OPTIONS='--import ./public/instrument.server.mjs' vinxi start",
|
|
"test": "bun test",
|
|
"test:security": "bun test src/server/security/",
|
|
"test:watch": "bun test --watch",
|
|
"test:coverage": "bun test --coverage",
|
|
"perf": "bun run scripts/perf-test.ts",
|
|
"perf:compare": "bun run scripts/perf-compare.ts",
|
|
"metrics:weekly": "bun --env-file=.env scripts/weekly-metrics.ts",
|
|
"nook:grant": "NODE_ENV=production bun --env-file=.env scripts/grant-nook-license.ts"
|
|
},
|
|
"dependencies": {
|
|
"@aws-sdk/client-s3": "^3.953.0",
|
|
"@aws-sdk/s3-request-presigner": "^3.953.0",
|
|
"@libsql/client": "^0.15.15",
|
|
"@sentry/solidstart": "^10.67.0",
|
|
"@solidjs/meta": "^0.29.4",
|
|
"@solidjs/router": "^0.15.0",
|
|
"@solidjs/start": "^1.1.0",
|
|
"@tailwindcss/vite": "^4.0.7",
|
|
"@tiptap/core": "^3.14.0",
|
|
"@tiptap/extension-code-block-lowlight": "^3.14.0",
|
|
"@tiptap/extension-details": "^3.14.0",
|
|
"@tiptap/extension-details-content": "^2.26.2",
|
|
"@tiptap/extension-details-summary": "^2.26.2",
|
|
"@tiptap/extension-image": "^3.14.0",
|
|
"@tiptap/extension-link": "^3.14.0",
|
|
"@tiptap/extension-subscript": "^3.14.0",
|
|
"@tiptap/extension-superscript": "^3.14.0",
|
|
"@tiptap/extension-table": "^3.14.0",
|
|
"@tiptap/extension-table-cell": "^3.14.0",
|
|
"@tiptap/extension-table-header": "^3.14.0",
|
|
"@tiptap/extension-table-row": "^3.14.0",
|
|
"@tiptap/extension-task-item": "^3.14.0",
|
|
"@tiptap/extension-task-list": "^3.14.0",
|
|
"@tiptap/extension-text-align": "^3.14.0",
|
|
"@tiptap/pm": "^3.14.0",
|
|
"@tiptap/starter-kit": "^3.14.0",
|
|
"@trpc/client": "^10.45.2",
|
|
"@trpc/server": "^10.45.2",
|
|
"@tursodatabase/api": "^1.9.2",
|
|
"bcrypt": "^6.0.0",
|
|
"es-toolkit": "^1.43.0",
|
|
"fast-diff": "^1.3.0",
|
|
"google-auth-library": "^10.5.0",
|
|
"highlight.js": "^11.11.1",
|
|
"jose": "^6.1.3",
|
|
"mermaid": "^11.12.2",
|
|
"motion": "^12.23.26",
|
|
"solid-js": "^1.9.5",
|
|
"solid-tiptap": "^0.8.0",
|
|
"ua-parser-js": "^2.0.7",
|
|
"uuid": "^13.0.0",
|
|
"vinxi": "^0.5.7",
|
|
"zod": "^4.2.1"
|
|
},
|
|
"engines": {
|
|
"node": "24.x"
|
|
},
|
|
"devDependencies": {
|
|
"@sentry/vite-plugin": "^5.4.0",
|
|
"@tailwindcss/typography": "^0.5.19",
|
|
"@types/bcrypt": "^6.0.0",
|
|
"playwright": "^1.57.0",
|
|
"prettier": "^3.7.4",
|
|
"prettier-plugin-tailwindcss": "^0.7.2"
|
|
}
|
|
}
|