feat: per-tier feature toggles for recipe variations/pairings (v0.50.0)
Admins can now disable specific AI features per tier from Admin > Tier Limits — new feature_flags table (feature x tier -> enabled, defaulting to true so adding a new gated feature never needs a backfill). Covers recipe variations, drink pairing, and meal pairing to start. When disabled for a user's tier, the button stays visible (with a small lock badge) but opens an upgrade dialog instead of running; the API route rejects the call server-side either way (requireFeatureEnabled, re-reads tier from the DB rather than trusting the session's cache, same rationale as checkAndIncrementTierLimit). The upgrade dialog is informational only — no Stripe checkout exists yet (STRIPE_PLAN.md is still just a plan) — its CTA links to /support prefilled as an upgrade-interest suggestion. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,14 +5,25 @@ import { db, supportTickets, eq, desc } from "@epicure/db";
|
||||
import { SupportManager } from "@/components/support/support-manager";
|
||||
import { getMessages } from "@/lib/i18n/server";
|
||||
import { getPublicUrl } from "@/lib/storage";
|
||||
import { FEATURE_DEFINITIONS } from "@/lib/feature-flags";
|
||||
|
||||
export const metadata: Metadata = {};
|
||||
|
||||
export default async function SupportPage() {
|
||||
export default async function SupportPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{ upgrade?: string }>;
|
||||
}) {
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
if (!session) return null;
|
||||
const m = getMessages((session.user as { locale?: string }).locale);
|
||||
|
||||
const { upgrade } = await searchParams;
|
||||
const upgradeFeature = FEATURE_DEFINITIONS.find((f) => f.key === upgrade);
|
||||
const prefill = upgradeFeature
|
||||
? { type: "suggestion" as const, title: `Interested in upgrading for: ${upgradeFeature.label}` }
|
||||
: undefined;
|
||||
|
||||
const rows = await db.query.supportTickets.findMany({
|
||||
where: eq(supportTickets.userId, session.user.id),
|
||||
orderBy: desc(supportTickets.createdAt),
|
||||
@@ -26,6 +37,7 @@ export default async function SupportPage() {
|
||||
<p className="text-muted-foreground text-sm mt-1">{m.support.subtitle}</p>
|
||||
</div>
|
||||
<SupportManager
|
||||
prefill={prefill}
|
||||
initialTickets={rows.map((r) => ({
|
||||
id: r.id,
|
||||
type: r.type,
|
||||
|
||||
Reference in New Issue
Block a user