> ## Documentation Index
> Fetch the complete documentation index at: https://docs.auction-rise.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Feature Flags

> Global and workspace-level feature flags with plan-based gating and admin management.

# Feature Flags

Feature flags let you ship code dark, roll out to specific workspaces, or gate features by subscription plan — all without redeploying.

## How Flags Work

Each flag has three resolution layers checked in order:

1. **Workspace override** — a workspace-specific `true`/`false` stored in the `workspace_overrides` JSONB column. Overrides the global state for that workspace.
2. **Plan-based gating** — (hook point, not yet implemented) check the workspace's active plan against `plan_ids`.
3. **Global default** — `enabled_globally` boolean on the flag row.

## Checking a Flag

```typescript theme={null}
import { checkFlag } from "@/lib/flags/actions";

// In a server action or server component
const isEnabled = await checkFlag("new-dashboard", workspaceId);
if (!isEnabled) redirect("/dashboard");
```

For client-side gating, use `FeatureFlagProvider` and the `useFlag()` hook (build these on top of `getFlags()` if needed).

## Flag Schema

```typescript theme={null}
type FeatureFlag = {
  id: string;
  name: string;
  description: string | null;
  enabled_globally: boolean;
  plan_ids: string[];                      // Plans that get this feature
  workspace_overrides: Record<string, boolean>; // Per-workspace on/off
  created_at: string;
  updated_at: string;
};
```

## Managing Flags

Super admins manage flags via the admin panel or directly via server actions:

```typescript theme={null}
import { getFlags, setFlag, setWorkspaceOverride } from "@/lib/flags/actions";

// Turn a flag on globally
await setFlag("new-dashboard", true);

// Force-enable for one workspace (overrides global)
await setWorkspaceOverride("new-dashboard", workspaceId, true);

// Remove the workspace override (falls back to global)
await setWorkspaceOverride("new-dashboard", workspaceId, null);
```

## Creating a New Flag

Add a row to the `feature_flags` table:

```sql theme={null}
INSERT INTO feature_flags (name, description, enabled_globally)
VALUES ('new-dashboard', 'Redesigned dashboard UI', false);
```

Then check it in code with `checkFlag("new-dashboard", workspaceId)`.

## Plan-Based Gating

The `plan_ids` column is reserved for subscription-based gating. To implement it, extend the `checkFlag()` function in `lib/flags/actions.ts` to look up the workspace's active plan from your subscriptions table and return `true` if the plan ID is in `flag.plan_ids`.

<Note>
  The hook point is already in the code as a TODO comment in `checkFlag()`. Wire it up after you have subscription records in your database.
</Note>

## RLS

The `feature_flags` table uses RLS: all authenticated users can read flags, only super admins can write. This lets you safely call `getFlags()` from any authenticated server component without leaking sensitive state.
