YYayaw

Feature Flags

Strategy for migrating runtime config to managed feature flags without UI drift.

Why Feature Flags Here

Use feature flags when you need runtime control without redeploying:

  • progressive rollout of behavior
  • emergency disable switches
  • environment-specific behavior without config forks
  • short-lived experiments with explicit ownership

Keep static config for constants that are not product behavior (timeouts, hard security defaults, protocol-level settings).

Current Runtime Flags

Managed flags are declared in src/config/flags.config.ts, seeded into feature_flags, and exposed in Admin → Site Settings when they are wired to application behavior.

  • theme-management
  • enable-passkey-auth
  • enable-magic-link
  • auth-multi-session-enabled
  • require-2fa
  • auth-signup-enabled
  • auth-api-keys-enabled
  • org-self-serve-creation-enabled
  • org-invitations-enabled
  • enable-scim-plugin
  • billing-enabled
  • billing-enforcement-enabled
  • toast-duration-seconds
  • toast-stack-limit
  • toast-gap-px
  • toast-expand
  • toast-position
  • settings-layout-max-width
  • actions-as-icons
  • dashboard-breadcrumbs-enabled
  • dashboard-section-navigation-enabled
  • ai-components-enabled
  • media-image-generation-enabled
  • control-plane-mcp-enabled

settings-layout-max-width controls the width of dashboard settings-style surfaces, including Better Auth cards, Products & services, Authorization, and other admin configuration panels that use the settings wrapper. Dashboard Content catalog and library surfaces also read this value so dense working pages can use the same width policy. Dashboard section roots, including /dashboard, /dashboard/admin, /dashboard/content, /dashboard/organization, /dashboard/settings, and /dashboard/test, also inherit this policy through the shared page dashboard wrapper. It supports the standard Tailwind max-width scale, the dashboard container width, and full.

actions-as-icons switches supported dashboard action groups between full text buttons and compact icon buttons with tooltips, including Content catalog actions and Yayaw Table toolbars wired to the runtime flag.

dashboard-breadcrumbs-enabled and dashboard-section-navigation-enabled control the dashboard shell navigation chrome. Both are server-side experience flags, seeded as enabled by default, and can be disabled independently from Admin → Site Settings when evaluating alternate dashboard navigation patterns.

control-plane-mcp-enabled is the server-side kill switch for Codex-facing MCP control-plane tools. It is seeded as disabled by default and should be checked by MCP/API entry points before allowing Yayaw operations through the control plane.

Runtime Access Pattern

The Flags SDK is the canonical declaration and discovery contract. Yayaw keeps feature_flags as the internal site-settings provider, exposes metadata through the Vercel Flags discovery endpoint, and can evaluate PostHog-backed keys through the PostHog adapter when the slug is listed in POSTHOG_FLAG_KEYS.

Use getManagedFlagValues([...]) or getManagedBooleanFlagValues([...]) in server layouts, providers, dashboard navigation, auth runtime config, and any other hot path that needs multiple flags. Single-flag helpers are kept for narrow compatibility paths, but repeated unit reads should not be added to request critical code.

Client components may only consume flags whose managed definition has exposeClient: true. Those values are loaded server-side with loadClientRuntimeFlags(), hydrated into RuntimeFlagsProvider, and revalidated with TanStack Query. Security, auth, authz, billing enforcement, and MCP flags must remain server-side sources of truth.

Custom Flags

Flags that are present in feature_flags but are not declared in MANAGED_FEATURE_FLAGS are treated as Custom Flags. The admin page generates controls for them automatically from the stored DB value:

  • booleans render as switches
  • numbers render as numeric inputs
  • strings render as text inputs
  • objects, arrays, and null values render as JSON text areas

Custom Flags are free-form runtime values. They are only used by the application when code explicitly calls getFlag("custom-slug") or one of the typed DB fallback helpers with that slug.

Deprecated rollout flags such as blocks-ai-plan-v1, blocks-ai-plan-persistence-v1, blocks-ai-plan-trigger-worker-v1, page-ai-deep-refinement-enabled, and pages-wysiwyg-v1 are hidden from the admin UI and removed by the seed because they no longer represent useful site settings.

Non-Negotiable Contract: Logic + UI

Any flag that controls a feature must gate both:

  • backend/plugin behavior
  • user-facing UI entry points

Example: auth flags now control Better Auth plugins and visible UI cards/views. If a plugin is off but UI still renders controls, users can reach dead paths.

Priority Auth/Org Flags

Current rollout priorities:

  1. auth-signup-enabled
  • Controls sign-up availability in auth UI and auth server options.
  • Replaces static toggling in auth config when running invitation-only periods.
  1. auth-api-keys-enabled
  • Controls API key plugin and API key screens.
  • Useful when rolling out API access gradually by customer tier.
  1. auth-multi-session-enabled
  • Controls the Better Auth multi-session plugin, the security sessions card, and the account-switching card in account settings.
  • Useful when you want a single active session model for stricter environments.
  1. org-self-serve-creation-enabled
  • Controls whether users can create organizations themselves.
  • Useful for enterprise setups where organizations are provisioned centrally.
  1. org-invitations-enabled
  • Controls invitation flows for adding members.
  • Allows temporarily freezing growth while keeping existing organizations usable.

What Should Stay Config/Env (Not Flags)

  • crypto/secrets and provider credentials
  • DB connection/runtime infra knobs
  • protocol/security invariants that must not drift at runtime
  • static routes, locale contracts, build config, and image optimizer config
  • billing catalog data, Stripe price IDs, and plan limits
  • true emergency maintenance hard switch (MAINTENANCE_MODE)

Maintenance mode in Yayaw is intentionally env-based and middleware-driven:

  • MAINTENANCE_MODE
  • MAINTENANCE_MODE_END_DATE

Implementation Pattern

  1. Add the managed definition in src/config/flags.config.ts with:
  • stable slug
  • category
  • explicit default value
  • clear description
  1. Read through one server-side accessor:
  • getFlag(key) for unified PostHog-first lookup with DB fallback
  • getManagedBooleanFlagValue(slug) for typed boolean gates
  1. Apply dual gating:
  • server behavior
  • UI visibility
  1. Add docs:
  • include flag in this page and architecture notes
  • explain whether it appears in Runtime settings or Custom Flags
  1. Validate:
  • enabled and disabled states
  • permission boundaries
  • no dead links/routes in UI

Seed Contract

The seed creates missing managed flags and repairs name, description, and category metadata. It does not overwrite enabled or value for existing rows, so admin choices made in Site Settings survive deploys and reseeds.

Definition of Done for New Flags

  • slug and description added in seed
  • server behavior gated
  • UI surface gated
  • no broken routes when disabled
  • docs updated
  • content/llm/llm-source.md updated when assistant guidance changes
  • generated assistant docs refreshed with bun run docs:llm:generate
  • CI checks pass (check, tsc, build, docs integrity)