Purchase flow: name -> placeholder -> configure via the shipped PlanConfigurator
-> Paddle overlay with custom_data -> paste install UUID to link and issue.
lineItemsFor mirrors the Go catalogue.LineItems/billable exactly (base included
in exactly one place). ManageBillingButton opens the hosted portal. Paddle token
and env are baked into the build, never fetched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Implements spec 7 tasks 2-10 on top of the six-plan payload from task 1.
Admin: plans re-keyed on (deployment, tier); new catalogue collection holds
every Paddle price ID (one row per priceable component); new entitlements
collection holds desired beside granted. admin/internal/catalogue owns both
folds — entitlement to licence limits, and entitlement to Paddle line items —
so the base allowance is subtracted in exactly one place. licensing.Issue now
snapshots the instance's granted entitlement, never desired. Free is enforced
per account AND deployment. Staff endpoints for plans, catalogue and
entitlements; Free self-hosted can be claimed and renewed on its annual term;
the reaper stays cloud-only.
Server: enforces the monitor cap, audit-log retention (daily sweep, skips
Unlimited and lapsed instances), and gates the OIDC callback. Unset limits are
filled from the seed plan at the single decode site so old blobs never read as
zero.
Frontends: adminsite gains a catalogue price-ID editor, six-plan allowance
screen, and a catalogue-driven PlanConfigurator mounted on the staff instance
page. web shows monitors, audit retention and support level on the licence page.
Docs: CLAUDE.md, spec index and plan 5 preamble updated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The members panel is absent for self-hosted instances rather than disabled:
the backend refuses those, and a panel rendering controls the server will
reject is a panel that lies.
/auth/me now reports the caller's account role, so the UI hides what the
backend would refuse rather than discovering it in an error toast.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds the create form with a live slug preview, a renew action inside the
seven-day window, and a deletion countdown that renders only when the
backend has actually promised a date.
The progress bar denominator now follows the tier; a 30-day Free licence
was rendering as an 8% sliver against the hardcoded 365.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The repo's first frontend test setup: Vitest, React Testing Library, jsdom.
Scoped to the flows that lose money or leak data when broken, per spec 4.
lib/api.ts collapses every failure into three the UI can act on:
NotConnected (unreachable, or no URL baked in), ApiError 401 (redirect), and
ApiError with the backend's own message, which is customer-facing and shown
verbatim rather than replaced with something vaguer.
The not-connected panel names the variable, the value baked in, and both
reasons it fails -- unreachable from the browser, or missing from admin's
ADMIN_ORIGIN. Proven by test before it existed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>