Release 0.15.0: Amplitude analytics (cookie-consent gated)

Roadmap item #13. Ships the frontend Amplitude SDK behind the v0.13.0
cookie/privacy consent gate. The analytics wrapper lives at
`frontend/src/lib/analytics.js` and exposes `track`, `identify`, and
`anonymize` over a stable nine-event taxonomy (Page Viewed, RFC
Viewed, User Signed In / Signed Out, RFC Proposed, PR Opened, Comment
Posted, Beta Access Requested, Admin Permission Decision). The
wrapper reads consent via `getConsent()` / `onConsentChange()` from
`frontend/src/lib/consent.js` (v0.13.0); the SDK module is
dynamically `import()`-ed only after `consent.analytics === true`,
and a later granted→denied flip calls `setOptOut(true)` so events
stop without a page reload. The Amplitude API key is read from
`VITE_AMPLITUDE_API_KEY` at build time; when unset the wrapper logs
one console warning and no-ops so dev environments keep working.

Wired into App.jsx (route-change Page Viewed + sign-in identify +
sign-out anonymize), Login.jsx (User Signed In with method =
otc/passcode/trust-device, Beta Access Requested on capture-profile
submit), ProposeModal.jsx (RFC Proposed), RFCView.jsx (RFC Viewed),
PRModal.jsx (PR Opened), RFCDiscussionPanel.jsx (Comment Posted with
surface=discussion), PRView.jsx (Comment Posted with surface=pr),
Admin.jsx (Admin Permission Decision with action=grant/revoke).
Event bodies carry only ids and enums — no titles, no comment
bodies, no names, no emails. The user binding passes only
`String(viewer.id)`.

Secret-vs-overlay binding caveat: Amplitude browser API keys are
visible in the shipped bundle via dev tools. Per the roadmap, the
key is still bound through `flotilla secret set` (rather than
`flotilla overlay set`) to keep all-keys-in-Secret-Manager
regularity for the OHM deployment; the CHANGELOG documents the
choice. Operator pre-deploy gesture (in the Upgrade steps block):
`pbpaste | ... ohm-rfc-app-flotilla secret set ohm-rfc-app
AMPLITUDE_API_KEY` — the wave-paused step before this release can
deploy.

No backend events ship in this release (Amplitude SaaS holds the
events); no schema migration; backend is unchanged. Migration slot
015 remains unused and available for the next minor that needs a
schema bump. New dependency: `@amplitude/analytics-browser`.
`VITE_AMPLITUDE_API_KEY` documented in `frontend/.env.example` with
the binding-choice caveat.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ben Stull
2026-05-28 04:40:04 -07:00
parent b3f1b15f65
commit 0fd8c52724
14 changed files with 663 additions and 12 deletions
+5
View File
@@ -11,6 +11,7 @@
import { useEffect, useState } from 'react'
import { proposeRFC } from '../api'
import { EVENTS, track } from '../lib/analytics'
function slugify(title) {
return title
@@ -52,6 +53,10 @@ export default function ProposeModal({ viewer, onClose, onSubmitted }) {
pitch: pitch.trim(),
tags,
})
// v0.15.0 — analytics: fire on the §9.1 propose-RFC submit.
// Slug is a stable, low-cardinality identifier (kebab-case
// ascii); title and pitch stay out of the event body.
track(EVENTS.RFC_PROPOSED, { rfc_slug: slug })
onSubmitted?.(result)
} catch (err) {
setError(err.message || 'Submission failed.')