feat: self-serve developer access for paid tiers, split BYOK into its own permission (v0.72.0)
Splits what was one isDeveloper flag (gating webhooks, API keys, AND BYOK together) into two independent permissions: - isDeveloper (webhooks + self-serve API keys): admin-toggled as before, but now ALSO self-serve -- PATCH /api/v1/users/me/developer-access lets any paid-tier (tier !== "free") user turn it on themselves, no added fee. Free tier still needs an admin grant. Turning it off is always self-serve regardless of tier, since revoking your own access needs no gatekeeping. canSelfServeDeveloperAccess() in lib/permissions.ts is the single check for "is this tier eligible." - isByokEnabled (BYOK AI provider keys): new column, admin-only, no self-serve path at all -- routing real AI provider spend through Epicure on the user's own key warrants a manual admin check-in that webhooks/API access don't need. requireByok() replaces requireDeveloper() on the three ai-keys routes. Migration adds is_byok_enabled and grandfathers in anyone who already has a BYOK key configured (the earlier grandfather migration only covered the combined isDeveloper flag, which BYOK no longer reads). Settings UI: webhooks/API-keys pages show a self-serve "Enable" toggle for paid-tier non-developers instead of the locked notice (still shown to free-tier users), plus a "Disable developer access" link once enabled. Settings -> AI's BYOK section now checks isByokEnabled instead of isDeveloper -- unaffected by the self-serve change, still fully admin-gated. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -105,7 +105,7 @@ Status legend: **Exists** (fully working) · **Partial** (works but with a real
|
||||
| **Self-serve billing portal** | **Missing** | No Stripe customer portal; tier changes today only happen via direct admin edit at `/admin/users/[id]` | — |
|
||||
| Admin dashboard | Exists | 13 sections: overview, insights/analytics, users, invites, recipe moderation, reports, support, tiers, webhooks, audit logs, storage, AI config, site settings, changelog | `apps/web/app/admin/**` |
|
||||
| Feature flags (per-tier) vs feature prefs (per-user cosmetic) | Exists, two distinct systems | Flags gate 3 AI capabilities by tier; prefs let users hide 7 nav sections, no billing implication | `apps/web/lib/{feature-flags,feature-prefs}.ts` |
|
||||
| **Developer permission** (new, 2026-07-22) | Exists | A fourth, orthogonal access dimension — `users.isDeveloper`, admin-toggled in `admin/users/[id]`, gates user webhooks + self-serve API keys + BYOK. Previously all three had zero gating (any logged-in user, any tier). Existing users with a webhook/API key/BYOK key were grandfathered in by the migration. Deliberately a single `hasDeveloperAccess()` function so a future subscription-tier auto-grant is a one-line change, not a redesign. | `apps/web/lib/permissions.ts`, `apps/web/lib/api-auth.ts` (`requireDeveloper`) |
|
||||
| **Developer permission** (2026-07-22, split 2026-07-23) | Exists | Two separate, orthogonal permissions — not one. `users.isDeveloper` gates webhooks + self-serve API keys: admin-toggled always, *and* self-serve toggleable by the user themselves once on a paid tier (no added fee) via `PATCH /api/v1/users/me/developer-access`; free-tier users still need an admin grant. `users.isByokEnabled` gates BYOK separately, admin-only, no self-serve — routing real AI spend through Epicure on the user's own key warrants a manual check-in. Previously all three (webhooks/API keys/BYOK) shared one flag with zero self-serve path. Existing users with a webhook/API key were already grandfathered for `isDeveloper`; a second migration grandfathered existing BYOK users into `isByokEnabled` specifically. | `apps/web/lib/permissions.ts` (`hasDeveloperAccess`, `hasByokAccess`, `canSelfServeDeveloperAccess`), `apps/web/lib/api-auth.ts` (`requireDeveloper`, `requireByok`) |
|
||||
| User webhooks (personal automation) | Exists | 7 events, Zapier-style, requires developer access | `apps/web/lib/webhooks.ts` |
|
||||
| Admin ops webhooks (site-wide) | Exists | 3 events (signup, ticket, report) — admin-only, unrelated to developer access | `apps/web/lib/admin-webhooks.ts` |
|
||||
| Support tickets ↔ Gitea two-way sync | Exists, verified real | Outbound (create/comment/close mirror to Gitea issue) + inbound (signed webhook receiver, dedup, loop-safe) | `apps/web/lib/gitea.ts`, `apps/web/app/api/webhooks/gitea/route.ts` |
|
||||
|
||||
Reference in New Issue
Block a user